diff --git a/README.md b/README.md
index a9b48d77..909b977a 100644
--- a/README.md
+++ b/README.md
@@ -45,8 +45,6 @@ workshops, and a variety of other needs.
1. Check out this repository to a machine with [Node.js] and [Yarn].
1. `git submodule update --init`
1. `yarn install`
-1. Either build or obtain the file `engine/wwtlib/bin/wwtlib.js` as described
- below.
1. `yarn lint` (uses [ESLint])
1. `yarn build` creates:
1. The core engine package in the `engine/` package.
@@ -80,8 +78,7 @@ The most important subdirectories are:
[monorepo]: https://en.wikipedia.org/wiki/Monorepo
-- `@wwtelescope/engine` in `engine/`, the core engine code transpiled from C# and
- wrapped in TypeScript annotations
+- `@wwtelescope/engine` in `engine/`, the core engine code with TypeScript annotations
- `@wwtelescope/engine-pinia` in `engine-pinia/`, a higher-level package that turns the
engine into a reusable [Vue]/[Pinia] component
- `@wwtelescope/embed` in `embed/`, a web application that turns WWT into a
@@ -99,41 +96,9 @@ subdirectory. That module has been superseded by the Pinia version.
[Vuex]: https://vuex.vuejs.org/
-## The `engine/wwtlib/bin/wwtlib.js` file
+## Building the code
-There’s one big wrinkle to the build process: the bulk of the engine code is
-actually C# code in the directory `engine/wwtlib/`. It’s forked from
-[wwt-windows-client] and is transpiled into JavaScript using an unreleased
-version of [ScriptSharp], an unmaintained tool. Fortunately, that build process
-results in a single file, `engine/wwtlib/bin/wwtlib.js`, that you can download
-from our CI systems if you’re not able to perform a Visual Studio build.
-
-[wwt-windows-client]: https://github.com/WorldWideTelescope/wwt-windows-client
-[ScriptSharp]: https://github.com/nikhilk/scriptsharp
-
-To build the engine library starting from C#:
-
-1. You need a Windows machine with Visual Studio 2017. Other versions of Visual
- Studio might also work.
-1. Open the `engine/WebGLEngine.sln` solution and build the project it contains.
- This should create the file `engine/wwtlib/bin/wwtlib.js`.
-
-Otherwise, check out the latest continuous integration build of this repository,
-download the `scriptsharp` artifact, and copy the `wwtlib.js` file to the location
-given above. (To find the artifact, go to the appropriate build in this project's
-[pipeline] on [Azure DevOps]). Under 'Related', select '9 published', and download
-artifacts for `scriptsharp`). If you want to change the C# code, you can file a pull
-request and access the artifacts associated with your pull request builds.
-
-[Azure DevOps]: https://azure.microsoft.com/en-us/services/devops/?nav=min
-[pipeline]: https://dev.azure.com/aasworldwidetelescope/WWT/_build?definitionId=21
-
-
-
-## Building the rest of the code
-
-Besides the creation of the file `engine/wwtlib/bin/wwtlib.js`, virtually
-everything in this repository is built using standard [Node.js]/[Yarn] tooling.
+Code in this repository is built using standard [Node.js]/[Yarn] tooling.
These tools must be installed before you can do anything else. To set up your
checkout, follow the instructions in the [Developers’ Quick Start][dqs] above.
diff --git a/ci/azure-job-setup.yml b/ci/azure-job-setup.yml
index c3a77664..bdf4eb2d 100644
--- a/ci/azure-job-setup.yml
+++ b/ci/azure-job-setup.yml
@@ -1,4 +1,4 @@
-# Copyright 2020-2022 the .NET Foundation
+# Copyright 2020-2023 the .NET Foundation
# Licensed under the MIT License
# Setup steps for the build and deployment processes.
@@ -70,12 +70,6 @@ steps:
inputs:
versionSpec: '16'
- - bash: |
- set -xeuo pipefail
- mkdir -p engine/wwtlib/bin
- cp $PIPELINE_WORKSPACE/scriptsharp/wwtlib.js engine/wwtlib/bin/
- displayName: Restore ScriptSharp wwtlib.js
-
- bash: yarn install
displayName: Install Yarn dependencies
diff --git a/ci/azure-main-build.yml b/ci/azure-main-build.yml
index 6e7bb8cc..8369c658 100644
--- a/ci/azure-main-build.yml
+++ b/ci/azure-main-build.yml
@@ -1,9 +1,7 @@
-# Copyright 2020-2022 the .NET Foundation
+# Copyright 2020-2023 the .NET Foundation
# Licensed under the MIT License
-# Main build stage. The ScriptSharp stage has already run, creating a Cranko
-# release commit bundle and the magic wwtlib.js JavaScript file. With those in
-# hand, these parts of the build can run on any platform (yay!).
+# Main build stage.
parameters:
- name: 'zolaVersion'
@@ -40,7 +38,6 @@ jobs:
- bash: |
set -xeuo pipefail
mkdir -p $ARTIFACT_STAGING/engine-hosted
- cp engine/wwtlib/bin/wwtlib.js $ARTIFACT_STAGING/engine-hosted/wwtlib.js
cp engine/src/index.js $ARTIFACT_STAGING/engine-hosted/wwtsdk.js
cp engine/src/index.min.js $ARTIFACT_STAGING/engine-hosted/wwtsdk.min.js
cp engine/src/index.d.ts $ARTIFACT_STAGING/engine-hosted/wwtsdk.d.ts
diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml
index d5510533..08b98178 100644
--- a/ci/azure-pipelines.yml
+++ b/ci/azure-pipelines.yml
@@ -1,4 +1,4 @@
-# Copyright 2020 the .NET Foundation
+# Copyright 2020-2023 the .NET Foundation
# Licensed under the MIT License
trigger:
@@ -8,9 +8,9 @@ trigger:
- rc
stages:
-- stage: ScriptSharpBuild
+- stage: Prep
jobs:
- - template: azure-scriptsharp-build.yml
+ - template: azure-prep.yml
- stage: MainBuild
jobs:
diff --git a/ci/azure-scriptsharp-build.yml b/ci/azure-prep.yml
similarity index 67%
rename from ci/azure-scriptsharp-build.yml
rename to ci/azure-prep.yml
index 532d1175..ff3d56a9 100644
--- a/ci/azure-scriptsharp-build.yml
+++ b/ci/azure-prep.yml
@@ -1,8 +1,7 @@
-# Copyright 2020-2022 the .NET Foundation
+# Copyright 2020-2023 the .NET Foundation
# Licensed under the MIT License
-# Create the Cranko release commit and build the engine JavaScript using
-# ScriptSharp on Windows.
+# Create the Cranko release commit.
jobs:
- job: main
@@ -55,28 +54,3 @@ jobs:
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)/git-release'
artifactName: git-release
-
- # ScriptSharp build
-
- - task: MSBuild@1
- displayName: Build WebGL Engine with ScriptSharp
- inputs:
- solution: 'engine/WebGlEngine.sln'
- msbuildVersion: '16.0'
- msbuildArchitecture: 'x64'
- clean: true
-
- - task: CopyFiles@2
- displayName: Stage ScriptSharp artifacts
- inputs:
- sourceFolder: '.'
- contents: |
- engine/wwtlib/bin/wwtlib.js
- targetFolder: $(Build.ArtifactStagingDirectory)
- cleanTargetFolder: true
-
- - task: PublishPipelineArtifact@0
- displayName: Publish ScriptSharp artifacts
- inputs:
- artifactName: scriptsharp
- targetPath: $(Build.ArtifactStagingDirectory)/engine/wwtlib/bin
diff --git a/docs/engine/engine-pinia-index.md b/docs/engine/engine-pinia-index.md
index a6de596a..b7566003 100644
--- a/docs/engine/engine-pinia-index.md
+++ b/docs/engine/engine-pinia-index.md
@@ -91,7 +91,23 @@ createApp(App, {
Note that for now, **you can only include one WWT component in each app**,
because the WWT engine library maintains global state. To work around this, use
-iframes.
+iframes.
+
+Alternatively, it is possible to mount separate *full instances* of
+the application to the same web page by passing in a unique `id` when creating
+the Vue app using the `customId` prop.
+
+```ts
+...
+
+createApp(App, {
+ wwtNamespace: "mywwt",
+ customId: "myCustomId"
+ })
+ .use(wwtPinia)
+ .component('WorldWideTelescope', WWTComponent)
+ .mount("#app");
+```
Finally, if you’re using [Webpack], you may run into a pitfall because this
library must explicitly depend on the Vue package to obtain its TypeScript
diff --git a/embed-common/CHANGELOG.md b/embed-common/CHANGELOG.md
index 5b522bd4..599c96a2 100644
--- a/embed-common/CHANGELOG.md
+++ b/embed-common/CHANGELOG.md
@@ -1,47 +1,8 @@
-# rc: micro bump
+# See elsewhere for changelog
-- Add a `type: module` field to the `package.json` file (#264, @pkgw). This more
- accurately reflects the files that we're distributing.
+This project’s release notes are curated from the Git history of its main
+branch. You can find them by looking at [the version of this file on the
+`release` branch][branch] or the [GitHub release history][gh-releases].
-
-# @wwtelescope/embed-common 0.3.3 (2022-11-30)
-
-- No code changes.
-- Update the `package.json` file to align with new Yarn-based build system (#217, @Carifio24, @pkgw).
-
-
-# @wwtelescope/embed-common 0.3.2 (2022-04-01)
-
-- Fix a URL typo in the package.json file (@Carifio24).
-
-
-# @wwtelescope/embed-common 0.3.1 (2021-06-03)
-
-- No code changes, just syncing up Cranko with changes in the repository.
-
-
-# @wwtelescope/embed-common 0.3.0 (2021-01-27)
-
-This release contains a **breaking change** relating to a rework of how
-"settings" are expressed in TypeScript. The previous system was pretty limited
-and limiting; the new system is much more functional.
-
-- Move enumLookup out of here into engine-types
-- Track API changes in how settings are expressed
-- Upgrade TypeDoc and TypeScript
-- Correct temporary GitHub URLs in the package.json files
-
-
-# @wwtelescope/embed-common 0.2.1 (2020-09-23)
-
-- No code changes; issuing a new release for the Cranko switchover.
-
-
-# [0.2.0](https://github.com/pkgw/wwt-webgl-engine/compare/@wwtelescope/embed-common@0.2.0-beta.0...@wwtelescope/embed-common@0.2.0) (2020-06-12)
-
-- Export a tourUrl setting
-
-
-# [0.1.0](https://github.com/pkgw/wwt-webgl-engine/compare/@wwtelescope/embed-common@0.1.0-beta.0...@wwtelescope/embed-common@0.1.0) (2020-05-23)
-
-**Note:** Version bump only for package @wwtelescope/embed-common
+[branch]: https://github.com/WorldWideTelescope/wwt-webgl-engine/blob/release/embed-common/CHANGELOG.md
+[gh-releases]: https://github.com/WorldWideTelescope/wwt-webgl-engine/releases
diff --git a/engine-helpers/CHANGELOG.md b/engine-helpers/CHANGELOG.md
index 76a0f4f7..698011eb 100644
--- a/engine-helpers/CHANGELOG.md
+++ b/engine-helpers/CHANGELOG.md
@@ -1,140 +1,8 @@
-# rc: micro bump
+# See elsewhere for changelog
-- Add a `type: module` field to the `package.json` file (#264, @pkgw). This more
- accurately reflects the files that we're distributing.
+This project’s release notes are curated from the Git history of its main
+branch. You can find them by looking at [the version of this file on the
+`release` branch][branch] or the [GitHub release history][gh-releases].
-
-# @wwtelescope/engine-helpers 0.15.0 (2023-06-08)
-
-- Have the `addImagesetToRepository` method return an imageset (#256, @pkgw).
-
-
-# @wwtelescope/engine-helpers 0.14.0 (2023-03-31)
-
-- Expose the "addImageSetToRepository" function through the engine stack (#241, @pkgw)
-- Remove unnecessary `name` parameter in the frame export code (#240, @Carifio24)
-
-
-# @wwtelescope/engine-helpers 0.13.0 (2023-03-29)
-
-- Expose the new, expanded frame-capture functionality which can capture a
- sequence of frames (#239, @Carifio24).
-
-
-# @wwtelescope/engine-helpers 0.12.0 (2023-03-20)
-
-- Expose the engine's new frame capture functionality (#235, @Carifio24).
-
-
-# @wwtelescope/engine-helpers 0.11.1 (2023-02-27)
-
-- No code changes; just making Cranko happy.
-
-
-# @wwtelescope/engine-helpers 0.11.0 (2023-02-15)
-
-- Expose the "freestanding mode" that was added to the engine (#230, @pkgw).
-
-
-# @wwtelescope/engine-helpers 0.10.0 (2023-02-13)
-
-- Expose some new engine settings that make make it possible to customize the
- colors used for various coordinate grid overlays and the heigh of the
- constellation names (#226, @Carifio24).
-
-
-# @wwtelescope/engine-helpers 0.9.0 (2023-01-19)
-
-- Expose new engine APIs for getting the amount of time that basic "goto"
- movements will take to execute (#222, @Carifio24)
-
-
-# @wwtelescope/engine-helpers 0.8.3 (2022-11-30)
-
-- No code changes.
-- Cleanups and improvements to the build and packaging infrastructure (#217,
- @Carifio24, @pkgw). The source repository is now based on Yarn.
-
-
-# @wwtelescope/engine-helpers 0.8.2 (2022-04-01)
-
-- Fix a URL typo in the package.json file (@Carifio24).
-
-
-# @wwtelescope/engine-helpers 0.8.1 (2021-11-17)
-
-- Fix bad copy/paste-o that made the `polylineannotation` module pretty useless
- (#155, @Carifio24).
-
-
-# @wwtelescope/engine-helpers 0.8.0 (2021-09-20)
-
-- Provide a homogeneous set of settings interfaces, building on the new
- interfaces provided by some of the lower-level packages (@pkgw, #131, #134).
- There is a new suite of functions for extracting, copying, and storing
- settings, which make it easier to bridge WWT settings into systems external to
- WWT itself, such as Vue and Vuex.
-- Properly type `StretchFitsLayerOptions.stretch` as a `ScaleTypes`. This
- is technically a breaking change although the TypeScript compiler doesn't
- always seem to mind if you still initialize the field with a number.
-
-
-# @wwtelescope/engine-helpers 0.7.0 (2021-07-23)
-
-- Add various wrappers for catalog HiPS functionality: an async-ified wrapper
- for getCatalogHipsDataInView, an API to pull settings out of a spreadsheet
- layer, and a new async addCatalogHipsByName implementation (#126, @pkgw)
-
-
-# @wwtelescope/engine-helpers 0.6.0 (2021-06-03)
-
-- Add helpers relating to some of the new APIs in the 7.11 series of the engine.
- These include roll controls, optional recursive loading of WTML collections,
- showing warnings if WebGL 2.0 isn't available, URL-based loading of imageset
- layers, controlling "goto" functionality when loading imageset layers, and
- catalog HiPS APIs.
-
-
-# @wwtelescope/engine-helpers 0.5.0 (2021-01-27)
-
-This release contains a **breaking change** relating to a rework of how
-"settings" are expressed in TypeScript. The previous system was pretty limited
-and limiting; the new system is much more functional.
-
-- Many new APIs and types related to our improved system for handling settings.
-- Expose the layer manager as one of the core state objects
-- Add wrappers for layer mutations
-- Implement FITS layer colormap control
-- Implement FITS layer stretch control
-- Upgrade TypeDoc and TypeScript
-- Correct temporary GitHub URLs in the package.json files
-
-
-# @wwtelescope/engine-helpers 0.4.0 (2020-12-30)
-
-- A variety of new APIs to support better tour playback (#73, @pkgw)
- - `seekToTourTimecode()`
- - `getEffectiveTourTimecode()`
- - `getIsTourPlaying()`
- - `loadTour()`
- - a simple hook for detecting when a tour finishes playing
-
-
-# @wwtelescope/engine-helpers 0.3.1 (2020-09-23)
-
-- No code changes; issuing a new release for the Cranko switchover.
-
-
-# [0.3.0](https://github.com/pkgw/wwt-webgl-engine/compare/@wwtelescope/engine-helpers@0.3.0-beta.1...@wwtelescope/engine-helpers@0.3.0) (2020-06-12)
-
-- Export helpers relating to tour playback
-
-
-# [0.2.0](https://github.com/pkgw/wwt-webgl-engine/compare/@wwtelescope/engine-helpers@0.2.0-beta.0...@wwtelescope/engine-helpers@0.2.0) (2020-06-09)
-
-- Expose setForegroundOpacity
-
-
-# [0.1.0](https://github.com/pkgw/wwt-webgl-engine/compare/@wwtelescope/engine-helpers@0.1.0-beta.2...@wwtelescope/engine-helpers@0.1.0) (2020-05-23)
-
-**Note:** Version bump only for package @wwtelescope/engine-helpers
+[branch]: https://github.com/WorldWideTelescope/wwt-webgl-engine/blob/release/engine-helpers/CHANGELOG.md
+[gh-releases]: https://github.com/WorldWideTelescope/wwt-webgl-engine/releases
diff --git a/engine-pinia/CHANGELOG.md b/engine-pinia/CHANGELOG.md
index 61ecc8f6..81bd91f8 100644
--- a/engine-pinia/CHANGELOG.md
+++ b/engine-pinia/CHANGELOG.md
@@ -1,8 +1,69 @@
-# See elsewhere for changelog
+# rc: minor bump
-This project’s release notes are curated from the Git history of its main
-branch. You can find them by looking at [the version of this file on the
-`release` branch][branch] or the [GitHub release history][gh-releases].
+- Add a `customId` prop the WWT component (#265, @nmearl). This allows you to
+ precisely control the DOM id of the `
` that the app will bind to, in case
+ the default ID selection (`wwtcmpt${N}`) does not work. In particular, if you
+ have multiple independent WWT Vue apps within the same DOM tree, you can use
+ this to avoid clashes.
-[branch]: https://github.com/WorldWideTelescope/wwt-webgl-engine/blob/release/engine-pinia/CHANGELOG.md
-[gh-releases]: https://github.com/WorldWideTelescope/wwt-webgl-engine/releases
+
+# @wwtelescope/engine-pinia 0.7.0 (2023-06-08)
+
+- Have the `addImagesetToRepository` method return an imageset (#256, @pkgw).
+
+
+# @wwtelescope/engine-pinia 0.6.0 (2023-03-31)
+
+- Expose the "addImageSetToRepository" function through the engine stack (#241, @pkgw)
+
+
+# @wwtelescope/engine-pinia 0.5.0 (2023-03-29)
+
+- Expose the new, expanded frame-capture functionality which can capture a
+ sequence of frames (#239, @Carifio24).
+
+
+# @wwtelescope/engine-pinia 0.4.0 (2023-03-20)
+
+- Expose the engine's new frame capture functionality (#235, @Carifio24).
+
+
+# @wwtelescope/engine-pinia 0.3.1 (2023-02-27)
+
+- No code changes; just making Cranko happy.
+
+
+# @wwtelescope/engine-pinia 0.3.0 (2023-02-15)
+
+- Expose the "freestanding mode" that was added to the engine (#230, @pkgw). It
+ can be activated by setting a Vue "prop" on the WWT Vue component.
+
+
+# @wwtelescope/engine-pinia 0.2.0 (2023-01-19)
+
+- Expose new engine APIs for getting the amount of time that basic "goto"
+ movements will take to execute (#222, @Carifio24)
+- Add new store APIs for accessing generic layers and imageset layers in the
+ Pinia framework: `layerById`, `imagesetLayerById` (#223, @Carifio24)
+
+
+# @wwtelescope/engine-pinia 0.1.0 (2022-11-30)
+
+This package wraps the core rendering engine of the [AAS] [WorldWide
+Telescope][wwt-home] (WWT) stack ([@wwtelescope/engine]) into a plugin for the
+[Pinia] state management library. It is the successor to the
+[@wwtelescope/engine-vuex] package, which targeted Vuex 3.0. Pinia is
+effectively Vuex 5, according to its authors, and is the recommended state
+management system for Vue 3.
+
+[AAS]: https://aas.org/
+[wwt-home]: https://worldwidetelescope.org/home/
+[@wwtelescope/engine]: https://www.npmjs.com/package/@wwtelescope/engine
+[Pinia]: https://pinia.vuejs.org/
+[@wwtelescope/engine-vuex]: https://www.npmjs.com/package/@wwtelescope/engine-vuex
+
+Changes in this package compared to [@wwtelescope/engine-vuex]:
+
+- Adapt to Pinia (#215, @Carifio24). Duh.
+- Cleanups and improvements to the build and packaging infrastructure (#217,
+ @Carifio24, @pkgw). The source repository is now based on Yarn.
diff --git a/engine-pinia/src/Component.vue b/engine-pinia/src/Component.vue
index 57fe9f51..5a5b85b9 100644
--- a/engine-pinia/src/Component.vue
+++ b/engine-pinia/src/Component.vue
@@ -23,6 +23,7 @@ export default defineComponent({
props: {
wwtNamespace: { type: String, default: "wwt", required: true },
wwtFreestandingAssetBaseurl: String,
+ customId: String
},
data(): ComponentData {
@@ -45,7 +46,7 @@ export default defineComponent({
created() {
// Create a globally unique ID for the div that the WWT engine can latch onto.
- const uid = `wwtcmpt${idCounter}`;
+ const uid = this.customId === undefined ? `wwtcmpt${idCounter}` : this.customId;
Object.defineProperties(this, {
uniqueId: { get() { return uid; } },
});
diff --git a/engine-types/CHANGELOG.md b/engine-types/CHANGELOG.md
index eebe7a19..804e549c 100644
--- a/engine-types/CHANGELOG.md
+++ b/engine-types/CHANGELOG.md
@@ -1,75 +1,8 @@
-# rc: micro bump
+# See elsewhere for changelog
-- Add a `type: module` field to the `package.json` file (#264, @pkgw). This more
- accurately reflects the files that we're distributing.
+This project’s release notes are curated from the Git history of its main
+branch. You can find them by looking at [the version of this file on the
+`release` branch][branch] or the [GitHub release history][gh-releases].
-
-# @wwtelescope/engine-types 0.6.4 (2022-11-30)
-
-- No code changes. Make another release because the package of the previous
- release was accidentally incomplete, due to being produced manually as the
- kinks were being worked out in the updated build system.
-
-
-# @wwtelescope/engine-types 0.6.3 (2022-11-30)
-
-- No code changes.
-- Update the `package.json` file to align with new Yarn-based build system
- (#217, @Carifio24, @pkgw).
-
-
-# @wwtelescope/engine-types 0.6.2 (2022-04-01)
-
-- Fix a URL typo in the package.json file (@Carifio24).
-
-
-# @wwtelescope/engine-types 0.6.1 (2021-11-17)
-
-- Correctly handle Date types in `isBaseSpreadSheetLayerSetting` (#155, @Carifio24).
-
-
-# @wwtelescope/engine-types 0.6.0 (2021-09-20)
-
-- Wire in the "Layer.enabled" setting
-- Delist "settings" that can't be modified. This is nominally a breaking change,
- although such settings would have been of extremely limited use anyway.
-
-
-# @wwtelescope/engine-types 0.5.0 (2021-07-20)
-
-- Expose some engine color settings (#125, @pkgw). Unlike certain other
- settings, these are exposed in the API as strings, so they can go
- into this package.
-
-
-# @wwtelescope/engine-types 0.4.0 (2021-06-03)
-
-- Expose new core catalog-HiPS types used by the engine; namely,
- `BaseVoTableLayerSetting` and related items.
-
-
-# @wwtelescope/engine-types 0.3.0 (2021-01-27)
-
-This release contains a **breaking change** relating to a rework of how
-"settings" are expressed in TypeScript. The previous system was pretty limited
-and limiting; the new system is much more functional.
-
-- New enumerations in support of SpreadSheetLayer and ImageSetLayer
-- Rework how settings are expressed
-- Upgrade TypeDoc and TypeScript
-- Correct temporary GitHub URLs in the package.json files
-
-
-# @wwtelescope/engine-types 0.2.0 (2020-12-30)
-
-- Add the SettingsInterface
-
-
-# @wwtelescope/engine-types 0.1.1 (2020-09-23)
-
-- No code changes; issuing a new release as part of the Cranko switchover.
-
-
-# [0.1.0](https://github.com/pkgw/wwt-webgl-engine/compare/@wwtelescope/engine-types@0.1.0-beta.0...@wwtelescope/engine-types@0.1.0) (2020-05-23)
-
-**Note:** Version bump only for package @wwtelescope/engine-types
+[branch]: https://github.com/WorldWideTelescope/wwt-webgl-engine/blob/release/engine-types/CHANGELOG.md
+[gh-releases]: https://github.com/WorldWideTelescope/wwt-webgl-engine/releases
diff --git a/engine/.eslintrc.js b/engine/.eslintrc.js
index e24bd82e..8fc83189 100644
--- a/engine/.eslintrc.js
+++ b/engine/.eslintrc.js
@@ -1,16 +1,27 @@
module.exports = {
root: true,
env: {
- node: true
+ browser: true,
+ es6: true,
},
extends: [
"eslint:recommended"
],
parserOptions: {
- ecmaVersion: 2020
+ ecmaVersion: 2020,
+ sourceType: "module"
+ },
+ globals: {
+ globalThis: true, // eventually aim to remove this
},
rules: {
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
- "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off"
+ "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
+ // Temporary while we get the codebase up to speed:
+ "no-constant-condition": "off",
+ "no-empty": "off",
+ "no-extra-boolean-cast": "off",
+ "no-redeclare": "off",
+ "no-unused-vars": "off",
}
};
diff --git a/engine/.gitignore b/engine/.gitignore
index be6239f6..d242d636 100644
--- a/engine/.gitignore
+++ b/engine/.gitignore
@@ -1,6 +1,6 @@
/src/index.js
+/src/index.js.map
/src/index.min.js
+/src/index.min.js.LICENSE.txt
/tests/results.xml
/tsconfig.tsbuildinfo
-/wwtlib/bin/
-/wwtlib/obj/
diff --git a/engine/CHANGELOG.md b/engine/CHANGELOG.md
index 048f7072..84b60864 100644
--- a/engine/CHANGELOG.md
+++ b/engine/CHANGELOG.md
@@ -1,4 +1,55 @@
-# rc: micro bump
+# rc: minor bump
+
+Historically, the WWT engine in this module has consisted of JavaScript code
+that was transpiled from a C# codebase using an unmaintained tool called
+ScriptSharp. In this release, we drop the C# and work directly from JavaScript
+(#261, #262, @pkgw).
+
+The intention is that this change should be invisible to consumers of this
+module. However, a few internal APIs have been renamed as part of the
+adaptation, to better isolate dependencies. It is possible that external code
+referenced these symbols despite their internal nature, but since this is
+unsupported and we are not aware of any actual instances of this, we are not
+categorizing these as API breaks:
+
+- Some APIs in the `Planets` module/class have been moved into a new
+ `Planets3d` name
+- `RenderContext.useGl` become `render_globals.(set_)useGl`
+- `RenderContext.useGlVersion2` become `render_globals.(set_)useGlVersion2`
+- `Tile.demEnabled` become `render_globals.(set_)tileDemEnabled`
+- `Tile.prepDevice` become `render_globals.(set_)tilePrepDevice`
+- `Tile.uvMultiple` become `render_globals.(set_)tileUvMultiple`
+- `TileCache.accessID` become `render_globals.(set_)tileCacheAccessID`
+- `TileCache.addTileToQueue` become `render_globals.(set_)tileCacheAddTileToQueue`
+- `TileCache.getCachedTile` become `render_globals.(set_)tileCacheGetCachedTile`
+- `TileCache.getTile` become `render_globals.(set_)tileCacheGetTile`
+- `TileCache.removeFromQueue` become `render_globals.(set_)tileCacheRemoveFromQueue`
+- `WWTControl.singleton.freestandingMode` became `data_globals.(set_)freestandingMode`
+- `Object3d.maX_VERTICES` and `Object3d.maX_POLYGONS` have disappeared.
+
+It is also possible that the reorganization has unintentionally introduced
+changes breaking existing code or behaviors, although a great deal of effort has
+been spent to test that no visible changes have occurred. Any behavior changes
+traceable to this migration are bugs that will be fixed.
+
+The new codebase is written in plain JavaScript with ES6 (["ESM"]) module
+syntax. [Webpack] then assembles the modularized source files into a [UMD]-style
+single module file, the same form factor as delivered in previous releases. This
+new approach will dramatically ease many aspects of WWT engine development
+especially the use of JavaScript libraries and browser features, debugging, and
+streamlining the build.
+
+[Webpack]: https://webpack.js.org/
+["ESM"]: https://nodejs.org/api/esm.html#modules-ecmascript-modules
+[UMD]: https://github.com/umdjs/umd
+
+This release does *not* support building against the individual ESM module
+files, although you might be able to get such a use case to work. This is an
+obvious potential direction for future work. Another possible direction for work
+is a port to TypeScript.
+
+
+# @wwtelescope/engine 7.28.2 (2023-07-23)
- Actually use the crosshairs color setting (#260, @Carifio24).
diff --git a/engine/README.md b/engine/README.md
index 58a635b5..850af714 100644
--- a/engine/README.md
+++ b/engine/README.md
@@ -13,3 +13,21 @@ For more information, see [the main README of the wwt-webgl-engine
repository][main-readme], which contains the source for this package.
[main-readme]: https://github.com/WorldWideTelescope/wwt-webgl-engine/#readme
+
+
+## Source structure
+
+The WWT engine code originated in the C# implementation of the [WWT Windows
+Client][winclient]. Initially, this code was transpiled into JavaScript using a
+tool called [ScriptSharp], which has been unmaintained for a long time.
+
+[winclient]: https://github.com/WorldWideTelescope/wwt-windows-client/
+[ScriptSharp]: https://github.com/nikhilk/scriptsharp
+
+Currently, the engine is built from the (very human-readable) JS outputs of the
+ScriptSharp tool, stored in the `js/` subdirectory here. Code that hasn't yet
+been extracted into more idiomatic JS lives in `js/transpiled.js`.
+
+The directory `csharp_ref` contains the C# code that was used as the basis for
+the JS at the time of the switch away from ScriptSharp. To avoid confusion,
+these files will be removed as they are fully superseded by idiomatic JS.
diff --git a/engine/WebGLEngine.sln b/engine/WebGLEngine.sln
deleted file mode 100644
index 53085fa5..00000000
--- a/engine/WebGLEngine.sln
+++ /dev/null
@@ -1,21 +0,0 @@
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2013
-VisualStudioVersion = 12.0.31101.0
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "wwtlib", "wwtlib\wwtlib.csproj", "{886C426F-732F-4649-95AC-CE0395E07285}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {886C426F-732F-4649-95AC-CE0395E07285}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {886C426F-732F-4649-95AC-CE0395E07285}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {886C426F-732F-4649-95AC-CE0395E07285}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {886C426F-732F-4649-95AC-CE0395E07285}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
diff --git a/engine/esm/annotation.js b/engine/esm/annotation.js
new file mode 100644
index 00000000..293156ff
--- /dev/null
+++ b/engine/esm/annotation.js
@@ -0,0 +1,521 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Web GL support for annotations.
+//
+// Annotations all share a set of supporting primitives. Each time any
+// annotation changes the primitives, they must be regenerated if they have been
+// drawn already. It is best to do updates in large batches.
+
+import { registerType } from "./typesystem.js";
+import { ss } from "./ss.js";
+import { Vector3d } from "./double3d.js";
+import { Dates, LineList, TriangleList, TriangleFanList, PointList } from "./graphics/primitives3d.js";
+import { Tessellator } from "./graphics/tessellator.js";
+import { Color, Colors } from "./color.js";
+import { Coordinates } from "./coordinates.js";
+
+
+// wwtlib.Annotation
+
+export function Annotation() {
+ this.addedToPrimitives = false;
+ this.annotationDirty = true;
+ this._opacity = 1;
+ this._showHoverLabel = false;
+}
+
+Annotation.pointList = null;
+Annotation.lineList = null;
+Annotation.triangleFanPointList = null;
+Annotation.triangleList = null;
+Annotation.batchDirty = true;
+
+Annotation.prepBatch = function (renderContext) {
+ if (Annotation.pointList == null || Annotation.batchDirty) {
+ Annotation.pointList = new PointList(renderContext);
+ Annotation.lineList = new LineList();
+ Annotation.triangleFanPointList = new TriangleFanList();
+ Annotation.triangleList = new TriangleList();
+ Annotation.lineList.set_depthBuffered(false);
+ Annotation.triangleList.depthBuffered = false;
+ }
+};
+
+Annotation.drawBatch = function (renderContext) {
+ Annotation.batchDirty = false;
+ if (renderContext.gl == null) {
+ return;
+ }
+ if (Annotation.pointList != null) {
+ Annotation.pointList.draw(renderContext, 1, false);
+ }
+ if (Annotation.lineList != null) {
+ Annotation.lineList.drawLines(renderContext, 1);
+ }
+ if (Annotation.triangleFanPointList != null) {
+ Annotation.triangleFanPointList.draw(renderContext, 1);
+ }
+ if (Annotation.triangleList != null) {
+ Annotation.triangleList.draw(renderContext, 1, 0);
+ }
+};
+
+Annotation.separation = function (Alpha1, Delta1, Alpha2, Delta2) {
+ Delta1 = Delta1 / 180 * Math.PI;
+ Delta2 = Delta2 / 180 * Math.PI;
+ Alpha1 = Alpha1 / 12 * Math.PI;
+ Alpha2 = Alpha2 / 12 * Math.PI;
+ var x = Math.cos(Delta1) * Math.sin(Delta2) - Math.sin(Delta1) * Math.cos(Delta2) * Math.cos(Alpha2 - Alpha1);
+ var y = Math.cos(Delta2) * Math.sin(Alpha2 - Alpha1);
+ var z = Math.sin(Delta1) * Math.sin(Delta2) + Math.cos(Delta1) * Math.cos(Delta2) * Math.cos(Alpha2 - Alpha1);
+ var vvalue = Math.atan2(Math.sqrt(x * x + y * y), z);
+ vvalue = vvalue / Math.PI * 180;
+ if (vvalue < 0) {
+ vvalue += 180;
+ }
+ return vvalue;
+};
+
+Annotation.colorToUint = function (col) {
+ return (col.a) << 24 | (col.r << 16) | (col.g) << 8 | col.b;
+};
+
+Annotation.colorToUintAlpha = function (col, opacity) {
+ return opacity << 24 | col.r << 16 | col.g << 8 | col.b;
+};
+
+var Annotation$ = {
+ draw: function (renderContext) { },
+
+ get_opacity: function () {
+ return this._opacity;
+ },
+
+ set_opacity: function (value) {
+ Annotation.batchDirty = true;
+ this._opacity = value;
+ return value;
+ },
+
+ get_id: function () {
+ return this._id;
+ },
+
+ set_id: function (value) {
+ this._id = value;
+ return value;
+ },
+
+ get_tag: function () {
+ return this._tag;
+ },
+
+ set_tag: function (value) {
+ this._tag = value;
+ return value;
+ },
+
+ get_label: function () {
+ return this._label;
+ },
+
+ set_label: function (value) {
+ this._label = value;
+ return value;
+ },
+
+ get_showHoverLabel: function () {
+ return this._showHoverLabel;
+ },
+
+ set_showHoverLabel: function (value) {
+ this._showHoverLabel = value;
+ return value;
+ },
+
+ hitTest: function (renderContext, RA, dec, x, y) {
+ return false;
+ },
+
+ get_center: function () {
+ return this.center;
+ },
+
+ set_center: function (value) {
+ this.center = value;
+ return value;
+ }
+};
+
+registerType("Annotation", [Annotation, Annotation$, null]);
+
+
+// wwtlib.Circle
+
+export function Circle() {
+ this._fill$1 = false;
+ this._skyRelative$1 = false;
+ this._strokeWidth$1 = 1;
+ this._radius$1 = 10;
+ this._lineColor$1 = Colors.get_white();
+ this._fillColor$1 = Colors.get_white();
+ this._ra$1 = 0;
+ this._dec$1 = 0;
+ Annotation.call(this);
+}
+
+var Circle$ = {
+ get_fill: function () {
+ return this._fill$1;
+ },
+
+ set_fill: function (value) {
+ Annotation.batchDirty = true;
+ this._fill$1 = value;
+ return value;
+ },
+
+ get_skyRelative: function () {
+ return this._skyRelative$1;
+ },
+
+ set_skyRelative: function (value) {
+ Annotation.batchDirty = true;
+ this._skyRelative$1 = value;
+ return value;
+ },
+
+ get_lineWidth: function () {
+ return this._strokeWidth$1;
+ },
+
+ set_lineWidth: function (value) {
+ Annotation.batchDirty = true;
+ this._strokeWidth$1 = value;
+ return value;
+ },
+
+ get_radius: function () {
+ return this._radius$1;
+ },
+
+ set_radius: function (value) {
+ Annotation.batchDirty = true;
+ this._radius$1 = value;
+ return value;
+ },
+
+ get_lineColor: function () {
+ return this._lineColor$1.toString();
+ },
+
+ set_lineColor: function (value) {
+ Annotation.batchDirty = true;
+ this._lineColor$1 = Color.load(value);
+ return value;
+ },
+
+ get_fillColor: function () {
+ return this._fillColor$1.toString();
+ },
+
+ set_fillColor: function (value) {
+ Annotation.batchDirty = true;
+ this._fillColor$1 = Color.fromName(value);
+ return value;
+ },
+
+ setCenter: function (ra, dec) {
+ Annotation.batchDirty = true;
+ this._ra$1 = ra / 15;
+ this._dec$1 = dec;
+ this.center = Coordinates.raDecTo3d(this._ra$1, this._dec$1);
+ },
+
+ draw: function (renderContext) {
+ var onScreen = true;
+ var rad = this._radius$1;
+ if (this._skyRelative$1) {
+ rad /= renderContext.get_fovScale() / 3600;
+ }
+ var screenSpacePnt = renderContext.WVP.transform(this.center);
+ if (screenSpacePnt.z < 0) {
+ onScreen = false;
+ }
+ if (Vector3d.dot(renderContext.get_viewPoint(), this.center) < 0.55) {
+ onScreen = false;
+ }
+ if (renderContext.gl != null) {
+ if (Annotation.batchDirty || this.annotationDirty) {
+ var up = Vector3d.create(0, 1, 0);
+ var xNormal = Vector3d.cross(this.center, up);
+ var yNormal = Vector3d.cross(this.center, xNormal);
+ var r = this._radius$1 / 44;
+ var segments = 72;
+ var radiansPerSegment = Math.PI * 2 / segments;
+ var vertexList = [];
+ for (var j = 0; j <= segments; j++) {
+ var x = Math.cos(j * radiansPerSegment) * r;
+ var y = Math.sin(j * radiansPerSegment) * r;
+ vertexList.push(Vector3d.create(this.center.x + x * xNormal.x + y * yNormal.x, this.center.y + x * xNormal.y + y * yNormal.y, this.center.z + x * xNormal.z + y * yNormal.z));
+ }
+ if (this._strokeWidth$1 > 0 && vertexList.length > 1) {
+ var lineColorWithOpacity = this._lineColor$1._clone();
+ lineColorWithOpacity.a = Math.round(lineColorWithOpacity.a * this.get_opacity());
+ for (var i = 0; i < (vertexList.length - 1); i++) {
+ Annotation.lineList.addLine(vertexList[i], vertexList[i + 1], lineColorWithOpacity, new Dates(0, 1));
+ }
+ }
+ if (this._fill$1) {
+ var fillColorWithOpacity = this._fillColor$1._clone();
+ fillColorWithOpacity.a = Math.round(fillColorWithOpacity.a * this.get_opacity());
+ var pos = Vector3d.create(this.center.x, this.center.y, this.center.z);
+ vertexList.splice(0, 0, pos);
+ Annotation.triangleFanPointList.addShape(vertexList, fillColorWithOpacity, new Dates(0, 1));
+ }
+ this.annotationDirty = false;
+ }
+ } else {
+ if (onScreen) {
+ var ctx = renderContext.device;
+ ctx.save();
+ ctx.globalAlpha = this.get_opacity();
+ ctx.beginPath();
+ ctx.arc(screenSpacePnt.x, screenSpacePnt.y, rad, 0, Math.PI * 2, true);
+ ctx.lineWidth = this._strokeWidth$1;
+ ctx.fillStyle = this._fillColor$1.toString();
+ if (this._fill$1) {
+ ctx.fill();
+ }
+ ctx.globalAlpha = 1;
+ ctx.strokeStyle = this._lineColor$1.toString();
+ ctx.stroke();
+ ctx.restore();
+ }
+ }
+ },
+
+ hitTest: function (renderContext, RA, dec, x, y) {
+ if (ss.emptyString(this.get_id())) {
+ return false;
+ }
+ var rad = this._radius$1;
+ if (!this._skyRelative$1) {
+ rad *= renderContext.get_fovScale() / 3600;
+ }
+ return Annotation.separation(RA, dec, this._ra$1, this._dec$1) < rad;
+ }
+};
+
+registerType("Circle", [Circle, Circle$, Annotation]);
+
+
+// wwtlib.Poly
+
+export function Poly() {
+ this._points$1 = [];
+ this._fill$1 = false;
+ this._strokeWidth$1 = 1;
+ this._lineColor$1 = Colors.get_white();
+ this._fillColor$1 = Colors.get_white();
+ Annotation.call(this);
+}
+
+var Poly$ = {
+ addPoint: function (x, y) {
+ Annotation.batchDirty = true;
+ this._points$1.push(Coordinates.raDecTo3d(x / 15, y));
+ },
+
+ get_fill: function () {
+ return this._fill$1;
+ },
+
+ set_fill: function (value) {
+ Annotation.batchDirty = true;
+ this._fill$1 = value;
+ return value;
+ },
+
+ get_lineWidth: function () {
+ return this._strokeWidth$1;
+ },
+
+ set_lineWidth: function (value) {
+ Annotation.batchDirty = true;
+ this._strokeWidth$1 = value;
+ return value;
+ },
+
+ get_lineColor: function () {
+ return this._lineColor$1.toString();
+ },
+
+ set_lineColor: function (value) {
+ Annotation.batchDirty = true;
+ this._lineColor$1 = Color.fromName(value);
+ return value;
+ },
+
+ get_fillColor: function () {
+ return this._fillColor$1.toString();
+ },
+
+ set_fillColor: function (value) {
+ Annotation.batchDirty = true;
+ this._fillColor$1 = Color.fromName(value);
+ return value;
+ },
+
+ draw: function (renderContext) {
+ if (renderContext.gl != null) {
+ if (Annotation.batchDirty || this.annotationDirty) {
+ //todo can we save this work for later?
+ var vertexList = this._points$1;
+
+ if (this._strokeWidth$1 > 0 && this._points$1.length > 1) {
+ var lineColorWithOpacity = this._lineColor$1._clone();
+ lineColorWithOpacity.a = Math.round(lineColorWithOpacity.a * this.get_opacity());
+ for (var i = 0; i < (this._points$1.length - 1); i++) {
+ Annotation.lineList.addLine(vertexList[i], vertexList[i + 1], lineColorWithOpacity, new Dates(0, 1));
+ }
+ Annotation.lineList.addLine(vertexList[this._points$1.length - 1], vertexList[0], lineColorWithOpacity, new Dates(0, 1));
+ }
+ if (this._fill$1) {
+ var fillColorWithOpacity = this._fillColor$1._clone();
+ fillColorWithOpacity.a = Math.round(fillColorWithOpacity.a * this.get_opacity());
+ var indexes = Tessellator.tesselateSimplePoly(vertexList);
+ for (var i = 0; i < indexes.length; i += 3) {
+ Annotation.triangleList.addSubdividedTriangles(vertexList[indexes[i]], vertexList[indexes[i + 1]], vertexList[indexes[i + 2]], fillColorWithOpacity, new Dates(0, 1), 2);
+ }
+ }
+ this.annotationDirty = false;
+ }
+ } else {
+ var ctx = renderContext.device;
+ ctx.save();
+ ctx.globalAlpha = this.get_opacity();
+ ctx.beginPath();
+ var first = true;
+ var $enum1 = ss.enumerate(this._points$1);
+ while ($enum1.moveNext()) {
+ var pnt = $enum1.current;
+ var screenSpacePnt = renderContext.WVP.transform(pnt);
+ if (screenSpacePnt.z < 0) {
+ ctx.restore();
+ return;
+ }
+ if (Vector3d.dot(renderContext.get_viewPoint(), pnt) < 0.75) {
+ ctx.restore();
+ return;
+ }
+ if (first) {
+ first = false;
+ ctx.moveTo(screenSpacePnt.x, screenSpacePnt.y);
+ }
+ else {
+ ctx.lineTo(screenSpacePnt.x, screenSpacePnt.y);
+ }
+ }
+ ctx.closePath();
+ ctx.lineWidth = this._strokeWidth$1;
+ if (this._fill$1) {
+ ctx.fillStyle = this._fillColor$1.toString();
+ ctx.fill();
+ }
+ ctx.strokeStyle = this._lineColor$1.toString();
+ ctx.globalAlpha = 1;
+ ctx.stroke();
+ ctx.restore();
+ }
+ }
+};
+
+registerType("Poly", [Poly, Poly$, Annotation]);
+
+
+// wwtlib.PolyLine
+
+export function PolyLine() {
+ this._points$1 = [];
+ this._strokeWidth$1 = 1;
+ this._lineColor$1 = Colors.get_white();
+ Annotation.call(this);
+}
+
+var PolyLine$ = {
+ addPoint: function (x, y) {
+ Annotation.batchDirty = true;
+ this._points$1.push(Coordinates.raDecTo3d(x / 15, y));
+ },
+
+ get_lineWidth: function () {
+ return this._strokeWidth$1;
+ },
+
+ set_lineWidth: function (value) {
+ Annotation.batchDirty = true;
+ this._strokeWidth$1 = value;
+ return value;
+ },
+
+ get_lineColor: function () {
+ return this._lineColor$1.toString();
+ },
+
+ set_lineColor: function (value) {
+ Annotation.batchDirty = true;
+ this._lineColor$1 = Color.fromName(value);
+ return value;
+ },
+
+ draw: function (renderContext) {
+ if (renderContext.gl != null) {
+ if (Annotation.batchDirty || this.annotationDirty) {
+ //todo can we save this work for later?
+ var vertexList = this._points$1;
+ if (this._strokeWidth$1 > 0) {
+ var lineColorWithOpacity = this._lineColor$1._clone();
+ lineColorWithOpacity.a = Math.round(lineColorWithOpacity.a * this.get_opacity());
+ for (var i = 0; i < (this._points$1.length - 1); i++) {
+ Annotation.lineList.addLine(vertexList[i], vertexList[i + 1], lineColorWithOpacity, new Dates(0, 1));
+ }
+ }
+ this.annotationDirty = false;
+ }
+ } else {
+ var ctx = renderContext.device;
+ ctx.save();
+ ctx.globalAlpha = this.get_opacity();
+ var first = true;
+ var $enum1 = ss.enumerate(this._points$1);
+ while ($enum1.moveNext()) {
+ var pnt = $enum1.current;
+ var screenSpacePnt = renderContext.WVP.transform(pnt);
+ if (screenSpacePnt.z < 0) {
+ ctx.restore();
+ return;
+ }
+ if (Vector3d.dot(renderContext.get_viewPoint(), pnt) < 0.75) {
+ ctx.restore();
+ return;
+ }
+ if (first) {
+ first = false;
+ ctx.beginPath();
+ ctx.moveTo(screenSpacePnt.x, screenSpacePnt.y);
+ }
+ else {
+ ctx.lineTo(screenSpacePnt.x, screenSpacePnt.y);
+ }
+ }
+ ctx.lineWidth = this._strokeWidth$1;
+ ctx.strokeStyle = this._lineColor$1.toString();
+ ctx.stroke();
+ ctx.restore();
+ }
+ }
+};
+
+registerType("PolyLine", [PolyLine, PolyLine$, Annotation]);
diff --git a/engine/esm/astrocalc.js b/engine/esm/astrocalc.js
new file mode 100644
index 00000000..1354993b
--- /dev/null
+++ b/engine/esm/astrocalc.js
@@ -0,0 +1,216 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Some miscellaneous types relating to astronomy calculations.
+
+import { registerType } from "./typesystem.js";
+import { ss } from "./ss.js";
+import { Util } from "./util.js";
+import { CT } from "./astrocalc/coordinate_transformation.js";
+import { DT } from "./astrocalc/date.js";
+import { CAANutation } from "./astrocalc/nutation.js";
+import { CAAParallax } from "./astrocalc/parallax.js";
+import { CAAPhysicalJupiter, CAAPhysicalJupiterDetails } from "./astrocalc/physical_jupiter.js";
+import { CAARiseTransitSet } from "./astrocalc/rise_transit_set.js";
+import { ELL, EPD } from "./astrocalc/elliptical.js";
+import { GM, GMDS } from "./astrocalc/galilean_moons.js";
+import { CAAMoon } from "./astrocalc/moon.js";
+
+
+// Global state
+
+var galDetails = new GMDS();
+var jupDetails = new EPD();
+var jupPhisical = new CAAPhysicalJupiterDetails();
+var jDateLast = 0;
+
+
+// wwtlib.AstroRaDec
+
+export function AstroRaDec(ra, dec, dist, shadow, eclipsed) {
+ this.RA = 0;
+ this.dec = 0;
+ this.distance = 0;
+ this.shadow = false;
+ this.eclipsed = false;
+ this.RA = ra;
+ this.dec = dec;
+ this.distance = dist;
+ this.shadow = shadow;
+ this.eclipsed = eclipsed;
+}
+
+var AstroRaDec$ = {};
+
+registerType("AstroRaDec", [AstroRaDec, AstroRaDec$, null]);
+
+
+// wwtlib.RiseSetDetails
+
+export function RiseSetDetails(bValid, Rise, Transit, Set, neverRises) {
+ this.bValid = false;
+ this.rise = 0;
+ this.transit = 0;
+ this.set = 0;
+ this.bNeverRises = false;
+ this.bValid = bValid;
+ this.rise = Rise;
+ this.transit = Transit;
+ this.set = Set;
+ this.bNeverRises = neverRises;
+}
+
+var RiseSetDetails$ = {};
+
+registerType("RiseSetDetails", [RiseSetDetails, RiseSetDetails$, null]);
+
+
+// wwtlib.AstroCalc
+
+export function AstroCalc() { }
+
+AstroCalc.getPlanet = function (jDate, planetIn, locLat, locLong, locHeight) {
+ var planet = planetIn;
+ locLong = -locLong;
+
+ if (planet < 9) {
+ var Details = ELL.calculate(jDate, planetIn);
+ var corrected = CAAParallax.equatorial2Topocentric(Details.apparentGeocentricRA, Details.apparentGeocentricDeclination, Details.apparentGeocentricDistance, locLong, locLat, locHeight, jDate);
+ return new AstroRaDec(corrected.x, corrected.y, Details.apparentGeocentricDistance, false, false);
+ }
+ else if (planet === 9) {
+ var lat = CAAMoon.eclipticLatitude(jDate);
+ var lng = CAAMoon.eclipticLongitude(jDate);
+ var dis = CAAMoon.radiusVector(jDate) / 149598000;
+ var epsilon = CAANutation.trueObliquityOfEcliptic(jDate);
+ var d = CT.ec2Eq(lng, lat, epsilon);
+ var corrected = CAAParallax.equatorial2Topocentric(d.x, d.y, dis, locLong, locLat, locHeight, jDate);
+ return new AstroRaDec(corrected.x, corrected.y, dis, false, false);
+ }
+ else {
+ if (jDate !== jDateLast) {
+ jupDetails = ELL.calculate(jDate, 4);
+ jupPhisical = CAAPhysicalJupiter.calculate(jDate);
+ var corrected = CAAParallax.equatorial2Topocentric(jupDetails.apparentGeocentricRA, jupDetails.apparentGeocentricDeclination, jupDetails.apparentGeocentricDistance, locLong, locLat, locHeight, jDate);
+ jupDetails.apparentGeocentricRA = corrected.x;
+ jupDetails.apparentGeocentricDeclination = corrected.y;
+ galDetails = GM.calculate(jDate);
+ jDateLast = jDate;
+ }
+ var jupiterDiameter = 0.000954501;
+ var scale = Math.atan(0.5 * (jupiterDiameter / jupDetails.apparentGeocentricDistance)) / 3.1415927 * 180;
+ var raScale = (scale / Math.cos(jupDetails.apparentGeocentricDeclination / 180 * 3.1415927)) / 15;
+ var xMoon = 0;
+ var yMoon = 0;
+ var zMoon = 0;
+ var shadow = false;
+ var eclipsed = false;
+ switch (planet) {
+ case 10: // IO
+ xMoon = galDetails.satellite1.apparentRectangularCoordinates.x;
+ yMoon = galDetails.satellite1.apparentRectangularCoordinates.y;
+ zMoon = galDetails.satellite1.apparentRectangularCoordinates.z;
+ eclipsed = galDetails.satellite1.bInEclipse;
+ shadow = galDetails.satellite1.bInShadowTransit;
+ break;
+ case 11: // Europa
+ xMoon = galDetails.satellite2.apparentRectangularCoordinates.x;
+ yMoon = galDetails.satellite2.apparentRectangularCoordinates.y;
+ zMoon = galDetails.satellite2.apparentRectangularCoordinates.z;
+ eclipsed = galDetails.satellite2.bInEclipse;
+ shadow = galDetails.satellite2.bInShadowTransit;
+ break;
+ case 12: // Ganymede
+ xMoon = galDetails.satellite3.apparentRectangularCoordinates.x;
+ yMoon = galDetails.satellite3.apparentRectangularCoordinates.y;
+ zMoon = galDetails.satellite3.apparentRectangularCoordinates.z;
+ eclipsed = galDetails.satellite3.bInEclipse;
+ shadow = galDetails.satellite3.bInShadowTransit;
+ break;
+ case 13: // Callisto
+ xMoon = galDetails.satellite4.apparentRectangularCoordinates.x;
+ yMoon = galDetails.satellite4.apparentRectangularCoordinates.y;
+ zMoon = galDetails.satellite4.apparentRectangularCoordinates.z;
+ eclipsed = galDetails.satellite4.bInEclipse;
+ shadow = galDetails.satellite4.bInShadowTransit;
+ break;
+ case 14: // Io shadow
+ xMoon = galDetails.satellite1.apparentShadowRectangularCoordinates.x;
+ yMoon = galDetails.satellite1.apparentShadowRectangularCoordinates.y;
+ zMoon = galDetails.satellite1.apparentShadowRectangularCoordinates.z * 0.9;
+ shadow = galDetails.satellite1.bInShadowTransit;
+ break;
+ case 15: // Europa shadow
+ xMoon = galDetails.satellite2.apparentShadowRectangularCoordinates.x;
+ yMoon = galDetails.satellite2.apparentShadowRectangularCoordinates.y;
+ zMoon = galDetails.satellite2.apparentShadowRectangularCoordinates.z * 0.9;
+ shadow = galDetails.satellite2.bInShadowTransit;
+ break;
+ case 16: // Ganymede shadow
+ xMoon = galDetails.satellite3.apparentShadowRectangularCoordinates.x;
+ yMoon = galDetails.satellite3.apparentShadowRectangularCoordinates.y;
+ zMoon = galDetails.satellite3.apparentShadowRectangularCoordinates.z * 0.9;
+ shadow = galDetails.satellite3.bInShadowTransit;
+ break;
+ case 17: // Callisto shadow
+ xMoon = galDetails.satellite4.apparentShadowRectangularCoordinates.x;
+ yMoon = galDetails.satellite4.apparentShadowRectangularCoordinates.y;
+ zMoon = galDetails.satellite4.apparentShadowRectangularCoordinates.z * 0.9;
+ shadow = galDetails.satellite4.bInShadowTransit;
+ break;
+ }
+ var xTemp;
+ var yTemp;
+ var radians = jupPhisical.p / 180 * 3.1415927;
+ xTemp = xMoon * Math.cos(radians) - yMoon * Math.sin(radians);
+ yTemp = xMoon * Math.sin(radians) + yMoon * Math.cos(radians);
+ xMoon = xTemp;
+ yMoon = yTemp;
+ return new AstroRaDec(jupDetails.apparentGeocentricRA - (xMoon * raScale), jupDetails.apparentGeocentricDeclination + yMoon * scale, jupDetails.apparentGeocentricDistance + (zMoon * jupiterDiameter / 2), shadow, eclipsed);
+ }
+};
+
+AstroCalc.getJulianDay = function (year, month, day) {
+ return DT.dateToJD(ss.truncate(year), ss.truncate(month), day, true);
+};
+
+AstroCalc.eclipticToJ2000 = function (l, b, jNow) {
+ var radec = CT.ec2Eq(l, b, CAANutation.trueObliquityOfEcliptic(jNow));
+ return new AstroRaDec(radec.x, radec.y, 0, false, false);
+};
+
+AstroCalc.galacticToJ2000 = function (l, b) {
+ var radec = CT.g2Eq(l, b);
+ return new AstroRaDec(radec.x, radec.y, 0, false, false);
+};
+
+AstroCalc.j2000ToGalactic = function (ra, dec) {
+ var galactic = CT.eq2G(ra, dec);
+ return new AstroRaDec(galactic.x, galactic.y, 0, false, false);
+};
+
+AstroCalc.getRiseTrinsitSet = function (jd, lat, lng, ra1, dec1, ra2, dec2, ra3, dec3, type) {
+ var alt = -0.5667;
+
+ switch (type) {
+ case 0: // Planet or star
+ alt = -0.5667;
+ break;
+ case 1: // Sun
+ alt = -0.8333;
+ break;
+ case 2:
+ alt = 0.125;
+ break;
+ }
+ var RiseTransitSetTime = CAARiseTransitSet.rise(jd, ra1, dec1, ra2, dec2, ra3, dec3, lng, lat, alt);
+ var neverRises = false;
+ if (!RiseTransitSetTime.bValid) {
+ neverRises = Util.sign(lat) !== Util.sign(dec2);
+ }
+ return new RiseSetDetails(RiseTransitSetTime.bValid, RiseTransitSetTime.rise, RiseTransitSetTime.transit, RiseTransitSetTime.set, neverRises);
+};
+
+var AstroCalc$ = {};
+
+registerType("AstroCalc", [AstroCalc, AstroCalc$, null]);
diff --git a/engine/esm/astrocalc/aberration.js b/engine/esm/astrocalc/aberration.js
new file mode 100644
index 00000000..2d652e68
--- /dev/null
+++ b/engine/esm/astrocalc/aberration.js
@@ -0,0 +1,152 @@
+// Originally `AAABERRATION.CPP`
+// "Purpose: Implementation for the algorithms for Aberration"
+// Last update of original: PJN / 21-04-2005
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { C3D, COR, CT } from "./coordinate_transformation.js";
+import { CAASun } from "./sun.js";
+
+
+// ACFT
+
+export function ACFT(L2, L3, L4, L5, L6, L7, L8, Ldash, D, Mdash, F, xsin, xsint, xcos, xcost, ysin, ysint, ycos, ycost, zsin, zsint, zcos, zcost) {
+ this.l2 = 0;
+ this.l3 = 0;
+ this.l4 = 0;
+ this.l5 = 0;
+ this.l6 = 0;
+ this.l7 = 0;
+ this.l8 = 0;
+ this.ldash = 0;
+ this.d = 0;
+ this.mdash = 0;
+ this.f = 0;
+ this.xsin = 0;
+ this.xsint = 0;
+ this.xcos = 0;
+ this.xcost = 0;
+ this.ysin = 0;
+ this.ysint = 0;
+ this.ycos = 0;
+ this.ycost = 0;
+ this.zsin = 0;
+ this.zsint = 0;
+ this.zcos = 0;
+ this.zcost = 0;
+ this.l2 = L2;
+ this.l3 = L3;
+ this.l4 = L4;
+ this.l5 = L5;
+ this.l6 = L6;
+ this.l7 = L7;
+ this.l8 = L8;
+ this.ldash = Ldash;
+ this.d = D;
+ this.mdash = Mdash;
+ this.f = F;
+ this.xsin = xsin;
+ this.xsint = xsint;
+ this.xcos = xcos;
+ this.xcost = xcost;
+ this.ysin = ysin;
+ this.ysint = ysint;
+ this.ycos = ycos;
+ this.ycost = ycost;
+ this.zsin = zsin;
+ this.zsint = zsint;
+ this.zcos = zcos;
+ this.zcost = zcost;
+}
+
+var ACFT$ = {};
+
+registerType("ACFT", [ACFT, ACFT$, null]);
+
+
+// Coefficients
+
+const g_ACft = [new ACFT(0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1719914, -2, -25, 0, 25, -13, 1578089, 156, 10, 32, 684185, -358), new ACFT(0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6434, 141, 28007, -107, 25697, -95, -5904, -130, 11141, -48, -2559, -55), new ACFT(0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 715, 0, 0, 0, 6, 0, -657, 0, -15, 0, -282, 0), new ACFT(0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 715, 0, 0, 0, 0, 0, -656, 0, 0, 0, -285, 0), new ACFT(0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 486, -5, -236, -4, -216, -4, -446, 5, -94, 0, -193, 0), new ACFT(0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 159, 0, 0, 0, 2, 0, -147, 0, -6, 0, -61, 0), new ACFT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, -59, 0), new ACFT(0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 39, 0, 0, 0, 0, 0, -36, 0, 0, 0, -16, 0), new ACFT(0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 33, 0, -10, 0, -9, 0, -30, 0, -5, 0, -13, 0), new ACFT(0, 2, 0, -1, 0, 0, 0, 0, 0, 0, 0, 31, 0, 1, 0, 1, 0, -28, 0, 0, 0, -12, 0), new ACFT(0, 3, -8, 3, 0, 0, 0, 0, 0, 0, 0, 8, 0, -28, 0, 25, 0, 8, 0, 11, 0, 3, 0), new ACFT(0, 5, -8, 3, 0, 0, 0, 0, 0, 0, 0, 8, 0, -28, 0, -25, 0, -8, 0, -11, 0, -3, 0), new ACFT(2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, -19, 0, 0, 0, -8, 0), new ACFT(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -19, 0, 0, 0, 0, 0, 17, 0, 0, 0, 8, 0), new ACFT(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, -16, 0, 0, 0, -7, 0), new ACFT(0, 1, 0, -2, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 15, 0, 1, 0, 7, 0), new ACFT(0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 16, 0, 0, 0, 1, 0, -15, 0, -3, 0, -6, 0), new ACFT(0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 11, 0, -1, 0, -1, 0, -10, 0, -1, 0, -5, 0), new ACFT(2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -11, 0, -10, 0, 0, 0, -4, 0, 0, 0), new ACFT(0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, -11, 0, -2, 0, -2, 0, 9, 0, -1, 0, 4, 0), new ACFT(0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, -7, 0, -8, 0, -8, 0, 6, 0, -3, 0, 3, 0), new ACFT(0, 3, 0, -2, 0, 0, 0, 0, 0, 0, 0, -10, 0, 0, 0, 0, 0, 9, 0, 0, 0, 4, 0), new ACFT(1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, -9, 0, 0, 0, 0, 0, -9, 0, 0, 0, -4, 0), new ACFT(2, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, -9, 0, 0, 0, 0, 0, -8, 0, 0, 0, -4, 0), new ACFT(0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, -9, 0, -8, 0, 0, 0, -3, 0, 0, 0), new ACFT(2, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -9, 0, 8, 0, 0, 0, 3, 0, 0, 0), new ACFT(0, 3, -2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, -8, 0, 0, 0, -3, 0), new ACFT(0, 0, 0, 0, 0, 0, 0, 1, 2, -1, 0, 8, 0, 0, 0, 0, 0, -7, 0, 0, 0, -3, 0), new ACFT(8, -12, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 0, -7, 0, -6, 0, 4, 0, -3, 0, 2, 0), new ACFT(8, -14, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 0, -7, 0, 6, 0, -4, 0, 3, 0, -2, 0), new ACFT(0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, -6, 0, -5, 0, -4, 0, 5, 0, -2, 0, 2, 0), new ACFT(3, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, -2, 0, -7, 0, 1, 0, -4, 0), new ACFT(0, 2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 4, 0, -6, 0, -5, 0, -4, 0, -2, 0, -2, 0), new ACFT(3, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -7, 0, -6, 0, 0, 0, -3, 0, 0, 0), new ACFT(0, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, -5, 0, -4, 0, -5, 0, -2, 0, -2, 0), new ACFT(0, 0, 0, 0, 0, 0, 0, 1, -2, 0, 0, 5, 0, 0, 0, 0, 0, -5, 0, 0, 0, -2, 0)];
+
+
+// ABR - was CAAAberration
+
+export function ABR() { }
+
+ABR.earthVelocity = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var L2 = 3.1761467 + 1021.3285546 * T;
+ var L3 = 1.7534703 + 628.3075849 * T;
+ var L4 = 6.2034809 + 334.0612431 * T;
+ var L5 = 0.5995465 + 52.9690965 * T;
+ var L6 = 0.8740168 + 21.3299095 * T;
+ var L7 = 5.4812939 + 7.4781599 * T;
+ var L8 = 5.3118863 + 3.8133036 * T;
+ var Ldash = 3.8103444 + 8399.6847337 * T;
+ var D = 5.1984667 + 7771.3771486 * T;
+ var Mdash = 2.3555559 + 8328.6914289 * T;
+ var F = 1.6279052 + 8433.4661601 * T;
+ var velocity = new C3D();
+ var nAberrationCoefficients = g_ACft.length;
+ for (var i = 0; i < nAberrationCoefficients; i++) {
+ var Argument = g_ACft[i].l2 * L2 + g_ACft[i].l3 * L3 + g_ACft[i].l4 * L4 + g_ACft[i].l5 * L5 + g_ACft[i].l6 * L6 + g_ACft[i].l7 * L7 + g_ACft[i].l8 * L8 + g_ACft[i].ldash * Ldash + g_ACft[i].d * D + g_ACft[i].mdash * Mdash + g_ACft[i].f * F;
+ velocity.x += (g_ACft[i].xsin + g_ACft[i].xsint * T) * Math.sin(Argument);
+ velocity.x += (g_ACft[i].xcos + g_ACft[i].xcost * T) * Math.cos(Argument);
+ velocity.y += (g_ACft[i].ysin + g_ACft[i].ysint * T) * Math.sin(Argument);
+ velocity.y += (g_ACft[i].ycos + g_ACft[i].ycost * T) * Math.cos(Argument);
+ velocity.z += (g_ACft[i].zsin + g_ACft[i].zsint * T) * Math.sin(Argument);
+ velocity.z += (g_ACft[i].zcos + g_ACft[i].zcost * T) * Math.cos(Argument);
+ }
+ return velocity;
+};
+
+ABR.eclipticAberration = function (Lambda, Beta, JD) {
+ var aberration = new COR();
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var e = 0.016708634 - 4.2037E-05 * T - 1.267E-07 * Tsquared;
+ var pi = 102.93735 + 1.71946 * T + 0.00046 * Tsquared;
+ var k = 20.49552;
+ var SunLongitude = CAASun.geometricEclipticLongitude(JD);
+ pi = CT.d2R(pi);
+ Lambda = CT.d2R(Lambda);
+ Beta = CT.d2R(Beta);
+ SunLongitude = CT.d2R(SunLongitude);
+ aberration.x = (-k * Math.cos(SunLongitude - Lambda) + e * k * Math.cos(pi - Lambda)) / Math.cos(Beta) / 3600;
+ aberration.y = -k * Math.sin(Beta) * (Math.sin(SunLongitude - Lambda) - e * Math.sin(pi - Lambda)) / 3600;
+ return aberration;
+};
+
+ABR.equatorialAberration = function (Alpha, Delta, JD) {
+ Alpha = CT.d2R(Alpha * 15);
+ Delta = CT.d2R(Delta);
+ var cosAlpha = Math.cos(Alpha);
+ var sinAlpha = Math.sin(Alpha);
+ var cosDelta = Math.cos(Delta);
+ var sinDelta = Math.sin(Delta);
+ var velocity = ABR.earthVelocity(JD);
+ var aberration = new COR();
+ aberration.x = CT.r2H((velocity.y * cosAlpha - velocity.x * sinAlpha) / (17314463350 * cosDelta));
+ aberration.y = CT.r2D(-(((velocity.x * cosAlpha + velocity.y * sinAlpha) * sinDelta - velocity.z * cosDelta) / 17314463350));
+ return aberration;
+};
+
+var ABR$ = {};
+
+registerType("ABR", [ABR, ABR$, null]);
diff --git a/engine/esm/astrocalc/angular_separation.js b/engine/esm/astrocalc/angular_separation.js
new file mode 100644
index 00000000..79ab3d11
--- /dev/null
+++ b/engine/esm/astrocalc/angular_separation.js
@@ -0,0 +1,91 @@
+// Originally `AAANGULARSEPARATION.CPP`
+// "Purpose: Implementation for the algorithms which obtain various separation distances between celestial objects"
+// Last update of original: PJN / 29-12-2003
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+
+
+// ASEP - was CAAAngularSeparation
+
+export function ASEP() { }
+
+ASEP.separation = function (Alpha1, Delta1, Alpha2, Delta2) {
+ Delta1 = CT.d2R(Delta1);
+ Delta2 = CT.d2R(Delta2);
+ Alpha1 = CT.h2R(Alpha1);
+ Alpha2 = CT.h2R(Alpha2);
+ var x = Math.cos(Delta1) * Math.sin(Delta2) - Math.sin(Delta1) * Math.cos(Delta2) * Math.cos(Alpha2 - Alpha1);
+ var y = Math.cos(Delta2) * Math.sin(Alpha2 - Alpha1);
+ var z = Math.sin(Delta1) * Math.sin(Delta2) + Math.cos(Delta1) * Math.cos(Delta2) * Math.cos(Alpha2 - Alpha1);
+ var vvalue = Math.atan2(Math.sqrt(x * x + y * y), z);
+ vvalue = CT.r2D(vvalue);
+ if (vvalue < 0) {
+ vvalue += 180;
+ }
+ return vvalue;
+};
+
+ASEP.positionAngle = function (alpha1, delta1, alpha2, delta2) {
+ var Alpha1;
+ var Delta1;
+ var Alpha2;
+ var Delta2;
+ Delta1 = CT.d2R(delta1);
+ Delta2 = CT.d2R(delta2);
+ Alpha1 = CT.h2R(alpha1);
+ Alpha2 = CT.h2R(alpha2);
+ var DeltaAlpha = Alpha1 - Alpha2;
+ var demoninator = Math.cos(Delta2) * Math.tan(Delta1) - Math.sin(Delta2) * Math.cos(DeltaAlpha);
+ var numerator = Math.sin(DeltaAlpha);
+ var vvalue = Math.atan2(numerator, demoninator);
+ vvalue = CT.r2D(vvalue);
+ return vvalue;
+};
+
+ASEP.distanceFromGreatArc = function (Alpha1, Delta1, Alpha2, Delta2, Alpha3, Delta3) {
+ Delta1 = CT.d2R(Delta1);
+ Delta2 = CT.d2R(Delta2);
+ Delta3 = CT.d2R(Delta3);
+ Alpha1 = CT.h2R(Alpha1);
+ Alpha2 = CT.h2R(Alpha2);
+ Alpha3 = CT.h2R(Alpha3);
+ var X1 = Math.cos(Delta1) * Math.cos(Alpha1);
+ var X2 = Math.cos(Delta2) * Math.cos(Alpha2);
+ var Y1 = Math.cos(Delta1) * Math.sin(Alpha1);
+ var Y2 = Math.cos(Delta2) * Math.sin(Alpha2);
+ var Z1 = Math.sin(Delta1);
+ var Z2 = Math.sin(Delta2);
+ var A = Y1 * Z2 - Z1 * Y2;
+ var B = Z1 * X2 - X1 * Z2;
+ var C = X1 * Y2 - Y1 * X2;
+ var m = Math.tan(Alpha3);
+ var n = Math.tan(Delta3) / Math.cos(Alpha3);
+ var vvalue = Math.asin((A + B * m + C * n) / (Math.sqrt(A * A + B * B + C * C) * Math.sqrt(1 + m * m + n * n)));
+ vvalue = CT.r2D(vvalue);
+ if (vvalue < 0) {
+ vvalue = Math.abs(vvalue);
+ }
+ return vvalue;
+};
+
+var ASEP$ = {};
+
+registerType("ASEP", [ASEP, ASEP$, null]);
diff --git a/engine/esm/astrocalc/coordinate_transformation.js b/engine/esm/astrocalc/coordinate_transformation.js
new file mode 100644
index 00000000..b076ddaa
--- /dev/null
+++ b/engine/esm/astrocalc/coordinate_transformation.js
@@ -0,0 +1,211 @@
+// Originally `AACOORDINATETRANSFORMATION.CPP`
+// "Purpose: Implementation for the algorithms which convert between the various celestial coordinate systems"
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+
+
+// COR - was CAA2DCoordinate
+
+export function COR() {
+ this.x = 0;
+ this.y = 0;
+ this.x = 0;
+ this.y = 0;
+}
+
+COR.create = function (x, y) {
+ var item = new COR();
+ item.x = x;
+ item.y = y;
+ return item;
+};
+
+var COR$ = {};
+
+registerType("COR", [COR, COR$, null]);
+
+
+// C3D - was CAA3DCoordinate
+
+export function C3D() {
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+}
+
+C3D.create = function (x, y, z) {
+ var item = new C3D();
+ item.x = x;
+ item.y = y;
+ item.z = z;
+ return item;
+};
+
+var C3D$ = {};
+
+registerType("C3D", [C3D, C3D$, null]);
+
+
+// CT - was CAACoordinateTransformation
+
+export function CT() {
+}
+
+CT.eq2Ec = function (Alpha, Delta, Epsilon) {
+ Alpha = CT.h2R(Alpha);
+ Delta = CT.d2R(Delta);
+ Epsilon = CT.d2R(Epsilon);
+ var Ecliptic = new COR();
+ Ecliptic.x = CT.r2D(Math.atan2(Math.sin(Alpha) * Math.cos(Epsilon) + Math.tan(Delta) * Math.sin(Epsilon), Math.cos(Alpha)));
+ if (Ecliptic.x < 0) {
+ Ecliptic.x += 360;
+ }
+ Ecliptic.y = CT.r2D(Math.asin(Math.sin(Delta) * Math.cos(Epsilon) - Math.cos(Delta) * Math.sin(Epsilon) * Math.sin(Alpha)));
+ return Ecliptic;
+};
+
+CT.ec2Eq = function (Lambda, Beta, Epsilon) {
+ Lambda = CT.d2R(Lambda);
+ Beta = CT.d2R(Beta);
+ Epsilon = CT.d2R(Epsilon);
+ var Equatorial = new COR();
+ Equatorial.x = CT.r2H(Math.atan2(Math.sin(Lambda) * Math.cos(Epsilon) - Math.tan(Beta) * Math.sin(Epsilon), Math.cos(Lambda)));
+ if (Equatorial.x < 0) {
+ Equatorial.x += 24;
+ }
+ Equatorial.y = CT.r2D(Math.asin(Math.sin(Beta) * Math.cos(Epsilon) + Math.cos(Beta) * Math.sin(Epsilon) * Math.sin(Lambda)));
+ return Equatorial;
+};
+
+CT.eq2H = function (LocalHourAngle, Delta, Latitude) {
+ LocalHourAngle = CT.h2R(LocalHourAngle);
+ Delta = CT.d2R(Delta);
+ Latitude = CT.d2R(Latitude);
+ var Horizontal = new COR();
+ Horizontal.x = CT.r2D(Math.atan2(Math.sin(LocalHourAngle), Math.cos(LocalHourAngle) * Math.sin(Latitude) - Math.tan(Delta) * Math.cos(Latitude)));
+ if (Horizontal.x < 0) {
+ Horizontal.x += 360;
+ }
+ Horizontal.y = CT.r2D(Math.asin(Math.sin(Latitude) * Math.sin(Delta) + Math.cos(Latitude) * Math.cos(Delta) * Math.cos(LocalHourAngle)));
+ return Horizontal;
+};
+
+CT.h2Eq = function (Azimuth, Altitude, Latitude) {
+ Azimuth = CT.d2R(Azimuth);
+ Altitude = CT.d2R(Altitude);
+ Latitude = CT.d2R(Latitude);
+ var Equatorial = new COR();
+ Equatorial.x = CT.r2H(Math.atan2(Math.sin(Azimuth), Math.cos(Azimuth) * Math.sin(Latitude) + Math.tan(Altitude) * Math.cos(Latitude)));
+ if (Equatorial.x < 0) {
+ Equatorial.x += 24;
+ }
+ Equatorial.y = CT.r2D(Math.asin(Math.sin(Latitude) * Math.sin(Altitude) - Math.cos(Latitude) * Math.cos(Altitude) * Math.cos(Azimuth)));
+ return Equatorial;
+};
+
+CT.eq2G = function (Alpha, Delta) {
+ Alpha = 192.25 - CT.h2D(Alpha);
+ Alpha = CT.d2R(Alpha);
+ Delta = CT.d2R(Delta);
+ var Galactic = new COR();
+ Galactic.x = CT.r2D(Math.atan2(Math.sin(Alpha), Math.cos(Alpha) * Math.sin(CT.d2R(27.4)) - Math.tan(Delta) * Math.cos(CT.d2R(27.4))));
+ Galactic.x = 303 - Galactic.x;
+ if (Galactic.x >= 360) {
+ Galactic.x -= 360;
+ }
+ Galactic.y = CT.r2D(Math.asin(Math.sin(Delta) * Math.sin(CT.d2R(27.4)) + Math.cos(Delta) * Math.cos(CT.d2R(27.4)) * Math.cos(Alpha)));
+ return Galactic;
+};
+
+CT.g2Eq = function (l, b) {
+ l -= 123;
+ l = CT.d2R(l);
+ b = CT.d2R(b);
+ var Equatorial = new COR();
+ Equatorial.x = CT.r2D(Math.atan2(Math.sin(l), Math.cos(l) * Math.sin(CT.d2R(27.4)) - Math.tan(b) * Math.cos(CT.d2R(27.4))));
+ Equatorial.x += 12.25;
+ if (Equatorial.x < 0) {
+ Equatorial.x += 360;
+ }
+ Equatorial.x = CT.d2H(Equatorial.x);
+ Equatorial.y = CT.r2D(Math.asin(Math.sin(b) * Math.sin(CT.d2R(27.4)) + Math.cos(b) * Math.cos(CT.d2R(27.4)) * Math.cos(l)));
+ return Equatorial;
+};
+
+CT.d2R = function (Degrees) {
+ return Degrees * 0.0174532925199433;
+};
+
+CT.r2D = function (Radians) {
+ return Radians * 57.2957795130823;
+};
+
+CT.r2H = function (Radians) {
+ return Radians * 3.81971863420549;
+};
+
+CT.h2R = function (Hours) {
+ return Hours * 0.261799387799149;
+};
+
+CT.h2D = function (Hours) {
+ return Hours * 15;
+};
+
+CT.d2H = function (Degrees) {
+ return Degrees / 15;
+};
+
+CT.PI = function () {
+ return 3.14159265358979;
+};
+
+CT.m360 = function (Degrees) {
+ return Degrees - Math.floor(Degrees / 360) * 360;
+};
+
+CT.m24 = function (HourAngle) {
+ return HourAngle - Math.floor(HourAngle / 24) * 24;
+};
+
+CT.dmS2D = function (Degrees, Minutes, Seconds) {
+ return CT.dmS2Dp(Degrees, Minutes, Seconds, true);
+};
+
+CT.dmS2Dp = function (Degrees, Minutes, Seconds, bPositive) {
+ if (!bPositive) {
+ console.assert(Degrees >= 0);
+ console.assert(Minutes >= 0);
+ console.assert(Seconds >= 0);
+ }
+ if (bPositive) {
+ return Degrees + Minutes / 60 + Seconds / 3600;
+ }
+ else {
+ return -Degrees - Minutes / 60 - Seconds / 3600;
+ }
+};
+
+var CT$ = {};
+
+registerType("CT", [CT, CT$, null]);
diff --git a/engine/esm/astrocalc/date.js b/engine/esm/astrocalc/date.js
new file mode 100644
index 00000000..6acae8df
--- /dev/null
+++ b/engine/esm/astrocalc/date.js
@@ -0,0 +1,301 @@
+// Originally `AADATE.CPP`
+// "Purpose: Implementation for the algorithms which convert between the
+// Gregorian and Julian calendars and the Julian Day"
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { ss } from "../ss.js";
+import { registerType } from "../typesystem.js";
+
+
+// CalD
+
+export function CalD() {
+ this.year = 0;
+ this.month = 0;
+ this.day = 0;
+ this.year = 0;
+ this.month = 0;
+ this.day = 0;
+}
+
+CalD.create = function (year, month, day) {
+ var item = new CalD();
+ item.year = year;
+ item.month = month;
+ item.day = day;
+ return item;
+};
+
+var CalD$ = {};
+
+registerType("CalD", [CalD, CalD$, null]);
+
+
+// DAY_OF_WEEK
+
+export var DAY_OF_WEEK = {
+ SUNDAY: 0,
+ MONDAY: 1,
+ TUESDAY: 2,
+ WEDNESDAY: 3,
+ THURSDAY: 4,
+ FRIDAY: 5,
+ SATURDAY: 6
+};
+
+registerType("DAY_OF_WEEK", DAY_OF_WEEK);
+
+
+// DT
+
+export function DT() {
+ this.m_dblJulian = 0;
+ this.m_bGregorianCalendar = false;
+ this.m_dblJulian = 0;
+ this.m_bGregorianCalendar = false;
+}
+
+DT.create = function (Year, Month, Day, bGregorianCalendar) {
+ var item = new DT();
+ item.set(Year, Month, Day, 0, 0, 0, bGregorianCalendar);
+ return item;
+};
+
+DT.createHMS = function (Year, Month, Day, Hour, Minute, Second, bGregorianCalendar) {
+ var item = new DT();
+ item.set(Year, Month, Day, Hour, Minute, Second, bGregorianCalendar);
+ return item;
+};
+
+DT.createJD = function (JD, bGregorianCalendar) {
+ var item = new DT();
+ item.setJD(JD, bGregorianCalendar);
+ return item;
+};
+
+DT.dateToJD = function (Year, Month, Day, bGregorianCalendar) {
+ var Y = Year;
+ var M = Month;
+ if (M < 3) {
+ Y = Y - 1;
+ M = M + 12;
+ }
+ var A = 0;
+ var B = 0;
+ if (bGregorianCalendar) {
+ A = ss.truncate((Y / 100));
+ B = 2 - A + ss.truncate((A / 4));
+ }
+ return ss.truncate((365.25 * (Y + 4716))) + ss.truncate((30.6001 * (M + 1))) + Day + B - 1524.5;
+};
+
+DT.isLeap = function (Year, bGregorianCalendar) {
+ if (bGregorianCalendar) {
+ if (!(Year % 100)) {
+ return (!(Year % 400)) ? true : false;
+ }
+ else {
+ return (!(Year % 4)) ? true : false;
+ }
+ }
+ else {
+ return (!(Year % 4)) ? true : false;
+ }
+};
+
+DT.afterPapalReform = function (Year, Month, Day) {
+ return ((Year > 1582) || ((Year === 1582) && (Month > 10)) || ((Year === 1582) && (Month === 10) && (Day >= 15)));
+};
+
+DT.afterPapalReformJD = function (JD) {
+ return (JD >= 2299160.5);
+};
+
+DT.dayOfYearJD = function (JD, Year, bGregorianCalendar) {
+ return JD - DT.dateToJD(Year, 1, 1, bGregorianCalendar) + 1;
+};
+
+DT.daysInMonthForMonth = function (Month, bLeap) {
+ console.assert(Month >= 1 && Month <= 12);
+ var MonthLength = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0];
+ if (bLeap) {
+ MonthLength[1]++;
+ }
+ return MonthLength[Month - 1];
+};
+
+DT.INT = function (vvalue) {
+ if (vvalue >= 0) {
+ return ss.truncate(vvalue);
+ }
+ else {
+ return ss.truncate((vvalue - 1));
+ }
+};
+
+var DT$ = {
+ julian: function () {
+ return this.m_dblJulian;
+ },
+
+ day: function () {
+ var D = this.get();
+ return ss.truncate(D[2]);
+ },
+
+ month: function () {
+ var D = this.get();
+ return ss.truncate(D[1]);
+ },
+
+ year: function () {
+ var D = this.get();
+ return ss.truncate(D[0]);
+ },
+
+ hour: function () {
+ var D = this.get();
+ return ss.truncate(D[3]);
+ },
+
+ minute: function () {
+ var D = this.get();
+ return ss.truncate(D[4]);
+ },
+
+ second: function () {
+ var D = this.get();
+ return ss.truncate(D[5]);
+ },
+
+ set: function (Year, Month, Day, Hour, Minute, Second, bGregorianCalendar) {
+ var dblDay = Day + (Hour / 24) + (Minute / 1440) + (Second / 86400);
+ this.setJD(DT.dateToJD(Year, Month, dblDay, bGregorianCalendar), bGregorianCalendar);
+ },
+
+ setJD: function (JD, bGregorianCalendar) {
+ this.m_dblJulian = JD;
+ this.setInGregorianCalendar(bGregorianCalendar);
+ },
+
+ setInGregorianCalendar: function (bGregorianCalendar) {
+ var bAfterPapalReform = (this.m_dblJulian >= 2299160.5);
+ this.m_bGregorianCalendar = bGregorianCalendar && bAfterPapalReform;
+ },
+
+ get: function () {
+ var Year;
+ var Month;
+ var Day;
+ var Hour;
+ var Minute;
+ var Second;
+ var JD = this.m_dblJulian + 0.5;
+ var tempZ = Math.floor(JD);
+ var F = JD - tempZ;
+ var Z = ss.truncate(tempZ);
+ var A;
+ if (this.m_bGregorianCalendar) {
+ var alpha = ss.truncate(((Z - 1867216.25) / 36524.25));
+ A = Z + 1 + alpha - ss.truncate((alpha / 4));
+ }
+ else {
+ A = Z;
+ }
+ var B = A + 1524;
+ var C = ss.truncate(((B - 122.1) / 365.25));
+ var D = ss.truncate((365.25 * C));
+ var E = ss.truncate(((B - D) / 30.6001));
+ var dblDay = B - D - ss.truncate((30.6001 * E)) + F;
+ Day = ss.truncate(dblDay);
+ if (E < 14) {
+ Month = E - 1;
+ }
+ else {
+ Month = E - 13;
+ }
+ if (Month > 2) {
+ Year = C - 4716;
+ }
+ else {
+ Year = C - 4715;
+ }
+ tempZ = Math.floor(dblDay);
+ F = dblDay - tempZ;
+ Hour = ss.truncate((F * 24));
+ Minute = ss.truncate(((F - Hour / 24) * 1440));
+ Second = (F - (Hour / 24) - (Minute / 1440)) * 86400;
+ return [Year, Month, Day, Hour, Minute, Second];
+ },
+
+ dayOfWeek: function () {
+ return (ss.truncate((this.m_dblJulian + 1.5)) % 7);
+ },
+
+ dayOfYear: function () {
+ var year = ss.truncate(this.get()[0]);
+ return DT.dayOfYearJD(this.m_dblJulian, year, DT.afterPapalReform(year, 1, 1));
+ },
+
+ daysInMonth: function () {
+ var D = this.get();
+ var Year = ss.truncate(D[0]);
+ var Month = ss.truncate(D[1]);
+ return DT.daysInMonthForMonth(Month, DT.isLeap(Year, this.m_bGregorianCalendar));
+ },
+
+ daysInYear: function () {
+ var D = this.get();
+ var Year = ss.truncate(D[0]);
+ if (DT.isLeap(Year, this.m_bGregorianCalendar)) {
+ return 366;
+ }
+ else {
+ return 365;
+ }
+ },
+
+ leap: function () {
+ return DT.isLeap(this.year(), this.m_bGregorianCalendar);
+ },
+
+ inGregorianCalendar: function () {
+ return this.m_bGregorianCalendar;
+ },
+
+ fractionalYear: function () {
+ var D = this.get();
+ var Year = ss.truncate(D[0]);
+ var Month = ss.truncate(D[1]);
+ var Day = ss.truncate(D[2]);
+ var Hour = ss.truncate(D[3]);
+ var Minute = ss.truncate(D[4]);
+ var Second = D[5];
+ var DaysInYear;
+ if (DT.isLeap(Year, this.m_bGregorianCalendar)) {
+ DaysInYear = 366;
+ }
+ else {
+ DaysInYear = 365;
+ }
+ return Year + ((this.m_dblJulian - DT.dateToJD(Year, 1, 1, DT.afterPapalReform(Year, 1, 1))) / DaysInYear);
+ }
+};
+
+registerType("DT", [DT, DT$, null]);
diff --git a/engine/esm/astrocalc/dynamical_time.js b/engine/esm/astrocalc/dynamical_time.js
new file mode 100644
index 00000000..e472bdb4
--- /dev/null
+++ b/engine/esm/astrocalc/dynamical_time.js
@@ -0,0 +1,68 @@
+// Originally `AADYNAMICALTIME.CPP`
+// "Purpose: Implementation for the algorithms which calculate the difference between Dynamical Time and Universal Time"
+// Last update of original: PJN / 28-01-2007
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { ss } from "../ss.js";
+import { DT } from "./date.js";
+
+
+// Constants
+
+const deltaTTable = [121, 112, 103, 95, 88, 82, 77, 72, 68, 63, 60, 56, 53, 51, 48, 46, 44, 42, 40, 38, 35, 33, 31, 29, 26, 24, 22, 20, 18, 16, 14, 12, 11, 10, 9, 8, 7, 7, 7, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 14, 13, 13.1, 12.5, 12.2, 12, 12, 12, 12, 12, 12, 11.9, 11.6, 11, 10.2, 9.2, 8.2, 7.1, 6.2, 5.6, 5.4, 5.3, 5.4, 5.6, 5.9, 6.2, 6.5, 6.8, 7.1, 7.3, 7.5, 7.6, 7.7, 7.3, 6.2, 5.2, 2.7, 1.4, -1.2, -2.8, -3.8, -4.8, -5.5, -5.3, -5.6, -5.7, -5.9, -6, -6.3, -6.5, -6.2, -4.7, -2.8, -0.1, 2.6, 5.3, 7.7, 10.4, 13.3, 16, 18.2, 20.2, 21.2, 22.4, 23.5, 23.8, 24.3, 24, 23.9, 23.9, 23.7, 24, 24.3, 25.3, 26.2, 27.3, 28.2, 29.1, 30, 30.7, 31.4, 32.2, 33.1, 34, 35, 36.5, 38.3, 40.18, 42.2, 44.5, 46.5, 48.5, 50.54, 52.2, 53.8, 54.9, 55.8, 56.86, 58.31, 59.99, 61.63, 62.97];
+
+
+// DYT - was CAADynamicalTime
+
+export function DYT() { }
+
+DYT.deltaT = function (JD) {
+ var date = DT.createJD(JD, DT.afterPapalReformJD(JD));
+ var y = date.fractionalYear();
+ var T = (y - 2000) / 100;
+ var Delta;
+ if (y < 948) {
+ Delta = 2177 + (497 * T) + (44.1 * T * T);
+ }
+ else if (y < 1620) {
+ Delta = 102 + (102 * T) + (25.3 * T * T);
+ }
+ else if (y < 1998) {
+ var Index = ss.truncate(((y - 1620) / 2));
+ console.assert(Index < deltaTTable.length);
+ y = y / 2 - Index - 810;
+ Delta = (deltaTTable[Index] + (deltaTTable[Index + 1] - deltaTTable[Index]) * y);
+ }
+ else if (y <= 2000) {
+ var nLookupSize = deltaTTable.length;
+ Delta = deltaTTable[nLookupSize - 1];
+ }
+ else if (y < 2100) {
+ Delta = 102 + (102 * T) + (25.3 * T * T) + 0.37 * (y - 2100);
+ }
+ else {
+ Delta = 102 + (102 * T) + (25.3 * T * T);
+ }
+ return Delta;
+};
+
+var DYT$ = {};
+
+registerType("DYT", [DYT, DYT$, null]);
diff --git a/engine/esm/astrocalc/earth.js b/engine/esm/astrocalc/earth.js
new file mode 100644
index 00000000..1d680e32
--- /dev/null
+++ b/engine/esm/astrocalc/earth.js
@@ -0,0 +1,272 @@
+// Originally `AAEARTH.CPP`
+// "Purpose: Implementation for the algorithms which calculate the position of Earth"
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+
+
+// VSC
+
+export function VSC(a, b, c) {
+ this.a = 0;
+ this.b = 0;
+ this.c = 0;
+ this.a = a;
+ this.b = b;
+ this.c = c;
+}
+
+var VSC$ = {};
+
+registerType("VSC", [VSC, VSC$, null]);
+
+
+// Coefficients
+
+const g_L0EarthCoefficients = [new VSC(175347046, 0, 0), new VSC(3341656, 4.6692568, 6283.07585), new VSC(34894, 4.6261, 12566.1517), new VSC(3497, 2.7441, 5753.3849), new VSC(3418, 2.8289, 3.5231), new VSC(3136, 3.6277, 77713.7715), new VSC(2676, 4.4181, 7860.4194), new VSC(2343, 6.1352, 3930.2097), new VSC(1324, 0.7425, 11506.7698), new VSC(1273, 2.0371, 529.691), new VSC(1199, 1.1096, 1577.3435), new VSC(990, 5.233, 5884.927), new VSC(902, 2.045, 26.298), new VSC(857, 3.508, 398.149), new VSC(780, 1.179, 5223.694), new VSC(753, 2.533, 5507.553), new VSC(505, 4.583, 18849.228), new VSC(492, 4.205, 775.523), new VSC(357, 2.92, 0.067), new VSC(317, 5.849, 11790.629), new VSC(284, 1.899, 796.288), new VSC(271, 0.315, 10977.079), new VSC(243, 0.345, 5486.778), new VSC(206, 4.806, 2544.314), new VSC(205, 1.869, 5573.143), new VSC(202, 2.458, 6069.777), new VSC(156, 0.833, 213.299), new VSC(132, 3.411, 2942.463), new VSC(126, 1.083, 20.775), new VSC(115, 0.645, 0.98), new VSC(103, 0.636, 4694.003), new VSC(102, 0.976, 15720.839), new VSC(102, 4.267, 7.114), new VSC(99, 6.21, 2146.17), new VSC(98, 0.68, 155.42), new VSC(86, 5.98, 161000.69), new VSC(85, 1.3, 6275.96), new VSC(85, 3.67, 71430.7), new VSC(80, 1.81, 17260.15), new VSC(79, 3.04, 12036.46), new VSC(75, 1.76, 5088.63), new VSC(74, 3.5, 3154.69), new VSC(74, 4.68, 801.82), new VSC(70, 0.83, 9437.76), new VSC(62, 3.98, 8827.39), new VSC(61, 1.82, 7084.9), new VSC(57, 2.78, 6286.6), new VSC(56, 4.39, 14143.5), new VSC(56, 3.47, 6279.55), new VSC(52, 0.19, 12139.55), new VSC(52, 1.33, 1748.02), new VSC(51, 0.28, 5856.48), new VSC(49, 0.49, 1194.45), new VSC(41, 5.37, 8429.24), new VSC(41, 2.4, 19651.05), new VSC(39, 6.17, 10447.39), new VSC(37, 6.04, 10213.29), new VSC(37, 2.57, 1059.38), new VSC(36, 1.71, 2352.87), new VSC(36, 1.78, 6812.77), new VSC(33, 0.59, 17789.85), new VSC(30, 0.44, 83996.85), new VSC(30, 2.74, 1349.87), new VSC(25, 3.16, 4690.48)];
+const g_L1EarthCoefficients = [new VSC(628331966747, 0, 0), new VSC(206059, 2.678235, 6283.07585), new VSC(4303, 2.6351, 12566.1517), new VSC(425, 1.59, 3.523), new VSC(119, 5.796, 26.298), new VSC(109, 2.966, 1577.344), new VSC(93, 2.59, 18849.23), new VSC(72, 1.14, 529.69), new VSC(68, 1.87, 398.15), new VSC(67, 4.41, 5507.55), new VSC(59, 2.89, 5223.69), new VSC(56, 2.17, 155.42), new VSC(45, 0.4, 796.3), new VSC(36, 0.47, 775.52), new VSC(29, 2.65, 7.11), new VSC(21, 5.43, 0.98), new VSC(19, 1.85, 5486.78), new VSC(19, 4.97, 213.3), new VSC(17, 2.99, 6275.96), new VSC(16, 0.03, 2544.31), new VSC(16, 1.43, 2146.17), new VSC(15, 1.21, 10977.08), new VSC(12, 2.83, 1748.02), new VSC(12, 3.26, 5088.63), new VSC(12, 5.27, 1194.45), new VSC(12, 2.08, 4694), new VSC(11, 0.77, 553.57), new VSC(10, 1.3, 6286.6), new VSC(10, 4.24, 1349.87), new VSC(9, 2.7, 242.73), new VSC(9, 5.64, 951.72), new VSC(8, 5.3, 2352.87), new VSC(6, 2.65, 9437.76), new VSC(6, 4.67, 4690.48)];
+const g_L2EarthCoefficients = [new VSC(52919, 0, 0), new VSC(8720, 1.0721, 6283.0758), new VSC(309, 0.867, 12566.152), new VSC(27, 0.05, 3.52), new VSC(16, 5.19, 26.3), new VSC(16, 3.68, 155.42), new VSC(10, 0.76, 18849.23), new VSC(9, 2.06, 77713.77), new VSC(7, 0.83, 775.52), new VSC(5, 4.66, 1577.34), new VSC(4, 1.03, 7.11), new VSC(4, 3.44, 5573.14), new VSC(3, 5.14, 796.3), new VSC(3, 6.05, 5507.55), new VSC(3, 1.19, 242.73), new VSC(3, 6.12, 529.69), new VSC(3, 0.31, 398.15), new VSC(3, 2.28, 553.57), new VSC(2, 4.38, 5223.69), new VSC(2, 3.75, 0.98)];
+const g_L3EarthCoefficients = [new VSC(289, 5.844, 6283.076), new VSC(35, 0, 0), new VSC(17, 5.49, 12566.15), new VSC(3, 5.2, 155.42), new VSC(1, 4.72, 3.52), new VSC(1, 5.3, 18849.23), new VSC(1, 5.97, 242.73)];
+const g_L4EarthCoefficients = [new VSC(114, 3.142, 0), new VSC(8, 4.13, 6283.08), new VSC(1, 3.84, 12566.15)];
+const g_L5EarthCoefficients = [new VSC(1, 3.14, 0)];
+const g_B0EarthCoefficients = [new VSC(280, 3.199, 84334.662), new VSC(102, 5.422, 5507.553), new VSC(80, 3.88, 5223.69), new VSC(44, 3.7, 2352.87), new VSC(32, 4, 1577.34)];
+const g_B1EarthCoefficients = [new VSC(9, 3.9, 5507.55), new VSC(6, 1.73, 5223.69)];
+const g_B2EarthCoefficients = [new VSC(22378, 3.38509, 10213.28555), new VSC(282, 0, 0), new VSC(173, 5.256, 20426.571), new VSC(27, 3.87, 30639.86)];
+const g_B3EarthCoefficients = [new VSC(647, 4.992, 10213.286), new VSC(20, 3.14, 0), new VSC(6, 0.77, 20426.57), new VSC(3, 5.44, 30639.86)];
+const g_B4EarthCoefficients = [new VSC(14, 0.32, 10213.29)];
+const g_R0EarthCoefficients = [new VSC(100013989, 0, 0), new VSC(1670700, 3.0984635, 6283.07585), new VSC(13956, 3.05525, 12566.1517), new VSC(3084, 5.1985, 77713.7715), new VSC(1628, 1.1739, 5753.3849), new VSC(1576, 2.8469, 7860.4194), new VSC(925, 5.453, 11506.77), new VSC(542, 4.564, 3930.21), new VSC(472, 3.661, 5884.927), new VSC(346, 0.964, 5507.553), new VSC(329, 5.9, 5223.694), new VSC(307, 0.299, 5573.143), new VSC(243, 4.273, 11790.629), new VSC(212, 5.847, 1577.344), new VSC(186, 5.022, 10977.079), new VSC(175, 3.012, 18849.228), new VSC(110, 5.055, 5486.778), new VSC(98, 0.89, 6069.78), new VSC(86, 5.69, 15720.84), new VSC(86, 1.27, 161000.69), new VSC(65, 0.27, 17260.15), new VSC(63, 0.92, 529.69), new VSC(57, 2.01, 83996.85), new VSC(56, 5.24, 71430.7), new VSC(49, 3.25, 2544.31), new VSC(47, 2.58, 775.52), new VSC(45, 5.54, 9437.76), new VSC(43, 6.01, 6275.96), new VSC(39, 5.36, 4694), new VSC(38, 2.39, 8827.39), new VSC(37, 0.83, 19651.05), new VSC(37, 4.9, 12139.55), new VSC(36, 1.67, 12036.46), new VSC(35, 1.84, 2942.46), new VSC(33, 0.24, 7084.9), new VSC(32, 0.18, 5088.63), new VSC(32, 1.78, 398.15), new VSC(28, 1.21, 6286.6), new VSC(28, 1.9, 6279.55), new VSC(26, 4.59, 10447.39)];
+const g_R1EarthCoefficients = [new VSC(103019, 1.10749, 6283.07585), new VSC(1721, 1.0644, 12566.1517), new VSC(702, 3.142, 0), new VSC(32, 1.02, 18849.23), new VSC(31, 2.84, 5507.55), new VSC(25, 1.32, 5223.69), new VSC(18, 1.42, 1577.34), new VSC(10, 5.91, 10977.08), new VSC(9, 1.42, 6275.96), new VSC(9, 0.27, 5486.78)];
+const g_R2EarthCoefficients = [new VSC(4359, 5.7846, 6283.0758), new VSC(124, 5.579, 12566.152), new VSC(12, 3.14, 0), new VSC(9, 3.63, 77713.77), new VSC(6, 1.87, 5573.14), new VSC(3, 5.47, 18849.23)];
+const g_R3EarthCoefficients = [new VSC(145, 4.273, 6283.076), new VSC(7, 3.92, 12566.15)];
+const g_R4EarthCoefficients = [new VSC(4, 2.56, 6283.08)];
+const g_L1EarthCoefficientsJ2000 = [new VSC(628307584999, 0, 0), new VSC(206059, 2.678235, 6283.07585), new VSC(4303, 2.6351, 12566.1517), new VSC(425, 1.59, 3.523), new VSC(119, 5.796, 26.298), new VSC(109, 2.966, 1577.344), new VSC(93, 2.59, 18849.23), new VSC(72, 1.14, 529.69), new VSC(68, 1.87, 398.15), new VSC(67, 4.41, 5507.55), new VSC(59, 2.89, 5223.69), new VSC(56, 2.17, 155.42), new VSC(45, 0.4, 796.3), new VSC(36, 0.47, 775.52), new VSC(29, 2.65, 7.11), new VSC(21, 5.43, 0.98), new VSC(19, 1.85, 5486.78), new VSC(19, 4.97, 213.3), new VSC(17, 2.99, 6275.96), new VSC(16, 0.03, 2544.31), new VSC(16, 1.43, 2146.17), new VSC(15, 1.21, 10977.08), new VSC(12, 2.83, 1748.02), new VSC(12, 3.26, 5088.63), new VSC(12, 5.27, 1194.45), new VSC(12, 2.08, 4694), new VSC(11, 0.77, 553.57), new VSC(10, 1.3, 6286.6), new VSC(10, 4.24, 1349.87), new VSC(9, 2.7, 242.73), new VSC(9, 5.64, 951.72), new VSC(8, 5.3, 2352.87), new VSC(6, 2.65, 9437.76), new VSC(6, 4.67, 4690.48)];
+const g_L2EarthCoefficientsJ2000 = [new VSC(8722, 1.0725, 6283.0758), new VSC(991, 3.1416, 0), new VSC(295, 0.437, 12566.152), new VSC(27, 0.05, 3.52), new VSC(16, 5.19, 26.3), new VSC(16, 3.69, 155.42), new VSC(9, 0.3, 18849.23), new VSC(9, 2.06, 77713.77), new VSC(7, 0.83, 775.52), new VSC(5, 4.66, 1577.34), new VSC(4, 1.03, 7.11), new VSC(4, 3.44, 5573.14), new VSC(3, 5.14, 796.3), new VSC(3, 6.05, 5507.55), new VSC(3, 1.19, 242.73), new VSC(3, 6.12, 529.69), new VSC(3, 0.3, 398.15), new VSC(3, 2.28, 553.57), new VSC(2, 4.38, 5223.69), new VSC(2, 3.75, 0.98)];
+const g_L3EarthCoefficientsJ2000 = [new VSC(289, 5.842, 6283.076), new VSC(21, 6.05, 12566.15), new VSC(3, 5.2, 155.42), new VSC(3, 3.14, 0), new VSC(1, 4.72, 3.52), new VSC(1, 5.97, 242.73), new VSC(1, 5.54, 18849.23)];
+const g_L4EarthCoefficientsJ2000 = [new VSC(8, 4.14, 6283.08), new VSC(1, 3.28, 12566.15)];
+const g_B1EarthCoefficientsJ2000 = [new VSC(227778, 3.413766, 6283.07585), new VSC(3806, 3.3706, 12566.1517), new VSC(3620, 0, 0), new VSC(72, 3.33, 18849.23), new VSC(8, 3.89, 5507.55), new VSC(8, 1.79, 5223.69), new VSC(6, 5.2, 2352.87)];
+const g_B2EarthCoefficientsJ2000 = [new VSC(9721, 5.1519, 6283.07585), new VSC(233, 3.1416, 0), new VSC(134, 0.644, 12566.152), new VSC(7, 1.07, 18849.23)];
+const g_B3EarthCoefficientsJ2000 = [new VSC(276, 0.595, 6283.076), new VSC(17, 3.14, 0), new VSC(4, 0.12, 12566.15)];
+const g_B4EarthCoefficientsJ2000 = [new VSC(6, 2.27, 6283.08), new VSC(1, 0, 0)];
+
+
+// CAAEarth
+
+export function CAAEarth() { }
+
+CAAEarth.eclipticLongitude = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var rho5 = rho4 * rho;
+ var nL0Coefficients = g_L0EarthCoefficients.length;
+ var L0 = 0;
+ var i;
+ for (i = 0; i < nL0Coefficients; i++) {
+ L0 += g_L0EarthCoefficients[i].a * Math.cos(g_L0EarthCoefficients[i].b + g_L0EarthCoefficients[i].c * rho);
+ }
+ var nL1Coefficients = g_L1EarthCoefficients.length;
+ var L1 = 0;
+ for (i = 0; i < nL1Coefficients; i++) {
+ L1 += g_L1EarthCoefficients[i].a * Math.cos(g_L1EarthCoefficients[i].b + g_L1EarthCoefficients[i].c * rho);
+ }
+ var nL2Coefficients = g_L2EarthCoefficients.length;
+ var L2 = 0;
+ for (i = 0; i < nL2Coefficients; i++) {
+ L2 += g_L2EarthCoefficients[i].a * Math.cos(g_L2EarthCoefficients[i].b + g_L2EarthCoefficients[i].c * rho);
+ }
+ var nL3Coefficients = g_L3EarthCoefficients.length;
+ var L3 = 0;
+ for (i = 0; i < nL3Coefficients; i++) {
+ L3 += g_L3EarthCoefficients[i].a * Math.cos(g_L3EarthCoefficients[i].b + g_L3EarthCoefficients[i].c * rho);
+ }
+ var nL4Coefficients = g_L4EarthCoefficients.length;
+ var L4 = 0;
+ for (i = 0; i < nL4Coefficients; i++) {
+ L4 += g_L4EarthCoefficients[i].a * Math.cos(g_L4EarthCoefficients[i].b + g_L4EarthCoefficients[i].c * rho);
+ }
+ var nL5Coefficients = g_L5EarthCoefficients.length;
+ var L5 = 0;
+ for (i = 0; i < nL5Coefficients; i++) {
+ L5 += g_L5EarthCoefficients[i].a * Math.cos(g_L5EarthCoefficients[i].b + g_L5EarthCoefficients[i].c * rho);
+ }
+ var vvalue = (L0 + L1 * rho + L2 * rhosquared + L3 * rhocubed + L4 * rho4 + L5 * rho5) / 100000000;
+ vvalue = CT.m360(CT.r2D(vvalue));
+ return vvalue;
+};
+
+CAAEarth.eclipticLatitude = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var nB0Coefficients = g_B0EarthCoefficients.length;
+ var B0 = 0;
+ var i;
+ for (i = 0; i < nB0Coefficients; i++) {
+ B0 += g_B0EarthCoefficients[i].a * Math.cos(g_B0EarthCoefficients[i].b + g_B0EarthCoefficients[i].c * rho);
+ }
+ var nB1Coefficients = g_B1EarthCoefficients.length;
+ var B1 = 0;
+ for (i = 0; i < nB1Coefficients; i++) {
+ B1 += g_B1EarthCoefficients[i].a * Math.cos(g_B1EarthCoefficients[i].b + g_B1EarthCoefficients[i].c * rho);
+ }
+ var nB2Coefficients = g_B2EarthCoefficients.length;
+ var B2 = 0;
+ for (i = 0; i < nB2Coefficients; i++) {
+ B2 += g_B2EarthCoefficients[i].a * Math.cos(g_B2EarthCoefficients[i].b + g_B2EarthCoefficients[i].c * rho);
+ }
+ var nB3Coefficients = g_B3EarthCoefficients.length;
+ var B3 = 0;
+ for (i = 0; i < nB3Coefficients; i++) {
+ B3 += g_B3EarthCoefficients[i].a * Math.cos(g_B3EarthCoefficients[i].b + g_B3EarthCoefficients[i].c * rho);
+ }
+ var nB4Coefficients = g_B4EarthCoefficients.length;
+ var B4 = 0;
+ for (i = 0; i < nB4Coefficients; i++) {
+ B4 += g_B4EarthCoefficients[i].a * Math.cos(g_B4EarthCoefficients[i].b + g_B4EarthCoefficients[i].c * rho);
+ }
+ var vvalue = (B0 + B1 * rho + B2 * rhosquared + B3 * rhocubed + B4 * rho4) / 100000000;
+ vvalue = CT.r2D(vvalue);
+ return vvalue;
+};
+
+CAAEarth.radiusVector = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var nR0Coefficients = g_R0EarthCoefficients.length;
+ var R0 = 0;
+ var i;
+ for (i = 0; i < nR0Coefficients; i++) {
+ R0 += g_R0EarthCoefficients[i].a * Math.cos(g_R0EarthCoefficients[i].b + g_R0EarthCoefficients[i].c * rho);
+ }
+ var nR1Coefficients = g_R1EarthCoefficients.length;
+ var R1 = 0;
+ for (i = 0; i < nR1Coefficients; i++) {
+ R1 += g_R1EarthCoefficients[i].a * Math.cos(g_R1EarthCoefficients[i].b + g_R1EarthCoefficients[i].c * rho);
+ }
+ var nR2Coefficients = g_R2EarthCoefficients.length;
+ var R2 = 0;
+ for (i = 0; i < nR2Coefficients; i++) {
+ R2 += g_R2EarthCoefficients[i].a * Math.cos(g_R2EarthCoefficients[i].b + g_R2EarthCoefficients[i].c * rho);
+ }
+ var nR3Coefficients = g_R3EarthCoefficients.length;
+ var R3 = 0;
+ for (i = 0; i < nR3Coefficients; i++) {
+ R3 += g_R3EarthCoefficients[i].a * Math.cos(g_R3EarthCoefficients[i].b + g_R3EarthCoefficients[i].c * rho);
+ }
+ var nR4Coefficients = g_R4EarthCoefficients.length;
+ var R4 = 0;
+ for (i = 0; i < nR4Coefficients; i++) {
+ R4 += g_R4EarthCoefficients[i].a * Math.cos(g_R4EarthCoefficients[i].b + g_R4EarthCoefficients[i].c * rho);
+ }
+ return (R0 + R1 * rho + R2 * rhosquared + R3 * rhocubed + R4 * rho4) / 100000000;
+};
+
+CAAEarth.sunMeanAnomaly = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(357.5291092 + 35999.0502909 * T - 0.0001536 * Tsquared + Tcubed / 24490000);
+};
+
+CAAEarth.eccentricity = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ return 1 - 0.002516 * T - 7.4E-06 * Tsquared;
+};
+
+CAAEarth.eclipticLongitudeJ2000 = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var nL0Coefficients = g_L0EarthCoefficients.length;
+ var L0 = 0;
+ var i;
+ for (i = 0; i < nL0Coefficients; i++) {
+ L0 += g_L0EarthCoefficients[i].a * Math.cos(g_L0EarthCoefficients[i].b + g_L0EarthCoefficients[i].c * rho);
+ }
+ var nL1Coefficients = g_L1EarthCoefficientsJ2000.length;
+ var L1 = 0;
+ for (i = 0; i < nL1Coefficients; i++) {
+ L1 += g_L1EarthCoefficientsJ2000[i].a * Math.cos(g_L1EarthCoefficientsJ2000[i].b + g_L1EarthCoefficientsJ2000[i].c * rho);
+ }
+ var nL2Coefficients = g_L2EarthCoefficientsJ2000.length;
+ var L2 = 0;
+ for (i = 0; i < nL2Coefficients; i++) {
+ L2 += g_L2EarthCoefficientsJ2000[i].a * Math.cos(g_L2EarthCoefficientsJ2000[i].b + g_L2EarthCoefficientsJ2000[i].c * rho);
+ }
+ var nL3Coefficients = g_L3EarthCoefficientsJ2000.length;
+ var L3 = 0;
+ for (i = 0; i < nL3Coefficients; i++) {
+ L3 += g_L3EarthCoefficientsJ2000[i].a * Math.cos(g_L3EarthCoefficientsJ2000[i].b + g_L3EarthCoefficientsJ2000[i].c * rho);
+ }
+ var nL4Coefficients = g_L4EarthCoefficientsJ2000.length;
+ var L4 = 0;
+ for (i = 0; i < nL4Coefficients; i++) {
+ L4 += g_L4EarthCoefficientsJ2000[i].a * Math.cos(g_L4EarthCoefficientsJ2000[i].b + g_L4EarthCoefficientsJ2000[i].c * rho);
+ }
+ var vvalue = (L0 + L1 * rho + L2 * rhosquared + L3 * rhocubed + L4 * rho4) / 100000000;
+ vvalue = CT.m360(CT.r2D(vvalue));
+ return vvalue;
+};
+
+CAAEarth.eclipticLatitudeJ2000 = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var nB0Coefficients = g_B0EarthCoefficients.length;
+ var B0 = 0;
+ var i;
+ for (i = 0; i < nB0Coefficients; i++) {
+ B0 += g_B0EarthCoefficients[i].a * Math.cos(g_B0EarthCoefficients[i].b + g_B0EarthCoefficients[i].c * rho);
+ }
+ var nB1Coefficients = g_B1EarthCoefficientsJ2000.length;
+ var B1 = 0;
+ for (i = 0; i < nB1Coefficients; i++) {
+ B1 += g_B1EarthCoefficientsJ2000[i].a * Math.cos(g_B1EarthCoefficientsJ2000[i].b + g_B1EarthCoefficientsJ2000[i].c * rho);
+ }
+ var nB2Coefficients = g_B2EarthCoefficientsJ2000.length;
+ var B2 = 0;
+ for (i = 0; i < nB2Coefficients; i++) {
+ B2 += g_B2EarthCoefficientsJ2000[i].a * Math.cos(g_B2EarthCoefficientsJ2000[i].b + g_B2EarthCoefficientsJ2000[i].c * rho);
+ }
+ var nB3Coefficients = g_B3EarthCoefficientsJ2000.length;
+ var B3 = 0;
+ for (i = 0; i < nB3Coefficients; i++) {
+ B3 += g_B3EarthCoefficientsJ2000[i].a * Math.cos(g_B3EarthCoefficientsJ2000[i].b + g_B3EarthCoefficientsJ2000[i].c * rho);
+ }
+ var nB4Coefficients = g_B4EarthCoefficientsJ2000.length;
+ var B4 = 0;
+ for (i = 0; i < nB4Coefficients; i++) {
+ B4 += g_B4EarthCoefficientsJ2000[i].a * Math.cos(g_B4EarthCoefficientsJ2000[i].b + g_B4EarthCoefficientsJ2000[i].c * rho);
+ }
+ var vvalue = (B0 + B1 * rho + B2 * rhosquared + B3 * rhocubed + B4 * rho4) / 100000000;
+ vvalue = CT.r2D(vvalue);
+ return vvalue;
+};
+
+var CAAEarth$ = {};
+
+registerType("CAAEarth", [CAAEarth, CAAEarth$, null]);
diff --git a/engine/esm/astrocalc/ecliptical_elements.js b/engine/esm/astrocalc/ecliptical_elements.js
new file mode 100644
index 00000000..7a9e1a01
--- /dev/null
+++ b/engine/esm/astrocalc/ecliptical_elements.js
@@ -0,0 +1,111 @@
+// Originally `AAECLIPTICALELEMENTS.CPP`
+// "Purpose: Implementation for the algorithms which map the ecliptical elements from one equinox to another"
+// Last update of original: PJN / 29-11-2006
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+
+
+// CAAEclipticalElementDetails
+
+export function CAAEclipticalElementDetails() {
+ this.i = 0;
+ this.w = 0;
+ this.omega = 0;
+ this.i = 0;
+ this.w = 0;
+ this.omega = 0;
+}
+
+var CAAEclipticalElementDetails$ = {};
+
+registerType("CAAEclipticalElementDetails", [CAAEclipticalElementDetails, CAAEclipticalElementDetails$, null]);
+
+
+// CAAEclipticalElements
+
+export function CAAEclipticalElements() { }
+
+CAAEclipticalElements.calculate = function (i0, w0, omega0, JD0, JD) {
+ var T = (JD0 - 2451545) / 36525;
+ var Tsquared = T * T;
+ var t = (JD - JD0) / 36525;
+ var tsquared = t * t;
+ var tcubed = tsquared * t;
+ var i0rad = CT.d2R(i0);
+ var omega0rad = CT.d2R(omega0);
+ var eta = (47.0029 - 0.06603 * T + 0.000598 * Tsquared) * t + (-0.03302 + 0.000598 * T) * tsquared + 6E-05 * tcubed;
+ eta = CT.d2R(CT.dmS2D(0, 0, eta));
+ var pi = 174.876384 * 3600 + 3289.4789 * T + 0.60622 * Tsquared - (869.8089 + 0.50491 * T) * t + 0.03536 * tsquared;
+ pi = CT.d2R(CT.dmS2D(0, 0, pi));
+ var p = (5029.0966 + 2.22226 * T - 4.2E-05 * Tsquared) * t + (1.11113 - 4.2E-05 * T) * tsquared - 6E-06 * tcubed;
+ p = CT.d2R(CT.dmS2D(0, 0, p));
+ var sini0rad = Math.sin(i0rad);
+ var cosi0rad = Math.cos(i0rad);
+ var sinomega0rad_pi = Math.sin(omega0rad - pi);
+ var cosomega0rad_pi = Math.cos(omega0rad - pi);
+ var sineta = Math.sin(eta);
+ var coseta = Math.cos(eta);
+ var A = sini0rad * sinomega0rad_pi;
+ var B = -sineta * cosi0rad + coseta * sini0rad * cosomega0rad_pi;
+ var irad = Math.asin(Math.sqrt(A * A + B * B));
+ var details = new CAAEclipticalElementDetails();
+ details.i = CT.r2D(irad);
+ var cosi = cosi0rad * coseta + sini0rad * sineta * cosomega0rad_pi;
+ if (cosi < 0) {
+ details.i = 180 - details.i;
+ }
+ var phi = pi + p;
+ details.omega = CT.m360(CT.r2D(Math.atan2(A, B) + phi));
+ A = -sineta * sinomega0rad_pi;
+ B = sini0rad * coseta - cosi0rad * sineta * cosomega0rad_pi;
+ var deltaw = CT.r2D(Math.atan2(A, B));
+ details.w = CT.m360(w0 + deltaw);
+ return details;
+};
+
+CAAEclipticalElements.fK4B1950ToFK5J2000 = function (i0, w0, omega0) {
+ var L = CT.d2R(5.19856209);
+ var J = CT.d2R(0.00651966);
+ var i0rad = CT.d2R(i0);
+ var omega0rad = CT.d2R(omega0);
+ var sini0rad = Math.sin(i0rad);
+ var cosi0rad = Math.cos(i0rad);
+ var cosJ = Math.cos(J);
+ var sinJ = Math.sin(J);
+ var W = L + omega0rad;
+ var cosW = Math.cos(W);
+ var sinW = Math.sin(W);
+ var A = sinJ * sinW;
+ var B = sini0rad * cosJ + cosi0rad * sinJ * cosW;
+ var details = new CAAEclipticalElementDetails();
+ details.i = CT.r2D(Math.asin(Math.sqrt(A * A + B * B)));
+ var cosi = cosi0rad * cosJ - sini0rad * sinJ * cosW;
+ if (cosi < 0) {
+ details.i = 180 - details.i;
+ }
+ details.w = CT.m360(w0 + CT.r2D(Math.atan2(A, B)));
+ details.omega = CT.m360(CT.r2D(Math.atan2(sini0rad * sinW, cosi0rad * sinJ + sini0rad * cosJ * cosW)) - 4.50001688);
+ return details;
+};
+
+var CAAEclipticalElements$ = {};
+
+registerType("CAAEclipticalElements", [CAAEclipticalElements, CAAEclipticalElements$, null]);
diff --git a/engine/esm/astrocalc/elements_planetary_orbit.js b/engine/esm/astrocalc/elements_planetary_orbit.js
new file mode 100644
index 00000000..4c8cd5ea
--- /dev/null
+++ b/engine/esm/astrocalc/elements_planetary_orbit.js
@@ -0,0 +1,562 @@
+// Originally `AAELEMENTSPLANETARYORBIT.CPP`
+// "Purpose: Implementation for the algorithms to calculate the elements of the planetary orbits"
+// Last update of original: PJN / 29-12-2003
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+
+
+// EPO - was CAAElementsPlanetaryOrbit
+
+export function EPO() { }
+
+EPO.mercuryMeanLongitude = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(252.250906 + 149474.0722491 * T + 0.0003035 * Tsquared + 1.8E-08 * Tcubed);
+};
+
+EPO.mercurySemimajorAxis = function (UnnamedParameter1) {
+ return 0.38709831;
+};
+
+EPO.mercuryEccentricity = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return 0.20563175 + 2.0407E-05 * T - 2.83E-08 * Tsquared - 1.8E-10 * Tcubed;
+};
+
+EPO.mercuryInclination = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(7.004986 + 0.0018215 * T - 1.81E-05 * Tsquared + 5.6E-08 * Tcubed);
+};
+
+EPO.mercuryLongitudeAscendingNode = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(48.330893 + 1.1861883 * T + 0.00017542 * Tsquared + 2.15E-07 * Tcubed);
+};
+
+EPO.mercuryLongitudePerihelion = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(77.456119 + 1.5564776 * T + 0.00029544 * Tsquared + 9E-09 * Tcubed);
+};
+
+EPO.venusMeanLongitude = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(181.979801 + 58519.2130302 * T + 0.00031014 * Tsquared + 1.5E-08 * Tcubed);
+};
+
+EPO.venusSemimajorAxis = function (UnnamedParameter1) {
+ return 0.72332982;
+};
+
+EPO.venusEccentricity = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return 0.00677192 - 4.7765E-05 * T + 9.81E-08 * Tsquared + 4.6E-10 * Tcubed;
+};
+
+EPO.venusInclination = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(3.394662 + 0.0010037 * T - 8.8E-07 * Tsquared - 7E-09 * Tcubed);
+};
+
+EPO.venusLongitudeAscendingNode = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(76.67992 + 0.9011206 * T + 0.00040618 * Tsquared - 9.3E-08 * Tcubed);
+};
+
+EPO.venusLongitudePerihelion = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(131.563703 + 1.4022288 * T - 0.00107618 * Tsquared - 5.678E-06 * Tcubed);
+};
+
+EPO.earthMeanLongitude = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(100.466457 + 36000.7698278 * T + 0.00030322 * Tsquared + 2E-08 * Tcubed);
+};
+
+EPO.earthSemimajorAxis = function (UnnamedParameter1) {
+ return 1.000001018;
+};
+
+EPO.earthEccentricity = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return 0.01670863 - 4.2037E-05 * T - 1.267E-07 * Tsquared + 1.4E-10 * Tcubed;
+};
+
+EPO.earthInclination = function (UnnamedParameter1) {
+ return 0;
+};
+
+EPO.earthLongitudePerihelion = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(102.937348 + 1.17195366 * T + 0.00045688 * Tsquared - 1.8E-08 * Tcubed);
+};
+
+EPO.marsMeanLongitude = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(355.433 + 19141.6964471 * T + 0.00031052 * Tsquared + 1.6E-08 * Tcubed);
+};
+
+EPO.marsSemimajorAxis = function (UnnamedParameter1) {
+ return 1.523679342;
+};
+
+EPO.marsEccentricity = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return 0.09340065 + 9.0484E-05 * T - 8.06E-08 * Tsquared - 2.5E-10 * Tcubed;
+};
+
+EPO.marsInclination = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(1.849726 - 0.0006011 * T + 1.276E-05 * Tsquared - 7E-09 * Tcubed);
+};
+
+EPO.marsLongitudeAscendingNode = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(49.588093 + 0.7720959 * T + 1.557E-05 * Tsquared + 2.267E-06 * Tcubed);
+};
+
+EPO.marsLongitudePerihelion = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(336.060234 + 1.8410449 * T + 0.00013477 * Tsquared + 5.36E-07 * Tcubed);
+};
+
+EPO.jupiterMeanLongitude = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(34.351519 + 3036.3027748 * T + 0.0002233 * Tsquared + 3.7E-08 * Tcubed);
+};
+
+EPO.jupiterSemimajorAxis = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ return 5.202603209 + 1.913E-07 * T;
+};
+
+EPO.jupiterEccentricity = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return 0.04849793 + 0.000163225 * T - 4.714E-07 * Tsquared - 2.01E-09 * Tcubed;
+};
+
+EPO.jupiterInclination = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(1.303267 - 0.0054965 * T + 4.66E-06 * Tsquared - 2E-09 * Tcubed);
+};
+
+EPO.jupiterLongitudeAscendingNode = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(100.464407 + 1.0209774 * T + 0.00040315 * Tsquared + 4.04E-07 * Tcubed);
+};
+
+EPO.jupiterLongitudePerihelion = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(14.331207 + 1.6126352 * T + 0.00103042 * Tsquared - 4.464E-06 * Tcubed);
+};
+
+EPO.saturnMeanLongitude = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(50.077444 + 1223.5110686 * T + 0.00051908 * Tsquared - 3E-08 * Tcubed);
+};
+
+EPO.saturnSemimajorAxis = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ return 9.554909192 - 2.139E-06 * T + 4E-09 * Tsquared;
+};
+
+EPO.saturnEccentricity = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return 0.05554814 - 0.0003446641 * T - 6.436E-07 * Tsquared + 3.4E-09 * Tcubed;
+};
+
+EPO.saturnInclination = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(2.488879 - 0.0037362 * T - 1.519E-05 * Tsquared + 8.7E-08 * Tcubed);
+};
+
+EPO.saturnLongitudeAscendingNode = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(113.665503 + 0.877088 * T - 0.00012176 * Tsquared - 2.249E-06 * Tcubed);
+};
+
+EPO.saturnLongitudePerihelion = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(93.057237 + 1.19637613 * T + 0.00083753 * Tsquared + 4.928E-06 * Tcubed);
+};
+
+EPO.uranusMeanLongitude = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(314.055005 + 429.8640561 * T + 0.0003039 * Tsquared + 2.6E-08 * Tcubed);
+};
+
+EPO.uranusSemimajorAxis = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ return 19.218446062 - 3.72E-08 * T + 9.8E-10 * Tsquared;
+};
+
+EPO.uranusEccentricity = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return 0.04638122 - 2.7293E-05 * T + 7.89E-08 * Tsquared + 2.4E-10 * Tcubed;
+};
+
+EPO.uranusInclination = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(0.773197 + 0.0007744 * T + 3.749E-05 * Tsquared - 9.2E-08 * Tcubed);
+};
+
+EPO.uranusLongitudeAscendingNode = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(74.005957 + 0.5211278 * T + 0.00133947 * Tsquared + 1.8484E-05 * Tcubed);
+};
+
+EPO.uranusLongitudePerihelion = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(173.005291 + 1.486379 * T + 0.00021406 * Tsquared + 4.34E-07 * Tcubed);
+};
+
+EPO.neptuneMeanLongitude = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(304.348665 + 219.8833092 * T + 0.00030882 * Tsquared + 1.8E-08 * Tcubed);
+};
+
+EPO.neptuneSemimajorAxis = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ return 30.110386869 - 1.663E-07 * T + 6.9E-10 * Tsquared;
+};
+
+EPO.neptuneEccentricity = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tcubed = T * T * T;
+ return 0.00945575 + 6.033E-06 * T - 5E-11 * Tcubed;
+};
+
+EPO.neptuneInclination = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(1.769953 - 0.0093082 * T - 7.08E-06 * Tsquared + 2.7E-08 * Tcubed);
+};
+
+EPO.neptuneLongitudeAscendingNode = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(131.784057 + 1.1022039 * T + 0.00025952 * Tsquared - 6.37E-07 * Tcubed);
+};
+
+EPO.neptuneLongitudePerihelion = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(48.120276 + 1.4262957 * T + 0.00038434 * Tsquared + 2E-08 * Tcubed);
+};
+
+EPO.mercuryMeanLongitudeJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(252.250906 + 149472.6746358 * T - 5.36E-06 * Tsquared + 2E-09 * Tcubed);
+};
+
+EPO.mercuryInclinationJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(7.004986 - 0.0059516 * T + 8E-07 * Tsquared + 4.3E-08 * Tcubed);
+};
+
+EPO.mercuryLongitudeAscendingNodeJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(48.330893 - 0.1254227 * T - 8.833E-05 * Tsquared - 2E-07 * Tcubed);
+};
+
+EPO.mercuryLongitudePerihelionJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(77.456119 + 0.1588643 * T - 1.342E-05 * Tsquared - 7E-09 * Tcubed);
+};
+
+EPO.venusMeanLongitudeJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(181.979801 + 58517.815676 * T + 1.65E-06 * Tsquared - 2E-09 * Tcubed);
+};
+
+EPO.venusInclinationJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(3.394662 - 0.0008568 * T - 3.244E-05 * Tsquared + 9E-09 * Tcubed);
+};
+
+EPO.venusLongitudeAscendingNodeJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(76.67992 - 0.2780134 * T - 0.00014257 * Tsquared - 1.64E-07 * Tcubed);
+};
+
+EPO.venusLongitudePerihelionJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(131.563703 + 0.0048746 * T - 0.00138467 * Tsquared - 5.695E-06 * Tcubed);
+};
+
+EPO.earthMeanLongitudeJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(100.466457 + 35999.3728565 * T - 5.68E-06 * Tsquared - 1E-09 * Tcubed);
+};
+
+EPO.earthInclinationJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return 0.0130548 * T - 9.31E-06 * Tsquared - 3.4E-08 * Tcubed;
+};
+
+EPO.earthLongitudeAscendingNodeJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(174.873176 - 0.241098 * T + 4.262E-05 * Tsquared + 1E-09 * Tcubed);
+};
+
+EPO.earthLongitudePerihelionJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(102.937348 + 0.3225654 * T + 0.00014799 * Tsquared - 3.9E-08 * Tcubed);
+};
+
+EPO.marsMeanLongitudeJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(355.433 + 19140.2993039 * T + 2.62E-06 * Tsquared - 3E-09 * Tcubed);
+};
+
+EPO.marsInclinationJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(1.849726 - 0.0081477 * T - 2.255E-05 * Tsquared - 2.9E-08 * Tcubed);
+};
+
+EPO.marsLongitudeAscendingNodeJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(49.588093 - 0.295025 * T - 0.00064048 * Tsquared - 1.964E-06 * Tcubed);
+};
+
+EPO.marsLongitudePerihelionJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(336.060234 + 0.4439016 * T - 0.00017313 * Tsquared + 5.18E-07 * Tcubed);
+};
+
+EPO.jupiterMeanLongitudeJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(34.351519 + 3034.9056606 * T - 8.501E-05 * Tsquared + 1.6E-08 * Tcubed);
+};
+
+EPO.jupiterInclinationJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(1.303267 - 0.0019877 * T + 3.32E-05 * Tsquared + 9.7E-08 * Tcubed);
+};
+
+EPO.jupiterLongitudeAscendingNodeJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(100.464407 + 0.1767232 * T + 0.000907 * Tsquared - 7.272E-06 * Tcubed);
+};
+
+EPO.jupiterLongitudePerihelionJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(14.331207 + 0.2155209 * T + 0.00072211 * Tsquared - 4.485E-06 * Tcubed);
+};
+
+EPO.saturnMeanLongitudeJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(50.077444 + 1222.1138488 * T + 0.00021004 * Tsquared - 4.6E-08 * Tcubed);
+};
+
+EPO.saturnInclinationJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(2.488879 + 0.0025514 * T - 4.906E-05 * Tsquared + 1.7E-08 * Tcubed);
+};
+
+EPO.saturnLongitudeAscendingNodeJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(113.665503 - 0.2566722 * T - 0.00018399 * Tsquared + 4.8E-07 * Tcubed);
+};
+
+EPO.saturnLongitudePerihelionJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(93.057237 + 0.5665415 * T + 0.0005285 * Tsquared + 4.912E-06 * Tcubed);
+};
+
+EPO.uranusMeanLongitudeJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(314.055005 + 428.4669983 * T - 4.86E-06 * Tsquared + 6E-09 * Tcubed);
+};
+
+EPO.uranusInclinationJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(0.773197 - 0.0016869 * T + 3.49E-06 * Tsquared + 1.6E-08 * Tcubed);
+};
+
+EPO.uranusLongitudeAscendingNodeJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(74.005957 + 0.0741431 * T + 0.00040539 * Tsquared + 1.19E-07 * Tcubed);
+};
+
+EPO.uranusLongitudePerihelionJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(173.005291 + 0.0893212 * T - 9.47E-05 * Tsquared + 4.14E-07 * Tcubed);
+};
+
+EPO.neptuneMeanLongitudeJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(304.348665 + 218.4862002 * T + 5.9E-07 * Tsquared - 2E-09 * Tcubed);
+};
+
+EPO.neptuneInclinationJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ return CT.m360(1.769953 + 0.0002256 * T + 2.3E-07 * Tsquared);
+};
+
+EPO.neptuneLongitudeAscendingNodeJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ return CT.m360(131.784057 - 0.0061651 * T - 2.19E-06 * Tsquared - 7.8E-08 * Tcubed);
+};
+
+EPO.neptuneLongitudePerihelionJ2000 = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ return CT.m360(48.120276 + 0.0291866 * T + 7.61E-05 * Tsquared);
+};
+
+var EPO$ = {};
+
+registerType("EPO", [EPO, EPO$, null]);
diff --git a/engine/esm/astrocalc/elliptical.js b/engine/esm/astrocalc/elliptical.js
new file mode 100644
index 00000000..04941270
--- /dev/null
+++ b/engine/esm/astrocalc/elliptical.js
@@ -0,0 +1,490 @@
+// Originally `AAELLIPTICAL.CPP`
+// "Purpose: Implementation for the algorithms for an elliptical orbit"
+// Last update of original: PJN / 05-06-2006
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { Util } from "../baseutil.js";
+import { C3D, CT } from "./coordinate_transformation.js";
+import { CAAEarth } from "./earth.js";
+import { CAAFK5 } from "./fk5.js";
+import { CAANutation } from "./nutation.js";
+import { CAASun } from "./sun.js";
+import { CAAMercury } from "./mercury.js";
+import { CAAVenus } from "./venus.js";
+import { CAAMars } from "./mars.js";
+import { CAAJupiter } from "./jupiter.js";
+import { CAASaturn } from "./saturn.js";
+import { CAAUranus } from "./uranus.js";
+import { CAANeptune } from "./neptune.js";
+import { CAAPluto } from "./pluto.js";
+import { ABR } from "./aberration.js";
+import { CAAKepler } from "./kepler.js";
+import { Vector3d } from "../double3d.js";
+
+
+// EOE - was CAAEllipticalObjectElements
+
+export function EOE() {
+ this.a = 0;
+ this.e = 0;
+ this.i = 0;
+ this.w = 0;
+ this.omega = 0;
+ this.jdEquinox = 0;
+ this.t = 0;
+ this.n = 0;
+ this.meanAnnomolyOut = 0;
+ this.a = 0;
+ this.e = 0;
+ this.i = 0;
+ this.w = 0;
+ this.omega = 0;
+ this.jdEquinox = 0;
+ this.t = 0;
+}
+
+EOE._create = function (br) {
+ var tmp = new EOE();
+ tmp.a = br.readSingle();
+ tmp.e = br.readSingle();
+ tmp.i = br.readSingle();
+ tmp.w = br.readSingle();
+ tmp.omega = br.readSingle();
+ tmp.jdEquinox = br.readSingle();
+ tmp.t = br.readSingle();
+ return tmp;
+};
+
+var EOE$ = {};
+
+registerType("EOE", [EOE, EOE$, null]);
+
+
+// EPD - was CAAEllipticalPlanetaryDetails
+
+export function EPD() {
+ this.apparentGeocentricLongitude = 0;
+ this.apparentGeocentricLatitude = 0;
+ this.apparentGeocentricDistance = 0;
+ this.apparentLightTime = 0;
+ this.apparentGeocentricRA = 0;
+ this.apparentGeocentricDeclination = 0;
+ this.apparentGeocentricLongitude = 0;
+ this.apparentGeocentricLatitude = 0;
+ this.apparentGeocentricDistance = 0;
+ this.apparentLightTime = 0;
+ this.apparentGeocentricRA = 0;
+ this.apparentGeocentricDeclination = 0;
+}
+
+var EPD$ = {};
+
+registerType("EPD", [EPD, EPD$, null]);
+
+
+// EOD - was CAAEllipticalObjectDetails
+
+export function EOD() {
+ this.heliocentricRectangularEquatorial = new C3D();
+ this.heliocentricRectangularEcliptical = new C3D();
+ this.heliocentricEclipticLongitude = 0;
+ this.heliocentricEclipticLatitude = 0;
+ this.trueGeocentricRA = 0;
+ this.trueGeocentricDeclination = 0;
+ this.trueGeocentricDistance = 0;
+ this.trueGeocentricLightTime = 0;
+ this.astrometricGeocenticRA = 0;
+ this.astrometricGeocentricDeclination = 0;
+ this.astrometricGeocentricDistance = 0;
+ this.astrometricGeocentricLightTime = 0;
+ this.elongation = 0;
+ this.phaseAngle = 0;
+ this.heliocentricEclipticLongitude = 0;
+ this.heliocentricEclipticLatitude = 0;
+ this.trueGeocentricRA = 0;
+ this.trueGeocentricDeclination = 0;
+ this.trueGeocentricDistance = 0;
+ this.trueGeocentricLightTime = 0;
+ this.astrometricGeocenticRA = 0;
+ this.astrometricGeocentricDeclination = 0;
+ this.astrometricGeocentricDistance = 0;
+ this.astrometricGeocentricLightTime = 0;
+ this.elongation = 0;
+ this.phaseAngle = 0;
+}
+
+var EOD$ = {};
+
+registerType("EOD", [EOD, EOD$, null]);
+
+
+// EO - was EllipticalObject
+
+export var EO = {
+ SUN: 0,
+ MERCURY: 1,
+ VENUS: 2,
+ MARS: 3,
+ JUPITER: 4,
+ SATURN: 5,
+ URANUS: 6,
+ NEPTUNE: 7,
+ PLUTO: 8
+};
+
+registerType("EO", EO);
+
+
+// ELL - was CAAElliptical
+
+export function ELL() { }
+
+ELL.distanceToLightTime = function (Distance) {
+ return Distance * 0.0057755183;
+};
+
+ELL.calculate = function (JD, oobject) {
+ var details = new EPD();
+ var JD0 = JD;
+ var L0 = 0;
+ var B0 = 0;
+ var R0 = 0;
+ var cosB0 = 0;
+ if (!!oobject) {
+ L0 = CAAEarth.eclipticLongitude(JD0);
+ B0 = CAAEarth.eclipticLatitude(JD0);
+ R0 = CAAEarth.radiusVector(JD0);
+ L0 = CT.d2R(L0);
+ B0 = CT.d2R(B0);
+ cosB0 = Math.cos(B0);
+ }
+ var L = 0;
+ var B = 0;
+ var R = 0;
+ var Lrad;
+ var Brad;
+ var cosB;
+ var cosL;
+ var x;
+ var y;
+ var z;
+ var bRecalc = true;
+ var bFirstRecalc = true;
+ var LPrevious = 0;
+ var BPrevious = 0;
+ var RPrevious = 0;
+ while (bRecalc) {
+ switch (oobject) {
+ case 0:
+ L = CAASun.geometricEclipticLongitude(JD0);
+ B = CAASun.geometricEclipticLatitude(JD0);
+ R = CAAEarth.radiusVector(JD0);
+ break;
+ case 1:
+ L = CAAMercury.eclipticLongitude(JD0);
+ B = CAAMercury.eclipticLatitude(JD0);
+ R = CAAMercury.radiusVector(JD0);
+ break;
+ case 2:
+ L = CAAVenus.eclipticLongitude(JD0);
+ B = CAAVenus.eclipticLatitude(JD0);
+ R = CAAVenus.radiusVector(JD0);
+ break;
+ case 3:
+ L = CAAMars.eclipticLongitude(JD0);
+ B = CAAMars.eclipticLatitude(JD0);
+ R = CAAMars.radiusVector(JD0);
+ break;
+ case 4:
+ L = CAAJupiter.eclipticLongitude(JD0);
+ B = CAAJupiter.eclipticLatitude(JD0);
+ R = CAAJupiter.radiusVector(JD0);
+ break;
+ case 5:
+ L = CAASaturn.eclipticLongitude(JD0);
+ B = CAASaturn.eclipticLatitude(JD0);
+ R = CAASaturn.radiusVector(JD0);
+ break;
+ case 6:
+ L = CAAUranus.eclipticLongitude(JD0);
+ B = CAAUranus.eclipticLatitude(JD0);
+ R = CAAUranus.radiusVector(JD0);
+ break;
+ case 7:
+ L = CAANeptune.eclipticLongitude(JD0);
+ B = CAANeptune.eclipticLatitude(JD0);
+ R = CAANeptune.radiusVector(JD0);
+ break;
+ case 8:
+ L = CAAPluto.eclipticLongitude(JD0);
+ B = CAAPluto.eclipticLatitude(JD0);
+ R = CAAPluto.radiusVector(JD0);
+ break;
+ default:
+ console.assert(false);
+ break;
+ }
+ if (!bFirstRecalc) {
+ bRecalc = ((Math.abs(L - LPrevious) > 1E-05) || (Math.abs(B - BPrevious) > 1E-05) || (Math.abs(R - RPrevious) > 1E-06));
+ LPrevious = L;
+ BPrevious = B;
+ RPrevious = R;
+ }
+ else {
+ bFirstRecalc = false;
+ }
+ if (bRecalc) {
+ var distance = 0;
+ if (!!oobject) {
+ Lrad = CT.d2R(L);
+ Brad = CT.d2R(B);
+ cosB = Math.cos(Brad);
+ cosL = Math.cos(Lrad);
+ x = R * cosB * cosL - R0 * cosB0 * Math.cos(L0);
+ y = R * cosB * Math.sin(Lrad) - R0 * cosB0 * Math.sin(L0);
+ z = R * Math.sin(Brad) - R0 * Math.sin(B0);
+ distance = Math.sqrt(x * x + y * y + z * z);
+ }
+ else {
+ distance = R;
+ }
+ JD0 = JD - ELL.distanceToLightTime(distance);
+ }
+ }
+ Lrad = CT.d2R(L);
+ Brad = CT.d2R(B);
+ cosB = Math.cos(Brad);
+ cosL = Math.cos(Lrad);
+ x = R * cosB * cosL - R0 * cosB0 * Math.cos(L0);
+ y = R * cosB * Math.sin(Lrad) - R0 * cosB0 * Math.sin(L0);
+ z = R * Math.sin(Brad) - R0 * Math.sin(B0);
+ var x2 = x * x;
+ var y2 = y * y;
+ details.apparentGeocentricLatitude = CT.r2D(Math.atan2(z, Math.sqrt(x2 + y2)));
+ details.apparentGeocentricDistance = Math.sqrt(x2 + y2 + z * z);
+ details.apparentGeocentricLongitude = CT.m360(CT.r2D(Math.atan2(y, x)));
+ details.apparentLightTime = ELL.distanceToLightTime(details.apparentGeocentricDistance);
+ var Aberration = ABR.eclipticAberration(details.apparentGeocentricLongitude, details.apparentGeocentricLatitude, JD);
+ details.apparentGeocentricLongitude += Aberration.x;
+ details.apparentGeocentricLatitude += Aberration.y;
+ var DeltaLong = CAAFK5.correctionInLongitude(details.apparentGeocentricLongitude, details.apparentGeocentricLatitude, JD);
+ details.apparentGeocentricLatitude += CAAFK5.correctionInLatitude(details.apparentGeocentricLongitude, JD);
+ details.apparentGeocentricLongitude += DeltaLong;
+ var NutationInLongitude = CAANutation.nutationInLongitude(JD);
+ var Epsilon = CAANutation.trueObliquityOfEcliptic(JD);
+ details.apparentGeocentricLongitude += CT.dmS2D(0, 0, NutationInLongitude);
+ var ApparentEqu = CT.ec2Eq(details.apparentGeocentricLongitude, details.apparentGeocentricLatitude, Epsilon);
+ details.apparentGeocentricRA = ApparentEqu.x;
+ details.apparentGeocentricDeclination = ApparentEqu.y;
+ return details;
+};
+
+ELL.semiMajorAxisFromPerihelionDistance = function (q, e) {
+ return q / (1 - e);
+};
+
+ELL.meanMotionFromSemiMajorAxis = function (a) {
+ return 0.9856076686 / (a * Math.sqrt(a));
+};
+
+ELL.calculateRectangularJD = function (JD, elements) {
+ var JD0 = JD;
+ var omega = CT.d2R(elements.omega);
+ var w = CT.d2R(elements.w);
+ var i = CT.d2R(elements.i);
+ var sinEpsilon = 0;
+ var cosEpsilon = 1;
+ var sinOmega = Math.sin(omega);
+ var cosOmega = Math.cos(omega);
+ var cosi = Math.cos(i);
+ var sini = Math.sin(i);
+ var F = cosOmega;
+ var G = sinOmega * cosEpsilon;
+ var H = sinOmega * sinEpsilon;
+ var P = -sinOmega * cosi;
+ var Q = cosOmega * cosi * cosEpsilon - sini * sinEpsilon;
+ var R = cosOmega * cosi * sinEpsilon + sini * cosEpsilon;
+ var a = Math.sqrt(F * F + P * P);
+ var b = Math.sqrt(G * G + Q * Q);
+ var c = Math.sqrt(H * H + R * R);
+ var A = Math.atan2(F, P);
+ var B = Math.atan2(G, Q);
+ var C = Math.atan2(H, R);
+ var M = elements.n * (JD0 - elements.t);
+ elements.meanAnnomolyOut = M;
+ var E = CAAKepler.calculate(M, elements.e);
+ E = CT.d2R(E);
+ var v = 2 * Math.atan(Math.sqrt((1 + elements.e) / (1 - elements.e)) * Math.tan(E / 2));
+ var r = elements.a * (1 - elements.e * Math.cos(E));
+ var x = r * a * Math.sin(A + w + v);
+ var y = r * b * Math.sin(B + w + v);
+ var z = r * c * Math.sin(C + w + v);
+ return Vector3d.create(x, z, y);
+};
+
+ELL.calculateRectangular = function (elements, meanAnomoly) {
+ var omega = CT.d2R(elements.omega);
+ var w = CT.d2R(elements.w);
+ var i = CT.d2R(elements.i);
+ var sinEpsilon = 0;
+ var cosEpsilon = 1;
+ var sinOmega = Math.sin(omega);
+ var cosOmega = Math.cos(omega);
+ var cosi = Math.cos(i);
+ var sini = Math.sin(i);
+ var F = cosOmega;
+ var G = sinOmega * cosEpsilon;
+ var H = sinOmega * sinEpsilon;
+ var P = -sinOmega * cosi;
+ var Q = cosOmega * cosi * cosEpsilon - sini * sinEpsilon;
+ var R = cosOmega * cosi * sinEpsilon + sini * cosEpsilon;
+ var a = Math.sqrt(F * F + P * P);
+ var b = Math.sqrt(G * G + Q * Q);
+ var c = Math.sqrt(H * H + R * R);
+ var A = Math.atan2(F, P);
+ var B = Math.atan2(G, Q);
+ var C = Math.atan2(H, R);
+ var n = elements.n;
+ var M = meanAnomoly;
+ var E = CAAKepler.calculate(M, elements.e);
+ E = CT.d2R(E);
+ var v = 2 * Math.atan(Math.sqrt((1 + elements.e) / (1 - elements.e)) * Math.tan(E / 2));
+ var r = elements.a * (1 - elements.e * Math.cos(E));
+ var x = r * a * Math.sin(A + w + v);
+ var y = r * b * Math.sin(B + w + v);
+ var z = r * c * Math.sin(C + w + v);
+ return Vector3d.create(x, z, y);
+};
+
+ELL.calculateElements = function (JD, elements) {
+ var Epsilon = CAANutation.meanObliquityOfEcliptic(elements.jdEquinox);
+ var JD0 = JD;
+ var details = new EOD();
+ Epsilon = CT.d2R(Epsilon);
+ var omega = CT.d2R(elements.omega);
+ var w = CT.d2R(elements.w);
+ var i = CT.d2R(elements.i);
+ var sinEpsilon = Math.sin(Epsilon);
+ var cosEpsilon = Math.cos(Epsilon);
+ var sinOmega = Math.sin(omega);
+ var cosOmega = Math.cos(omega);
+ var cosi = Math.cos(i);
+ var sini = Math.sin(i);
+ var F = cosOmega;
+ var G = sinOmega * cosEpsilon;
+ var H = sinOmega * sinEpsilon;
+ var P = -sinOmega * cosi;
+ var Q = cosOmega * cosi * cosEpsilon - sini * sinEpsilon;
+ var R = cosOmega * cosi * sinEpsilon + sini * cosEpsilon;
+ var a = Math.sqrt(F * F + P * P);
+ var b = Math.sqrt(G * G + Q * Q);
+ var c = Math.sqrt(H * H + R * R);
+ var A = Math.atan2(F, P);
+ var B = Math.atan2(G, Q);
+ var C = Math.atan2(H, R);
+ var n = ELL.meanMotionFromSemiMajorAxis(elements.a);
+ var SunCoord = CAASun.equatorialRectangularCoordinatesAnyEquinox(JD, elements.jdEquinox);
+ for (var j = 0; j < 2; j++) {
+ var M = n * (JD0 - elements.t);
+ var E = CAAKepler.calculate(M, elements.e);
+ E = CT.d2R(E);
+ var v = 2 * Math.atan(Math.sqrt((1 + elements.e) / (1 - elements.e)) * Math.tan(E / 2));
+ var r = elements.a * (1 - elements.e * Math.cos(E));
+ var x = r * a * Math.sin(A + w + v);
+ var y = r * b * Math.sin(B + w + v);
+ var z = r * c * Math.sin(C + w + v);
+ if (!j) {
+ details.heliocentricRectangularEquatorial.x = x;
+ details.heliocentricRectangularEquatorial.y = y;
+ details.heliocentricRectangularEquatorial.z = z;
+ var u = omega + v;
+ var cosu = Math.cos(u);
+ var sinu = Math.sin(u);
+ details.heliocentricRectangularEcliptical.x = r * (cosOmega * cosu - sinOmega * sinu * cosi);
+ details.heliocentricRectangularEcliptical.y = r * (sinOmega * cosu + cosOmega * sinu * cosi);
+ details.heliocentricRectangularEcliptical.z = r * sini * sinu;
+ details.heliocentricEclipticLongitude = Math.atan2(y, x);
+ details.heliocentricEclipticLongitude = CT.m24(CT.r2D(details.heliocentricEclipticLongitude) / 15);
+ details.heliocentricEclipticLatitude = Math.asin(z / r);
+ details.heliocentricEclipticLatitude = CT.r2D(details.heliocentricEclipticLatitude);
+ }
+ var psi = SunCoord.x + x;
+ var nu = SunCoord.y + y;
+ var sigma = SunCoord.z + z;
+ var Alpha = Math.atan2(nu, psi);
+ Alpha = CT.r2D(Alpha);
+ var Delta = Math.atan2(sigma, Math.sqrt(psi * psi + nu * nu));
+ Delta = CT.r2D(Delta);
+ var Distance = Math.sqrt(psi * psi + nu * nu + sigma * sigma);
+ if (!j) {
+ details.trueGeocentricRA = CT.m24(Alpha / 15);
+ details.trueGeocentricDeclination = Delta;
+ details.trueGeocentricDistance = Distance;
+ details.trueGeocentricLightTime = ELL.distanceToLightTime(Distance);
+ }
+ else {
+ details.astrometricGeocenticRA = CT.m24(Alpha / 15);
+ details.astrometricGeocentricDeclination = Delta;
+ details.astrometricGeocentricDistance = Distance;
+ details.astrometricGeocentricLightTime = ELL.distanceToLightTime(Distance);
+ var RES = Math.sqrt(SunCoord.x * SunCoord.x + SunCoord.y * SunCoord.y + SunCoord.z * SunCoord.z);
+ details.elongation = Math.acos((RES * RES + Distance * Distance - r * r) / (2 * RES * Distance));
+ details.elongation = CT.r2D(details.elongation);
+ details.phaseAngle = Math.acos((r * r + Distance * Distance - RES * RES) / (2 * r * Distance));
+ details.phaseAngle = CT.r2D(details.phaseAngle);
+ }
+ if (!j) {
+ JD0 = JD - details.trueGeocentricLightTime;
+ }
+ }
+ return details;
+};
+
+ELL.instantaneousVelocity = function (r, a) {
+ return 42.1219 * Math.sqrt((1 / r) - (1 / (2 * a)));
+};
+
+ELL.velocityAtPerihelion = function (e, a) {
+ return 29.7847 / Math.sqrt(a) * Math.sqrt((1 + e) / (1 - e));
+};
+
+ELL.velocityAtAphelion = function (e, a) {
+ return 29.7847 / Math.sqrt(a) * Math.sqrt((1 - e) / (1 + e));
+};
+
+ELL.lengthOfEllipse = function (e, a) {
+ var b = a * Math.sqrt(1 - e * e);
+ return CT.PI() * (3 * (a + b) - Math.sqrt((a + 3 * b) * (3 * a + b)));
+};
+
+ELL.cometMagnitude = function (g, delta, k, r) {
+ return g + 5 * Util.log10(delta) + k * Util.log10(r);
+};
+
+ELL.minorPlanetMagnitude = function (H, delta, G, r, PhaseAngle) {
+ PhaseAngle = CT.d2R(PhaseAngle);
+ var phi1 = Math.exp(-3.33 * Math.pow(Math.tan(PhaseAngle / 2), 0.63));
+ var phi2 = Math.exp(-1.87 * Math.pow(Math.tan(PhaseAngle / 2), 1.22));
+ return H + 5 * Util.log10(r * delta) - 2.5 * Util.log10((1 - G) * phi1 + G * phi2);
+};
+
+var ELL$ = {};
+
+registerType("ELL", [ELL, ELL$, null]);
diff --git a/engine/esm/astrocalc/equation_of_time.js b/engine/esm/astrocalc/equation_of_time.js
new file mode 100644
index 00000000..037ca094
--- /dev/null
+++ b/engine/esm/astrocalc/equation_of_time.js
@@ -0,0 +1,54 @@
+// Originally `AAEQUATIONOFTIME.CPP`
+// "Purpose: Implementation for the algorithms to calculate the "Equation of Time""
+// Last update of original: PJN / 05-07-2005
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+import { CAANutation } from "./nutation.js";
+import { CAASun } from "./sun.js";
+
+
+// EOT
+
+export function EOT() { }
+
+EOT.calculate = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var rho5 = rho4 * rho;
+ var L0 = CT.m360(280.4664567 + 360007.6982779 * rho + 0.03032028 * rhosquared + rhocubed / 49931 - rho4 / 15300 - rho5 / 2000000);
+ var SunLong = CAASun.apparentEclipticLongitude(JD);
+ var SunLat = CAASun.apparentEclipticLatitude(JD);
+ var epsilon = CAANutation.trueObliquityOfEcliptic(JD);
+ var Equatorial = CT.ec2Eq(SunLong, SunLat, epsilon);
+ epsilon = CT.d2R(epsilon);
+ var E = L0 - 0.0057183 - Equatorial.x * 15 + CT.dmS2D(0, 0, CAANutation.nutationInLongitude(JD)) * Math.cos(epsilon);
+ if (E > 180) {
+ E = -(360 - E);
+ }
+ E *= 4;
+ return E;
+};
+
+var EOT$ = {};
+
+registerType("EOT", [EOT, EOT$, null]);
diff --git a/engine/esm/astrocalc/fk5.js b/engine/esm/astrocalc/fk5.js
new file mode 100644
index 00000000..33b2cbd0
--- /dev/null
+++ b/engine/esm/astrocalc/fk5.js
@@ -0,0 +1,98 @@
+// Originally `AAFK5.CPP`
+// "Purpose: Implementation for the algorithms to convert to the FK5 standard reference frame"
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { C3D, CT } from "./coordinate_transformation.js";
+
+
+// CAAFK5
+
+export function CAAFK5() { }
+
+CAAFK5.correctionInLongitude = function (Longitude, Latitude, JD) {
+ var T = (JD - 2451545) / 36525;
+ var Ldash = Longitude - 1.397 * T - 0.00031 * T * T;
+ Ldash = CT.d2R(Ldash);
+ Longitude = CT.d2R(Longitude);
+ Latitude = CT.d2R(Latitude);
+ var vvalue = -0.09033 + 0.03916 * (Math.cos(Ldash) + Math.sin(Ldash)) * Math.tan(Latitude);
+ return CT.dmS2D(0, 0, vvalue);
+};
+
+CAAFK5.correctionInLatitude = function (Longitude, JD) {
+ var T = (JD - 2451545) / 36525;
+ var Ldash = Longitude - 1.397 * T - 0.00031 * T * T;
+ Ldash = CT.d2R(Ldash);
+ Longitude = CT.d2R(Longitude);
+ var vvalue = 0.03916 * (Math.cos(Ldash) - Math.sin(Ldash));
+ return CT.dmS2D(0, 0, vvalue);
+};
+
+CAAFK5.convertVSOPToFK5J2000 = function (vvalue) {
+ var result = new C3D();
+ result.x = vvalue.x + 4.4036E-07 * vvalue.y - 1.90919E-07 * vvalue.z;
+ result.y = -4.79966E-07 * vvalue.x + 0.917482137087 * vvalue.y - 0.397776982902 * vvalue.z;
+ result.z = 0.397776982902 * vvalue.y + 0.917482137087 * vvalue.z;
+ return result;
+};
+
+CAAFK5.convertVSOPToFK5B1950 = function (vvalue) {
+ var result = new C3D();
+ result.x = 0.999925702634 * vvalue.x + 0.012189716217 * vvalue.y + 1.1134016E-05 * vvalue.z;
+ result.y = -0.011179418036 * vvalue.x + 0.917413998946 * vvalue.y - 0.397777041885 * vvalue.z;
+ result.z = -0.004859003787 * vvalue.x + 0.397747363646 * vvalue.y + 0.917482111428 * vvalue.z;
+ return result;
+};
+
+CAAFK5.convertVSOPToFK5AnyEquinox = function (vvalue, JDEquinox) {
+ var t = (JDEquinox - 2451545) / 36525;
+ var tsquared = t * t;
+ var tcubed = tsquared * t;
+ var sigma = 2306.2181 * t + 0.30188 * tsquared + 0.017988 * tcubed;
+ sigma = CT.d2R(CT.dmS2D(0, 0, sigma));
+ var zeta = 2306.2181 * t + 1.09468 * tsquared + 0.018203 * tcubed;
+ zeta = CT.d2R(CT.dmS2D(0, 0, zeta));
+ var phi = 2004.3109 * t - 0.42665 * tsquared - 0.041833 * tcubed;
+ phi = CT.d2R(CT.dmS2D(0, 0, phi));
+ var cossigma = Math.cos(sigma);
+ var coszeta = Math.cos(zeta);
+ var cosphi = Math.cos(phi);
+ var sinsigma = Math.sin(sigma);
+ var sinzeta = Math.sin(zeta);
+ var sinphi = Math.sin(phi);
+ var xx = cossigma * coszeta * cosphi - sinsigma * sinzeta;
+ var xy = sinsigma * coszeta + cossigma * sinzeta * cosphi;
+ var xz = cossigma * sinphi;
+ var yx = -cossigma * sinzeta - sinsigma * coszeta * cosphi;
+ var yy = cossigma * coszeta - sinsigma * sinzeta * cosphi;
+ var yz = -sinsigma * sinphi;
+ var zx = -coszeta * sinphi;
+ var zy = -sinzeta * sinphi;
+ var zz = cosphi;
+ var result = new C3D();
+ result.x = xx * vvalue.x + yx * vvalue.y + zx * vvalue.z;
+ result.y = xy * vvalue.x + yy * vvalue.y + zy * vvalue.z;
+ result.z = xz * vvalue.x + yz * vvalue.y + zz * vvalue.z;
+ return result;
+};
+
+var CAAFK5$ = {};
+
+registerType("CAAFK5", [CAAFK5, CAAFK5$, null]);
diff --git a/engine/esm/astrocalc/galilean_moons.js b/engine/esm/astrocalc/galilean_moons.js
new file mode 100644
index 00000000..97a3c4f8
--- /dev/null
+++ b/engine/esm/astrocalc/galilean_moons.js
@@ -0,0 +1,388 @@
+// Originally `AAGALILEANMOONS.CPP`
+// "Purpose: Implementation for the algorithms which obtain the positions of the 4 great moons of Jupiter"
+// Last update of original: PJN / 06-01-2004
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { C3D, CT } from "./coordinate_transformation.js";
+import { CAASun } from "./sun.js";
+import { CAAEarth } from "./earth.js";
+import { CAAJupiter } from "./jupiter.js";
+import { ELL } from "./elliptical.js";
+import { EPO } from "./elements_planetary_orbit.js";
+
+
+// GMD - was CAAGalileanMoonDetail
+
+export function GMD() {
+ this.meanLongitude = 0;
+ this.trueLongitude = 0;
+ this.tropicalLongitude = 0;
+ this.equatorialLatitude = 0;
+ this.r = 0;
+ this.eclipticRectangularCoordinates = new C3D();
+ this.trueRectangularCoordinates = new C3D();
+ this.apparentRectangularCoordinates = new C3D();
+ this.bInTransit = false;
+ this.bInOccultation = false;
+ this.bInEclipse = false;
+ this.bInShadowTransit = false;
+ this.apparentShadowRectangularCoordinates = new C3D();
+ this.meanLongitude = 0;
+ this.trueLongitude = 0;
+ this.tropicalLongitude = 0;
+ this.equatorialLatitude = 0;
+ this.r = 0;
+ this.bInTransit = false;
+ this.bInOccultation = false;
+ this.bInEclipse = false;
+ this.bInShadowTransit = false;
+}
+
+var GMD$ = {};
+
+registerType("GMD", [GMD, GMD$, null]);
+
+
+// GMDS - was CAAGalileanMoonsDetails
+
+export function GMDS() {
+ this.satellite1 = new GMD();
+ this.satellite2 = new GMD();
+ this.satellite3 = new GMD();
+ this.satellite4 = new GMD();
+}
+
+var GMDS$ = {};
+
+registerType("GMDS", [GMDS, GMDS$, null]);
+
+
+// GM - was CAAGalileanMoons
+
+export function GM() { }
+
+GM.calculate = function (JD) {
+ var sunlong = CAASun.geometricEclipticLongitude(JD);
+ var sunlongrad = CT.d2R(sunlong);
+ var beta = CAASun.geometricEclipticLatitude(JD);
+ var betarad = CT.d2R(beta);
+ var R = CAAEarth.radiusVector(JD);
+ var DELTA = 5;
+ var PreviousEarthLightTravelTime = 0;
+ var EarthLightTravelTime = ELL.distanceToLightTime(DELTA);
+ var JD1 = JD - EarthLightTravelTime;
+ var bIterate = true;
+ var x = 0;
+ var y = 0;
+ var z = 0;
+ var l = 0;
+ var lrad = 0;
+ var b = 0;
+ var brad = 0;
+ var r = 0;
+ while (bIterate) {
+ l = CAAJupiter.eclipticLongitude(JD1);
+ lrad = CT.d2R(l);
+ b = CAAJupiter.eclipticLatitude(JD1);
+ brad = CT.d2R(b);
+ r = CAAJupiter.radiusVector(JD1);
+ x = r * Math.cos(brad) * Math.cos(lrad) + R * Math.cos(sunlongrad);
+ y = r * Math.cos(brad) * Math.sin(lrad) + R * Math.sin(sunlongrad);
+ z = r * Math.sin(brad) + R * Math.sin(betarad);
+ DELTA = Math.sqrt(x * x + y * y + z * z);
+ EarthLightTravelTime = ELL.distanceToLightTime(DELTA);
+ bIterate = (Math.abs(EarthLightTravelTime - PreviousEarthLightTravelTime) > 2E-06);
+ if (bIterate) {
+ JD1 = JD - EarthLightTravelTime;
+ PreviousEarthLightTravelTime = EarthLightTravelTime;
+ }
+ }
+ var details1 = GM.calculateHelper(JD, sunlongrad, betarad, R);
+ GM.fillInPhenomenaDetails(details1.satellite1);
+ GM.fillInPhenomenaDetails(details1.satellite2);
+ GM.fillInPhenomenaDetails(details1.satellite3);
+ GM.fillInPhenomenaDetails(details1.satellite4);
+ JD1 = JD - EarthLightTravelTime;
+ l = CAAJupiter.eclipticLongitude(JD1);
+ lrad = CT.d2R(l);
+ b = CAAJupiter.eclipticLatitude(JD1);
+ brad = CT.d2R(b);
+ r = CAAJupiter.radiusVector(JD1);
+ x = r * Math.cos(brad) * Math.cos(lrad);
+ y = r * Math.cos(brad) * Math.sin(lrad);
+ z = r * Math.sin(brad);
+ DELTA = Math.sqrt(x * x + y * y + z * z);
+ var SunLightTravelTime = ELL.distanceToLightTime(DELTA);
+ var details2 = GM.calculateHelper(JD + SunLightTravelTime - EarthLightTravelTime, sunlongrad, betarad, 0);
+ GM.fillInPhenomenaDetails(details2.satellite1);
+ GM.fillInPhenomenaDetails(details2.satellite2);
+ GM.fillInPhenomenaDetails(details2.satellite3);
+ GM.fillInPhenomenaDetails(details2.satellite4);
+ details1.satellite1.bInEclipse = details2.satellite1.bInOccultation;
+ details1.satellite2.bInEclipse = details2.satellite2.bInOccultation;
+ details1.satellite3.bInEclipse = details2.satellite3.bInOccultation;
+ details1.satellite4.bInEclipse = details2.satellite4.bInOccultation;
+ details1.satellite1.bInShadowTransit = details2.satellite1.bInTransit;
+ details1.satellite2.bInShadowTransit = details2.satellite2.bInTransit;
+ details1.satellite3.bInShadowTransit = details2.satellite3.bInTransit;
+ details1.satellite4.bInShadowTransit = details2.satellite4.bInTransit;
+ details1.satellite1.apparentShadowRectangularCoordinates = details2.satellite1.apparentRectangularCoordinates;
+ details1.satellite2.apparentShadowRectangularCoordinates = details2.satellite2.apparentRectangularCoordinates;
+ details1.satellite3.apparentShadowRectangularCoordinates = details2.satellite3.apparentRectangularCoordinates;
+ details1.satellite4.apparentShadowRectangularCoordinates = details2.satellite4.apparentRectangularCoordinates;
+ return details1;
+};
+
+GM.calculateHelper = function (JD, sunlongrad, betarad, R) {
+ var details = new GMDS();
+ var DELTA = 5;
+ var PreviousLightTravelTime = 0;
+ var LightTravelTime = ELL.distanceToLightTime(DELTA);
+ var x = 0;
+ var y = 0;
+ var z = 0;
+ var l = 0;
+ var lrad = 0;
+ var b = 0;
+ var brad = 0;
+ var r = 0;
+ var JD1 = JD - LightTravelTime;
+ var bIterate = true;
+ while (bIterate) {
+ l = CAAJupiter.eclipticLongitude(JD1);
+ lrad = CT.d2R(l);
+ b = CAAJupiter.eclipticLatitude(JD1);
+ brad = CT.d2R(b);
+ r = CAAJupiter.radiusVector(JD1);
+ x = r * Math.cos(brad) * Math.cos(lrad) + R * Math.cos(sunlongrad);
+ y = r * Math.cos(brad) * Math.sin(lrad) + R * Math.sin(sunlongrad);
+ z = r * Math.sin(brad) + R * Math.sin(betarad);
+ DELTA = Math.sqrt(x * x + y * y + z * z);
+ LightTravelTime = ELL.distanceToLightTime(DELTA);
+ bIterate = (Math.abs(LightTravelTime - PreviousLightTravelTime) > 2E-06);
+ if (bIterate) {
+ JD1 = JD - LightTravelTime;
+ PreviousLightTravelTime = LightTravelTime;
+ }
+ }
+ var lambda0 = Math.atan2(y, x);
+ var beta0 = Math.atan(z / Math.sqrt(x * x + y * y));
+ var t = JD - 2443000.5 - LightTravelTime;
+ var l1 = 106.07719 + 203.48895579 * t;
+ var l1rad = CT.d2R(l1);
+ var l2 = 175.73161 + 101.374724735 * t;
+ var l2rad = CT.d2R(l2);
+ var l3 = 120.55883 + 50.317609207 * t;
+ var l3rad = CT.d2R(l3);
+ var l4 = 84.44459 + 21.571071177 * t;
+ var l4rad = CT.d2R(l4);
+ var pi1 = CT.d2R(CT.m360(97.0881 + 0.16138586 * t));
+ var pi2 = CT.d2R(CT.m360(154.8663 + 0.04726307 * t));
+ var pi3 = CT.d2R(CT.m360(188.184 + 0.00712734 * t));
+ var pi4 = CT.d2R(CT.m360(335.2868 + 0.00184 * t));
+ var w1 = 312.3346 - 0.13279386 * t;
+ var w1rad = CT.d2R(w1);
+ var w2 = 100.4411 - 0.03263064 * t;
+ var w2rad = CT.d2R(w2);
+ var w3 = 119.1942 - 0.00717703 * t;
+ var w3rad = CT.d2R(w3);
+ var w4 = 322.6186 - 0.00175934 * t;
+ var w4rad = CT.d2R(w4);
+ var GAMMA = 0.33033 * Math.sin(CT.d2R(163.679 + 0.0010512 * t)) + 0.03439 * Math.sin(CT.d2R(34.486 - 0.0161731 * t));
+ var philambda = CT.d2R(199.6766 + 0.1737919 * t);
+ var psi = CT.d2R(316.5182 - 2.08E-06 * t);
+ var G = CT.d2R(30.23756 + 0.0830925701 * t + GAMMA);
+ var Gdash = CT.d2R(31.97853 + 0.0334597339 * t);
+ var PI = CT.d2R(13.469942);
+ var Sigma1 = 0.47259 * Math.sin(2 * (l1rad - l2rad)) + -0.03478 * Math.sin(pi3 - pi4) + 0.01081 * Math.sin(l2rad - 2 * l3rad + pi3) + 0.00738 * Math.sin(philambda) + 0.00713 * Math.sin(l2rad - 2 * l3rad + pi2) + -0.00674 * Math.sin(pi1 + pi3 - 2 * PI - 2 * G) + 0.00666 * Math.sin(l2rad - 2 * l3rad + pi4) + 0.00445 * Math.sin(l1rad - pi3) + -0.00354 * Math.sin(l1rad - l2rad) + -0.00317 * Math.sin(2 * psi - 2 * PI) + 0.00265 * Math.sin(l1rad - pi4) + -0.00186 * Math.sin(G) + 0.00162 * Math.sin(pi2 - pi3) + 0.00158 * Math.sin(4 * (l1rad - l2rad)) + -0.00155 * Math.sin(l1rad - l3rad) + -0.00138 * Math.sin(psi + w3rad - 2 * PI - 2 * G) + -0.00115 * Math.sin(2 * (l1rad - 2 * l2rad + w2rad)) + 0.00089 * Math.sin(pi2 - pi4) + 0.00085 * Math.sin(l1rad + pi3 - 2 * PI - 2 * G) + 0.00083 * Math.sin(w2rad - w3rad) + 0.00053 * Math.sin(psi - w2rad);
+ var Sigma2 = 1.06476 * Math.sin(2 * (l2rad - l3rad)) + 0.04256 * Math.sin(l1rad - 2 * l2rad + pi3) + 0.03581 * Math.sin(l2rad - pi3) + 0.02395 * Math.sin(l1rad - 2 * l2rad + pi4) + 0.01984 * Math.sin(l2rad - pi4) + -0.01778 * Math.sin(philambda) + 0.01654 * Math.sin(l2rad - pi2) + 0.01334 * Math.sin(l2rad - 2 * l3rad + pi2) + 0.01294 * Math.sin(pi3 - pi4) + -0.01142 * Math.sin(l2rad - l3rad) + -0.01057 * Math.sin(G) + -0.00775 * Math.sin(2 * (psi - PI)) + 0.00524 * Math.sin(2 * (l1rad - l2rad)) + -0.0046 * Math.sin(l1rad - l3rad) + 0.00316 * Math.sin(psi - 2 * G + w3rad - 2 * PI) + -0.00203 * Math.sin(pi1 + pi3 - 2 * PI - 2 * G) + 0.00146 * Math.sin(psi - w3rad) + -0.00145 * Math.sin(2 * G) + 0.00125 * Math.sin(psi - w4rad) + -0.00115 * Math.sin(l1rad - 2 * l3rad + pi3) + -0.00094 * Math.sin(2 * (l2rad - w2rad)) + 0.00086 * Math.sin(2 * (l1rad - 2 * l2rad + w2rad)) + -0.00086 * Math.sin(5 * Gdash - 2 * G + CT.d2R(52.225)) + -0.00078 * Math.sin(l2rad - l4rad) + -0.00064 * Math.sin(3 * l3rad - 7 * l4rad + 4 * pi4) + 0.00064 * Math.sin(pi1 - pi4) + -0.00063 * Math.sin(l1rad - 2 * l3rad + pi4) + 0.00058 * Math.sin(w3rad - w4rad) + 0.00056 * Math.sin(2 * (psi - PI - G)) + 0.00056 * Math.sin(2 * (l2rad - l4rad)) + 0.00055 * Math.sin(2 * (l1rad - l3rad)) + 0.00052 * Math.sin(3 * l3rad - 7 * l4rad + pi3 + 3 * pi4) + -0.00043 * Math.sin(l1rad - pi3) + 0.00041 * Math.sin(5 * (l2rad - l3rad)) + 0.00041 * Math.sin(pi4 - PI) + 0.00032 * Math.sin(w2rad - w3rad) + 0.00032 * Math.sin(2 * (l3rad - G - PI));
+ var Sigma3 = 0.1649 * Math.sin(l3rad - pi3) + 0.09081 * Math.sin(l3rad - pi4) + -0.06907 * Math.sin(l2rad - l3rad) + 0.03784 * Math.sin(pi3 - pi4) + 0.01846 * Math.sin(2 * (l3rad - l4rad)) + -0.0134 * Math.sin(G) + -0.01014 * Math.sin(2 * (psi - PI)) + 0.00704 * Math.sin(l2rad - 2 * l3rad + pi3) + -0.0062 * Math.sin(l2rad - 2 * l3rad + pi2) + -0.00541 * Math.sin(l3rad - l4rad) + 0.00381 * Math.sin(l2rad - 2 * l3rad + pi4) + 0.00235 * Math.sin(psi - w3rad) + 0.00198 * Math.sin(psi - w4rad) + 0.00176 * Math.sin(philambda) + 0.0013 * Math.sin(3 * (l3rad - l4rad)) + 0.00125 * Math.sin(l1rad - l3rad) + -0.00119 * Math.sin(5 * Gdash - 2 * G + CT.d2R(52.225)) + 0.00109 * Math.sin(l1rad - l2rad) + -0.001 * Math.sin(3 * l3rad - 7 * l4rad + 4 * pi4) + 0.00091 * Math.sin(w3rad - w4rad) + 0.0008 * Math.sin(3 * l3rad - 7 * l4rad + pi3 + 3 * pi4) + -0.00075 * Math.sin(2 * l2rad - 3 * l3rad + pi3) + 0.00072 * Math.sin(pi1 + pi3 - 2 * PI - 2 * G) + 0.00069 * Math.sin(pi4 - PI) + -0.00058 * Math.sin(2 * l3rad - 3 * l4rad + pi4) + -0.00057 * Math.sin(l3rad - 2 * l4rad + pi4) + 0.00056 * Math.sin(l3rad + pi3 - 2 * PI - 2 * G) + -0.00052 * Math.sin(l2rad - 2 * l3rad + pi1) + -0.0005 * Math.sin(pi2 - pi3) + 0.00048 * Math.sin(l3rad - 2 * l4rad + pi3) + -0.00045 * Math.sin(2 * l2rad - 3 * l3rad + pi4) + -0.00041 * Math.sin(pi2 - pi4) + -0.00038 * Math.sin(2 * G) + -0.00037 * Math.sin(pi3 - pi4 + w3rad - w4rad) + -0.00032 * Math.sin(3 * l3rad - 7 * l4rad + 2 * pi3 + 2 * pi4) + 0.0003 * Math.sin(4 * (l3rad - l4rad)) + 0.00029 * Math.sin(l3rad + pi4 - 2 * PI - 2 * G) + -0.00028 * Math.sin(w3rad + psi - 2 * PI - 2 * G) + 0.00026 * Math.sin(l3rad - PI - G) + 0.00024 * Math.sin(l2rad - 3 * l3rad + 2 * l4rad) + 0.00021 * Math.sin(l3rad - PI - G) + -0.00021 * Math.sin(l3rad - pi2) + 0.00017 * Math.sin(2 * (l3rad - pi3));
+ var Sigma4 = 0.84287 * Math.sin(l4rad - pi4) + 0.03431 * Math.sin(pi4 - pi3) + -0.03305 * Math.sin(2 * (psi - PI)) + -0.03211 * Math.sin(G) + -0.01862 * Math.sin(l4rad - pi3) + 0.01186 * Math.sin(psi - w4rad) + 0.00623 * Math.sin(l4rad + pi4 - 2 * G - 2 * PI) + 0.00387 * Math.sin(2 * (l4rad - pi4)) + -0.00284 * Math.sin(5 * Gdash - 2 * G + CT.d2R(52.225)) + -0.00234 * Math.sin(2 * (psi - pi4)) + -0.00223 * Math.sin(l3rad - l4rad) + -0.00208 * Math.sin(l4rad - PI) + 0.00178 * Math.sin(psi + w4rad - 2 * pi4) + 0.00134 * Math.sin(pi4 - PI) + 0.00125 * Math.sin(2 * (l4rad - G - PI)) + -0.00117 * Math.sin(2 * G) + -0.00112 * Math.sin(2 * (l3rad - l4rad)) + 0.00107 * Math.sin(3 * l3rad - 7 * l4rad + 4 * pi4) + 0.00102 * Math.sin(l4rad - G - PI) + 0.00096 * Math.sin(2 * l4rad - psi - w4rad) + 0.00087 * Math.sin(2 * (psi - w4rad)) + -0.00085 * Math.sin(3 * l3rad - 7 * l4rad + pi3 + 3 * pi4) + 0.00085 * Math.sin(l3rad - 2 * l4rad + pi4) + -0.00081 * Math.sin(2 * (l4rad - psi)) + 0.00071 * Math.sin(l4rad + pi4 - 2 * PI - 3 * G) + 0.00061 * Math.sin(l1rad - l4rad) + -0.00056 * Math.sin(psi - w3rad) + -0.00054 * Math.sin(l3rad - 2 * l4rad + pi3) + 0.00051 * Math.sin(l2rad - l4rad) + 0.00042 * Math.sin(2 * (psi - G - PI)) + 0.00039 * Math.sin(2 * (pi4 - w4rad)) + 0.00036 * Math.sin(psi + PI - pi4 - w4rad) + 0.00035 * Math.sin(2 * Gdash - G + CT.d2R(188.37)) + -0.00035 * Math.sin(l4rad - pi4 + 2 * PI - 2 * psi) + -0.00032 * Math.sin(l4rad + pi4 - 2 * PI - G) + 0.0003 * Math.sin(2 * Gdash - 2 * G + CT.d2R(149.15)) + 0.00029 * Math.sin(3 * l3rad - 7 * l4rad + 2 * pi3 + 2 * pi4) + 0.00028 * Math.sin(l4rad - pi4 + 2 * psi - 2 * PI) + -0.00028 * Math.sin(2 * (l4rad - w4rad)) + -0.00027 * Math.sin(pi3 - pi4 + w3rad - w4rad) + -0.00026 * Math.sin(5 * Gdash - 3 * G + CT.d2R(188.37)) + 0.00025 * Math.sin(w4rad - w3rad) + -0.00025 * Math.sin(l2rad - 3 * l3rad + 2 * l4rad) + -0.00023 * Math.sin(3 * (l3rad - l4rad)) + 0.00021 * Math.sin(2 * l4rad - 2 * PI - 3 * G) + -0.00021 * Math.sin(2 * l3rad - 3 * l4rad + pi4) + 0.00019 * Math.sin(l4rad - pi4 - G) + -0.00019 * Math.sin(2 * l4rad - pi3 - pi4) + -0.00018 * Math.sin(l4rad - pi4 + G) + -0.00016 * Math.sin(l4rad + pi3 - 2 * PI - 2 * G);
+ details.satellite1.meanLongitude = CT.m360(l1);
+ details.satellite1.trueLongitude = CT.m360(l1 + Sigma1);
+ var L1 = CT.d2R(details.satellite1.trueLongitude);
+ details.satellite2.meanLongitude = CT.m360(l2);
+ details.satellite2.trueLongitude = CT.m360(l2 + Sigma2);
+ var L2 = CT.d2R(details.satellite2.trueLongitude);
+ details.satellite3.meanLongitude = CT.m360(l3);
+ details.satellite3.trueLongitude = CT.m360(l3 + Sigma3);
+ var L3 = CT.d2R(details.satellite3.trueLongitude);
+ details.satellite4.meanLongitude = CT.m360(l4);
+ details.satellite4.trueLongitude = CT.m360(l4 + Sigma4);
+ var L4 = CT.d2R(details.satellite4.trueLongitude);
+ var B1 = Math.atan(0.0006393 * Math.sin(L1 - w1rad) + 0.0001825 * Math.sin(L1 - w2rad) + 3.29E-05 * Math.sin(L1 - w3rad) + -3.11E-05 * Math.sin(L1 - psi) + 9.3E-06 * Math.sin(L1 - w4rad) + 7.5E-06 * Math.sin(3 * L1 - 4 * l2rad - 1.9927 * Sigma1 + w2rad) + 4.6E-06 * Math.sin(L1 + psi - 2 * PI - 2 * G));
+ details.satellite1.equatorialLatitude = CT.r2D(B1);
+ var B2 = Math.atan(0.0081004 * Math.sin(L2 - w2rad) + 0.0004512 * Math.sin(L2 - w3rad) + -0.0003284 * Math.sin(L2 - psi) + 0.000116 * Math.sin(L2 - w4rad) + 2.72E-05 * Math.sin(l1rad - 2 * l3rad + 1.0146 * Sigma2 + w2rad) + -1.44E-05 * Math.sin(L2 - w1rad) + 1.43E-05 * Math.sin(L2 + psi - 2 * PI - 2 * G) + 3.5E-06 * Math.sin(L2 - psi + G) + -2.8E-06 * Math.sin(l1rad - 2 * l3rad + 1.0146 * Sigma2 + w3rad));
+ details.satellite2.equatorialLatitude = CT.r2D(B2);
+ var B3 = Math.atan(0.0032402 * Math.sin(L3 - w3rad) + -0.0016911 * Math.sin(L3 - psi) + 0.0006847 * Math.sin(L3 - w4rad) + -0.0002797 * Math.sin(L3 - w2rad) + 3.21E-05 * Math.sin(L3 + psi - 2 * PI - 2 * G) + 5.1E-06 * Math.sin(L3 - psi + G) + -4.5E-06 * Math.sin(L3 - psi - G) + -4.5E-06 * Math.sin(L3 + psi - 2 * PI) + 3.7E-06 * Math.sin(L3 + psi - 2 * PI - 3 * G) + 3E-06 * Math.sin(2 * l2rad - 3 * L3 + 4.03 * Sigma3 + w2rad) + -2.1E-06 * Math.sin(2 * l2rad - 3 * L3 + 4.03 * Sigma3 + w3rad));
+ details.satellite3.equatorialLatitude = CT.r2D(B3);
+ var B4 = Math.atan(-0.0076579 * Math.sin(L4 - psi) + 0.0044134 * Math.sin(L4 - w4rad) + -0.0005112 * Math.sin(L4 - w3rad) + 7.73E-05 * Math.sin(L4 + psi - 2 * PI - 2 * G) + 1.04E-05 * Math.sin(L4 - psi + G) + -1.02E-05 * Math.sin(L4 - psi - G) + 8.8E-06 * Math.sin(L4 + psi - 2 * PI - 3 * G) + -3.8E-06 * Math.sin(L4 + psi - 2 * PI - G));
+ details.satellite4.equatorialLatitude = CT.r2D(B4);
+ details.satellite1.r = 5.90569 * (1 + (-0.0041339 * Math.cos(2 * (l1rad - l2rad)) + -3.87E-05 * Math.cos(l1rad - pi3) + -2.14E-05 * Math.cos(l1rad - pi4) + 1.7E-05 * Math.cos(l1rad - l2rad) + -1.31E-05 * Math.cos(4 * (l1rad - l2rad)) + 1.06E-05 * Math.cos(l1rad - l3rad) + -6.6E-06 * Math.cos(l1rad + pi3 - 2 * PI - 2 * G)));
+ details.satellite2.r = 9.39657 * (1 + (0.0093848 * Math.cos(l1rad - l2rad) + -0.0003116 * Math.cos(l2rad - pi3) + -0.0001744 * Math.cos(l2rad - pi4) + -0.0001442 * Math.cos(l2rad - pi2) + 5.53E-05 * Math.cos(l2rad - l3rad) + 5.23E-05 * Math.cos(l1rad - l3rad) + -2.9E-05 * Math.cos(2 * (l1rad - l2rad)) + 1.64E-05 * Math.cos(2 * (l2rad - w2rad)) + 1.07E-05 * Math.cos(l1rad - 2 * l3rad + pi3) + -1.02E-05 * Math.cos(l2rad - pi1) + -9.1E-06 * Math.cos(2 * (l1rad - l3rad))));
+ details.satellite3.r = 14.98832 * (1 + (-0.0014388 * Math.cos(l3rad - pi3) + -0.0007919 * Math.cos(l3rad - pi4) + 0.0006342 * Math.cos(l2rad - l3rad) + -0.0001761 * Math.cos(2 * (l3rad - l4rad)) + 2.94E-05 * Math.cos(l3rad - l4rad) + -1.56E-05 * Math.cos(3 * (l3rad - l4rad)) + 1.56E-05 * Math.cos(l1rad - l3rad) + -1.53E-05 * Math.cos(l1rad - l2rad) + 7E-06 * Math.cos(2 * l2rad - 3 * l3rad + pi3) + -5.1E-06 * Math.cos(l3rad + pi3 - 2 * PI - 2 * G)));
+ details.satellite4.r = 26.36273 * (1 + (-0.0073546 * Math.cos(l4rad - pi4) + 0.0001621 * Math.cos(l4rad - pi3) + 9.74E-05 * Math.cos(l3rad - l4rad) + -5.43E-05 * Math.cos(l4rad + pi4 - 2 * PI - 2 * G) + -2.71E-05 * Math.cos(2 * (l4rad - pi4)) + 1.82E-05 * Math.cos(l4rad - PI) + 1.77E-05 * Math.cos(2 * (l3rad - l4rad)) + -1.67E-05 * Math.cos(2 * l4rad - psi - w4rad) + 1.67E-05 * Math.cos(psi - w4rad) + -1.55E-05 * Math.cos(2 * (l4rad - PI - G)) + 1.42E-05 * Math.cos(2 * (l4rad - psi)) + 1.05E-05 * Math.cos(l1rad - l4rad) + 9.2E-06 * Math.cos(l2rad - l4rad) + -8.9E-06 * Math.cos(l4rad - PI - G) + -6.2E-06 * Math.cos(l4rad + pi4 - 2 * PI - 3 * G) + 4.8E-06 * Math.cos(2 * (l4rad - w4rad))));
+ var T0 = (JD - 2433282.423) / 36525;
+ var P = CT.d2R(1.3966626 * T0 + 0.0003088 * T0 * T0);
+ L1 += P;
+ details.satellite1.tropicalLongitude = CT.m360(CT.r2D(L1));
+ L2 += P;
+ details.satellite2.tropicalLongitude = CT.m360(CT.r2D(L2));
+ L3 += P;
+ details.satellite3.tropicalLongitude = CT.m360(CT.r2D(L3));
+ L4 += P;
+ details.satellite4.tropicalLongitude = CT.m360(CT.r2D(L4));
+ psi += P;
+ var T = (JD - 2415020.5) / 36525;
+ var I = 3.120262 + 0.0006 * T;
+ var Irad = CT.d2R(I);
+ var X1 = details.satellite1.r * Math.cos(L1 - psi) * Math.cos(B1);
+ var X2 = details.satellite2.r * Math.cos(L2 - psi) * Math.cos(B2);
+ var X3 = details.satellite3.r * Math.cos(L3 - psi) * Math.cos(B3);
+ var X4 = details.satellite4.r * Math.cos(L4 - psi) * Math.cos(B4);
+ var X5 = 0;
+ var Y1 = details.satellite1.r * Math.sin(L1 - psi) * Math.cos(B1);
+ var Y2 = details.satellite2.r * Math.sin(L2 - psi) * Math.cos(B2);
+ var Y3 = details.satellite3.r * Math.sin(L3 - psi) * Math.cos(B3);
+ var Y4 = details.satellite4.r * Math.sin(L4 - psi) * Math.cos(B4);
+ var Y5 = 0;
+ var Z1 = details.satellite1.r * Math.sin(B1);
+ var Z2 = details.satellite2.r * Math.sin(B2);
+ var Z3 = details.satellite3.r * Math.sin(B3);
+ var Z4 = details.satellite4.r * Math.sin(B4);
+ var Z5 = 1;
+ var omega = CT.d2R(EPO.jupiterLongitudeAscendingNode(JD));
+ var i = CT.d2R(EPO.jupiterInclination(JD));
+ var A6 = 0;
+ var B6 = 0;
+ var C6 = 0;
+ var north = new C3D();
+ var abc = GM.rotations(X5, Y5, Z5, Irad, psi, i, omega, lambda0, beta0, north);
+ A6 = abc[0];
+ B6 = abc[1];
+ C6 = abc[2];
+ var D = Math.atan2(A6, C6);
+ abc = GM.rotations(X1, Y1, Z1, Irad, psi, i, omega, lambda0, beta0, details.satellite1.eclipticRectangularCoordinates);
+ A6 = abc[0];
+ B6 = abc[1];
+ C6 = abc[2];
+ details.satellite1.trueRectangularCoordinates.x = A6 * Math.cos(D) - C6 * Math.sin(D);
+ details.satellite1.trueRectangularCoordinates.y = A6 * Math.sin(D) + C6 * Math.cos(D);
+ details.satellite1.trueRectangularCoordinates.z = B6;
+ abc = GM.rotations(X2, Y2, Z2, Irad, psi, i, omega, lambda0, beta0, details.satellite2.eclipticRectangularCoordinates);
+ A6 = abc[0];
+ B6 = abc[1];
+ C6 = abc[2];
+ details.satellite2.trueRectangularCoordinates.x = A6 * Math.cos(D) - C6 * Math.sin(D);
+ details.satellite2.trueRectangularCoordinates.y = A6 * Math.sin(D) + C6 * Math.cos(D);
+ details.satellite2.trueRectangularCoordinates.z = B6;
+ abc = GM.rotations(X3, Y3, Z3, Irad, psi, i, omega, lambda0, beta0, details.satellite3.eclipticRectangularCoordinates);
+ A6 = abc[0];
+ B6 = abc[1];
+ C6 = abc[2];
+ details.satellite3.trueRectangularCoordinates.x = A6 * Math.cos(D) - C6 * Math.sin(D);
+ details.satellite3.trueRectangularCoordinates.y = A6 * Math.sin(D) + C6 * Math.cos(D);
+ details.satellite3.trueRectangularCoordinates.z = B6;
+ abc = GM.rotations(X4, Y4, Z4, Irad, psi, i, omega, lambda0, beta0, details.satellite4.eclipticRectangularCoordinates);
+ A6 = abc[0];
+ B6 = abc[1];
+ C6 = abc[2];
+ details.satellite4.trueRectangularCoordinates.x = A6 * Math.cos(D) - C6 * Math.sin(D);
+ details.satellite4.trueRectangularCoordinates.y = A6 * Math.sin(D) + C6 * Math.cos(D);
+ details.satellite4.trueRectangularCoordinates.z = B6;
+ details.satellite1.apparentRectangularCoordinates.x = details.satellite1.trueRectangularCoordinates.x + Math.abs(details.satellite1.trueRectangularCoordinates.z) / 17295 * Math.sqrt(1 - (details.satellite1.trueRectangularCoordinates.x / details.satellite1.r) * (details.satellite1.trueRectangularCoordinates.x / details.satellite1.r));
+ details.satellite1.apparentRectangularCoordinates.y = details.satellite1.trueRectangularCoordinates.y;
+ details.satellite1.apparentRectangularCoordinates.z = details.satellite1.trueRectangularCoordinates.z;
+ details.satellite2.apparentRectangularCoordinates.x = details.satellite2.trueRectangularCoordinates.x + Math.abs(details.satellite2.trueRectangularCoordinates.z) / 21819 * Math.sqrt(1 - (details.satellite2.trueRectangularCoordinates.x / details.satellite2.r) * (details.satellite2.trueRectangularCoordinates.x / details.satellite2.r));
+ details.satellite2.apparentRectangularCoordinates.y = details.satellite2.trueRectangularCoordinates.y;
+ details.satellite2.apparentRectangularCoordinates.z = details.satellite2.trueRectangularCoordinates.z;
+ details.satellite3.apparentRectangularCoordinates.x = details.satellite3.trueRectangularCoordinates.x + Math.abs(details.satellite3.trueRectangularCoordinates.z) / 27558 * Math.sqrt(1 - (details.satellite3.trueRectangularCoordinates.x / details.satellite3.r) * (details.satellite3.trueRectangularCoordinates.x / details.satellite3.r));
+ details.satellite3.apparentRectangularCoordinates.y = details.satellite3.trueRectangularCoordinates.y;
+ details.satellite3.apparentRectangularCoordinates.z = details.satellite3.trueRectangularCoordinates.z;
+ details.satellite4.apparentRectangularCoordinates.x = details.satellite4.trueRectangularCoordinates.x + Math.abs(details.satellite4.trueRectangularCoordinates.z) / 36548 * Math.sqrt(1 - (details.satellite4.trueRectangularCoordinates.x / details.satellite4.r) * (details.satellite4.trueRectangularCoordinates.x / details.satellite4.r));
+ details.satellite4.apparentRectangularCoordinates.y = details.satellite4.trueRectangularCoordinates.y;
+ details.satellite4.apparentRectangularCoordinates.z = details.satellite4.trueRectangularCoordinates.z;
+ var W = DELTA / (DELTA + details.satellite1.trueRectangularCoordinates.z / 2095);
+ details.satellite1.apparentRectangularCoordinates.x *= W;
+ details.satellite1.apparentRectangularCoordinates.y *= W;
+ W = DELTA / (DELTA + details.satellite2.trueRectangularCoordinates.z / 2095);
+ details.satellite2.apparentRectangularCoordinates.x *= W;
+ details.satellite2.apparentRectangularCoordinates.y *= W;
+ W = DELTA / (DELTA + details.satellite3.trueRectangularCoordinates.z / 2095);
+ details.satellite3.apparentRectangularCoordinates.x *= W;
+ details.satellite3.apparentRectangularCoordinates.y *= W;
+ W = DELTA / (DELTA + details.satellite4.trueRectangularCoordinates.z / 2095);
+ details.satellite4.apparentRectangularCoordinates.x *= W;
+ details.satellite4.apparentRectangularCoordinates.y *= W;
+ return details;
+};
+
+GM.rotations = function (X, Y, Z, I, psi, i, omega, lambda0, beta0, eclipticCoord) {
+ var A6;
+ var B6;
+ var C6;
+ var phi = psi - omega;
+ var A1 = X;
+ var B1 = Y * Math.cos(I) - Z * Math.sin(I);
+ var C1 = Y * Math.sin(I) + Z * Math.cos(I);
+ var A2 = A1 * Math.cos(phi) - B1 * Math.sin(phi);
+ var B2 = A1 * Math.sin(phi) + B1 * Math.cos(phi);
+ var C2 = C1;
+ var A3 = A2;
+ var B3 = B2 * Math.cos(i) - C2 * Math.sin(i);
+ var C3 = B2 * Math.sin(i) + C2 * Math.cos(i);
+ var A4 = A3 * Math.cos(omega) - B3 * Math.sin(omega);
+ var B4 = A3 * Math.sin(omega) + B3 * Math.cos(omega);
+ var C4 = C3;
+ var JupiterRadiiToAU = 1 / 2095;
+ eclipticCoord.x = A4 * JupiterRadiiToAU;
+ eclipticCoord.y = B4 * JupiterRadiiToAU;
+ eclipticCoord.z = C4 * JupiterRadiiToAU;
+ var A5 = A4 * Math.sin(lambda0) - B4 * Math.cos(lambda0);
+ var B5 = A4 * Math.cos(lambda0) + B4 * Math.sin(lambda0);
+ var C5 = C4;
+ A6 = A5;
+ B6 = C5 * Math.sin(beta0) + B5 * Math.cos(beta0);
+ C6 = C5 * Math.cos(beta0) - B5 * Math.sin(beta0);
+ return [A6, B6, C6];
+};
+
+GM.fillInPhenomenaDetails = function (detail) {
+ var Y1 = 1.071374 * detail.apparentRectangularCoordinates.y;
+ var r = Y1 * Y1 + detail.apparentRectangularCoordinates.x * detail.apparentRectangularCoordinates.x;
+ if (r < 1) {
+ if (detail.apparentRectangularCoordinates.z < 0) {
+ detail.bInTransit = true;
+ detail.bInOccultation = false;
+ }
+ else {
+ detail.bInTransit = false;
+ detail.bInOccultation = true;
+ }
+ }
+ else {
+ detail.bInTransit = false;
+ detail.bInOccultation = false;
+ }
+};
+
+var GM$ = {};
+
+registerType("GM", [GM, GM$, null]);
diff --git a/engine/esm/astrocalc/globe.js b/engine/esm/astrocalc/globe.js
new file mode 100644
index 00000000..fc5f79d9
--- /dev/null
+++ b/engine/esm/astrocalc/globe.js
@@ -0,0 +1,81 @@
+// Originally `AAGLOBE.CPP`
+// "Purpose: Implementation for the algorithms for the Earth's Globe"
+// Last update of original: PJN / 29-12-2003
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+
+
+// CAAGlobe
+
+export function CAAGlobe() { }
+
+CAAGlobe.rhoSinThetaPrime = function (GeographicalLatitude, Height) {
+ GeographicalLatitude = CT.d2R(GeographicalLatitude);
+ var U = Math.atan(0.99664719 * Math.tan(GeographicalLatitude));
+ return 0.99664719 * Math.sin(U) + (Height / 6378149 * Math.sin(GeographicalLatitude));
+};
+
+CAAGlobe.rhoCosThetaPrime = function (GeographicalLatitude, Height) {
+ GeographicalLatitude = CT.d2R(GeographicalLatitude);
+ var U = Math.atan(0.99664719 * Math.tan(GeographicalLatitude));
+ return Math.cos(U) + (Height / 6378149 * Math.cos(GeographicalLatitude));
+};
+
+CAAGlobe.radiusOfParallelOfLatitude = function (GeographicalLatitude) {
+ GeographicalLatitude = CT.d2R(GeographicalLatitude);
+ var sinGeo = Math.sin(GeographicalLatitude);
+ return (6378.14 * Math.cos(GeographicalLatitude)) / Math.sqrt(1 - 0.0066943847614084 * sinGeo * sinGeo);
+};
+
+CAAGlobe.radiusOfCurvature = function (GeographicalLatitude) {
+ GeographicalLatitude = CT.d2R(GeographicalLatitude);
+ var sinGeo = Math.sin(GeographicalLatitude);
+ return (6378.14 * (1 - 0.0066943847614084)) / Math.pow((1 - 0.0066943847614084 * sinGeo * sinGeo), 1.5);
+};
+
+CAAGlobe.distanceBetweenPoints = function (GeographicalLatitude1, GeographicalLongitude1, GeographicalLatitude2, GeographicalLongitude2) {
+ GeographicalLatitude1 = CT.d2R(GeographicalLatitude1);
+ GeographicalLatitude2 = CT.d2R(GeographicalLatitude2);
+ GeographicalLongitude1 = CT.d2R(GeographicalLongitude1);
+ GeographicalLongitude2 = CT.d2R(GeographicalLongitude2);
+ var F = (GeographicalLatitude1 + GeographicalLatitude2) / 2;
+ var G = (GeographicalLatitude1 - GeographicalLatitude2) / 2;
+ var lambda = (GeographicalLongitude1 - GeographicalLongitude2) / 2;
+ var sinG = Math.sin(G);
+ var cosG = Math.cos(G);
+ var cosF = Math.cos(F);
+ var sinF = Math.sin(F);
+ var sinLambda = Math.sin(lambda);
+ var cosLambda = Math.cos(lambda);
+ var S = (sinG * sinG * cosLambda * cosLambda) + (cosF * cosF * sinLambda * sinLambda);
+ var C = (cosG * cosG * cosLambda * cosLambda) + (sinF * sinF * sinLambda * sinLambda);
+ var w = Math.atan(Math.sqrt(S / C));
+ var R = Math.sqrt(S * C) / w;
+ var D = 2 * w * 6378.14;
+ var Hprime = (3 * R - 1) / (2 * C);
+ var Hprime2 = (3 * R + 1) / (2 * S);
+ var f = 0.00335281317789691;
+ return D * (1 + (f * Hprime * sinF * sinF * cosG * cosG) - (f * Hprime2 * cosF * cosF * sinG * sinG));
+};
+
+var CAAGlobe$ = {};
+
+registerType("CAAGlobe", [CAAGlobe, CAAGlobe$, null]);
diff --git a/engine/esm/astrocalc/illuminated_fraction.js b/engine/esm/astrocalc/illuminated_fraction.js
new file mode 100644
index 00000000..48c4b7b1
--- /dev/null
+++ b/engine/esm/astrocalc/illuminated_fraction.js
@@ -0,0 +1,129 @@
+// Originally `AAILLUMINATEDFRACTION.CPP`
+// "Purpose: Implementation for the algorithms for a planet's Phase Angle, Illuminated Fraction and Magnitude"
+// Last update of original: PJN / 21-01-2005
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { Util } from "../baseutil.js";
+import { CT } from "./coordinate_transformation.js";
+
+
+// IFR
+
+export function IFR() { }
+
+IFR.phaseAngle = function (r, R, Delta) {
+ return CT.m360(CT.r2D(Math.acos((r * r + Delta * Delta - R * R) / (2 * r * Delta))));
+};
+
+IFR.phaseAngle2 = function (R, R0, B, L, L0, Delta) {
+ B = CT.d2R(B);
+ L = CT.d2R(L);
+ L0 = CT.d2R(L0);
+ return CT.m360(CT.r2D(Math.acos((R - R0 * Math.cos(B) * Math.cos(L - L0)) / Delta)));
+};
+
+IFR.phaseAngleRectangular = function (x, y, z, B, L, Delta) {
+ B = CT.d2R(B);
+ L = CT.d2R(L);
+ var cosB = Math.cos(B);
+ return CT.m360(CT.r2D(Math.acos((x * cosB * Math.cos(L) + y * cosB * Math.sin(L) + z * Math.sin(B)) / Delta)));
+};
+
+IFR.illuminatedFraction = function (PhaseAngle) {
+ PhaseAngle = CT.d2R(PhaseAngle);
+ return (1 + Math.cos(PhaseAngle)) / 2;
+};
+
+IFR.illuminatedFraction2 = function (r, R, Delta) {
+ return (((r + Delta) * (r + Delta) - R * R) / (4 * r * Delta));
+};
+
+IFR.mercuryMagnitudeMuller = function (r, Delta, i) {
+ var I_50 = i - 50;
+ return 1.16 + 5 * Util.log10(r * Delta) + 0.02838 * I_50 + 0.0001023 * I_50 * I_50;
+};
+
+IFR.venusMagnitudeMuller = function (r, Delta, i) {
+ return -4 + 5 * Util.log10(r * Delta) + 0.01322 * i + 4.247E-07 * i * i * i;
+};
+
+IFR.marsMagnitudeMuller = function (r, Delta, i) {
+ return -1.3 + 5 * Util.log10(r * Delta) + 0.01486 * i;
+};
+
+IFR.jupiterMagnitudeMuller = function (r, Delta) {
+ return -8.93 + 5 * Util.log10(r * Delta);
+};
+
+IFR.saturnMagnitudeMuller = function (r, Delta, DeltaU, B) {
+ B = CT.d2R(B);
+ var sinB = Math.sin(B);
+ return -8.68 + 5 * Util.log10(r * Delta) + 0.044 * Math.abs(DeltaU) - 2.6 * Math.sin(Math.abs(B)) + 1.25 * sinB * sinB;
+};
+
+IFR.uranusMagnitudeMuller = function (r, Delta) {
+ return -6.85 + 5 * Util.log10(r * Delta);
+};
+
+IFR.neptuneMagnitudeMuller = function (r, Delta) {
+ return -7.05 + 5 * Util.log10(r * Delta);
+};
+
+IFR.mercuryMagnitudeAA = function (r, Delta, i) {
+ var i2 = i * i;
+ var i3 = i2 * i;
+ return -0.42 + 5 * Util.log10(r * Delta) + 0.038 * i - 0.000273 * i2 + 2E-06 * i3;
+};
+
+IFR.venusMagnitudeAA = function (r, Delta, i) {
+ var i2 = i * i;
+ var i3 = i2 * i;
+ return -4.4 + 5 * Util.log10(r * Delta) + 0.0009 * i + 0.000239 * i2 - 6.5E-07 * i3;
+};
+
+IFR.marsMagnitudeAA = function (r, Delta, i) {
+ return -1.52 + 5 * Util.log10(r * Delta) + 0.016 * i;
+};
+
+IFR.jupiterMagnitudeAA = function (r, Delta, i) {
+ return -9.4 + 5 * Util.log10(r * Delta) + 0.005 * i;
+};
+
+IFR.saturnMagnitudeAA = function (r, Delta, DeltaU, B) {
+ B = CT.d2R(B);
+ var sinB = Math.sin(B);
+ return -8.88 + 5 * Util.log10(r * Delta) + 0.044 * Math.abs(DeltaU) - 2.6 * Math.sin(Math.abs(B)) + 1.25 * sinB * sinB;
+};
+
+IFR.uranusMagnitudeAA = function (r, Delta) {
+ return -7.19 + 5 * Util.log10(r * Delta);
+};
+
+IFR.neptuneMagnitudeAA = function (r, Delta) {
+ return -6.87 + 5 * Util.log10(r * Delta);
+};
+
+IFR.plutoMagnitudeAA = function (r, Delta) {
+ return -1 + 5 * Util.log10(r * Delta);
+};
+
+var IFR$ = {};
+
+registerType("IFR", [IFR, IFR$, null]);
diff --git a/engine/esm/astrocalc/interpolate.js b/engine/esm/astrocalc/interpolate.js
new file mode 100644
index 00000000..c1e1573a
--- /dev/null
+++ b/engine/esm/astrocalc/interpolate.js
@@ -0,0 +1,167 @@
+// Originally `AAINTERPOLATE.CPP`
+// "Purpose: Implementation for the algorithms for Interpolation"
+// Last update of original: PJN / 29-12-2003
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+
+
+// INTP - was CAAInterpoate
+
+export function INTP() { }
+
+INTP.interpolate = function (n, Y1, Y2, Y3) {
+ var a = Y2 - Y1;
+ var b = Y3 - Y2;
+ var c = Y1 + Y3 - 2 * Y2;
+ return Y2 + n / 2 * (a + b + n * c);
+};
+
+INTP.interpolate2 = function (n, Y1, Y2, Y3, Y4, Y5) {
+ var A = Y2 - Y1;
+ var B = Y3 - Y2;
+ var C = Y4 - Y3;
+ var D = Y5 - Y4;
+ var E = B - A;
+ var F = C - B;
+ var G = D - C;
+ var H = F - E;
+ var J = G - F;
+ var K = J - H;
+ var N2 = n * n;
+ var N3 = N2 * n;
+ var N4 = N3 * n;
+ return Y3 + n * ((B + C) / 2 - (H + J) / 12) + N2 * (F / 2 - K / 24) + N3 * ((H + J) / 12) + N4 * (K / 24);
+};
+
+INTP.interpolateToHalves = function (Y1, Y2, Y3, Y4) {
+ return (9 * (Y2 + Y3) - Y1 - Y4) / 16;
+};
+
+INTP.lagrangeInterpolate = function (X, n, pX, pY) {
+ var V = 0;
+ for (var i = 1; i <= n; i++) {
+ var C = 1;
+ for (var j = 1; j <= n; j++) {
+ if (j !== i) {
+ C = C * (X - pX[j - 1]) / (pX[i - 1] - pX[j - 1]);
+ }
+ }
+ V += C * pY[i - 1];
+ }
+ return V;
+};
+
+INTP.zero = function (Y1, Y2, Y3) {
+ var a = Y2 - Y1;
+ var b = Y3 - Y2;
+ var c = Y1 + Y3 - 2 * Y2;
+ var bRecalc = true;
+ var n0prev = 0;
+ var n0 = n0prev;
+ while (bRecalc) {
+ n0 = -2 * Y2 / (a + b + c * n0prev);
+ bRecalc = (Math.abs(n0 - n0prev) > 1E-12);
+ if (bRecalc) {
+ n0prev = n0;
+ }
+ }
+ return n0;
+};
+
+INTP.zeroB = function (Y1, Y2, Y3, Y4, Y5) {
+ var A = Y2 - Y1;
+ var B = Y3 - Y2;
+ var C = Y4 - Y3;
+ var D = Y5 - Y4;
+ var E = B - A;
+ var F = C - B;
+ var G = D - C;
+ var H = F - E;
+ var J = G - F;
+ var K = J - H;
+ var bRecalc = true;
+ var n0prev = 0;
+ var n0 = n0prev;
+ while (bRecalc) {
+ var n0prev2 = n0prev * n0prev;
+ var n0prev3 = n0prev2 * n0prev;
+ var n0prev4 = n0prev3 * n0prev;
+ n0 = (-24 * Y3 + n0prev2 * (K - 12 * F) - 2 * n0prev3 * (H + J) - n0prev4 * K) / (2 * (6 * B + 6 * C - H - J));
+ bRecalc = (Math.abs(n0 - n0prev) > 1E-12);
+ if (bRecalc) {
+ n0prev = n0;
+ }
+ }
+ return n0;
+};
+
+INTP.zero2 = function (Y1, Y2, Y3) {
+ var a = Y2 - Y1;
+ var b = Y3 - Y2;
+ var c = Y1 + Y3 - 2 * Y2;
+ var bRecalc = true;
+ var n0prev = 0;
+ var n0 = n0prev;
+ while (bRecalc) {
+ var deltan0 = -(2 * Y2 + n0prev * (a + b + c * n0prev)) / (a + b + 2 * c * n0prev);
+ n0 = n0prev + deltan0;
+ bRecalc = (Math.abs(deltan0) > 1E-12);
+ if (bRecalc) {
+ n0prev = n0;
+ }
+ }
+ return n0;
+};
+
+INTP.zero2B = function (Y1, Y2, Y3, Y4, Y5) {
+ var A = Y2 - Y1;
+ var B = Y3 - Y2;
+ var C = Y4 - Y3;
+ var D = Y5 - Y4;
+ var E = B - A;
+ var F = C - B;
+ var G = D - C;
+ var H = F - E;
+ var J = G - F;
+ var K = J - H;
+ var M = K / 24;
+ var N = (H + J) / 12;
+ var P = F / 2 - M;
+ var Q = (B + C) / 2 - N;
+ var bRecalc = true;
+ var n0prev = 0;
+ var n0 = n0prev;
+ while (bRecalc) {
+ var n0prev2 = n0prev * n0prev;
+ var n0prev3 = n0prev2 * n0prev;
+ var n0prev4 = n0prev3 * n0prev;
+ var deltan0 = -(M * n0prev4 + N * n0prev3 + P * n0prev2 + Q * n0prev + Y3) / (4 * M * n0prev3 + 3 * N * n0prev2 + 2 * P * n0prev + Q);
+ n0 = n0prev + deltan0;
+ bRecalc = (Math.abs(deltan0) > 1E-12);
+ if (bRecalc) {
+ n0prev = n0;
+ }
+ }
+ return n0;
+};
+
+var INTP$ = {};
+
+registerType("INTP", [INTP, INTP$, null]);
diff --git a/engine/esm/astrocalc/jupiter.js b/engine/esm/astrocalc/jupiter.js
new file mode 100644
index 00000000..d2d62955
--- /dev/null
+++ b/engine/esm/astrocalc/jupiter.js
@@ -0,0 +1,180 @@
+// Originally `AAJUPITER.CPP`
+// "Purpose: Implementation for the algorithms which obtain the heliocentric position of Uranus [sic]"
+// Last update of original: PJN / 31-05-2004
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+import { VSC } from "./earth.js";
+
+
+// Coefficients
+
+const g_L0JupiterCoefficients = [new VSC(59954691, 0, 0), new VSC(9695899, 5.0619179, 529.6909651), new VSC(573610, 1.444062, 7.113547), new VSC(306389, 5.417347, 1059.38193), new VSC(97178, 4.14265, 632.78374), new VSC(72903, 3.64043, 522.57742), new VSC(64264, 3.41145, 103.09277), new VSC(39806, 2.29377, 419.48464), new VSC(38858, 1.27232, 316.39187), new VSC(27965, 1.78455, 536.80451), new VSC(13590, 5.77481, 1589.0729), new VSC(8769, 3.63, 949.1756), new VSC(8246, 3.5823, 206.1855), new VSC(7368, 5.081, 735.8765), new VSC(6263, 0.025, 213.2991), new VSC(6114, 4.5132, 1162.4747), new VSC(5305, 4.1863, 1052.2684), new VSC(5305, 1.3067, 14.2271), new VSC(4905, 1.3208, 110.2063), new VSC(4647, 4.6996, 3.9322), new VSC(3045, 4.3168, 426.5982), new VSC(2610, 1.5667, 846.0828), new VSC(2028, 1.0638, 3.1814), new VSC(1921, 0.9717, 639.8973), new VSC(1765, 2.1415, 1066.4955), new VSC(1723, 3.8804, 1265.5675), new VSC(1633, 3.582, 515.4639), new VSC(1432, 4.2968, 625.6702), new VSC(973, 4.098, 95.979), new VSC(884, 2.437, 412.371), new VSC(733, 6.085, 838.969), new VSC(731, 3.806, 1581.959), new VSC(709, 1.293, 742.99), new VSC(692, 6.134, 2118.764), new VSC(614, 4.109, 1478.867), new VSC(582, 4.54, 309.278), new VSC(495, 3.756, 323.505), new VSC(441, 2.958, 454.909), new VSC(417, 1.036, 2.488), new VSC(390, 4.897, 1692.166), new VSC(376, 4.703, 1368.66), new VSC(341, 5.715, 533.623), new VSC(330, 4.74, 0.048), new VSC(262, 1.877, 0.963), new VSC(261, 0.82, 380.128), new VSC(257, 3.724, 199.072), new VSC(244, 5.22, 728.763), new VSC(235, 1.227, 909.819), new VSC(220, 1.651, 543.918), new VSC(207, 1.855, 525.759), new VSC(202, 1.807, 1375.774), new VSC(197, 5.293, 1155.361), new VSC(175, 3.73, 942.062), new VSC(175, 3.226, 1898.351), new VSC(175, 5.91, 956.289), new VSC(158, 4.365, 1795.258), new VSC(151, 3.906, 74.782), new VSC(149, 4.377, 1685.052), new VSC(141, 3.136, 491.558), new VSC(138, 1.318, 1169.588), new VSC(131, 4.169, 1045.155), new VSC(117, 2.5, 1596.186), new VSC(117, 3.389, 0.521), new VSC(106, 4.554, 526.51)];
+const g_L1JupiterCoefficients = [new VSC(52993480757, 0, 0), new VSC(489741, 4.220667, 529.690965), new VSC(228919, 6.026475, 7.113547), new VSC(27655, 4.57266, 1059.38193), new VSC(20721, 5.45939, 522.57742), new VSC(12106, 0.16986, 536.80451), new VSC(6068, 4.4242, 103.0928), new VSC(5434, 3.9848, 419.4846), new VSC(4238, 5.8901, 14.2271), new VSC(2212, 5.2677, 206.1855), new VSC(1746, 4.9267, 1589.0729), new VSC(1296, 5.5513, 3.1814), new VSC(1173, 5.8565, 1052.2684), new VSC(1163, 0.5145, 3.9322), new VSC(1099, 5.307, 515.4639), new VSC(1007, 0.4648, 735.8765), new VSC(1004, 3.1504, 426.5982), new VSC(848, 5.758, 110.206), new VSC(827, 4.803, 213.299), new VSC(816, 0.586, 1066.495), new VSC(725, 5.518, 639.897), new VSC(568, 5.989, 625.67), new VSC(474, 4.132, 412.371), new VSC(413, 5.737, 95.979), new VSC(345, 4.242, 632.784), new VSC(336, 3.732, 1162.475), new VSC(234, 4.035, 949.176), new VSC(234, 6.243, 309.278), new VSC(199, 1.505, 838.969), new VSC(195, 2.219, 323.505), new VSC(187, 6.086, 742.99), new VSC(184, 6.28, 543.918), new VSC(171, 5.417, 199.072), new VSC(131, 0.626, 728.763), new VSC(115, 0.68, 846.083), new VSC(115, 5.286, 2118.764), new VSC(108, 4.493, 956.289), new VSC(80, 5.82, 1045.15), new VSC(72, 5.34, 942.06), new VSC(70, 5.97, 532.87), new VSC(67, 5.73, 21.34), new VSC(66, 0.13, 526.51), new VSC(65, 6.09, 1581.96), new VSC(59, 0.59, 1155.36), new VSC(58, 0.99, 1596.19), new VSC(57, 5.97, 1169.59), new VSC(57, 1.41, 533.62), new VSC(55, 5.43, 10.29), new VSC(52, 5.73, 117.32), new VSC(52, 0.23, 1368.66), new VSC(50, 6.08, 525.76), new VSC(47, 3.63, 1478.87), new VSC(47, 0.51, 1265.57), new VSC(40, 4.16, 1692.17), new VSC(34, 0.1, 302.16), new VSC(33, 5.04, 220.41), new VSC(32, 5.37, 508.35), new VSC(29, 5.42, 1272.68), new VSC(29, 3.36, 4.67), new VSC(29, 0.76, 88.87), new VSC(25, 1.61, 831.86)];
+const g_L2JupiterCoefficients = [new VSC(47234, 4.32148, 7.11355), new VSC(38966, 0, 0), new VSC(30629, 2.93021, 529.69097), new VSC(3189, 1.055, 522.5774), new VSC(2729, 4.8455, 536.8045), new VSC(2723, 3.4141, 1059.3819), new VSC(1721, 4.1873, 14.2271), new VSC(383, 5.768, 419.485), new VSC(378, 0.76, 515.464), new VSC(367, 6.055, 103.093), new VSC(337, 3.786, 3.181), new VSC(308, 0.694, 206.186), new VSC(218, 3.814, 1589.073), new VSC(199, 5.34, 1066.495), new VSC(197, 2.484, 3.932), new VSC(156, 1.406, 1052.268), new VSC(146, 3.814, 639.897), new VSC(142, 1.634, 426.598), new VSC(130, 5.837, 412.371), new VSC(117, 1.414, 625.67), new VSC(97, 4.03, 110.21), new VSC(91, 1.11, 95.98), new VSC(87, 2.52, 632.78), new VSC(79, 4.64, 543.92), new VSC(72, 2.22, 735.88), new VSC(58, 0.83, 199.07), new VSC(57, 3.12, 213.3), new VSC(49, 1.67, 309.28), new VSC(40, 4.02, 21.34), new VSC(40, 0.62, 323.51), new VSC(36, 2.33, 728.76), new VSC(29, 3.61, 10.29), new VSC(28, 3.24, 838.97), new VSC(26, 4.5, 742.99), new VSC(26, 2.51, 1162.47), new VSC(25, 1.22, 1045.15), new VSC(24, 3.01, 956.29), new VSC(19, 4.29, 532.87), new VSC(18, 0.81, 508.35), new VSC(17, 4.2, 2118.76), new VSC(17, 1.83, 526.51), new VSC(15, 5.81, 1596.19), new VSC(15, 0.68, 942.06), new VSC(15, 4, 117.32), new VSC(14, 5.95, 316.39), new VSC(14, 1.8, 302.16), new VSC(13, 2.52, 88.87), new VSC(13, 4.37, 1169.59), new VSC(11, 4.44, 525.76), new VSC(10, 1.72, 1581.96), new VSC(9, 2.18, 1155.36), new VSC(9, 3.29, 220.41), new VSC(9, 3.32, 831.86), new VSC(8, 5.76, 846.08), new VSC(8, 2.71, 533.62), new VSC(7, 2.18, 1265.57), new VSC(6, 0.5, 949.18)];
+const g_L3JupiterCoefficients = [new VSC(6502, 2.5986, 7.1135), new VSC(1357, 1.3464, 529.691), new VSC(471, 2.475, 14.227), new VSC(417, 3.245, 536.805), new VSC(353, 2.974, 522.577), new VSC(155, 2.076, 1059.382), new VSC(87, 2.51, 515.46), new VSC(44, 0, 0), new VSC(34, 3.83, 1066.5), new VSC(28, 2.45, 206.19), new VSC(24, 1.28, 412.37), new VSC(23, 2.98, 543.92), new VSC(20, 2.1, 639.9), new VSC(20, 1.4, 419.48), new VSC(19, 1.59, 103.09), new VSC(17, 2.3, 21.34), new VSC(17, 2.6, 1589.07), new VSC(16, 3.15, 625.67), new VSC(16, 3.36, 1052.27), new VSC(13, 2.76, 95.98), new VSC(13, 2.54, 199.07), new VSC(13, 6.27, 426.6), new VSC(9, 1.76, 10.29), new VSC(9, 2.27, 110.21), new VSC(7, 3.43, 309.28), new VSC(7, 4.04, 728.76), new VSC(6, 2.52, 508.35), new VSC(5, 2.91, 1045.15), new VSC(5, 5.25, 323.51), new VSC(4, 4.3, 88.87), new VSC(4, 3.52, 302.16), new VSC(4, 4.09, 735.88), new VSC(3, 1.43, 956.29), new VSC(3, 4.36, 1596.19), new VSC(3, 1.25, 213.3), new VSC(3, 5.02, 838.97), new VSC(3, 2.24, 117.32), new VSC(2, 2.9, 742.99), new VSC(2, 2.36, 942.06)];
+const g_L4JupiterCoefficients = [new VSC(669, 0.853, 7.114), new VSC(114, 3.142, 0), new VSC(100, 0.743, 14.227), new VSC(50, 1.65, 536.8), new VSC(44, 5.82, 529.69), new VSC(32, 4.86, 522.58), new VSC(15, 4.29, 515.46), new VSC(9, 0.71, 1059.38), new VSC(5, 1.3, 543.92), new VSC(4, 2.32, 1066.5), new VSC(4, 0.48, 21.34), new VSC(3, 3, 412.37), new VSC(2, 0.4, 639.9), new VSC(2, 4.26, 199.07), new VSC(2, 4.91, 625.67), new VSC(2, 4.26, 206.19), new VSC(1, 5.26, 1052.27), new VSC(1, 4.72, 95.98), new VSC(1, 1.29, 1589.07)];
+const g_L5JupiterCoefficients = [new VSC(50, 5.26, 7.11), new VSC(16, 5.25, 14.23), new VSC(4, 0.01, 536.8), new VSC(2, 1.1, 522.58), new VSC(1, 3.14, 0)];
+const g_B0JupiterCoefficients = [new VSC(2268616, 3.5585261, 529.6909651), new VSC(110090, 0, 0), new VSC(109972, 3.908093, 1059.38193), new VSC(8101, 3.6051, 522.5774), new VSC(6438, 0.3063, 536.8045), new VSC(6044, 4.2588, 1589.0729), new VSC(1107, 2.9853, 1162.4747), new VSC(944, 1.675, 426.598), new VSC(942, 2.936, 1052.268), new VSC(894, 1.754, 7.114), new VSC(836, 5.179, 103.093), new VSC(767, 2.155, 632.784), new VSC(684, 3.678, 213.299), new VSC(629, 0.643, 1066.495), new VSC(559, 0.014, 846.083), new VSC(532, 2.703, 110.206), new VSC(464, 1.173, 949.176), new VSC(431, 2.608, 419.485), new VSC(351, 4.611, 2118.764), new VSC(132, 4.778, 742.99), new VSC(123, 3.35, 1692.166), new VSC(116, 1.387, 323.505), new VSC(115, 5.049, 316.392), new VSC(104, 3.701, 515.464), new VSC(103, 2.319, 1478.867), new VSC(102, 3.153, 1581.959)];
+const g_B1JupiterCoefficients = [new VSC(177352, 5.701665, 529.690965), new VSC(3230, 5.7794, 1059.3819), new VSC(3081, 5.4746, 522.5774), new VSC(2212, 4.7348, 536.8045), new VSC(1694, 3.1416, 0), new VSC(346, 4.746, 1052.268), new VSC(234, 5.189, 1066.495), new VSC(196, 6.186, 7.114), new VSC(150, 3.927, 1589.073), new VSC(114, 3.439, 632.784), new VSC(97, 2.91, 949.18), new VSC(82, 5.08, 1162.47), new VSC(77, 2.51, 103.09), new VSC(77, 0.61, 419.48), new VSC(74, 5.5, 515.46), new VSC(61, 5.45, 213.3), new VSC(50, 3.95, 735.88), new VSC(46, 0.54, 110.21), new VSC(45, 1.9, 846.08), new VSC(37, 4.7, 543.92), new VSC(36, 6.11, 316.39), new VSC(32, 4.92, 1581.96)];
+const g_B2JupiterCoefficients = [new VSC(8094, 1.4632, 529.691), new VSC(813, 3.1416, 0), new VSC(742, 0.957, 522.577), new VSC(399, 2.899, 536.805), new VSC(342, 1.447, 1059.382), new VSC(74, 0.41, 1052.27), new VSC(46, 3.48, 1066.5), new VSC(30, 1.93, 1589.07), new VSC(29, 0.99, 515.46), new VSC(23, 4.27, 7.11), new VSC(14, 2.92, 543.92), new VSC(12, 5.22, 632.78), new VSC(11, 4.88, 949.18), new VSC(6, 6.21, 1045.15)];
+const g_B3JupiterCoefficients = [new VSC(252, 3.381, 529.691), new VSC(122, 2.733, 522.577), new VSC(49, 1.04, 536.8), new VSC(11, 2.31, 1052.27), new VSC(8, 2.77, 515.46), new VSC(7, 4.25, 1059.38), new VSC(6, 1.78, 1066.5), new VSC(4, 1.13, 543.92), new VSC(3, 3.14, 0)];
+const g_B4JupiterCoefficients = [new VSC(15, 4.53, 522.58), new VSC(5, 4.47, 529.69), new VSC(4, 5.44, 536.8), new VSC(3, 0, 0), new VSC(2, 4.52, 515.46), new VSC(1, 4.2, 1052.27)];
+const g_B5JupiterCoefficients = [new VSC(1, 0.09, 522.58)];
+const g_R0JupiterCoefficients = [new VSC(520887429, 0, 0), new VSC(25209327, 3.4910864, 529.69096509), new VSC(610600, 3.841154, 1059.38193), new VSC(282029, 2.574199, 632.783739), new VSC(187647, 2.075904, 522.577418), new VSC(86793, 0.71001, 419.48464), new VSC(72063, 0.21466, 536.80451), new VSC(65517, 5.97996, 316.39187), new VSC(30135, 2.16132, 949.17561), new VSC(29135, 1.67759, 103.09277), new VSC(23947, 0.27458, 7.11355), new VSC(23453, 3.54023, 735.87651), new VSC(22284, 4.19363, 1589.0729), new VSC(13033, 2.96043, 1162.4747), new VSC(12749, 2.7155, 1052.26838), new VSC(9703, 1.9067, 206.1855), new VSC(9161, 4.4135, 213.2991), new VSC(7895, 2.4791, 426.5982), new VSC(7058, 2.1818, 1265.5675), new VSC(6138, 6.2642, 846.0828), new VSC(5477, 5.6573, 639.8973), new VSC(4170, 2.0161, 515.4639), new VSC(4137, 2.7222, 625.6702), new VSC(3503, 0.5653, 1066.4955), new VSC(2617, 2.0099, 1581.9593), new VSC(2500, 4.5518, 838.9693), new VSC(2128, 6.1275, 742.9901), new VSC(1912, 0.8562, 412.3711), new VSC(1611, 3.0887, 1368.6603), new VSC(1479, 2.6803, 1478.8666), new VSC(1231, 1.8904, 323.5054), new VSC(1217, 1.8017, 110.2063), new VSC(1015, 1.3867, 454.9094), new VSC(999, 2.872, 309.278), new VSC(961, 4.549, 2118.764), new VSC(886, 4.148, 533.623), new VSC(821, 1.593, 1898.351), new VSC(812, 5.941, 909.819), new VSC(777, 3.677, 728.763), new VSC(727, 3.988, 1155.361), new VSC(655, 2.791, 1685.052), new VSC(654, 3.382, 1692.166), new VSC(621, 4.823, 956.289), new VSC(615, 2.276, 942.062), new VSC(562, 0.081, 543.918), new VSC(542, 0.284, 525.759)];
+const g_R1JupiterCoefficients = [new VSC(1271802, 2.6493751, 529.6909651), new VSC(61662, 3.00076, 1059.38193), new VSC(53444, 3.89718, 522.57742), new VSC(41390, 0, 0), new VSC(31185, 4.88277, 536.80451), new VSC(11847, 2.4133, 419.48464), new VSC(9166, 4.7598, 7.1135), new VSC(3404, 3.3469, 1589.0729), new VSC(3203, 5.2108, 735.8765), new VSC(3176, 2.793, 103.0928), new VSC(2806, 3.7422, 515.4639), new VSC(2677, 4.3305, 1052.2684), new VSC(2600, 3.6344, 206.1855), new VSC(2412, 1.4695, 426.5982), new VSC(2101, 3.9276, 639.8973), new VSC(1646, 4.4163, 1066.4955), new VSC(1641, 4.4163, 625.6702), new VSC(1050, 3.1611, 213.2991), new VSC(1025, 2.5543, 412.3711), new VSC(806, 2.678, 632.784), new VSC(741, 2.171, 1162.475), new VSC(677, 6.25, 838.969), new VSC(567, 4.577, 742.99), new VSC(485, 2.469, 949.176), new VSC(469, 4.71, 543.918), new VSC(445, 0.403, 323.505), new VSC(416, 5.368, 728.763), new VSC(402, 4.605, 309.278), new VSC(347, 4.681, 14.227), new VSC(338, 3.168, 956.289), new VSC(261, 5.343, 846.083), new VSC(247, 3.923, 942.062), new VSC(220, 4.842, 1368.66), new VSC(203, 5.6, 1155.361), new VSC(200, 4.439, 1045.155), new VSC(197, 3.706, 2118.764), new VSC(196, 3.759, 199.072), new VSC(184, 4.265, 95.979), new VSC(180, 4.402, 532.872), new VSC(170, 4.846, 526.51), new VSC(146, 6.13, 533.623), new VSC(133, 1.322, 110.206), new VSC(132, 4.512, 525.759)];
+const g_R2JupiterCoefficients = [new VSC(79645, 1.35866, 529.69097), new VSC(8252, 5.7777, 522.5774), new VSC(7030, 3.2748, 536.8045), new VSC(5314, 1.8384, 1059.3819), new VSC(1861, 2.9768, 7.1135), new VSC(964, 5.48, 515.464), new VSC(836, 4.199, 419.485), new VSC(498, 3.142, 0), new VSC(427, 2.228, 639.897), new VSC(406, 3.783, 1066.495), new VSC(377, 2.242, 1589.073), new VSC(363, 5.368, 206.186), new VSC(342, 6.099, 1052.268), new VSC(339, 6.127, 625.67), new VSC(333, 0.003, 426.598), new VSC(280, 4.262, 412.371), new VSC(257, 0.963, 632.784), new VSC(230, 0.705, 735.877), new VSC(201, 3.069, 543.918), new VSC(200, 4.429, 103.093), new VSC(139, 2.932, 14.227), new VSC(114, 0.787, 728.763), new VSC(95, 1.7, 838.97), new VSC(86, 5.14, 323.51), new VSC(83, 0.06, 309.28), new VSC(80, 2.98, 742.99), new VSC(75, 1.6, 956.29), new VSC(70, 1.51, 213.3), new VSC(67, 5.47, 199.07), new VSC(62, 6.1, 1045.15), new VSC(56, 0.96, 1162.47), new VSC(52, 5.58, 942.06), new VSC(50, 2.72, 532.87), new VSC(45, 5.52, 508.35), new VSC(44, 0.27, 526.51), new VSC(40, 5.95, 95.98)];
+const g_R3JupiterCoefficients = [new VSC(3519, 6.058, 529.691), new VSC(1073, 1.6732, 536.8045), new VSC(916, 1.413, 522.577), new VSC(342, 0.523, 1059.382), new VSC(255, 1.196, 7.114), new VSC(222, 0.952, 515.464), new VSC(90, 3.14, 0), new VSC(69, 2.27, 1066.5), new VSC(58, 1.41, 543.92), new VSC(58, 0.53, 639.9), new VSC(51, 5.98, 412.37), new VSC(47, 1.58, 625.67), new VSC(43, 6.12, 419.48), new VSC(37, 1.18, 14.23), new VSC(34, 1.67, 1052.27), new VSC(34, 0.85, 206.19), new VSC(31, 1.04, 1589.07), new VSC(30, 4.63, 426.6), new VSC(21, 2.5, 728.76), new VSC(15, 0.89, 199.07), new VSC(14, 0.96, 508.35), new VSC(13, 1.5, 1045.15), new VSC(12, 2.61, 735.88), new VSC(12, 3.56, 323.51), new VSC(11, 1.79, 309.28), new VSC(11, 6.28, 956.29), new VSC(10, 6.26, 103.09), new VSC(9, 3.45, 838.97)];
+const g_R4JupiterCoefficients = [new VSC(129, 0.084, 536.805), new VSC(113, 4.249, 529.691), new VSC(83, 3.3, 522.58), new VSC(38, 2.73, 515.46), new VSC(27, 5.69, 7.11), new VSC(18, 5.4, 1059.38), new VSC(13, 6.02, 543.92), new VSC(9, 0.77, 1066.5), new VSC(8, 5.68, 14.23), new VSC(7, 1.43, 412.37), new VSC(6, 5.12, 639.9), new VSC(5, 3.34, 625.67), new VSC(3, 3.4, 1052.27), new VSC(3, 4.16, 728.76), new VSC(3, 2.9, 426.6)];
+const g_R5JupiterCoefficients = [new VSC(11, 4.75, 536.8), new VSC(4, 5.92, 522.58), new VSC(2, 5.57, 515.46), new VSC(2, 4.3, 543.92), new VSC(2, 3.69, 7.11), new VSC(2, 4.13, 1059.38), new VSC(2, 5.49, 1066.5)];
+
+
+
+// CAAJupiter
+
+export function CAAJupiter() { }
+
+CAAJupiter.eclipticLongitude = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var rho5 = rho4 * rho;
+ var nL0Coefficients = g_L0JupiterCoefficients.length;
+ var L0 = 0;
+ var i;
+ for (i = 0; i < nL0Coefficients; i++) {
+ L0 += g_L0JupiterCoefficients[i].a * Math.cos(g_L0JupiterCoefficients[i].b + g_L0JupiterCoefficients[i].c * rho);
+ }
+ var nL1Coefficients = g_L1JupiterCoefficients.length;
+ var L1 = 0;
+ for (i = 0; i < nL1Coefficients; i++) {
+ L1 += g_L1JupiterCoefficients[i].a * Math.cos(g_L1JupiterCoefficients[i].b + g_L1JupiterCoefficients[i].c * rho);
+ }
+ var nL2Coefficients = g_L2JupiterCoefficients.length;
+ var L2 = 0;
+ for (i = 0; i < nL2Coefficients; i++) {
+ L2 += g_L2JupiterCoefficients[i].a * Math.cos(g_L2JupiterCoefficients[i].b + g_L2JupiterCoefficients[i].c * rho);
+ }
+ var nL3Coefficients = g_L3JupiterCoefficients.length;
+ var L3 = 0;
+ for (i = 0; i < nL3Coefficients; i++) {
+ L3 += g_L3JupiterCoefficients[i].a * Math.cos(g_L3JupiterCoefficients[i].b + g_L3JupiterCoefficients[i].c * rho);
+ }
+ var nL4Coefficients = g_L4JupiterCoefficients.length;
+ var L4 = 0;
+ for (i = 0; i < nL4Coefficients; i++) {
+ L4 += g_L4JupiterCoefficients[i].a * Math.cos(g_L4JupiterCoefficients[i].b + g_L4JupiterCoefficients[i].c * rho);
+ }
+ var nL5Coefficients = g_L5JupiterCoefficients.length;
+ var L5 = 0;
+ for (i = 0; i < nL5Coefficients; i++) {
+ L5 += g_L5JupiterCoefficients[i].a * Math.cos(g_L5JupiterCoefficients[i].b + g_L5JupiterCoefficients[i].c * rho);
+ }
+ var vvalue = (L0 + L1 * rho + L2 * rhosquared + L3 * rhocubed + L4 * rho4 + L5 * rho5) / 100000000;
+ vvalue = CT.m360(CT.r2D(vvalue));
+ return vvalue;
+};
+
+CAAJupiter.eclipticLatitude = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var rho5 = rho4 * rho;
+ var nB0Coefficients = g_B0JupiterCoefficients.length;
+ var B0 = 0;
+ var i;
+ for (i = 0; i < nB0Coefficients; i++) {
+ B0 += g_B0JupiterCoefficients[i].a * Math.cos(g_B0JupiterCoefficients[i].b + g_B0JupiterCoefficients[i].c * rho);
+ }
+ var nB1Coefficients = g_B1JupiterCoefficients.length;
+ var B1 = 0;
+ for (i = 0; i < nB1Coefficients; i++) {
+ B1 += g_B1JupiterCoefficients[i].a * Math.cos(g_B1JupiterCoefficients[i].b + g_B1JupiterCoefficients[i].c * rho);
+ }
+ var nB2Coefficients = g_B2JupiterCoefficients.length;
+ var B2 = 0;
+ for (i = 0; i < nB2Coefficients; i++) {
+ B2 += g_B2JupiterCoefficients[i].a * Math.cos(g_B2JupiterCoefficients[i].b + g_B2JupiterCoefficients[i].c * rho);
+ }
+ var nB3Coefficients = g_B3JupiterCoefficients.length;
+ var B3 = 0;
+ for (i = 0; i < nB3Coefficients; i++) {
+ B3 += g_B3JupiterCoefficients[i].a * Math.cos(g_B3JupiterCoefficients[i].b + g_B3JupiterCoefficients[i].c * rho);
+ }
+ var nB4Coefficients = g_B4JupiterCoefficients.length;
+ var B4 = 0;
+ for (i = 0; i < nB4Coefficients; i++) {
+ B4 += g_B4JupiterCoefficients[i].a * Math.cos(g_B4JupiterCoefficients[i].b + g_B4JupiterCoefficients[i].c * rho);
+ }
+ var nB5Coefficients = g_B5JupiterCoefficients.length;
+ var B5 = 0;
+ for (i = 0; i < nB5Coefficients; i++) {
+ B5 += g_B5JupiterCoefficients[i].a * Math.cos(g_B5JupiterCoefficients[i].b + g_B5JupiterCoefficients[i].c * rho);
+ }
+ var vvalue = (B0 + B1 * rho + B2 * rhosquared + B3 * rhocubed + B4 * rho4 + B5 * rho5) / 100000000;
+ vvalue = CT.r2D(vvalue);
+ return vvalue;
+};
+
+CAAJupiter.radiusVector = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var rho5 = rho4 * rho;
+ var nR0Coefficients = g_R0JupiterCoefficients.length;
+ var R0 = 0;
+ var i;
+ for (i = 0; i < nR0Coefficients; i++) {
+ R0 += g_R0JupiterCoefficients[i].a * Math.cos(g_R0JupiterCoefficients[i].b + g_R0JupiterCoefficients[i].c * rho);
+ }
+ var nR1Coefficients = g_R1JupiterCoefficients.length;
+ var R1 = 0;
+ for (i = 0; i < nR1Coefficients; i++) {
+ R1 += g_R1JupiterCoefficients[i].a * Math.cos(g_R1JupiterCoefficients[i].b + g_R1JupiterCoefficients[i].c * rho);
+ }
+ var nR2Coefficients = g_R2JupiterCoefficients.length;
+ var R2 = 0;
+ for (i = 0; i < nR2Coefficients; i++) {
+ R2 += g_R2JupiterCoefficients[i].a * Math.cos(g_R2JupiterCoefficients[i].b + g_R2JupiterCoefficients[i].c * rho);
+ }
+ var nR3Coefficients = g_R3JupiterCoefficients.length;
+ var R3 = 0;
+ for (i = 0; i < nR3Coefficients; i++) {
+ R3 += g_R3JupiterCoefficients[i].a * Math.cos(g_R3JupiterCoefficients[i].b + g_R3JupiterCoefficients[i].c * rho);
+ }
+ var nR4Coefficients = g_R4JupiterCoefficients.length;
+ var R4 = 0;
+ for (i = 0; i < nR4Coefficients; i++) {
+ R4 += g_R4JupiterCoefficients[i].a * Math.cos(g_R4JupiterCoefficients[i].b + g_R4JupiterCoefficients[i].c * rho);
+ }
+ var nR5Coefficients = g_R5JupiterCoefficients.length;
+ var R5 = 0;
+ for (i = 0; i < nR5Coefficients; i++) {
+ R5 += g_R5JupiterCoefficients[i].a * Math.cos(g_R5JupiterCoefficients[i].b + g_R5JupiterCoefficients[i].c * rho);
+ }
+ return (R0 + R1 * rho + R2 * rhosquared + R3 * rhocubed + R4 * rho4 + R5 * rho5) / 100000000;
+};
+
+var CAAJupiter$ = {};
+
+registerType("CAAJupiter", [CAAJupiter, CAAJupiter$, null]);
diff --git a/engine/esm/astrocalc/kepler.js b/engine/esm/astrocalc/kepler.js
new file mode 100644
index 00000000..d77da4ba
--- /dev/null
+++ b/engine/esm/astrocalc/kepler.js
@@ -0,0 +1,71 @@
+// Originally `AAKEPLER.CPP`
+// "Purpose: Implementation for the algorithms which solve Kepler's equation"
+// Last update of original: PJN / 29-12-2003
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { ss } from "../ss.js";
+import { CT } from "./coordinate_transformation.js";
+
+
+// CAAKepler
+
+export function CAAKepler() { }
+
+CAAKepler.calculate = function (M, e) {
+ return CAAKepler.calculateIter(M, e, 53);
+};
+
+CAAKepler.calculateIter = function (M, e, nIterations) {
+ M = CT.d2R(M);
+ var PI = CT.PI();
+ var F = 1;
+ if (M < 0) {
+ F = -1;
+ }
+ M = Math.abs(M) / (2 * PI);
+ M = (M - ss.truncate(M)) * 2 * PI * F;
+ if (M < 0) {
+ M += 2 * PI;
+ }
+ F = 1;
+ if (M > PI) {
+ F = -1;
+ }
+ if (M > PI) {
+ M = 2 * PI - M;
+ }
+ var E = PI / 2;
+ var scale = PI / 4;
+ for (var i = 0; i < nIterations; i++) {
+ var R = E - e * Math.sin(E);
+ if (M > R) {
+ E += scale;
+ }
+ else {
+ E -= scale;
+ }
+ scale /= 2;
+ }
+ return CT.r2D(E) * F;
+};
+
+var CAAKepler$ = {};
+
+registerType("CAAKepler", [CAAKepler, CAAKepler$, null]);
diff --git a/engine/esm/astrocalc/mars.js b/engine/esm/astrocalc/mars.js
new file mode 100644
index 00000000..e1d30af1
--- /dev/null
+++ b/engine/esm/astrocalc/mars.js
@@ -0,0 +1,165 @@
+// Originally `AAMARS.CPP`
+// "Purpose: Implementation for the algorithms which obtain the heliocentric position of Uranus [sic]"
+// Last update of original: PJN / 29-12-2003
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+import { VSC } from "./earth.js";
+
+
+// Coefficients
+
+const g_L0MarsCoefficients = [new VSC(620347712, 0, 0), new VSC(18656368, 5.050371, 3340.6124267), new VSC(1108217, 5.4009984, 6681.2248534), new VSC(91798, 5.75479, 10021.83728), new VSC(27745, 5.9705, 3.52312), new VSC(12316, 0.84956, 2810.92146), new VSC(10610, 2.93959, 2281.2305), new VSC(8927, 4.157, 0.0173), new VSC(8716, 6.1101, 13362.4497), new VSC(7775, 3.3397, 5621.8429), new VSC(6798, 0.3646, 398.149), new VSC(4161, 0.2281, 2942.4634), new VSC(3575, 1.6619, 2544.3144), new VSC(3075, 0.857, 191.4483), new VSC(2938, 6.0789, 0.0673), new VSC(2628, 0.6481, 3337.0893), new VSC(2580, 0.03, 3344.1355), new VSC(2389, 5.039, 796.298), new VSC(1799, 0.6563, 529.691), new VSC(1546, 2.9158, 1751.5395), new VSC(1528, 1.1498, 6151.5339), new VSC(1286, 3.068, 2146.1654), new VSC(1264, 3.6228, 5092.152), new VSC(1025, 3.6933, 8962.4553), new VSC(892, 0.183, 16703.062), new VSC(859, 2.401, 2914.014), new VSC(833, 4.495, 3340.63), new VSC(833, 2.464, 3340.595), new VSC(749, 3.822, 155.42), new VSC(724, 0.675, 3738.761), new VSC(713, 3.663, 1059.382), new VSC(655, 0.489, 3127.313), new VSC(636, 2.922, 8432.764), new VSC(553, 4.475, 1748.016), new VSC(550, 3.81, 0.98), new VSC(472, 3.625, 1194.447), new VSC(426, 0.554, 6283.076), new VSC(415, 0.497, 213.299), new VSC(312, 0.999, 6677.702), new VSC(307, 0.381, 6684.748), new VSC(302, 4.486, 3532.061), new VSC(299, 2.783, 6254.627), new VSC(293, 4.221, 20.775), new VSC(284, 5.769, 3149.164), new VSC(281, 5.882, 1349.867), new VSC(274, 0.542, 3340.545), new VSC(274, 0.134, 3340.68), new VSC(239, 5.372, 4136.91), new VSC(236, 5.755, 3333.499), new VSC(231, 1.282, 3870.303), new VSC(221, 3.505, 382.897), new VSC(204, 2.821, 1221.849), new VSC(193, 3.357, 3.59), new VSC(189, 1.491, 9492.146), new VSC(179, 1.006, 951.718), new VSC(174, 2.414, 553.569), new VSC(172, 0.439, 5486.778), new VSC(160, 3.949, 4562.461), new VSC(144, 1.419, 135.065), new VSC(140, 3.326, 2700.715), new VSC(138, 4.301, 7.114), new VSC(131, 4.045, 12303.068), new VSC(128, 2.208, 1592.596), new VSC(128, 1.807, 5088.629), new VSC(117, 3.128, 7903.073), new VSC(113, 3.701, 1589.073), new VSC(110, 1.052, 242.729), new VSC(105, 0.785, 8827.39), new VSC(100, 3.243, 11773.377)];
+const g_L1MarsCoefficients = [new VSC(334085627474, 0, 0), new VSC(1458227, 3.6042605, 3340.6124267), new VSC(164901, 3.926313, 6681.224853), new VSC(19963, 4.26594, 10021.83728), new VSC(3452, 4.7321, 3.5231), new VSC(2485, 4.6128, 13362.4497), new VSC(842, 4.459, 2281.23), new VSC(538, 5.016, 398.149), new VSC(521, 4.994, 3344.136), new VSC(433, 2.561, 191.448), new VSC(430, 5.316, 155.42), new VSC(382, 3.539, 796.298), new VSC(314, 4.963, 16703.062), new VSC(283, 3.16, 2544.314), new VSC(206, 4.569, 2146.165), new VSC(169, 1.329, 3337.089), new VSC(158, 4.185, 1751.54), new VSC(134, 2.233, 0.98), new VSC(134, 5.974, 1748.016), new VSC(118, 6.024, 6151.534), new VSC(117, 2.213, 1059.382), new VSC(114, 2.129, 1194.447), new VSC(114, 5.428, 3738.761), new VSC(91, 1.1, 1349.87), new VSC(85, 3.91, 553.57), new VSC(83, 5.3, 6684.75), new VSC(81, 4.43, 529.69), new VSC(80, 2.25, 8962.46), new VSC(73, 2.5, 951.72), new VSC(73, 5.84, 242.73), new VSC(71, 3.86, 2914.01), new VSC(68, 5.02, 382.9), new VSC(65, 1.02, 3340.6), new VSC(65, 3.05, 3340.63), new VSC(62, 4.15, 3149.16), new VSC(57, 3.89, 4136.91), new VSC(48, 4.87, 213.3), new VSC(48, 1.18, 3333.5), new VSC(47, 1.31, 3185.19), new VSC(41, 0.71, 1592.6), new VSC(40, 2.73, 7.11), new VSC(40, 5.32, 20043.67), new VSC(33, 5.41, 6283.08), new VSC(28, 0.05, 9492.15), new VSC(27, 3.89, 1221.85), new VSC(27, 5.11, 2700.72)];
+const g_L2MarsCoefficients = [new VSC(58016, 2.04979, 3340.61243), new VSC(54188, 0, 0), new VSC(13908, 2.45742, 6681.22485), new VSC(2465, 2.8, 10021.8373), new VSC(398, 3.141, 13362.45), new VSC(222, 3.194, 3.523), new VSC(121, 0.543, 155.42), new VSC(62, 3.49, 16703.06), new VSC(54, 3.54, 3344.14), new VSC(34, 6, 2281.23), new VSC(32, 4.14, 191.45), new VSC(30, 2, 796.3), new VSC(23, 4.33, 242.73), new VSC(22, 3.45, 398.15), new VSC(20, 5.42, 553.57), new VSC(16, 0.66, 0.98), new VSC(16, 6.11, 2146.17), new VSC(16, 1.22, 1748.02), new VSC(15, 6.1, 3185.19), new VSC(14, 4.02, 951.72), new VSC(14, 2.62, 1349.87), new VSC(13, 0.6, 1194.45), new VSC(12, 3.86, 6684.75), new VSC(11, 4.72, 2544.31), new VSC(10, 0.25, 382.9), new VSC(9, 0.68, 1059.38), new VSC(9, 3.83, 20043.67), new VSC(9, 3.88, 3738.76), new VSC(8, 5.46, 1751.54), new VSC(7, 2.58, 3149.16), new VSC(7, 2.38, 4136.91), new VSC(6, 5.48, 1592.6), new VSC(6, 2.34, 3097.88)];
+const g_L3MarsCoefficients = [new VSC(1482, 0.4443, 3340.6124), new VSC(662, 0.885, 6681.225), new VSC(188, 1.288, 10021.837), new VSC(41, 1.65, 13362.45), new VSC(26, 0, 0), new VSC(23, 2.05, 155.42), new VSC(10, 1.58, 3.52), new VSC(8, 2, 16703.06), new VSC(5, 2.82, 242.73), new VSC(4, 2.02, 3344.14), new VSC(3, 4.59, 3185.19), new VSC(3, 0.65, 553.57)];
+const g_L4MarsCoefficients = [new VSC(114, 3.1416, 0), new VSC(29, 5.64, 6681.22), new VSC(24, 5.14, 3340.61), new VSC(11, 6.03, 10021.84), new VSC(3, 0.13, 13362.45), new VSC(3, 3.56, 155.42), new VSC(1, 0.49, 16703.06), new VSC(1, 1.32, 242.73)];
+const g_L5MarsCoefficients = [new VSC(1, 3.14, 0), new VSC(1, 4.04, 6681.22)];
+const g_B0MarsCoefficients = [new VSC(3197135, 3.7683204, 3340.6124267), new VSC(298033, 4.10617, 6681.224853), new VSC(289105, 0, 0), new VSC(31366, 4.44651, 10021.83728), new VSC(3484, 4.7881, 13362.4497), new VSC(443, 5.026, 3344.136), new VSC(443, 5.652, 3337.089), new VSC(399, 5.131, 16703.062), new VSC(293, 3.793, 2281.23), new VSC(182, 6.136, 6151.534), new VSC(163, 4.264, 529.691), new VSC(160, 2.232, 1059.382), new VSC(149, 2.165, 5621.843), new VSC(143, 1.182, 3340.595), new VSC(143, 3.213, 3340.63), new VSC(139, 2.418, 8962.455)];
+const g_B1MarsCoefficients = [new VSC(350069, 5.368478, 3340.612427), new VSC(14116, 3.14159, 0), new VSC(9671, 5.4788, 6681.2249), new VSC(1472, 3.2021, 10021.8373), new VSC(426, 3.408, 13362.45), new VSC(102, 0.776, 3337.089), new VSC(79, 3.72, 16703.06), new VSC(33, 3.46, 5621.84), new VSC(26, 2.48, 2281.23)];
+const g_B2MarsCoefficients = [new VSC(16727, 0.60221, 3340.61243), new VSC(4987, 4.1416, 0), new VSC(302, 3.559, 6681.225), new VSC(26, 1.9, 13362.45), new VSC(21, 0.92, 10021.84), new VSC(12, 2.24, 3337.09), new VSC(8, 2.25, 16703.06)];
+const g_B3MarsCoefficients = [new VSC(607, 1.981, 3340.612), new VSC(43, 0, 0), new VSC(14, 1.8, 6681.22), new VSC(3, 3.45, 10021.84)];
+const g_B4MarsCoefficients = [new VSC(13, 0, 0), new VSC(11, 3.46, 3340.61), new VSC(1, 0.5, 6681.22)];
+const g_R0MarsCoefficients = [new VSC(153033488, 0, 0), new VSC(14184953, 3.47971284, 3340.6124267), new VSC(660776, 3.817834, 6681.224853), new VSC(46179, 4.15595, 10021.83728), new VSC(8110, 5.5596, 2810.9215), new VSC(7485, 1.7724, 5621.8429), new VSC(5523, 1.3644, 2281.2305), new VSC(3825, 4.4941, 13362.4497), new VSC(2484, 4.9255, 2942.4634), new VSC(2307, 0.0908, 2544.3144), new VSC(1999, 5.3606, 3337.0893), new VSC(1960, 4.7425, 3344.1355), new VSC(1167, 2.1126, 5092.152), new VSC(1103, 5.0091, 398.149), new VSC(992, 5.839, 6151.534), new VSC(899, 4.408, 529.691), new VSC(807, 2.102, 1059.382), new VSC(798, 3.448, 796.298), new VSC(741, 1.499, 2146.165), new VSC(726, 1.245, 8432.764), new VSC(692, 2.134, 8962.455), new VSC(633, 0.894, 3340.595), new VSC(633, 2.924, 3340.63), new VSC(630, 1.287, 1751.54), new VSC(574, 0.829, 2914.014), new VSC(526, 5.383, 3738.761), new VSC(473, 5.199, 3127.313), new VSC(348, 4.832, 16703.062), new VSC(284, 2.907, 3532.061), new VSC(280, 5.257, 6283.076), new VSC(276, 1.218, 6254.627), new VSC(275, 2.908, 1748.016), new VSC(270, 3.764, 5884.927), new VSC(239, 2.037, 1194.447), new VSC(234, 5.105, 5486.778), new VSC(228, 3.255, 6872.673), new VSC(223, 4.199, 3149.164), new VSC(219, 5.583, 191.448), new VSC(208, 5.255, 3340.545), new VSC(208, 4.846, 3340.68), new VSC(186, 5.699, 6677.702), new VSC(183, 5.081, 6684.748), new VSC(179, 4.184, 3333.499), new VSC(176, 5.953, 3870.303), new VSC(164, 3.799, 4136.91)];
+const g_R1MarsCoefficients = [new VSC(1107433, 2.0325052, 3340.6124267), new VSC(103176, 2.370718, 6681.224853), new VSC(12877, 0, 0), new VSC(10816, 2.70888, 10021.83728), new VSC(1195, 3.047, 13362.4497), new VSC(439, 2.888, 2281.23), new VSC(396, 3.423, 3344.136), new VSC(183, 1.584, 2544.314), new VSC(136, 3.385, 16703.062), new VSC(128, 6.043, 3337.089), new VSC(128, 0.63, 1059.382), new VSC(127, 1.954, 796.298), new VSC(118, 2.998, 2146.165), new VSC(88, 3.42, 398.15), new VSC(83, 3.86, 3738.76), new VSC(76, 4.45, 6151.53), new VSC(72, 2.76, 529.69), new VSC(67, 2.55, 1751.54), new VSC(66, 4.41, 1748.02), new VSC(58, 0.54, 1194.45), new VSC(54, 0.68, 8962.46), new VSC(51, 3.73, 6684.75), new VSC(49, 5.73, 3340.6), new VSC(49, 1.48, 3340.63), new VSC(48, 2.58, 3149.16), new VSC(48, 2.29, 2914.01), new VSC(39, 2.32, 4136.91)];
+const g_R2MarsCoefficients = [new VSC(44242, 0.47931, 3340.61243), new VSC(8138, 0.87, 6681.2249), new VSC(1275, 1.2259, 10021.8373), new VSC(187, 1.573, 13362.45), new VSC(52, 3.14, 0), new VSC(41, 1.97, 3344.14), new VSC(27, 1.92, 16703.06), new VSC(18, 4.43, 2281.23), new VSC(12, 4.53, 3185.19), new VSC(10, 5.39, 1059.38), new VSC(10, 0.42, 796.3)];
+const g_R3MarsCoefficients = [new VSC(1113, 5.1499, 3340.6124), new VSC(424, 5.613, 6681.225), new VSC(100, 5.997, 10021.837), new VSC(20, 0.08, 13362.45), new VSC(5, 3.14, 0), new VSC(3, 0.43, 16703.06)];
+const g_R4MarsCoefficients = [new VSC(20, 3.58, 3340.61), new VSC(16, 4.05, 6681.22), new VSC(6, 4.46, 10021.84), new VSC(2, 4.84, 13362.45)];
+
+
+// CAAMars
+
+export function CAAMars() { }
+
+CAAMars.eclipticLongitude = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var rho5 = rho4 * rho;
+ var nL0Coefficients = g_L0MarsCoefficients.length;
+ var L0 = 0;
+ var i;
+ for (i = 0; i < nL0Coefficients; i++) {
+ L0 += g_L0MarsCoefficients[i].a * Math.cos(g_L0MarsCoefficients[i].b + g_L0MarsCoefficients[i].c * rho);
+ }
+ var nL1Coefficients = g_L1MarsCoefficients.length;
+ var L1 = 0;
+ for (i = 0; i < nL1Coefficients; i++) {
+ L1 += g_L1MarsCoefficients[i].a * Math.cos(g_L1MarsCoefficients[i].b + g_L1MarsCoefficients[i].c * rho);
+ }
+ var nL2Coefficients = g_L2MarsCoefficients.length;
+ var L2 = 0;
+ for (i = 0; i < nL2Coefficients; i++) {
+ L2 += g_L2MarsCoefficients[i].a * Math.cos(g_L2MarsCoefficients[i].b + g_L2MarsCoefficients[i].c * rho);
+ }
+ var nL3Coefficients = g_L3MarsCoefficients.length;
+ var L3 = 0;
+ for (i = 0; i < nL3Coefficients; i++) {
+ L3 += g_L3MarsCoefficients[i].a * Math.cos(g_L3MarsCoefficients[i].b + g_L3MarsCoefficients[i].c * rho);
+ }
+ var nL4Coefficients = g_L4MarsCoefficients.length;
+ var L4 = 0;
+ for (i = 0; i < nL4Coefficients; i++) {
+ L4 += g_L4MarsCoefficients[i].a * Math.cos(g_L4MarsCoefficients[i].b + g_L4MarsCoefficients[i].c * rho);
+ }
+ var nL5Coefficients = g_L5MarsCoefficients.length;
+ var L5 = 0;
+ for (i = 0; i < nL5Coefficients; i++) {
+ L5 += g_L5MarsCoefficients[i].a * Math.cos(g_L5MarsCoefficients[i].b + g_L5MarsCoefficients[i].c * rho);
+ }
+ var vvalue = (L0 + L1 * rho + L2 * rhosquared + L3 * rhocubed + L4 * rho4 + L5 * rho5) / 100000000;
+ vvalue = CT.m360(CT.r2D(vvalue));
+ return vvalue;
+};
+
+CAAMars.eclipticLatitude = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var nB0Coefficients = g_B0MarsCoefficients.length;
+ var B0 = 0;
+ var i;
+ for (i = 0; i < nB0Coefficients; i++) {
+ B0 += g_B0MarsCoefficients[i].a * Math.cos(g_B0MarsCoefficients[i].b + g_B0MarsCoefficients[i].c * rho);
+ }
+ var nB1Coefficients = g_B1MarsCoefficients.length;
+ var B1 = 0;
+ for (i = 0; i < nB1Coefficients; i++) {
+ B1 += g_B1MarsCoefficients[i].a * Math.cos(g_B1MarsCoefficients[i].b + g_B1MarsCoefficients[i].c * rho);
+ }
+ var nB2Coefficients = g_B2MarsCoefficients.length;
+ var B2 = 0;
+ for (i = 0; i < nB2Coefficients; i++) {
+ B2 += g_B2MarsCoefficients[i].a * Math.cos(g_B2MarsCoefficients[i].b + g_B2MarsCoefficients[i].c * rho);
+ }
+ var nB3Coefficients = g_B3MarsCoefficients.length;
+ var B3 = 0;
+ for (i = 0; i < nB3Coefficients; i++) {
+ B3 += g_B3MarsCoefficients[i].a * Math.cos(g_B3MarsCoefficients[i].b + g_B3MarsCoefficients[i].c * rho);
+ }
+ var nB4Coefficients = g_B4MarsCoefficients.length;
+ var B4 = 0;
+ for (i = 0; i < nB4Coefficients; i++) {
+ B4 += g_B4MarsCoefficients[i].a * Math.cos(g_B4MarsCoefficients[i].b + g_B4MarsCoefficients[i].c * rho);
+ }
+ var vvalue = (B0 + B1 * rho + B2 * rhosquared + B3 * rhocubed + B4 * rho4) / 100000000;
+ vvalue = CT.r2D(vvalue);
+ return vvalue;
+};
+
+CAAMars.radiusVector = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var nR0Coefficients = g_R0MarsCoefficients.length;
+ var R0 = 0;
+ var i;
+ for (i = 0; i < nR0Coefficients; i++) {
+ R0 += g_R0MarsCoefficients[i].a * Math.cos(g_R0MarsCoefficients[i].b + g_R0MarsCoefficients[i].c * rho);
+ }
+ var nR1Coefficients = g_R1MarsCoefficients.length;
+ var R1 = 0;
+ for (i = 0; i < nR1Coefficients; i++) {
+ R1 += g_R1MarsCoefficients[i].a * Math.cos(g_R1MarsCoefficients[i].b + g_R1MarsCoefficients[i].c * rho);
+ }
+ var nR2Coefficients = g_R2MarsCoefficients.length;
+ var R2 = 0;
+ for (i = 0; i < nR2Coefficients; i++) {
+ R2 += g_R2MarsCoefficients[i].a * Math.cos(g_R2MarsCoefficients[i].b + g_R2MarsCoefficients[i].c * rho);
+ }
+ var nR3Coefficients = g_R3MarsCoefficients.length;
+ var R3 = 0;
+ for (i = 0; i < nR3Coefficients; i++) {
+ R3 += g_R3MarsCoefficients[i].a * Math.cos(g_R3MarsCoefficients[i].b + g_R3MarsCoefficients[i].c * rho);
+ }
+ var nR4Coefficients = g_R4MarsCoefficients.length;
+ var R4 = 0;
+ for (i = 0; i < nR4Coefficients; i++) {
+ R4 += g_R4MarsCoefficients[i].a * Math.cos(g_R4MarsCoefficients[i].b + g_R4MarsCoefficients[i].c * rho);
+ }
+ return (R0 + R1 * rho + R2 * rhosquared + R3 * rhocubed + R4 * rho4) / 100000000;
+};
+
+var CAAMars$ = {};
+
+registerType("CAAMars", [CAAMars, CAAMars$, null]);
diff --git a/engine/esm/astrocalc/mercury.js b/engine/esm/astrocalc/mercury.js
new file mode 100644
index 00000000..e5f53dbb
--- /dev/null
+++ b/engine/esm/astrocalc/mercury.js
@@ -0,0 +1,158 @@
+// Originally `AAMERCURY.CPP`
+// "Purpose: Implementation for the algorithms which obtain the heliocentric position of Mercury"
+// Last update of original: PJN / 12-05-2006
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+import { VSC } from "./earth.js";
+
+
+// Coefficients
+
+const g_L0MercuryCoefficients = [new VSC(440250710, 0, 0), new VSC(40989415, 1.48302034, 26087.90314157), new VSC(5046294, 4.47785449, 52175.8062831), new VSC(855347, 1.165203, 78263.709425), new VSC(165590, 4.119692, 104351.612566), new VSC(34562, 0.77931, 130439.51571), new VSC(7583, 3.7135, 156527.4188), new VSC(3560, 1.512, 1109.3786), new VSC(1803, 4.1033, 5661.332), new VSC(1726, 0.3583, 182615.322), new VSC(1590, 2.9951, 25028.5212), new VSC(1365, 4.5992, 27197.2817), new VSC(1017, 0.8803, 31749.2352), new VSC(714, 1.541, 24978.525), new VSC(644, 5.303, 21535.95), new VSC(451, 6.05, 51116.424), new VSC(404, 3.282, 208703.225), new VSC(352, 5.242, 20426.571), new VSC(345, 2.792, 15874.618), new VSC(343, 5.765, 955.6), new VSC(339, 5.863, 25558.212), new VSC(325, 1.337, 53285.185), new VSC(273, 2.495, 529.691), new VSC(264, 3.917, 57837.138), new VSC(260, 0.987, 4551.953), new VSC(239, 0.113, 1059.382), new VSC(235, 0.267, 11322.664), new VSC(217, 0.66, 13521.751), new VSC(209, 2.092, 47623.853), new VSC(183, 2.629, 27043.503), new VSC(182, 2.434, 25661.305), new VSC(176, 4.536, 51066.428), new VSC(173, 2.452, 24498.83), new VSC(142, 3.36, 37410.567), new VSC(138, 0.291, 10213.286), new VSC(125, 3.721, 39609.655), new VSC(118, 2.781, 77204.327), new VSC(106, 4.206, 19804.827)];
+const g_L1MercuryCoefficients = [new VSC(2608814706223, 0, 0), new VSC(1126008, 6.2170397, 26087.9031416), new VSC(303471, 3.055655, 52175.806283), new VSC(80538, 6.10455, 78263.70942), new VSC(21245, 2.83532, 104351.61257), new VSC(5592, 5.8268, 130439.5157), new VSC(1472, 2.5185, 156527.4188), new VSC(388, 5.48, 182615.322), new VSC(352, 3.052, 1109.379), new VSC(103, 2.149, 208703.225), new VSC(94, 6.12, 27197.28), new VSC(91, 0, 24978.52), new VSC(52, 5.62, 5661.33), new VSC(44, 4.57, 25028.52), new VSC(28, 3.04, 51066.43), new VSC(27, 5.09, 234791.13)];
+const g_L2MercuryCoefficients = [new VSC(53050, 0, 0), new VSC(16904, 4.69072, 26087.90314), new VSC(7397, 1.3474, 52175.8063), new VSC(3018, 4.4564, 78263.7094), new VSC(1107, 1.264, 104351.6126), new VSC(378, 4.32, 130439.516), new VSC(123, 1.069, 156527.419), new VSC(39, 4.08, 182615.32), new VSC(15, 4.63, 1109.38), new VSC(12, 0.79, 208703.23)];
+const g_L3MercuryCoefficients = [new VSC(188, 0.035, 52175.806), new VSC(142, 3.125, 26087.903), new VSC(97, 3, 78263.71), new VSC(44, 6.02, 104351.61), new VSC(35, 0, 0), new VSC(18, 2.78, 130439.52), new VSC(7, 5.82, 156527.42), new VSC(3, 2.57, 182615.32)];
+const g_L4MercuryCoefficients = [new VSC(114, 3.1416, 0), new VSC(2, 2.03, 26087.9), new VSC(2, 1.42, 78263.71), new VSC(2, 4.5, 52175.81), new VSC(1, 4.5, 104351.61), new VSC(1, 1.27, 130439.52)];
+const g_L5MercuryCoefficients = [new VSC(1, 3.14, 0)];
+const g_B0MercuryCoefficients = [new VSC(11737529, 1.98357499, 26087.90314157), new VSC(2388077, 5.0373896, 52175.8062831), new VSC(1222840, 3.1415927, 0), new VSC(543252, 1.796444, 78263.709425), new VSC(129779, 4.832325, 104351.612566), new VSC(31867, 1.58088, 130439.51571), new VSC(7963, 4.6097, 156527.4188), new VSC(2014, 1.3532, 182615.322), new VSC(514, 4.378, 208703.325), new VSC(209, 2.02, 24978.525), new VSC(208, 4.918, 27197.282), new VSC(132, 1.119, 234791.128), new VSC(121, 1.813, 53285.185), new VSC(100, 5.657, 20426.571)];
+const g_B1MercuryCoefficients = [new VSC(429151, 3.501698, 26087.903142), new VSC(146234, 3.141593, 0), new VSC(22675, 0.01515, 52175.80628), new VSC(10895, 0.4854, 78263.70942), new VSC(6353, 3.4294, 104351.6126), new VSC(2496, 0.1605, 130439.5157), new VSC(860, 3.185, 156527.419), new VSC(278, 6.21, 182615.322), new VSC(86, 2.95, 208703.23), new VSC(28, 0.29, 27197.28), new VSC(26, 5.98, 234791.13)];
+const g_B2MercuryCoefficients = [new VSC(11831, 4.79066, 26087.90314), new VSC(1914, 0, 0), new VSC(1045, 1.2122, 52175.8063), new VSC(266, 4.434, 78263.709), new VSC(170, 1.623, 104351.613), new VSC(96, 4.8, 130439.52), new VSC(45, 1.61, 156527.42), new VSC(18, 4.67, 182615.32), new VSC(7, 1.43, 208703.23)];
+const g_B3MercuryCoefficients = [new VSC(235, 0.354, 26087.903), new VSC(161, 0, 0), new VSC(19, 4.36, 52175.81), new VSC(6, 2.51, 78263.71), new VSC(5, 6.14, 104351.61), new VSC(3, 3.12, 130439.52), new VSC(2, 6.27, 156527.42)];
+const g_B4MercuryCoefficients = [new VSC(4, 1.75, 26087.9), new VSC(1, 3.14, 0)];
+const g_R0MercuryCoefficients = [new VSC(39528272, 0, 0), new VSC(7834132, 6.1923372, 26087.9031416), new VSC(795526, 2.959897, 52175.806283), new VSC(121282, 6.010642, 78263.709425), new VSC(21922, 2.7782, 104351.61257), new VSC(4354, 5.8289, 130439.5157), new VSC(918, 2.597, 156527.419), new VSC(290, 1.424, 25028.521), new VSC(260, 3.028, 27197.282), new VSC(202, 5.647, 182615.322), new VSC(201, 5.592, 31749.235), new VSC(142, 6.253, 24978.525), new VSC(100, 3.734, 21535.95)];
+const g_R1MercuryCoefficients = [new VSC(217348, 4.656172, 26087.903142), new VSC(44142, 1.42386, 52175.80628), new VSC(10094, 4.47466, 78263.70942), new VSC(2433, 1.2423, 104351.6126), new VSC(1624, 0, 0), new VSC(604, 4.293, 130439.516), new VSC(153, 1.061, 156527.419), new VSC(39, 4.11, 182615.32)];
+const g_R2MercuryCoefficients = [new VSC(3118, 3.0823, 26087.9031), new VSC(1245, 6.1518, 52175.8063), new VSC(425, 2.926, 78263.709), new VSC(136, 5.98, 104351.613), new VSC(42, 2.75, 130439.52), new VSC(22, 3.14, 0), new VSC(13, 5.8, 156527.42)];
+const g_R3MercuryCoefficients = [new VSC(33, 1.68, 26087.9), new VSC(24, 4.63, 52175.81), new VSC(12, 1.39, 78263.71), new VSC(5, 4.44, 104351.61), new VSC(2, 1.21, 130439.52)];
+
+
+// CAAMercury
+
+export function CAAMercury() { }
+
+CAAMercury.eclipticLongitude = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var rho5 = rho4 * rho;
+ var nL0Coefficients = g_L0MercuryCoefficients.length;
+ var L0 = 0;
+ var i;
+ for (i = 0; i < nL0Coefficients; i++) {
+ L0 += g_L0MercuryCoefficients[i].a * Math.cos(g_L0MercuryCoefficients[i].b + g_L0MercuryCoefficients[i].c * rho);
+ }
+ var nL1Coefficients = g_L1MercuryCoefficients.length;
+ var L1 = 0;
+ for (i = 0; i < nL1Coefficients; i++) {
+ L1 += g_L1MercuryCoefficients[i].a * Math.cos(g_L1MercuryCoefficients[i].b + g_L1MercuryCoefficients[i].c * rho);
+ }
+ var nL2Coefficients = g_L2MercuryCoefficients.length;
+ var L2 = 0;
+ for (i = 0; i < nL2Coefficients; i++) {
+ L2 += g_L2MercuryCoefficients[i].a * Math.cos(g_L2MercuryCoefficients[i].b + g_L2MercuryCoefficients[i].c * rho);
+ }
+ var nL3Coefficients = g_L3MercuryCoefficients.length;
+ var L3 = 0;
+ for (i = 0; i < nL3Coefficients; i++) {
+ L3 += g_L3MercuryCoefficients[i].a * Math.cos(g_L3MercuryCoefficients[i].b + g_L3MercuryCoefficients[i].c * rho);
+ }
+ var nL4Coefficients = g_L4MercuryCoefficients.length;
+ var L4 = 0;
+ for (i = 0; i < nL4Coefficients; i++) {
+ L4 += g_L4MercuryCoefficients[i].a * Math.cos(g_L4MercuryCoefficients[i].b + g_L4MercuryCoefficients[i].c * rho);
+ }
+ var nL5Coefficients = g_L5MercuryCoefficients.length;
+ var L5 = 0;
+ for (i = 0; i < nL5Coefficients; i++) {
+ L5 += g_L5MercuryCoefficients[i].a * Math.cos(g_L5MercuryCoefficients[i].b + g_L5MercuryCoefficients[i].c * rho);
+ }
+ var vvalue = (L0 + L1 * rho + L2 * rhosquared + L3 * rhocubed + L4 * rho4 + L5 * rho5) / 100000000;
+ vvalue = CT.m360(CT.r2D(vvalue));
+ return vvalue;
+};
+
+CAAMercury.eclipticLatitude = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var nB0Coefficients = g_B0MercuryCoefficients.length;
+ var B0 = 0;
+ var i;
+ for (i = 0; i < nB0Coefficients; i++) {
+ B0 += g_B0MercuryCoefficients[i].a * Math.cos(g_B0MercuryCoefficients[i].b + g_B0MercuryCoefficients[i].c * rho);
+ }
+ var nB1Coefficients = g_B1MercuryCoefficients.length;
+ var B1 = 0;
+ for (i = 0; i < nB1Coefficients; i++) {
+ B1 += g_B1MercuryCoefficients[i].a * Math.cos(g_B1MercuryCoefficients[i].b + g_B1MercuryCoefficients[i].c * rho);
+ }
+ var nB2Coefficients = g_B2MercuryCoefficients.length;
+ var B2 = 0;
+ for (i = 0; i < nB2Coefficients; i++) {
+ B2 += g_B2MercuryCoefficients[i].a * Math.cos(g_B2MercuryCoefficients[i].b + g_B2MercuryCoefficients[i].c * rho);
+ }
+ var nB3Coefficients = g_B3MercuryCoefficients.length;
+ var B3 = 0;
+ for (i = 0; i < nB3Coefficients; i++) {
+ B3 += g_B3MercuryCoefficients[i].a * Math.cos(g_B3MercuryCoefficients[i].b + g_B3MercuryCoefficients[i].c * rho);
+ }
+ var nB4Coefficients = g_B4MercuryCoefficients.length;
+ var B4 = 0;
+ for (i = 0; i < nB4Coefficients; i++) {
+ B4 += g_B4MercuryCoefficients[i].a * Math.cos(g_B4MercuryCoefficients[i].b + g_B4MercuryCoefficients[i].c * rho);
+ }
+ var vvalue = (B0 + B1 * rho + B2 * rhosquared + B3 * rhocubed + B4 * rho4) / 100000000;
+ vvalue = CT.r2D(vvalue);
+ return vvalue;
+};
+
+CAAMercury.radiusVector = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var nR0Coefficients = g_R0MercuryCoefficients.length;
+ var R0 = 0;
+ var i;
+ for (i = 0; i < nR0Coefficients; i++) {
+ R0 += g_R0MercuryCoefficients[i].a * Math.cos(g_R0MercuryCoefficients[i].b + g_R0MercuryCoefficients[i].c * rho);
+ }
+ var nR1Coefficients = g_R1MercuryCoefficients.length;
+ var R1 = 0;
+ for (i = 0; i < nR1Coefficients; i++) {
+ R1 += g_R1MercuryCoefficients[i].a * Math.cos(g_R1MercuryCoefficients[i].b + g_R1MercuryCoefficients[i].c * rho);
+ }
+ var nR2Coefficients = g_R2MercuryCoefficients.length;
+ var R2 = 0;
+ for (i = 0; i < nR2Coefficients; i++) {
+ R2 += g_R2MercuryCoefficients[i].a * Math.cos(g_R2MercuryCoefficients[i].b + g_R2MercuryCoefficients[i].c * rho);
+ }
+ var nR3Coefficients = g_R3MercuryCoefficients.length;
+ var R3 = 0;
+ for (i = 0; i < nR3Coefficients; i++) {
+ R3 += g_R3MercuryCoefficients[i].a * Math.cos(g_R3MercuryCoefficients[i].b + g_R3MercuryCoefficients[i].c * rho);
+ }
+ return (R0 + R1 * rho + R2 * rhosquared + R3 * rhocubed) / 100000000;
+};
+
+var CAAMercury$ = {};
+
+registerType("CAAMercury", [CAAMercury, CAAMercury$, null]);
diff --git a/engine/esm/astrocalc/moon.js b/engine/esm/astrocalc/moon.js
new file mode 100644
index 00000000..9517e12e
--- /dev/null
+++ b/engine/esm/astrocalc/moon.js
@@ -0,0 +1,255 @@
+// Originally `AAABERRATION.CPP`
+// "Purpose: Implementation for the algorithms which obtain the position of the Moon"
+// Last update of original: PJN / 29-12-2003
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+import { CAAEarth } from "./earth.js";
+import { CAANutation } from "./nutation.js";
+
+
+// MoonCoefficient1
+
+export function MoonCoefficient1(d, m, mdash, f) {
+ this.d = 0;
+ this.m = 0;
+ this.mdash = 0;
+ this.f = 0;
+ this.d = d;
+ this.m = m;
+ this.mdash = mdash;
+ this.f = f;
+}
+
+var MoonCoefficient1$ = {};
+
+registerType("MoonCoefficient1", [MoonCoefficient1, MoonCoefficient1$, null]);
+
+
+// MoonCoefficient2
+
+export function MoonCoefficient2(a, b) {
+ this.a = 0;
+ this.b = 0;
+ this.a = a;
+ this.b = b;
+}
+
+var MoonCoefficient2$ = {};
+
+registerType("MoonCoefficient2", [MoonCoefficient2, MoonCoefficient2$, null]);
+
+
+// Constants
+
+const g_MoonCoefficients1 = [new MoonCoefficient1(0, 0, 1, 0), new MoonCoefficient1(2, 0, -1, 0), new MoonCoefficient1(2, 0, 0, 0), new MoonCoefficient1(0, 0, 2, 0), new MoonCoefficient1(0, 1, 0, 0), new MoonCoefficient1(0, 0, 0, 2), new MoonCoefficient1(2, 0, -2, 0), new MoonCoefficient1(2, -1, -1, 0), new MoonCoefficient1(2, 0, 1, 0), new MoonCoefficient1(2, -1, 0, 0), new MoonCoefficient1(0, 1, -1, 0), new MoonCoefficient1(1, 0, 0, 0), new MoonCoefficient1(0, 1, 1, 0), new MoonCoefficient1(2, 0, 0, -2), new MoonCoefficient1(0, 0, 1, 2), new MoonCoefficient1(0, 0, 1, -2), new MoonCoefficient1(4, 0, -1, 0), new MoonCoefficient1(0, 0, 3, 0), new MoonCoefficient1(4, 0, -2, 0), new MoonCoefficient1(2, 1, -1, 0), new MoonCoefficient1(2, 1, 0, 0), new MoonCoefficient1(1, 0, -1, 0), new MoonCoefficient1(1, 1, 0, 0), new MoonCoefficient1(2, -1, 1, 0), new MoonCoefficient1(2, 0, 2, 0), new MoonCoefficient1(4, 0, 0, 0), new MoonCoefficient1(2, 0, -3, 0), new MoonCoefficient1(0, 1, -2, 0), new MoonCoefficient1(2, 0, -1, 2), new MoonCoefficient1(2, -1, -2, 0), new MoonCoefficient1(1, 0, 1, 0), new MoonCoefficient1(2, -2, 0, 0), new MoonCoefficient1(0, 1, 2, 0), new MoonCoefficient1(0, 2, 0, 0), new MoonCoefficient1(2, -2, -1, 0), new MoonCoefficient1(2, 0, 1, -2), new MoonCoefficient1(2, 0, 0, 2), new MoonCoefficient1(4, -1, -1, 0), new MoonCoefficient1(0, 0, 2, 2), new MoonCoefficient1(3, 0, -1, 0), new MoonCoefficient1(2, 1, 1, 0), new MoonCoefficient1(4, -1, -2, 0), new MoonCoefficient1(0, 2, -1, 0), new MoonCoefficient1(2, 2, -1, 0), new MoonCoefficient1(2, 1, -2, 0), new MoonCoefficient1(2, -1, 0, -2), new MoonCoefficient1(4, 0, 1, 0), new MoonCoefficient1(0, 0, 4, 0), new MoonCoefficient1(4, -1, 0, 0), new MoonCoefficient1(1, 0, -2, 0), new MoonCoefficient1(2, 1, 0, -2), new MoonCoefficient1(0, 0, 2, -2), new MoonCoefficient1(1, 1, 1, 0), new MoonCoefficient1(3, 0, -2, 0), new MoonCoefficient1(4, 0, -3, 0), new MoonCoefficient1(2, -1, 2, 0), new MoonCoefficient1(0, 2, 1, 0), new MoonCoefficient1(1, 1, -1, 0), new MoonCoefficient1(2, 0, 3, 0), new MoonCoefficient1(2, 0, -1, -2)];
+const g_MoonCoefficients2 = [new MoonCoefficient2(6288774, -20905355), new MoonCoefficient2(1274027, -3699111), new MoonCoefficient2(658314, -2955968), new MoonCoefficient2(213618, -569925), new MoonCoefficient2(-185116, 48888), new MoonCoefficient2(-114332, -3149), new MoonCoefficient2(58793, 246158), new MoonCoefficient2(57066, -152138), new MoonCoefficient2(53322, -170733), new MoonCoefficient2(45758, -204586), new MoonCoefficient2(-40923, -129620), new MoonCoefficient2(-34720, 108743), new MoonCoefficient2(-30383, 104755), new MoonCoefficient2(15327, 10321), new MoonCoefficient2(-12528, 0), new MoonCoefficient2(10980, 79661), new MoonCoefficient2(10675, -34782), new MoonCoefficient2(10034, -23210), new MoonCoefficient2(8548, -21636), new MoonCoefficient2(-7888, 24208), new MoonCoefficient2(-6766, 30824), new MoonCoefficient2(-5163, -8379), new MoonCoefficient2(4987, -16675), new MoonCoefficient2(4036, -12831), new MoonCoefficient2(3994, -10445), new MoonCoefficient2(3861, -11650), new MoonCoefficient2(3665, 14403), new MoonCoefficient2(-2689, -7003), new MoonCoefficient2(-2602, 0), new MoonCoefficient2(2390, 10056), new MoonCoefficient2(-2348, 6322), new MoonCoefficient2(2236, -9884), new MoonCoefficient2(-2120, 5751), new MoonCoefficient2(-2069, 0), new MoonCoefficient2(2048, -4950), new MoonCoefficient2(-1773, 4130), new MoonCoefficient2(-1595, 0), new MoonCoefficient2(1215, -3958), new MoonCoefficient2(-1110, 0), new MoonCoefficient2(-892, 3258), new MoonCoefficient2(-810, 2616), new MoonCoefficient2(759, -1897), new MoonCoefficient2(-713, -2117), new MoonCoefficient2(-700, 2354), new MoonCoefficient2(691, 0), new MoonCoefficient2(596, 0), new MoonCoefficient2(549, -1423), new MoonCoefficient2(537, -1117), new MoonCoefficient2(520, -1571), new MoonCoefficient2(-487, -1739), new MoonCoefficient2(-399, 0), new MoonCoefficient2(-381, -4421), new MoonCoefficient2(351, 0), new MoonCoefficient2(-340, 0), new MoonCoefficient2(330, 0), new MoonCoefficient2(327, 0), new MoonCoefficient2(-323, 1165), new MoonCoefficient2(299, 0), new MoonCoefficient2(294, 0), new MoonCoefficient2(0, 8752)];
+const g_MoonCoefficients3 = [new MoonCoefficient1(0, 0, 0, 1), new MoonCoefficient1(0, 0, 1, 1), new MoonCoefficient1(0, 0, 1, -1), new MoonCoefficient1(2, 0, 0, -1), new MoonCoefficient1(2, 0, -1, 1), new MoonCoefficient1(2, 0, -1, -1), new MoonCoefficient1(2, 0, 0, 1), new MoonCoefficient1(0, 0, 2, 1), new MoonCoefficient1(2, 0, 1, -1), new MoonCoefficient1(0, 0, 2, -1), new MoonCoefficient1(2, -1, 0, -1), new MoonCoefficient1(2, 0, -2, -1), new MoonCoefficient1(2, 0, 1, 1), new MoonCoefficient1(2, 1, 0, -1), new MoonCoefficient1(2, -1, -1, 1), new MoonCoefficient1(2, -1, 0, 1), new MoonCoefficient1(2, -1, -1, -1), new MoonCoefficient1(0, 1, -1, -1), new MoonCoefficient1(4, 0, -1, -1), new MoonCoefficient1(0, 1, 0, 1), new MoonCoefficient1(0, 0, 0, 3), new MoonCoefficient1(0, 1, -1, 1), new MoonCoefficient1(1, 0, 0, 1), new MoonCoefficient1(0, 1, 1, 1), new MoonCoefficient1(0, 1, 1, -1), new MoonCoefficient1(0, 1, 0, -1), new MoonCoefficient1(1, 0, 0, -1), new MoonCoefficient1(0, 0, 3, 1), new MoonCoefficient1(4, 0, 0, -1), new MoonCoefficient1(4, 0, -1, 1), new MoonCoefficient1(0, 0, 1, -3), new MoonCoefficient1(4, 0, -2, 1), new MoonCoefficient1(2, 0, 0, -3), new MoonCoefficient1(2, 0, 2, -1), new MoonCoefficient1(2, -1, 1, -1), new MoonCoefficient1(2, 0, -2, 1), new MoonCoefficient1(0, 0, 3, -1), new MoonCoefficient1(2, 0, 2, 1), new MoonCoefficient1(2, 0, -3, -1), new MoonCoefficient1(2, 1, -1, 1), new MoonCoefficient1(2, 1, 0, 1), new MoonCoefficient1(4, 0, 0, 1), new MoonCoefficient1(2, -1, 1, 1), new MoonCoefficient1(2, -2, 0, -1), new MoonCoefficient1(0, 0, 1, 3), new MoonCoefficient1(2, 1, 1, -1), new MoonCoefficient1(1, 1, 0, -1), new MoonCoefficient1(1, 1, 0, 1), new MoonCoefficient1(0, 1, -2, -1), new MoonCoefficient1(2, 1, -1, -1), new MoonCoefficient1(1, 0, 1, 1), new MoonCoefficient1(2, -1, -2, -1), new MoonCoefficient1(0, 1, 2, 1), new MoonCoefficient1(4, 0, -2, -1), new MoonCoefficient1(4, -1, -1, -1), new MoonCoefficient1(1, 0, 1, -1), new MoonCoefficient1(4, 0, 1, -1), new MoonCoefficient1(1, 0, -1, -1), new MoonCoefficient1(4, -1, 0, -1), new MoonCoefficient1(2, -2, 0, 1)];
+const g_MoonCoefficients4 = [5128122, 280602, 277693, 173237, 55413, 46271, 32573, 17198, 9266, 8822, 8216, 4324, 4200, -3359, 2463, 2211, 2065, -1870, 1828, -1794, -1749, -1565, -1491, -1475, -1410, -1344, -1335, 1107, 1021, 833, 777, 671, 607, 596, 491, -451, 439, 422, 421, -366, -351, 331, 315, 302, -283, -229, 223, 223, -220, -220, -185, 181, -177, 176, 166, -164, 132, -119, 115, 107];
+
+
+// CAAMoon
+
+export function CAAMoon() { }
+
+CAAMoon.meanLongitude = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ var T4 = Tcubed * T;
+ return CT.m360(218.3164477 + 481267.88123421 * T - 0.0015786 * Tsquared + Tcubed / 538841 - T4 / 65194000);
+};
+
+CAAMoon.meanElongation = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ var T4 = Tcubed * T;
+ return CT.m360(297.8501921 + 445267.1114034 * T - 0.0018819 * Tsquared + Tcubed / 545868 - T4 / 113065000);
+};
+
+CAAMoon.meanAnomaly = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ var T4 = Tcubed * T;
+ return CT.m360(134.9633964 + 477198.8675055 * T + 0.0087414 * Tsquared + Tcubed / 69699 - T4 / 14712000);
+};
+
+CAAMoon.argumentOfLatitude = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ var T4 = Tcubed * T;
+ return CT.m360(93.272095 + 483202.0175233 * T - 0.0036539 * Tsquared - Tcubed / 3526000 + T4 / 863310000);
+};
+
+CAAMoon.meanLongitudeAscendingNode = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ var T4 = Tcubed * T;
+ return CT.m360(125.0445479 - 1934.1362891 * T + 0.0020754 * Tsquared + Tcubed / 467441 - T4 / 60616000);
+};
+
+CAAMoon.meanLongitudePerigee = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ var T4 = Tcubed * T;
+ return CT.m360(83.3532465 + 4069.0137287 * T - 0.01032 * Tsquared - Tcubed / 80053 + T4 / 18999000);
+};
+
+CAAMoon.trueLongitudeAscendingNode = function (JD) {
+ var TrueAscendingNode = CAAMoon.meanLongitudeAscendingNode(JD);
+ var D = CAAMoon.meanElongation(JD);
+ D = CT.d2R(D);
+ var M = CAAEarth.sunMeanAnomaly(JD);
+ M = CT.d2R(M);
+ var Mdash = CAAMoon.meanAnomaly(JD);
+ Mdash = CT.d2R(Mdash);
+ var F = CAAMoon.argumentOfLatitude(JD);
+ F = CT.d2R(F);
+ TrueAscendingNode -= 1.4979 * Math.sin(2 * (D - F));
+ TrueAscendingNode -= 0.15 * Math.sin(M);
+ TrueAscendingNode -= 0.1226 * Math.sin(2 * D);
+ TrueAscendingNode += 0.1176 * Math.sin(2 * F);
+ TrueAscendingNode -= 0.0801 * Math.sin(2 * (Mdash - F));
+ return CT.m360(TrueAscendingNode);
+};
+
+CAAMoon.eclipticLongitude = function (JD) {
+ var Ldash = CAAMoon.meanLongitude(JD);
+ var LdashDegrees = Ldash;
+ Ldash = CT.d2R(Ldash);
+ var D = CAAMoon.meanElongation(JD);
+ D = CT.d2R(D);
+ var M = CAAEarth.sunMeanAnomaly(JD);
+ M = CT.d2R(M);
+ var Mdash = CAAMoon.meanAnomaly(JD);
+ Mdash = CT.d2R(Mdash);
+ var F = CAAMoon.argumentOfLatitude(JD);
+ F = CT.d2R(F);
+ var E = CAAEarth.eccentricity(JD);
+ var T = (JD - 2451545) / 36525;
+ var A1 = CT.m360(119.75 + 131.849 * T);
+ A1 = CT.d2R(A1);
+ var A2 = CT.m360(53.09 + 479264.29 * T);
+ A2 = CT.d2R(A2);
+ var A3 = CT.m360(313.45 + 481266.484 * T);
+ A3 = CT.d2R(A3);
+ var nLCoefficients = g_MoonCoefficients1.length;
+ console.assert(g_MoonCoefficients2.length === nLCoefficients);
+ var SigmaL = 0;
+ for (var i = 0; i < nLCoefficients; i++) {
+ var ThisSigma = g_MoonCoefficients2[i].a * Math.sin(g_MoonCoefficients1[i].d * D + g_MoonCoefficients1[i].m * M + g_MoonCoefficients1[i].mdash * Mdash + g_MoonCoefficients1[i].f * F);
+ if (!!g_MoonCoefficients1[i].m) {
+ ThisSigma *= E;
+ }
+ SigmaL += ThisSigma;
+ }
+ SigmaL += 3958 * Math.sin(A1);
+ SigmaL += 1962 * Math.sin(Ldash - F);
+ SigmaL += 318 * Math.sin(A2);
+ var NutationInLong = CAANutation.nutationInLongitude(JD);
+ return CT.m360(LdashDegrees + SigmaL / 1000000 + NutationInLong / 3600);
+};
+
+CAAMoon.eclipticLatitude = function (JD) {
+ var Ldash = CAAMoon.meanLongitude(JD);
+ Ldash = CT.d2R(Ldash);
+ var D = CAAMoon.meanElongation(JD);
+ D = CT.d2R(D);
+ var M = CAAEarth.sunMeanAnomaly(JD);
+ M = CT.d2R(M);
+ var Mdash = CAAMoon.meanAnomaly(JD);
+ Mdash = CT.d2R(Mdash);
+ var F = CAAMoon.argumentOfLatitude(JD);
+ F = CT.d2R(F);
+ var E = CAAEarth.eccentricity(JD);
+ var T = (JD - 2451545) / 36525;
+ var A1 = CT.m360(119.75 + 131.849 * T);
+ A1 = CT.d2R(A1);
+ var A2 = CT.m360(53.09 + 479264.29 * T);
+ A2 = CT.d2R(A2);
+ var A3 = CT.m360(313.45 + 481266.484 * T);
+ A3 = CT.d2R(A3);
+ var nBCoefficients = g_MoonCoefficients3.length;
+ console.assert(g_MoonCoefficients4.length === nBCoefficients);
+ var SigmaB = 0;
+ for (var i = 0; i < nBCoefficients; i++) {
+ var ThisSigma = g_MoonCoefficients4[i] * Math.sin(g_MoonCoefficients3[i].d * D + g_MoonCoefficients3[i].m * M + g_MoonCoefficients3[i].mdash * Mdash + g_MoonCoefficients3[i].f * F);
+ if (!!g_MoonCoefficients3[i].m) {
+ ThisSigma *= E;
+ }
+ SigmaB += ThisSigma;
+ }
+ SigmaB -= 2235 * Math.sin(Ldash);
+ SigmaB += 382 * Math.sin(A3);
+ SigmaB += 175 * Math.sin(A1 - F);
+ SigmaB += 175 * Math.sin(A1 + F);
+ SigmaB += 127 * Math.sin(Ldash - Mdash);
+ SigmaB -= 115 * Math.sin(Ldash + Mdash);
+ return SigmaB / 1000000;
+};
+
+CAAMoon.radiusVector = function (JD) {
+ var Ldash = CAAMoon.meanLongitude(JD);
+ Ldash = CT.d2R(Ldash);
+ var D = CAAMoon.meanElongation(JD);
+ D = CT.d2R(D);
+ var M = CAAEarth.sunMeanAnomaly(JD);
+ M = CT.d2R(M);
+ var Mdash = CAAMoon.meanAnomaly(JD);
+ Mdash = CT.d2R(Mdash);
+ var F = CAAMoon.argumentOfLatitude(JD);
+ F = CT.d2R(F);
+ var E = CAAEarth.eccentricity(JD);
+ var T = (JD - 2451545) / 36525;
+ var A1 = CT.m360(119.75 + 131.849 * T);
+ A1 = CT.d2R(A1);
+ var A2 = CT.m360(53.09 + 479264.29 * T);
+ A2 = CT.d2R(A2);
+ var A3 = CT.m360(313.45 + 481266.484 * T);
+ A3 = CT.d2R(A3);
+ var nRCoefficients = g_MoonCoefficients1.length;
+ console.assert(g_MoonCoefficients2.length === nRCoefficients);
+ var SigmaR = 0;
+ for (var i = 0; i < nRCoefficients; i++) {
+ var ThisSigma = g_MoonCoefficients2[i].b * Math.cos(g_MoonCoefficients1[i].d * D + g_MoonCoefficients1[i].m * M + g_MoonCoefficients1[i].mdash * Mdash + g_MoonCoefficients1[i].f * F);
+ if (!!g_MoonCoefficients1[i].m) {
+ ThisSigma *= E;
+ }
+ SigmaR += ThisSigma;
+ }
+ return 385000.56 + SigmaR / 1000;
+};
+
+CAAMoon.radiusVectorToHorizontalParallax = function (RadiusVector) {
+ return CT.r2D(Math.asin(6378.14 / RadiusVector));
+};
+
+CAAMoon.horizontalParallaxToRadiusVector = function (Parallax) {
+ return 6378.14 / Math.sin(CT.d2R(Parallax));
+};
+
+var CAAMoon$ = {};
+
+registerType("CAAMoon", [CAAMoon, CAAMoon$, null]);
diff --git a/engine/esm/astrocalc/moon_illuminated_fraction.js b/engine/esm/astrocalc/moon_illuminated_fraction.js
new file mode 100644
index 00000000..6924b5a9
--- /dev/null
+++ b/engine/esm/astrocalc/moon_illuminated_fraction.js
@@ -0,0 +1,59 @@
+// Originally `AAMOONILLUMINATEDFRACTION.CPP`
+// "Purpose: Implementation for the algorithms for the Moon's Elongation, Phase Angle and Illuminated Fraction"
+// Last update of original: PJN / 26-01-2007
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+
+
+// MIFR
+
+export function MIFR() {
+}
+
+MIFR.geocentricElongation = function (ObjectAlpha, ObjectDelta, SunAlpha, SunDelta) {
+ ObjectAlpha = CT.d2R(ObjectAlpha * 15);
+ SunAlpha = CT.d2R(SunAlpha * 15);
+ ObjectDelta = CT.d2R(ObjectDelta);
+ SunDelta = CT.d2R(SunDelta);
+ return CT.r2D(Math.acos(Math.sin(SunDelta) * Math.sin(ObjectDelta) + Math.cos(SunDelta) * Math.cos(ObjectDelta) * Math.cos(SunAlpha - ObjectAlpha)));
+};
+
+MIFR.phaseAngle = function (GeocentricElongation, EarthObjectDistance, EarthSunDistance) {
+ GeocentricElongation = CT.d2R(GeocentricElongation);
+ return CT.m360(CT.r2D(Math.atan2(EarthSunDistance * Math.sin(GeocentricElongation), EarthObjectDistance - EarthSunDistance * Math.cos(GeocentricElongation))));
+};
+
+MIFR.illuminatedFraction = function (PhaseAngle) {
+ PhaseAngle = CT.d2R(PhaseAngle);
+ return (1 + Math.cos(PhaseAngle)) / 2;
+};
+
+MIFR.positionAngle = function (Alpha0, Delta0, Alpha, Delta) {
+ Alpha0 = CT.h2R(Alpha0);
+ Alpha = CT.h2R(Alpha);
+ Delta0 = CT.d2R(Delta0);
+ Delta = CT.d2R(Delta);
+ return CT.m360(CT.r2D(Math.atan2(Math.cos(Delta0) * Math.sin(Alpha0 - Alpha), Math.sin(Delta0) * Math.cos(Delta) - Math.cos(Delta0) * Math.sin(Delta) * Math.cos(Alpha0 - Alpha))));
+};
+
+var MIFR$ = {};
+
+registerType("MIFR", [MIFR, MIFR$, null]);
diff --git a/engine/esm/astrocalc/moon_nodes.js b/engine/esm/astrocalc/moon_nodes.js
new file mode 100644
index 00000000..b89352f6
--- /dev/null
+++ b/engine/esm/astrocalc/moon_nodes.js
@@ -0,0 +1,61 @@
+// Originally `AAMOONNODES.CPP`
+// "Purpose: Implementation for the algorithms which obtain the dates when the Moon passes thro its nodes"
+// Last update of original: PJN / 29-12-2003
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+
+
+// CAAMoonNodes
+
+export function CAAMoonNodes() { }
+
+CAAMoonNodes.k = function (Year) {
+ return 13.4223 * (Year - 2000.05);
+};
+
+CAAMoonNodes.passageThroNode = function (k) {
+ var T = k / 1342.23;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ var T4 = Tcubed * T;
+ var D = CT.m360(183.638 + 331.73735682 * k + 0.0014852 * Tsquared + 2.09E-06 * Tcubed - 1E-08 * T4);
+ var M = CT.m360(17.4006 + 26.8203725 * k + 0.0001186 * Tsquared + 6E-08 * Tcubed);
+ var Mdash = CT.m360(38.3776 + 355.52747313 * k + 0.0123499 * Tsquared + 1.4627E-05 * Tcubed - 6.9E-08 * T4);
+ var omega = CT.m360(123.9767 - 1.44098956 * k + 0.0020608 * Tsquared + 2.14E-06 * Tcubed - 1.6E-08 * T4);
+ var V = CT.m360(299.75 + 132.85 * T - 0.009173 * Tsquared);
+ var P = CT.m360(omega + 272.75 - 2.3 * T);
+ var E = 1 - 0.002516 * T - 7.4E-06 * Tsquared;
+ D = CT.d2R(D);
+ var D2 = 2 * D;
+ var D4 = D2 * D2;
+ M = CT.d2R(M);
+ Mdash = CT.d2R(Mdash);
+ var Mdash2 = 2 * Mdash;
+ omega = CT.d2R(omega);
+ V = CT.d2R(V);
+ P = CT.d2R(P);
+ var JD = 2451565.1619 + 27.212220817 * k + 0.0002762 * Tsquared + 2.1E-08 * Tcubed - 8.8E-11 * T4 - 0.4721 * Math.sin(Mdash) - 0.1649 * Math.sin(D2) - 0.0868 * Math.sin(D2 - Mdash) + 0.0084 * Math.sin(D2 + Mdash) - E * 0.0083 * Math.sin(D2 - M) - E * 0.0039 * Math.sin(D2 - M - Mdash) + 0.0034 * Math.sin(Mdash2) - 0.0031 * Math.sin(D2 - Mdash2) + E * 0.003 * Math.sin(D2 + M) + E * 0.0028 * Math.sin(M - Mdash) + E * 0.0026 * Math.sin(M) + 0.0025 * Math.sin(D4) + 0.0024 * Math.sin(D) + E * 0.0022 * Math.sin(M + Mdash) + 0.0017 * Math.sin(omega) + 0.0014 * Math.sin(D4 - Mdash) + E * 0.0005 * Math.sin(D2 + M - Mdash) + E * 0.0004 * Math.sin(D2 - M + Mdash) - E * 0.0003 * Math.sin(D2 - M * M) + E * 0.0003 * Math.sin(D4 - M) + 0.0003 * Math.sin(V) + 0.0003 * Math.sin(P);
+ return JD;
+};
+
+var CAAMoonNodes$ = {};
+
+registerType("CAAMoonNodes", [CAAMoonNodes, CAAMoonNodes$, null]);
diff --git a/engine/esm/astrocalc/moon_perigee_apogee.js b/engine/esm/astrocalc/moon_perigee_apogee.js
new file mode 100644
index 00000000..4363fa16
--- /dev/null
+++ b/engine/esm/astrocalc/moon_perigee_apogee.js
@@ -0,0 +1,154 @@
+// Originally `AAMOONPERIGEEAPOGEE.CPP`
+// "Purpose: Implementation for the algorithms which obtain the dates of Lunar Apogee and Perigee"
+// Last update of original: PJN / 29-12-2003
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+
+
+// MPAC - was MoonPerigeeApogeeCoefficient
+
+export function MPAC(D, M, F, C, T) {
+ this.d = 0;
+ this.m = 0;
+ this.f = 0;
+ this.c = 0;
+ this.t = 0;
+ this.d = D;
+ this.m = M;
+ this.f = F;
+ this.c = C;
+ this.t = T;
+}
+
+var MPAC$ = {};
+
+registerType("MPAC", [MPAC, MPAC$, null]);
+
+
+// Constants
+
+const g_MoonPerigeeApogeeCoefficients1 = [new MPAC(2, 0, 0, -1.6769, 0), new MPAC(4, 0, 0, 0.4589, 0), new MPAC(6, 0, 0, -0.1856, 0), new MPAC(8, 0, 0, 0.0883, 0), new MPAC(2, -1, 0, -0.0773, 0.00019), new MPAC(0, 1, 0, 0.0502, -0.00013), new MPAC(10, 0, 0, -0.046, 0), new MPAC(4, -1, 0, 0.0422, -0.00011), new MPAC(6, -1, 0, -0.0256, 0), new MPAC(12, 0, 0, 0.0253, 0), new MPAC(1, 0, 0, 0.0237, 0), new MPAC(8, -1, 0, 0.0162, 0), new MPAC(14, 0, 0, -0.0145, 0), new MPAC(0, 0, 2, 0.0129, 0), new MPAC(3, 0, 0, -0.0112, 0), new MPAC(10, -1, 0, -0.0104, 0), new MPAC(16, 0, 0, 0.0086, 0), new MPAC(12, -1, 0, 0.0069, 0), new MPAC(5, 0, 0, 0.0066, 0), new MPAC(2, 0, 2, -0.0053, 0), new MPAC(18, 0, 0, -0.0052, 0), new MPAC(14, -1, 0, -0.0046, 0), new MPAC(7, 0, 0, -0.0041, 0), new MPAC(2, 1, 0, 0.004, 0), new MPAC(20, 0, 0, 0.0032, 0), new MPAC(1, 1, 0, -0.0032, 0), new MPAC(16, -1, 0, 0.0031, 0), new MPAC(4, 1, 0, -0.0029, 0), new MPAC(9, 0, 0, 0.0027, 0), new MPAC(4, 0, 2, 0.0027, 0), new MPAC(2, -2, 0, -0.0027, 0), new MPAC(4, -2, 0, 0.0024, 0), new MPAC(6, -2, 0, -0.0021, 0), new MPAC(22, 0, 0, -0.0021, 0), new MPAC(18, -1, 0, -0.0021, 0), new MPAC(6, 1, 0, 0.0019, 0), new MPAC(11, 0, 0, -0.0018, 0), new MPAC(8, 1, 0, -0.0014, 0), new MPAC(4, 0, -2, -0.0014, 0), new MPAC(6, 0, 2, -0.0014, 0), new MPAC(3, 1, 0, 0.0014, 0), new MPAC(5, 1, 0, -0.0014, 0), new MPAC(13, 0, 0, 0.0013, 0), new MPAC(20, -1, 0, 0.0013, 0), new MPAC(3, 2, 0, 0.0011, 0), new MPAC(4, -2, 2, -0.0011, 0), new MPAC(1, 2, 0, -0.0011, 0), new MPAC(22, -1, 0, -0.0009, 0), new MPAC(0, 0, 4, -0.0008, 0), new MPAC(6, 0, -2, 0.0008, 0), new MPAC(2, 1, -2, 0.0008, 0), new MPAC(0, 2, 0, 0.0007, 0), new MPAC(0, -1, 2, 0.0007, 0), new MPAC(2, 0, 4, 0.0007, 0), new MPAC(0, -2, 2, -0.0006, 0), new MPAC(2, 2, -2, -0.0006, 0), new MPAC(24, 0, 0, 0.0006, 0), new MPAC(4, 0, -4, 0.0005, 0), new MPAC(2, 2, 0, 0.0005, 0), new MPAC(1, -1, 0, -0.0004, 0)];
+const g_MoonPerigeeApogeeCoefficients2 = [new MPAC(2, 0, 0, 0.4392, 0), new MPAC(4, 0, 0, 0.0684, 0), new MPAC(0, 1, 0, 0.0456, -0.00011), new MPAC(2, -1, 0, 0.0426, -0.00011), new MPAC(0, 0, 2, 0.0212, 0), new MPAC(1, 0, 0, -0.0189, 0), new MPAC(6, 0, 0, 0.0144, 0), new MPAC(4, -1, 0, 0.0113, 0), new MPAC(2, 0, 2, 0.0047, 0), new MPAC(1, 1, 0, 0.0036, 0), new MPAC(8, 0, 0, 0.0035, 0), new MPAC(6, -1, 0, 0.0034, 0), new MPAC(2, 0, -2, -0.0034, 0), new MPAC(2, -2, 0, 0.0022, 0), new MPAC(3, 0, 0, -0.0017, 0), new MPAC(4, 0, 2, 0.0013, 0), new MPAC(8, -1, 0, 0.0011, 0), new MPAC(4, -2, 0, 0.001, 0), new MPAC(10, 0, 0, 0.0009, 0), new MPAC(3, 1, 0, 0.0007, 0), new MPAC(0, 2, 0, 0.0006, 0), new MPAC(2, 1, 0, 0.0005, 0), new MPAC(2, 2, 0, 0.0005, 0), new MPAC(6, 0, 2, 0.0004, 0), new MPAC(6, -2, 0, 0.0004, 0), new MPAC(10, -1, 0, 0.0004, 0), new MPAC(5, 0, 0, -0.0004, 0), new MPAC(4, 0, -2, -0.0004, 0), new MPAC(0, 1, 2, 0.0003, 0), new MPAC(12, 0, 0, 0.0003, 0), new MPAC(2, -1, 2, 0.0003, 0), new MPAC(1, -1, 0, -0.0003, 0)];
+const g_MoonPerigeeApogeeCoefficients3 = [new MPAC(2, 0, 0, 63.224, 0), new MPAC(4, 0, 0, -6.99, 0), new MPAC(2, -1, 0, 2.834, 0), new MPAC(2, -1, 0, 0, -0.0071), new MPAC(6, 0, 0, 1.927, 0), new MPAC(1, 0, 0, -1.263, 0), new MPAC(8, 0, 0, -0.702, 0), new MPAC(0, 1, 0, 0.696, 0), new MPAC(0, 1, 0, 0, -0.0017), new MPAC(0, 0, 2, -0.69, 0), new MPAC(4, -1, 0, -0.629, 0), new MPAC(4, -1, 0, 0, 0.0016), new MPAC(2, 0, -2, -0.392, 0), new MPAC(10, 0, 0, 0.297, 0), new MPAC(6, -1, 0, 0.26, 0), new MPAC(3, 0, 0, 0.201, 0), new MPAC(2, 1, 0, -0.161, 0), new MPAC(1, 1, 0, 0.157, 0), new MPAC(12, 0, 0, -0.138, 0), new MPAC(8, -1, 0, -0.127, 0), new MPAC(2, 0, 2, 0.104, 0), new MPAC(2, -2, 0, 0.104, 0), new MPAC(5, 0, 0, -0.079, 0), new MPAC(14, 0, 0, 0.068, 0), new MPAC(10, -1, 0, 0.067, 0), new MPAC(4, 1, 0, 0.054, 0), new MPAC(12, -1, 0, -0.038, 0), new MPAC(4, -2, 0, -0.038, 0), new MPAC(7, 0, 0, 0.037, 0), new MPAC(4, 0, 2, -0.037, 0), new MPAC(16, 0, 0, -0.035, 0), new MPAC(3, 1, 0, -0.03, 0), new MPAC(1, -1, 0, 0.029, 0), new MPAC(6, 1, 0, -0.025, 0), new MPAC(0, 2, 0, 0.023, 0), new MPAC(14, -1, 0, 0.023, 0), new MPAC(2, 2, 0, -0.023, 0), new MPAC(6, -2, 0, 0.022, 0), new MPAC(2, -1, -2, -0.021, 0), new MPAC(9, 0, 0, -0.02, 0), new MPAC(18, 0, 0, 0.019, 0), new MPAC(6, 0, 2, 0.017, 0), new MPAC(0, -1, 2, 0.014, 0), new MPAC(16, -1, 0, -0.014, 0), new MPAC(4, 0, -20, 0.013, 0), new MPAC(8, 1, 0, 0.012, 0), new MPAC(11, 0, 0, 0.011, 0), new MPAC(5, 1, 0, 0.01, 0), new MPAC(20, 0, 0, -0.01, 0)];
+const g_MoonPerigeeApogeeCoefficients4 = [new MPAC(2, 0, 0, -9.147, 0), new MPAC(1, 0, 0, -0.841, 0), new MPAC(0, 0, 2, 0.697, 0), new MPAC(0, 1, 0, -0.656, 0.0016), new MPAC(4, 0, 0, 0.355, 0), new MPAC(2, -1, 0, 0.159, 0), new MPAC(1, 1, 0, 0.127, 0), new MPAC(4, -1, 0, 0.065, 0), new MPAC(6, 0, 0, 0.052, 0), new MPAC(2, 1, 0, 0.043, 0), new MPAC(2, 0, 2, 0.031, 0), new MPAC(2, 0, -2, -0.023, 0), new MPAC(2, -2, 0, 0.022, 0), new MPAC(2, 2, 0, 0.019, 0), new MPAC(0, 2, 0, -0.016, 0), new MPAC(6, -1, 0, 0.014, 0), new MPAC(8, 0, 0, 0.01, 0)];
+
+
+// CAAMoonPerigeeApogee
+
+export function CAAMoonPerigeeApogee() { }
+
+CAAMoonPerigeeApogee.k = function (Year) {
+ return 13.2555 * (Year - 1999.97);
+};
+
+CAAMoonPerigeeApogee.meanPerigee = function (k) {
+ var T = k / 1325.55;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ var T4 = Tcubed * T;
+ return 2451534.6698 + 27.55454989 * k - 0.0006691 * Tsquared - 1.098E-06 * Tcubed + 5.2E-09 * T4;
+};
+
+CAAMoonPerigeeApogee.meanApogee = function (k) {
+ return CAAMoonPerigeeApogee.meanPerigee(k);
+};
+
+CAAMoonPerigeeApogee.truePerigee = function (k) {
+ var MeanJD = CAAMoonPerigeeApogee.meanPerigee(k);
+ var T = k / 1325.55;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ var T4 = Tcubed * T;
+ var D = CT.m360(171.9179 + 335.9106046 * k - 0.0100383 * Tsquared - 1.156E-05 * Tcubed + 5.5E-08 * T4);
+ D = CT.d2R(D);
+ var M = CT.m360(347.3477 + 27.1577721 * k - 0.000813 * Tsquared - 1E-06 * Tcubed);
+ M = CT.d2R(M);
+ var F = CT.m360(316.6109 + 364.5287911 * k - 0.0125053 * Tsquared - 1.48E-05 * Tcubed);
+ F = CT.d2R(F);
+ var nPerigeeCoefficients = g_MoonPerigeeApogeeCoefficients1.length;
+ var Sigma = 0;
+ for (var i = 0; i < nPerigeeCoefficients; i++) {
+ Sigma += g_MoonPerigeeApogeeCoefficients1[i].c * Math.sin(D * g_MoonPerigeeApogeeCoefficients1[i].d + M * g_MoonPerigeeApogeeCoefficients1[i].m + F * g_MoonPerigeeApogeeCoefficients1[i].f + T * g_MoonPerigeeApogeeCoefficients1[i].t);
+ }
+ return MeanJD + Sigma;
+};
+
+CAAMoonPerigeeApogee.trueApogee = function (k) {
+ var MeanJD = CAAMoonPerigeeApogee.meanApogee(k);
+ var T = k / 1325.55;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ var T4 = Tcubed * T;
+ var D = CT.m360(171.9179 + 335.9106046 * k - 0.0100383 * Tsquared - 1.156E-05 * Tcubed + 5.5E-08 * T4);
+ D = CT.d2R(D);
+ var M = CT.m360(347.3477 + 27.1577721 * k - 0.000813 * Tsquared - 1E-06 * Tcubed);
+ M = CT.d2R(M);
+ var F = CT.m360(316.6109 + 364.5287911 * k - 0.0125053 * Tsquared - 1.48E-05 * Tcubed);
+ F = CT.d2R(F);
+ var nApogeeCoefficients = g_MoonPerigeeApogeeCoefficients2.length;
+ var Sigma = 0;
+ for (var i = 0; i < nApogeeCoefficients; i++) {
+ Sigma += (g_MoonPerigeeApogeeCoefficients2[i].c + T * g_MoonPerigeeApogeeCoefficients2[i].t) * Math.sin(D * g_MoonPerigeeApogeeCoefficients2[i].d + M * g_MoonPerigeeApogeeCoefficients2[i].m + F * g_MoonPerigeeApogeeCoefficients2[i].f);
+ }
+ return MeanJD + Sigma;
+};
+
+CAAMoonPerigeeApogee.perigeeParallax = function (k) {
+ var T = k / 1325.55;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ var T4 = Tcubed * T;
+ var D = CT.m360(171.9179 + 335.9106046 * k - 0.0100383 * Tsquared - 1.156E-05 * Tcubed + 5.5E-08 * T4);
+ D = CT.d2R(D);
+ var M = CT.m360(347.3477 + 27.1577721 * k - 0.000813 * Tsquared - 1E-06 * Tcubed);
+ M = CT.d2R(M);
+ var F = CT.m360(316.6109 + 364.5287911 * k - 0.0125053 * Tsquared - 1.48E-05 * Tcubed);
+ F = CT.d2R(F);
+ var nPerigeeCoefficients = g_MoonPerigeeApogeeCoefficients3.length;
+ var Parallax = 3629.215;
+ for (var i = 0; i < nPerigeeCoefficients; i++) {
+ Parallax += (g_MoonPerigeeApogeeCoefficients3[i].c + T * g_MoonPerigeeApogeeCoefficients3[i].t) * Math.cos(D * g_MoonPerigeeApogeeCoefficients3[i].d + M * g_MoonPerigeeApogeeCoefficients3[i].m + F * g_MoonPerigeeApogeeCoefficients3[i].f);
+ }
+ return Parallax / 3600;
+};
+
+CAAMoonPerigeeApogee.apogeeParallax = function (k) {
+ var T = k / 1325.55;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ var T4 = Tcubed * T;
+ var D = CT.m360(171.9179 + 335.9106046 * k - 0.0100383 * Tsquared - 1.156E-05 * Tcubed + 5.5E-08 * T4);
+ D = CT.d2R(D);
+ var M = CT.m360(347.3477 + 27.1577721 * k - 0.000813 * Tsquared - 1E-06 * Tcubed);
+ M = CT.d2R(M);
+ var F = CT.m360(316.6109 + 364.5287911 * k - 0.0125053 * Tsquared - 1.48E-05 * Tcubed);
+ F = CT.d2R(F);
+ var nApogeeCoefficients = g_MoonPerigeeApogeeCoefficients4.length;
+ var Parallax = 3245.251;
+ for (var i = 0; i < nApogeeCoefficients; i++) {
+ Parallax += (g_MoonPerigeeApogeeCoefficients4[i].c + T * g_MoonPerigeeApogeeCoefficients4[i].t) * Math.cos(D * g_MoonPerigeeApogeeCoefficients4[i].d + M * g_MoonPerigeeApogeeCoefficients4[i].m + F * g_MoonPerigeeApogeeCoefficients4[i].f);
+ }
+ return Parallax / 3600;
+};
+
+var CAAMoonPerigeeApogee$ = {};
+
+registerType("CAAMoonPerigeeApogee", [CAAMoonPerigeeApogee, CAAMoonPerigeeApogee$, null]);
diff --git a/engine/esm/astrocalc/moon_phases.js b/engine/esm/astrocalc/moon_phases.js
new file mode 100644
index 00000000..c19969e0
--- /dev/null
+++ b/engine/esm/astrocalc/moon_phases.js
@@ -0,0 +1,120 @@
+// Originally `AAMOONPHASES.CPP`
+// "Purpose: Implementation for the algorithms which obtain the dates for the phases of the Moon"
+// Last update of original: PJN / 22-02-2004
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+
+
+// CAAMoonPhases
+
+export function CAAMoonPhases() { }
+
+CAAMoonPhases.k = function (Year) {
+ return 12.3685 * (Year - 2000);
+};
+
+CAAMoonPhases.meanPhase = function (k) {
+ var T = k / 1236.85;
+ var T2 = T * T;
+ var T3 = T2 * T;
+ var T4 = T3 * T;
+ return 2451550.09766 + 29.530588861 * k + 0.00015437 * T2 - 1.5E-07 * T3 + 7.3E-10 * T4;
+};
+
+CAAMoonPhases.truePhase = function (k) {
+ var JD = CAAMoonPhases.meanPhase(k);
+ var T = k / 1236.85;
+ var T2 = T * T;
+ var T3 = T2 * T;
+ var T4 = T3 * T;
+ var E = 1 - 0.002516 * T - 7.4E-06 * T2;
+ var E2 = E * E;
+ var M = CT.m360(2.5534 + 29.1053567 * k - 1.4E-06 * T2 - 1.1E-07 * T3);
+ M = CT.d2R(M);
+ var Mdash = CT.m360(201.5643 + 385.81693528 * k + 0.0107582 * T2 + 1.238E-05 * T3 - 5.8E-08 * T4);
+ Mdash = CT.d2R(Mdash);
+ var F = CT.m360(160.7108 + 390.67050284 * k - 0.0016118 * T2 - 2.27E-06 * T3 + 1E-08 * T4);
+ F = CT.d2R(F);
+ var omega = CT.m360(124.7746 - 1.56375588 * k + 0.0020672 * T2 + 2.15E-06 * T3);
+ omega = CT.d2R(omega);
+ var A1 = CT.m360(299.77 + 0.107408 * k - 0.009173 * T2);
+ A1 = CT.d2R(A1);
+ var A2 = CT.m360(251.88 + 0.016321 * k);
+ A2 = CT.d2R(A2);
+ var A3 = CT.m360(251.83 + 26.651886 * k);
+ A3 = CT.d2R(A3);
+ var A4 = CT.m360(349.42 + 36.412478 * k);
+ A4 = CT.d2R(A4);
+ var A5 = CT.m360(84.66 + 18.206239 * k);
+ A5 = CT.d2R(A5);
+ var A6 = CT.m360(141.74 + 53.303771 * k);
+ A6 = CT.d2R(A6);
+ var A7 = CT.m360(207.14 + 2.453732 * k);
+ A7 = CT.d2R(A7);
+ var A8 = CT.m360(154.84 + 7.30686 * k);
+ A8 = CT.d2R(A8);
+ var A9 = CT.m360(34.52 + 27.261239 * k);
+ A9 = CT.d2R(A9);
+ var A10 = CT.m360(207.19 + 0.121824 * k);
+ A10 = CT.d2R(A10);
+ var A11 = CT.m360(291.34 + 1.844379 * k);
+ A11 = CT.d2R(A11);
+ var A12 = CT.m360(161.72 + 24.198154 * k);
+ A12 = CT.d2R(A12);
+ var A13 = CT.m360(239.56 + 25.513099 * k);
+ A13 = CT.d2R(A13);
+ var A14 = CT.m360(331.55 + 3.592518 * k);
+ A14 = CT.d2R(A14);
+ var kint = Math.floor(k);
+ var kfrac = k - kint;
+ if (kfrac < 0) {
+ kfrac = 1 + kfrac;
+ }
+ if (!kfrac) {
+ var DeltaJD = -0.4072 * Math.sin(Mdash) + 0.17241 * E * Math.sin(M) + 0.01608 * Math.sin(2 * Mdash) + 0.01039 * Math.sin(2 * F) + 0.00739 * E * Math.sin(Mdash - M) + -0.00514 * E * Math.sin(Mdash + M) + 0.00208 * E2 * Math.sin(2 * M) + -0.00111 * Math.sin(Mdash - 2 * F) + -0.00057 * Math.sin(Mdash + 2 * F) + 0.00056 * E * Math.sin(2 * Mdash + M) + -0.00042 * Math.sin(3 * Mdash) + 0.00042 * E * Math.sin(M + 2 * F) + 0.00038 * E * Math.sin(M - 2 * F) + -0.00024 * E * Math.sin(2 * Mdash - M) + -0.00017 * Math.sin(omega) + -7E-05 * Math.sin(Mdash + 2 * M) + 4E-05 * Math.sin(2 * Mdash - 2 * F) + 4E-05 * Math.sin(3 * M) + 3E-05 * Math.sin(Mdash + M - 2 * F) + 3E-05 * Math.sin(2 * Mdash + 2 * F) + -3E-05 * Math.sin(Mdash + M + 2 * F) + 3E-05 * Math.sin(Mdash - M + 2 * F) + -2E-05 * Math.sin(Mdash - M - 2 * F) + -2E-05 * Math.sin(3 * Mdash + M) + 2E-05 * Math.sin(4 * Mdash);
+ JD += DeltaJD;
+ }
+ else if ((kfrac === 0.25) || (kfrac === 0.75)) {
+ var DeltaJD = -0.62801 * Math.sin(Mdash) + 0.17172 * E * Math.sin(M) + -0.01183 * E * Math.sin(Mdash + M) + 0.00862 * Math.sin(2 * Mdash) + 0.00804 * Math.sin(2 * F) + 0.00454 * E * Math.sin(Mdash - M) + 0.00204 * E2 * Math.sin(2 * M) + -0.0018 * Math.sin(Mdash - 2 * F) + -0.0007 * Math.sin(Mdash + 2 * F) + -0.0004 * Math.sin(3 * Mdash) + -0.00034 * E * Math.sin(2 * Mdash - M) + 0.00032 * E * Math.sin(M + 2 * F) + 0.00032 * E * Math.sin(M - 2 * F) + -0.00028 * E2 * Math.sin(Mdash + 2 * M) + 0.00027 * E * Math.sin(2 * Mdash + M) + -0.00017 * Math.sin(omega) + -5E-05 * Math.sin(Mdash - M - 2 * F) + 4E-05 * Math.sin(2 * Mdash + 2 * F) + -4E-05 * Math.sin(Mdash + M + 2 * F) + 4E-05 * Math.sin(Mdash - 2 * M) + 3E-05 * Math.sin(Mdash + M - 2 * F) + 3E-05 * Math.sin(3 * M) + 2E-05 * Math.sin(2 * Mdash - 2 * F) + 2E-05 * Math.sin(Mdash - M + 2 * F) + -2E-05 * Math.sin(3 * Mdash + M);
+ JD += DeltaJD;
+ var W = 0.00306 - 0.00038 * E * Math.cos(M) + 0.00026 * Math.cos(Mdash) - 2E-05 * Math.cos(Mdash - M) + 2E-05 * Math.cos(Mdash + M) + 2E-05 * Math.cos(2 * F);
+ if (kfrac === 0.25) {
+ JD += W;
+ }
+ else {
+ JD -= W;
+ }
+ }
+ else if (kfrac === 0.5) {
+ var DeltaJD = -0.40614 * Math.sin(Mdash) + 0.17302 * E * Math.sin(M) + 0.01614 * Math.sin(2 * Mdash) + 0.01043 * Math.sin(2 * F) + 0.00734 * E * Math.sin(Mdash - M) + -0.00514 * E * Math.sin(Mdash + M) + 0.00209 * E2 * Math.sin(2 * M) + -0.00111 * Math.sin(Mdash - 2 * F) + -0.00057 * Math.sin(Mdash + 2 * F) + 0.00056 * E * Math.sin(2 * Mdash + M) + -0.00042 * Math.sin(3 * Mdash) + 0.00042 * E * Math.sin(M + 2 * F) + 0.00038 * E * Math.sin(M - 2 * F) + -0.00024 * E * Math.sin(2 * Mdash - M) + -0.00017 * Math.sin(omega) + -7E-05 * Math.sin(Mdash + 2 * M) + 4E-05 * Math.sin(2 * Mdash - 2 * F) + 4E-05 * Math.sin(3 * M) + 3E-05 * Math.sin(Mdash + M - 2 * F) + 3E-05 * Math.sin(2 * Mdash + 2 * F) + -3E-05 * Math.sin(Mdash + M + 2 * F) + 3E-05 * Math.sin(Mdash - M + 2 * F) + -2E-05 * Math.sin(Mdash - M - 2 * F) + -2E-05 * Math.sin(3 * Mdash + M) + 2E-05 * Math.sin(4 * Mdash);
+ JD += DeltaJD;
+ }
+ else {
+ console.assert(false);
+ }
+ var DeltaJD2 = 0.000325 * Math.sin(A1) + 0.000165 * Math.sin(A2) + 0.000164 * Math.sin(A3) + 0.000126 * Math.sin(A4) + 0.00011 * Math.sin(A5) + 6.2E-05 * Math.sin(A6) + 6E-05 * Math.sin(A7) + 5.6E-05 * Math.sin(A8) + 4.7E-05 * Math.sin(A9) + 4.2E-05 * Math.sin(A10) + 4E-05 * Math.sin(A11) + 3.7E-05 * Math.sin(A12) + 3.5E-05 * Math.sin(A13) + 2.3E-05 * Math.sin(A14);
+ JD += DeltaJD2;
+ return JD;
+};
+
+var CAAMoonPhases$ = {};
+
+registerType("CAAMoonPhases", [CAAMoonPhases, CAAMoonPhases$, null]);
diff --git a/engine/esm/astrocalc/neptune.js b/engine/esm/astrocalc/neptune.js
new file mode 100644
index 00000000..21183ce4
--- /dev/null
+++ b/engine/esm/astrocalc/neptune.js
@@ -0,0 +1,151 @@
+// Originally `AANEPTUNE.CPP`
+// "Purpose: Implementation for the algorithms which obtain the heliocentric position of Neptune"
+// Last update of original: PJN / 29-12-2003
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+import { VSC } from "./earth.js";
+
+
+// Coefficients
+
+const g_L0NC = [new VSC(531188633, 0, 0), new VSC(1798476, 2.9010127, 38.1330356), new VSC(1019728, 0.4858092, 1.4844727), new VSC(124532, 4.830081, 36.648563), new VSC(42064, 5.41055, 2.96895), new VSC(37715, 6.09222, 35.16409), new VSC(33785, 1.24489, 76.26607), new VSC(16483, 8E-05, 491.55793), new VSC(9199, 4.9375, 39.6175), new VSC(8994, 0.2746, 175.1661), new VSC(4216, 1.9871, 73.2971), new VSC(3365, 1.0359, 33.6796), new VSC(2285, 4.2061, 4.4534), new VSC(1434, 2.7834, 74.7816), new VSC(900, 2.076, 109.946), new VSC(745, 3.19, 71.813), new VSC(506, 5.748, 114.399), new VSC(400, 0.35, 1021.249), new VSC(345, 3.462, 41.102), new VSC(340, 3.304, 77.751), new VSC(323, 2.248, 32.195), new VSC(306, 0.497, 0.521), new VSC(287, 4.505, 0.048), new VSC(282, 2.246, 146.594), new VSC(267, 4.889, 0.963), new VSC(252, 5.782, 388.465), new VSC(245, 1.247, 9.561), new VSC(233, 2.505, 137.033), new VSC(227, 1.797, 453.425), new VSC(170, 3.324, 108.461), new VSC(151, 2.192, 33.94), new VSC(150, 2.997, 5.938), new VSC(148, 0.859, 111.43), new VSC(119, 3.677, 2.448), new VSC(109, 2.416, 183.243), new VSC(103, 0.041, 0.261), new VSC(103, 4.404, 70.328), new VSC(102, 5.705, 0.112)];
+const g_L1NC = [new VSC(3837687717, 0, 0), new VSC(16604, 4.86319, 1.48447), new VSC(15807, 2.27923, 38.13304), new VSC(3335, 3.682, 76.2661), new VSC(1306, 3.6732, 2.9689), new VSC(605, 1.505, 35.164), new VSC(179, 3.453, 39.618), new VSC(107, 2.451, 4.453), new VSC(106, 2.755, 33.68), new VSC(73, 5.49, 36.65), new VSC(57, 1.86, 114.4), new VSC(57, 5.22, 0.52), new VSC(35, 4.52, 74.78), new VSC(32, 5.9, 77.75), new VSC(30, 3.67, 388.47), new VSC(29, 5.17, 9.56), new VSC(29, 5.17, 2.45), new VSC(26, 5.25, 168.05)];
+const g_L2NC = [new VSC(53893, 0, 0), new VSC(296, 1.855, 1.484), new VSC(281, 1.191, 38.133), new VSC(270, 5.721, 76.266), new VSC(23, 1.21, 2.97), new VSC(9, 4.43, 35.16), new VSC(7, 0.54, 2.45)];
+const g_L3NC = [new VSC(31, 0, 0), new VSC(15, 1.35, 76.27), new VSC(12, 6.04, 1.48), new VSC(12, 6.11, 38.13)];
+const g_L4NC = [new VSC(114, 3.142, 0)];
+const g_B0NC = [new VSC(3088623, 1.4410437, 38.1330356), new VSC(27789, 5.91272, 76.26607), new VSC(27624, 0, 0), new VSC(15448, 3.50877, 39.61751), new VSC(15355, 2.52124, 36.64856), new VSC(2000, 1.51, 74.7816), new VSC(1968, 4.3778, 1.4845), new VSC(1015, 3.2156, 35.1641), new VSC(606, 2.802, 73.297), new VSC(595, 2.129, 41.102), new VSC(589, 3.187, 2.969), new VSC(402, 4.169, 114.399), new VSC(280, 1.682, 77.751), new VSC(262, 3.767, 213.299), new VSC(254, 3.271, 453.425), new VSC(206, 4.257, 529.691), new VSC(140, 3.53, 137.033)];
+const g_B1NC = [new VSC(227279, 3.807931, 38.133036), new VSC(1803, 1.9758, 76.2661), new VSC(1433, 3.1416, 0), new VSC(1386, 4.8256, 36.6486), new VSC(1073, 6.0805, 39.6175), new VSC(148, 3.858, 74.782), new VSC(136, 0.478, 1.484), new VSC(70, 6.19, 35.16), new VSC(52, 5.05, 73.3), new VSC(43, 0.31, 114.4), new VSC(37, 4.89, 41.1), new VSC(37, 5.76, 2.97), new VSC(26, 5.22, 213.3)];
+const g_B2NC = [new VSC(9691, 5.5712, 38.133), new VSC(79, 3.63, 76.27), new VSC(72, 0.45, 36.65), new VSC(59, 3.14, 0), new VSC(30, 1.61, 39.62), new VSC(6, 5.61, 74.78)];
+const g_B3NC = [new VSC(273, 1.017, 38.133), new VSC(2, 0, 0), new VSC(2, 2.37, 36.65), new VSC(2, 5.33, 76.27)];
+const g_B4NC = [new VSC(6, 2.67, 38.13)];
+const g_R0NC = [new VSC(3007013206, 0, 0), new VSC(27062259, 1.32999459, 38.13303564), new VSC(1691764, 3.2518614, 36.6485629), new VSC(807831, 5.185928, 1.484473), new VSC(537761, 4.521139, 35.16409), new VSC(495726, 1.571057, 491.557929), new VSC(274572, 1.845523, 175.16606), new VSC(135134, 3.372206, 39.617508), new VSC(121802, 5.797544, 76.266071), new VSC(100895, 0.377027, 73.297126), new VSC(69792, 3.79617, 2.96895), new VSC(46688, 5.74938, 33.67962), new VSC(24594, 0.50802, 109.94569), new VSC(16939, 1.59422, 71.81265), new VSC(14230, 1.07786, 74.7816), new VSC(12012, 1.92062, 1021.24889), new VSC(8395, 0.6782, 146.5943), new VSC(7572, 1.0715, 388.4652), new VSC(5721, 2.5906, 4.4534), new VSC(4840, 1.9069, 41.102), new VSC(4483, 2.9057, 529.691), new VSC(4421, 1.7499, 108.4612), new VSC(4354, 0.6799, 32.1951), new VSC(4270, 3.4134, 453.4249), new VSC(3381, 0.8481, 183.2428), new VSC(2881, 1.986, 137.033), new VSC(2879, 3.6742, 350.3321), new VSC(2636, 3.0976, 213.2991), new VSC(2530, 5.7984, 490.0735), new VSC(2523, 0.4863, 493.0424), new VSC(2306, 2.8096, 70.3282), new VSC(2087, 0.6186, 33.9402)];
+const g_R1NC = [new VSC(236339, 0.70498, 38.133036), new VSC(13220, 3.32015, 1.48447), new VSC(8622, 6.2163, 35.1641), new VSC(2702, 1.8814, 39.6175), new VSC(2155, 2.0943, 2.9689), new VSC(2153, 5.1687, 76.2661), new VSC(1603, 0, 0), new VSC(1464, 1.1842, 33.6796), new VSC(1136, 3.9189, 36.6486), new VSC(898, 5.241, 388.465), new VSC(790, 0.533, 168.053), new VSC(760, 0.021, 182.28), new VSC(607, 1.077, 1021.249), new VSC(572, 3.401, 484.444), new VSC(561, 2.887, 498.671)];
+const g_R2NC = [new VSC(4247, 5.8991, 38.133), new VSC(218, 0.346, 1.484), new VSC(163, 2.239, 168.053), new VSC(156, 4.594, 182.28), new VSC(127, 2.848, 35.164)];
+const g_R3NC = [new VSC(166, 4.552, 38.133)];
+
+
+// CAANeptune
+
+export function CAANeptune() { }
+
+CAANeptune.eclipticLongitude = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var nL0Coefficients = g_L0NC.length;
+ var L0 = 0;
+ var i;
+ for (i = 0; i < nL0Coefficients; i++) {
+ L0 += g_L0NC[i].a * Math.cos(g_L0NC[i].b + g_L0NC[i].c * rho);
+ }
+ var nL1Coefficients = g_L1NC.length;
+ var L1 = 0;
+ for (i = 0; i < nL1Coefficients; i++) {
+ L1 += g_L1NC[i].a * Math.cos(g_L1NC[i].b + g_L1NC[i].c * rho);
+ }
+ var nL2Coefficients = g_L2NC.length;
+ var L2 = 0;
+ for (i = 0; i < nL2Coefficients; i++) {
+ L2 += g_L2NC[i].a * Math.cos(g_L2NC[i].b + g_L2NC[i].c * rho);
+ }
+ var nL3Coefficients = g_L3NC.length;
+ var L3 = 0;
+ for (i = 0; i < nL3Coefficients; i++) {
+ L3 += g_L3NC[i].a * Math.cos(g_L3NC[i].b + g_L3NC[i].c * rho);
+ }
+ var nL4Coefficients = g_L4NC.length;
+ var L4 = 0;
+ for (i = 0; i < nL4Coefficients; i++) {
+ L4 += g_L4NC[i].a * Math.cos(g_L4NC[i].b + g_L4NC[i].c * rho);
+ }
+ var vvalue = (L0 + L1 * rho + L2 * rhosquared + L3 * rhocubed + L4 * rho4) / 100000000;
+ vvalue = CT.m360(CT.r2D(vvalue));
+ return vvalue;
+};
+
+CAANeptune.eclipticLatitude = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var nB0Coefficients = g_B0NC.length;
+ var B0 = 0;
+ var i;
+ for (i = 0; i < nB0Coefficients; i++) {
+ B0 += g_B0NC[i].a * Math.cos(g_B0NC[i].b + g_B0NC[i].c * rho);
+ }
+ var nB1Coefficients = g_B1NC.length;
+ var B1 = 0;
+ for (i = 0; i < nB1Coefficients; i++) {
+ B1 += g_B1NC[i].a * Math.cos(g_B1NC[i].b + g_B1NC[i].c * rho);
+ }
+ var nB2Coefficients = g_B2NC.length;
+ var B2 = 0;
+ for (i = 0; i < nB2Coefficients; i++) {
+ B2 += g_B2NC[i].a * Math.cos(g_B2NC[i].b + g_B2NC[i].c * rho);
+ }
+ var nB3Coefficients = g_B3NC.length;
+ var B3 = 0;
+ for (i = 0; i < nB3Coefficients; i++) {
+ B3 += g_B3NC[i].a * Math.cos(g_B3NC[i].b + g_B3NC[i].c * rho);
+ }
+ var nB4Coefficients = g_B4NC.length;
+ var B4 = 0;
+ for (i = 0; i < nB4Coefficients; i++) {
+ B4 += g_B4NC[i].a * Math.cos(g_B4NC[i].b + g_B4NC[i].c * rho);
+ }
+ var vvalue = (B0 + B1 * rho + B2 * rhosquared + B3 * rhocubed + B4 * rho4) / 100000000;
+ vvalue = CT.r2D(vvalue);
+ return vvalue;
+};
+
+CAANeptune.radiusVector = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var nR0Coefficients = g_R0NC.length;
+ var R0 = 0;
+ var i;
+ for (i = 0; i < nR0Coefficients; i++) {
+ R0 += g_R0NC[i].a * Math.cos(g_R0NC[i].b + g_R0NC[i].c * rho);
+ }
+ var nR1Coefficients = g_R1NC.length;
+ var R1 = 0;
+ for (i = 0; i < nR1Coefficients; i++) {
+ R1 += g_R1NC[i].a * Math.cos(g_R1NC[i].b + g_R1NC[i].c * rho);
+ }
+ var nR2Coefficients = g_R2NC.length;
+ var R2 = 0;
+ for (i = 0; i < nR2Coefficients; i++) {
+ R2 += g_R2NC[i].a * Math.cos(g_R2NC[i].b + g_R2NC[i].c * rho);
+ }
+ var nR3Coefficients = g_R3NC.length;
+ var R3 = 0;
+ for (i = 0; i < nR3Coefficients; i++) {
+ R3 += g_R3NC[i].a * Math.cos(g_R3NC[i].b + g_R3NC[i].c * rho);
+ }
+ return (R0 + R1 * rho + R2 * rhosquared + R3 * rhocubed) / 100000000;
+};
+
+var CAANeptune$ = {};
+
+registerType("CAANeptune", [CAANeptune, CAANeptune$, null]);
diff --git a/engine/esm/astrocalc/nutation.js b/engine/esm/astrocalc/nutation.js
new file mode 100644
index 00000000..a236ed87
--- /dev/null
+++ b/engine/esm/astrocalc/nutation.js
@@ -0,0 +1,145 @@
+// Originally `AANUTATION.CPP`
+// "Purpose: Implementation for the algorithms for Nutation"
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { C3D, CT } from "./coordinate_transformation.js";
+import { CAAEarth } from "./earth.js";
+
+
+// NUC - was NutationCoefficient
+
+export function NUC(D, M, Mprime, F, omega, sincoeff1, sincoeff2, coscoeff1, coscoeff2) {
+ this.d = 0;
+ this.m = 0;
+ this.mprime = 0;
+ this.f = 0;
+ this.omega = 0;
+ this.sincoeff1 = 0;
+ this.sincoeff2 = 0;
+ this.coscoeff1 = 0;
+ this.coscoeff2 = 0;
+ this.d = D;
+ this.m = M;
+ this.mprime = Mprime;
+ this.f = F;
+ this.omega = omega;
+ this.sincoeff1 = sincoeff1;
+ this.sincoeff2 = sincoeff2;
+ this.coscoeff1 = coscoeff1;
+ this.coscoeff2 = coscoeff2;
+}
+
+var NUC$ = {};
+
+registerType("NUC", [NUC, NUC$, null]);
+
+
+// Coefficients
+
+const g_NuC = [new NUC(0, 0, 0, 0, 1, -171996, -174.2, 92025, 8.9), new NUC(-2, 0, 0, 2, 2, -13187, -1.6, 5736, -3.1), new NUC(0, 0, 0, 2, 2, -2274, -0.2, 977, -0.5), new NUC(0, 0, 0, 0, 2, 2062, 0.2, -895, 0.5), new NUC(0, 1, 0, 0, 0, 1426, -3.4, 54, -0.1), new NUC(0, 0, 1, 0, 0, 712, 0.1, -7, 0), new NUC(-2, 1, 0, 2, 2, -517, 1.2, 224, -0.6), new NUC(0, 0, 0, 2, 1, -386, -0.4, 200, 0), new NUC(0, 0, 1, 2, 2, -301, 0, 129, -0.1), new NUC(-2, -1, 0, 2, 2, 217, -0.5, -95, 0.3), new NUC(-2, 0, 1, 0, 0, -158, 0, 0, 0), new NUC(-2, 0, 0, 2, 1, 129, 0.1, -70, 0), new NUC(0, 0, -1, 2, 2, 123, 0, -53, 0), new NUC(2, 0, 0, 0, 0, 63, 0, 0, 0), new NUC(0, 0, 1, 0, 1, 63, 0.1, -33, 0), new NUC(2, 0, -1, 2, 2, -59, 0, 26, 0), new NUC(0, 0, -1, 0, 1, -58, -0.1, 32, 0), new NUC(0, 0, 1, 2, 1, -51, 0, 27, 0), new NUC(-2, 0, 2, 0, 0, 48, 0, 0, 0), new NUC(0, 0, -2, 2, 1, 46, 0, -24, 0), new NUC(2, 0, 0, 2, 2, -38, 0, 16, 0), new NUC(0, 0, 2, 2, 2, -31, 0, 13, 0), new NUC(0, 0, 2, 0, 0, 29, 0, 0, 0), new NUC(-2, 0, 1, 2, 2, 29, 0, -12, 0), new NUC(0, 0, 0, 2, 0, 26, 0, 0, 0), new NUC(-2, 0, 0, 2, 0, -22, 0, 0, 0), new NUC(0, 0, -1, 2, 1, 21, 0, -10, 0), new NUC(0, 2, 0, 0, 0, 17, -0.1, 0, 0), new NUC(2, 0, -1, 0, 1, 16, 0, -8, 0), new NUC(-2, 2, 0, 2, 2, -16, 0.1, 7, 0), new NUC(0, 1, 0, 0, 1, -15, 0, 9, 0), new NUC(-2, 0, 1, 0, 1, -13, 0, 7, 0), new NUC(0, -1, 0, 0, 1, -12, 0, 6, 0), new NUC(0, 0, 2, -2, 0, 11, 0, 0, 0), new NUC(2, 0, -1, 2, 1, -10, 0, 5, 0), new NUC(2, 0, 1, 2, 2, -8, 0, 3, 0), new NUC(0, 1, 0, 2, 2, 7, 0, -3, 0), new NUC(-2, 1, 1, 0, 0, -7, 0, 0, 0), new NUC(0, -1, 0, 2, 2, -7, 0, 3, 0), new NUC(2, 0, 0, 2, 1, -7, 0, 3, 0), new NUC(2, 0, 1, 0, 0, 6, 0, 0, 0), new NUC(-2, 0, 2, 2, 2, 6, 0, -3, 0), new NUC(-2, 0, 1, 2, 1, 6, 0, -3, 0), new NUC(2, 0, -2, 0, 1, -6, 0, 3, 0), new NUC(2, 0, 0, 0, 1, -6, 0, 3, 0), new NUC(0, -1, 1, 0, 0, 5, 0, 0, 0), new NUC(-2, -1, 0, 2, 1, -5, 0, 3, 0), new NUC(-2, 0, 0, 0, 1, -5, 0, 3, 0), new NUC(0, 0, 2, 2, 1, -5, 0, 3, 0), new NUC(-2, 0, 2, 0, 1, 4, 0, 0, 0), new NUC(-2, 1, 0, 2, 1, 4, 0, 0, 0), new NUC(0, 0, 1, -2, 0, 4, 0, 0, 0), new NUC(-1, 0, 1, 0, 0, -4, 0, 0, 0), new NUC(-2, 1, 0, 0, 0, -4, 0, 0, 0), new NUC(1, 0, 0, 0, 0, -4, 0, 0, 0), new NUC(0, 0, 1, 2, 0, 3, 0, 0, 0), new NUC(0, 0, -2, 2, 2, -3, 0, 0, 0), new NUC(-1, -1, 1, 0, 0, -3, 0, 0, 0), new NUC(0, 1, 1, 0, 0, -3, 0, 0, 0), new NUC(0, -1, 1, 2, 2, -3, 0, 0, 0), new NUC(2, -1, -1, 2, 2, -3, 0, 0, 0), new NUC(0, 0, 3, 2, 2, -3, 0, 0, 0), new NUC(2, -1, 0, 2, 2, -3, 0, 0, 0)];
+
+
+// CAANutation
+
+export function CAANutation() { }
+
+CAANutation.nutationInLongitude = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ var D = 297.85036 + 445267.11148 * T - 0.0019142 * Tsquared + Tcubed / 189474;
+ D = CT.m360(D);
+ var M = 357.52772 + 35999.05034 * T - 0.0001603 * Tsquared - Tcubed / 300000;
+ M = CT.m360(M);
+ var Mprime = 134.96298 + 477198.867398 * T + 0.0086972 * Tsquared + Tcubed / 56250;
+ Mprime = CT.m360(Mprime);
+ var F = 93.27191 + 483202.017538 * T - 0.0036825 * Tsquared + Tcubed / 327270;
+ F = CT.m360(F);
+ var omega = 125.04452 - 1934.136261 * T + 0.0020708 * Tsquared + Tcubed / 450000;
+ omega = CT.m360(omega);
+ var nCoefficients = g_NuC.length;
+ var vvalue = 0;
+ for (var i = 0; i < nCoefficients; i++) {
+ var argument = g_NuC[i].d * D + g_NuC[i].m * M + g_NuC[i].mprime * Mprime + g_NuC[i].f * F + g_NuC[i].omega * omega;
+ var radargument = CT.d2R(argument);
+ vvalue += (g_NuC[i].sincoeff1 + g_NuC[i].sincoeff2 * T) * Math.sin(radargument) * 0.0001;
+ }
+ return vvalue;
+};
+
+CAANutation.nutationInObliquity = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var Tsquared = T * T;
+ var Tcubed = Tsquared * T;
+ var D = 297.85036 + 445267.11148 * T - 0.0019142 * Tsquared + Tcubed / 189474;
+ D = CT.m360(D);
+ var M = 357.52772 + 35999.05034 * T - 0.0001603 * Tsquared - Tcubed / 300000;
+ M = CT.m360(M);
+ var Mprime = 134.96298 + 477198.867398 * T + 0.0086972 * Tsquared + Tcubed / 56250;
+ Mprime = CT.m360(Mprime);
+ var F = 93.27191 + 483202.017538 * T - 0.0036825 * Tsquared + Tcubed / 327270;
+ F = CT.m360(F);
+ var omega = 125.04452 - 1934.136261 * T + 0.0020708 * Tsquared + Tcubed / 450000;
+ omega = CT.m360(omega);
+ var nCoefficients = g_NuC.length;
+ var vvalue = 0;
+ for (var i = 0; i < nCoefficients; i++) {
+ var argument = g_NuC[i].d * D + g_NuC[i].m * M + g_NuC[i].mprime * Mprime + g_NuC[i].f * F + g_NuC[i].omega * omega;
+ var radargument = CT.d2R(argument);
+ vvalue += (g_NuC[i].coscoeff1 + g_NuC[i].coscoeff2 * T) * Math.cos(radargument) * 0.0001;
+ }
+ return vvalue;
+};
+
+CAANutation.nutationInRightAscension = function (Alpha, Delta, Obliquity, NutationInLongitude, NutationInObliquity) {
+ Alpha = CT.h2R(Alpha);
+ Delta = CT.d2R(Delta);
+ Obliquity = CT.d2R(Obliquity);
+ return (Math.cos(Obliquity) + Math.sin(Obliquity) * Math.sin(Alpha) * Math.tan(Delta)) * NutationInLongitude - Math.cos(Alpha) * Math.tan(Delta) * NutationInObliquity;
+};
+
+CAANutation.nutationInDeclination = function (Alpha, Delta, Obliquity, NutationInLongitude, NutationInObliquity) {
+ Alpha = CT.h2R(Alpha);
+ Delta = CT.d2R(Delta);
+ Obliquity = CT.d2R(Obliquity);
+ return Math.sin(Obliquity) * Math.cos(Alpha) * NutationInLongitude + Math.sin(Alpha) * NutationInObliquity;
+};
+
+CAANutation.meanObliquityOfEcliptic = function (JD) {
+ var U = (JD - 2451545) / 3652500;
+ var Usquared = U * U;
+ var Ucubed = Usquared * U;
+ var U4 = Ucubed * U;
+ var U5 = U4 * U;
+ var U6 = U5 * U;
+ var U7 = U6 * U;
+ var U8 = U7 * U;
+ var U9 = U8 * U;
+ var U10 = U9 * U;
+ return CT.dmS2D(23, 26, 21.448) - CT.dmS2D(0, 0, 4680.93) * U - CT.dmS2D(0, 0, 1.55) * Usquared + CT.dmS2D(0, 0, 1999.25) * Ucubed - CT.dmS2D(0, 0, 51.38) * U4 - CT.dmS2D(0, 0, 249.67) * U5 - CT.dmS2D(0, 0, 39.05) * U6 + CT.dmS2D(0, 0, 7.12) * U7 + CT.dmS2D(0, 0, 27.87) * U8 + CT.dmS2D(0, 0, 5.79) * U9 + CT.dmS2D(0, 0, 2.45) * U10;
+};
+
+CAANutation.trueObliquityOfEcliptic = function (JD) {
+ return CAANutation.meanObliquityOfEcliptic(JD) + CT.dmS2D(0, 0, CAANutation.nutationInObliquity(JD));
+};
+
+var CAANutation$ = {};
+
+registerType("CAANutation", [CAANutation, CAANutation$, null]);
diff --git a/engine/esm/astrocalc/parallax.js b/engine/esm/astrocalc/parallax.js
new file mode 100644
index 00000000..4128557c
--- /dev/null
+++ b/engine/esm/astrocalc/parallax.js
@@ -0,0 +1,128 @@
+// Originally `AAPARALLAX.CPP`
+// "Purpose: Implementation for the algorithms which convert a geocentric set of coordinates to their topocentric equivalent"
+// Last update of original: PJN / 29-12-2003
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { COR, CT } from "./coordinate_transformation.js";
+import { CAAGlobe } from "./globe.js";
+import { CAASidereal } from "./sidereal.js";
+
+
+// CAATopocentricEclipticDetails
+
+export function CAATopocentricEclipticDetails() {
+ this.lambda = 0;
+ this.beta = 0;
+ this.semidiameter = 0;
+ this.lambda = 0;
+ this.beta = 0;
+ this.semidiameter = 0;
+}
+
+var CAATopocentricEclipticDetails$ = {};
+
+registerType("CAATopocentricEclipticDetails", [CAATopocentricEclipticDetails, CAATopocentricEclipticDetails$, null]);
+
+
+// Constants
+
+const g_AAParallax_C1 = Math.sin(CT.d2R(CT.dmS2D(0, 0, 8.794)));
+
+
+// CAAParallax
+
+export function CAAParallax() { }
+
+CAAParallax.equatorial2TopocentricDelta = function (Alpha, Delta, Distance, Longitude, Latitude, Height, JD) {
+ var RhoSinThetaPrime = CAAGlobe.rhoSinThetaPrime(Latitude, Height);
+ var RhoCosThetaPrime = CAAGlobe.rhoCosThetaPrime(Latitude, Height);
+ var theta = CAASidereal.apparentGreenwichSiderealTime(JD);
+ Delta = CT.d2R(Delta);
+ var cosDelta = Math.cos(Delta);
+ var pi = Math.asin(g_AAParallax_C1 / Distance);
+ var H = CT.h2R(theta - Longitude / 15 - Alpha);
+ var cosH = Math.cos(H);
+ var sinH = Math.sin(H);
+ var DeltaTopocentric = new COR();
+ DeltaTopocentric.x = CT.r2H(-pi * RhoCosThetaPrime * sinH / cosDelta);
+ DeltaTopocentric.y = CT.r2D(-pi * (RhoSinThetaPrime * cosDelta - RhoCosThetaPrime * cosH * Math.sin(Delta)));
+ return DeltaTopocentric;
+};
+
+CAAParallax.equatorial2Topocentric = function (Alpha, Delta, Distance, Longitude, Latitude, Height, JD) {
+ var RhoSinThetaPrime = CAAGlobe.rhoSinThetaPrime(Latitude, Height);
+ var RhoCosThetaPrime = CAAGlobe.rhoCosThetaPrime(Latitude, Height);
+ var theta = CAASidereal.apparentGreenwichSiderealTime(JD);
+ Delta = CT.d2R(Delta);
+ var cosDelta = Math.cos(Delta);
+ var pi = Math.asin(g_AAParallax_C1 / Distance);
+ var sinpi = Math.sin(pi);
+ var H = CT.h2R(theta - Longitude / 15 - Alpha);
+ var cosH = Math.cos(H);
+ var sinH = Math.sin(H);
+ var DeltaAlpha = Math.atan2(-RhoCosThetaPrime * sinpi * sinH, cosDelta - RhoCosThetaPrime * sinpi * cosH);
+ var Topocentric = new COR();
+ Topocentric.x = CT.m24(Alpha + CT.r2H(DeltaAlpha));
+ Topocentric.y = CT.r2D(Math.atan2((Math.sin(Delta) - RhoSinThetaPrime * sinpi) * Math.cos(DeltaAlpha), cosDelta - RhoCosThetaPrime * sinpi * cosH));
+ return Topocentric;
+};
+
+CAAParallax.ecliptic2Topocentric = function (Lambda, Beta, Semidiameter, Distance, Epsilon, Longitude, Latitude, Height, JD) {
+ var S = CAAGlobe.rhoSinThetaPrime(Latitude, Height);
+ var C = CAAGlobe.rhoCosThetaPrime(Latitude, Height);
+ Lambda = CT.d2R(Lambda);
+ Beta = CT.d2R(Beta);
+ Epsilon = CT.d2R(Epsilon);
+ Longitude = CT.d2R(Longitude);
+ Latitude = CT.d2R(Latitude);
+ Semidiameter = CT.d2R(Semidiameter);
+ var sine = Math.sin(Epsilon);
+ var cose = Math.cos(Epsilon);
+ var cosBeta = Math.cos(Beta);
+ var sinBeta = Math.sin(Beta);
+ var theta = CAASidereal.apparentGreenwichSiderealTime(JD);
+ theta = CT.h2R(theta);
+ var sintheta = Math.sin(theta);
+ var pi = Math.asin(g_AAParallax_C1 / Distance);
+ var sinpi = Math.sin(pi);
+ var N = Math.cos(Lambda) * cosBeta - C * sinpi * Math.cos(theta);
+ var Topocentric = new CAATopocentricEclipticDetails();
+ Topocentric.lambda = Math.atan2(Math.sin(Lambda) * cosBeta - sinpi * (S * sine + C * cose * sintheta), N);
+ var cosTopocentricLambda = Math.cos(Topocentric.lambda);
+ Topocentric.beta = Math.atan(cosTopocentricLambda * (sinBeta - sinpi * (S * cose - C * sine * sintheta)) / N);
+ Topocentric.semidiameter = Math.asin(cosTopocentricLambda * Math.cos(Topocentric.beta) * Math.sin(Semidiameter) / N);
+ Topocentric.semidiameter = CT.r2D(Topocentric.semidiameter);
+ Topocentric.lambda = CT.m360(CT.r2D(Topocentric.lambda));
+ Topocentric.beta = CT.r2D(Topocentric.beta);
+ return Topocentric;
+};
+
+CAAParallax.parallaxToDistance = function (Parallax) {
+ return g_AAParallax_C1 / Math.sin(CT.d2R(Parallax));
+};
+
+CAAParallax.distanceToParallax = function (Distance) {
+ var pi = Math.asin(g_AAParallax_C1 / Distance);
+ return CT.r2D(pi);
+};
+
+var CAAParallax$ = {};
+
+registerType("CAAParallax", [CAAParallax, CAAParallax$, null]);
diff --git a/engine/esm/astrocalc/physical_jupiter.js b/engine/esm/astrocalc/physical_jupiter.js
new file mode 100644
index 00000000..99f50638
--- /dev/null
+++ b/engine/esm/astrocalc/physical_jupiter.js
@@ -0,0 +1,138 @@
+// Originally `AAPHYSICALJUPITER.CPP`
+// "Purpose: Implementation for the algorithms which obtain the physical parameters of the Jupiter"
+// Last update of original: PJN / 29-12-2003
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+import { CAANutation } from "./nutation.js";
+import { CAAEarth } from "./earth.js";
+import { CAAJupiter } from "./jupiter.js";
+
+
+// CAAPhysicalJupiterDetails
+
+export function CAAPhysicalJupiterDetails() {
+ this.DE = 0;
+ this.DS = 0;
+ this.geometricw1 = 0;
+ this.geometricw2 = 0;
+ this.apparentw1 = 0;
+ this.apparentw2 = 0;
+ this.p = 0;
+ this.DE = 0;
+ this.DS = 0;
+ this.geometricw1 = 0;
+ this.geometricw2 = 0;
+ this.apparentw1 = 0;
+ this.apparentw2 = 0;
+ this.p = 0;
+}
+
+var CAAPhysicalJupiterDetails$ = {};
+
+registerType("CAAPhysicalJupiterDetails", [CAAPhysicalJupiterDetails, CAAPhysicalJupiterDetails$, null]);
+
+
+// CAAPhysicalJupiter
+
+export function CAAPhysicalJupiter() { }
+
+CAAPhysicalJupiter.calculate = function (JD) {
+ var details = new CAAPhysicalJupiterDetails();
+ var d = JD - 2433282.5;
+ var T1 = d / 36525;
+ var alpha0 = 268 + 0.1061 * T1;
+ var alpha0rad = CT.d2R(alpha0);
+ var delta0 = 64.5 - 0.0164 * T1;
+ var delta0rad = CT.d2R(delta0);
+ var W1 = CT.m360(17.71 + 877.90003539 * d);
+ var W2 = CT.m360(16.838 + 870.27003539 * d);
+ var l0 = CAAEarth.eclipticLongitude(JD);
+ var l0rad = CT.d2R(l0);
+ var b0 = CAAEarth.eclipticLatitude(JD);
+ var b0rad = CT.d2R(b0);
+ var R = CAAEarth.radiusVector(JD);
+ var l = CAAJupiter.eclipticLongitude(JD);
+ var lrad = CT.d2R(l);
+ var b = CAAJupiter.eclipticLatitude(JD);
+ var brad = CT.d2R(b);
+ var r = CAAJupiter.radiusVector(JD);
+ var x = r * Math.cos(brad) * Math.cos(lrad) - R * Math.cos(l0rad);
+ var y = r * Math.cos(brad) * Math.sin(lrad) - R * Math.sin(l0rad);
+ var z = r * Math.sin(brad) - R * Math.sin(b0rad);
+ var DELTA = Math.sqrt(x * x + y * y + z * z);
+ l -= 0.01299 * DELTA / (r * r);
+ lrad = CT.d2R(l);
+ x = r * Math.cos(brad) * Math.cos(lrad) - R * Math.cos(l0rad);
+ y = r * Math.cos(brad) * Math.sin(lrad) - R * Math.sin(l0rad);
+ z = r * Math.sin(brad) - R * Math.sin(b0rad);
+ DELTA = Math.sqrt(x * x + y * y + z * z);
+ var e0 = CAANutation.meanObliquityOfEcliptic(JD);
+ var e0rad = CT.d2R(e0);
+ var alphas = Math.atan2(Math.cos(e0rad) * Math.sin(lrad) - Math.sin(e0rad) * Math.tan(brad), Math.cos(lrad));
+ var deltas = Math.asin(Math.cos(e0rad) * Math.sin(brad) + Math.sin(e0rad) * Math.cos(brad) * Math.sin(lrad));
+ details.DS = CT.r2D(Math.asin(-Math.sin(delta0rad) * Math.sin(deltas) - Math.cos(delta0rad) * Math.cos(deltas) * Math.cos(alpha0rad - alphas)));
+ var u = y * Math.cos(e0rad) - z * Math.sin(e0rad);
+ var v = y * Math.sin(e0rad) + z * Math.cos(e0rad);
+ var alpharad = Math.atan2(u, x);
+ var alpha = CT.r2D(alpharad);
+ var deltarad = Math.atan2(v, Math.sqrt(x * x + u * u));
+ var delta = CT.r2D(deltarad);
+ var xi = Math.atan2(Math.sin(delta0rad) * Math.cos(deltarad) * Math.cos(alpha0rad - alpharad) - Math.sin(deltarad) * Math.cos(delta0rad), Math.cos(deltarad) * Math.sin(alpha0rad - alpharad));
+ details.DE = CT.r2D(Math.asin(-Math.sin(delta0rad) * Math.sin(deltarad) - Math.cos(delta0rad) * Math.cos(deltarad) * Math.cos(alpha0rad - alpharad)));
+ details.geometricw1 = CT.m360(W1 - CT.r2D(xi) - 5.07033 * DELTA);
+ details.geometricw2 = CT.m360(W2 - CT.r2D(xi) - 5.02626 * DELTA);
+ var C = 57.2958 * (2 * r * DELTA + R * R - r * r - DELTA * DELTA) / (4 * r * DELTA);
+ if (Math.sin(lrad - l0rad) > 0) {
+ details.apparentw1 = CT.m360(details.geometricw1 + C);
+ details.apparentw2 = CT.m360(details.geometricw2 + C);
+ }
+ else {
+ details.apparentw1 = CT.m360(details.geometricw1 - C);
+ details.apparentw2 = CT.m360(details.geometricw2 - C);
+ }
+ var NutationInLongitude = CAANutation.nutationInLongitude(JD);
+ var NutationInObliquity = CAANutation.nutationInObliquity(JD);
+ e0 += NutationInObliquity / 3600;
+ e0rad = CT.d2R(e0);
+ alpha += 0.005693 * (Math.cos(alpharad) * Math.cos(l0rad) * Math.cos(e0rad) + Math.sin(alpharad) * Math.sin(l0rad)) / Math.cos(deltarad);
+ alpha = CT.m360(alpha);
+ alpharad = CT.d2R(alpha);
+ delta += 0.005693 * (Math.cos(l0rad) * Math.cos(e0rad) * (Math.tan(e0rad) * Math.cos(deltarad) - Math.sin(alpharad) * Math.sin(deltarad)) + Math.cos(alpharad) * Math.sin(deltarad) * Math.sin(l0rad));
+ deltarad = CT.d2R(delta);
+ var NutationRA = CAANutation.nutationInRightAscension(alpha / 15, delta, e0, NutationInLongitude, NutationInObliquity);
+ var alphadash = alpha + NutationRA / 3600;
+ var alphadashrad = CT.d2R(alphadash);
+ var NutationDec = CAANutation.nutationInDeclination(alpha / 15, delta, e0, NutationInLongitude, NutationInObliquity);
+ var deltadash = delta + NutationDec / 3600;
+ var deltadashrad = CT.d2R(deltadash);
+ NutationRA = CAANutation.nutationInRightAscension(alpha0 / 15, delta0, e0, NutationInLongitude, NutationInObliquity);
+ var alpha0dash = alpha0 + NutationRA / 3600;
+ var alpha0dashrad = CT.d2R(alpha0dash);
+ NutationDec = CAANutation.nutationInDeclination(alpha0 / 15, delta0, e0, NutationInLongitude, NutationInObliquity);
+ var delta0dash = delta0 + NutationDec / 3600;
+ var delta0dashrad = CT.d2R(delta0dash);
+ details.p = CT.m360(CT.r2D(Math.atan2(Math.cos(delta0dashrad) * Math.sin(alpha0dashrad - alphadashrad), Math.sin(delta0dashrad) * Math.cos(deltadashrad) - Math.cos(delta0dashrad) * Math.sin(deltadashrad) * Math.cos(alpha0dashrad - alphadashrad))));
+ return details;
+};
+
+var CAAPhysicalJupiter$ = {};
+
+registerType("CAAPhysicalJupiter", [CAAPhysicalJupiter, CAAPhysicalJupiter$, null]);
diff --git a/engine/esm/astrocalc/physical_mars.js b/engine/esm/astrocalc/physical_mars.js
new file mode 100644
index 00000000..9239437c
--- /dev/null
+++ b/engine/esm/astrocalc/physical_mars.js
@@ -0,0 +1,158 @@
+// Originally `AAPHYSICALMARS.CPP`
+// "Purpose: Implementation for the algorithms which obtain the physical parameters of Mars"
+// Last update of original: PJN / 04-01-2004
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+import { CAANutation } from "./nutation.js";
+import { CAASun } from "./sun.js";
+import { CAAEarth } from "./earth.js";
+import { CAAMars } from "./mars.js";
+import { ELL } from "./elliptical.js";
+import { IFR } from "./illuminated_fraction.js";
+import { MIFR } from "./moon_illuminated_fraction.js";
+
+// CAAPhysicalMarsDetails
+
+export function CAAPhysicalMarsDetails() {
+ this.DE = 0;
+ this.DS = 0;
+ this.w = 0;
+ this.p = 0;
+ this.x = 0;
+ this.k = 0;
+ this.q = 0;
+ this.d = 0;
+ this.DE = 0;
+ this.DS = 0;
+ this.w = 0;
+ this.p = 0;
+ this.x = 0;
+ this.k = 0;
+ this.q = 0;
+ this.d = 0;
+}
+
+var CAAPhysicalMarsDetails$ = {};
+
+registerType("CAAPhysicalMarsDetails", [CAAPhysicalMarsDetails, CAAPhysicalMarsDetails$, null]);
+
+
+// CAAPhysicalMars
+
+export function CAAPhysicalMars() { }
+
+CAAPhysicalMars.calculate = function (JD) {
+ var details = new CAAPhysicalMarsDetails();
+ var T = (JD - 2451545) / 36525;
+ var Lambda0 = 352.9065 + 1.1733 * T;
+ var Lambda0rad = CT.d2R(Lambda0);
+ var Beta0 = 63.2818 - 0.00394 * T;
+ var Beta0rad = CT.d2R(Beta0);
+ var l0 = CAAEarth.eclipticLongitude(JD);
+ var l0rad = CT.d2R(l0);
+ var b0 = CAAEarth.eclipticLatitude(JD);
+ var b0rad = CT.d2R(b0);
+ var R = CAAEarth.radiusVector(JD);
+ var PreviousLightTravelTime = 0;
+ var LightTravelTime = 0;
+ var x = 0;
+ var y = 0;
+ var z = 0;
+ var bIterate = true;
+ var DELTA = 0;
+ var l = 0;
+ var lrad = 0;
+ var b = 0;
+ var brad = 0;
+ var r = 0;
+ while (bIterate) {
+ var JD2 = JD - LightTravelTime;
+ l = CAAMars.eclipticLongitude(JD2);
+ lrad = CT.d2R(l);
+ b = CAAMars.eclipticLatitude(JD2);
+ brad = CT.d2R(b);
+ r = CAAMars.radiusVector(JD2);
+ x = r * Math.cos(brad) * Math.cos(lrad) - R * Math.cos(l0rad);
+ y = r * Math.cos(brad) * Math.sin(lrad) - R * Math.sin(l0rad);
+ z = r * Math.sin(brad) - R * Math.sin(b0rad);
+ DELTA = Math.sqrt(x * x + y * y + z * z);
+ LightTravelTime = ELL.distanceToLightTime(DELTA);
+ bIterate = (Math.abs(LightTravelTime - PreviousLightTravelTime) > 2E-06);
+ if (bIterate) {
+ PreviousLightTravelTime = LightTravelTime;
+ }
+ }
+ var lambdarad = Math.atan2(y, x);
+ var lambda = CT.r2D(lambdarad);
+ var betarad = Math.atan2(z, Math.sqrt(x * x + y * y));
+ var beta = CT.r2D(betarad);
+ details.DE = CT.r2D(Math.asin(-Math.sin(Beta0rad) * Math.sin(betarad) - Math.cos(Beta0rad) * Math.cos(betarad) * Math.cos(Lambda0rad - lambdarad)));
+ var N = 49.5581 + 0.7721 * T;
+ var Nrad = CT.d2R(N);
+ var ldash = l - 0.00697 / r;
+ var ldashrad = CT.d2R(ldash);
+ var bdash = b - 0.000225 * (Math.cos(lrad - Nrad) / r);
+ var bdashrad = CT.d2R(bdash);
+ details.DS = CT.r2D(Math.asin(-Math.sin(Beta0rad) * Math.sin(bdashrad) - Math.cos(Beta0rad) * Math.cos(bdashrad) * Math.cos(Lambda0rad - ldashrad)));
+ var W = CT.m360(11.504 + 350.89200025 * (JD - LightTravelTime - 2433282.5));
+ var e0 = CAANutation.meanObliquityOfEcliptic(JD);
+ var e0rad = CT.d2R(e0);
+ var PoleEquatorial = CT.ec2Eq(Lambda0, Beta0, e0);
+ var alpha0rad = CT.h2R(PoleEquatorial.x);
+ var delta0rad = CT.d2R(PoleEquatorial.y);
+ var u = y * Math.cos(e0rad) - z * Math.sin(e0rad);
+ var v = y * Math.sin(e0rad) + z * Math.cos(e0rad);
+ var alpharad = Math.atan2(u, x);
+ var alpha = CT.r2H(alpharad);
+ var deltarad = Math.atan2(v, Math.sqrt(x * x + u * u));
+ var delta = CT.r2D(deltarad);
+ var xi = Math.atan2(Math.sin(delta0rad) * Math.cos(deltarad) * Math.cos(alpha0rad - alpharad) - Math.sin(deltarad) * Math.cos(delta0rad), Math.cos(deltarad) * Math.sin(alpha0rad - alpharad));
+ details.w = CT.m360(W - CT.r2D(xi));
+ var NutationInLongitude = CAANutation.nutationInLongitude(JD);
+ var NutationInObliquity = CAANutation.nutationInObliquity(JD);
+ lambda += 0.005693 * Math.cos(l0rad - lambdarad) / Math.cos(betarad);
+ beta += 0.005693 * Math.sin(l0rad - lambdarad) * Math.sin(betarad);
+ Lambda0 += NutationInLongitude / 3600;
+ Lambda0rad = CT.d2R(Lambda0);
+ lambda += NutationInLongitude / 3600;
+ lambdarad = CT.d2R(lambda);
+ e0 += NutationInObliquity / 3600;
+ e0rad = CT.d2R(e0rad);
+ var ApparentPoleEquatorial = CT.ec2Eq(Lambda0, Beta0, e0);
+ var alpha0dash = CT.h2R(ApparentPoleEquatorial.x);
+ var delta0dash = CT.d2R(ApparentPoleEquatorial.y);
+ var ApparentMars = CT.ec2Eq(lambda, beta, e0);
+ var alphadash = CT.h2R(ApparentMars.x);
+ var deltadash = CT.d2R(ApparentMars.y);
+ details.p = CT.m360(CT.r2D(Math.atan2(Math.cos(delta0dash) * Math.sin(alpha0dash - alphadash), Math.sin(delta0dash) * Math.cos(deltadash) - Math.cos(delta0dash) * Math.sin(deltadash) * Math.cos(alpha0dash - alphadash))));
+ var SunLambda = CAASun.geometricEclipticLongitude(JD);
+ var SunBeta = CAASun.geometricEclipticLatitude(JD);
+ var SunEquatorial = CT.ec2Eq(SunLambda, SunBeta, e0);
+ details.x = MIFR.positionAngle(SunEquatorial.x, SunEquatorial.y, alpha, delta);
+ details.d = 9.36 / DELTA;
+ details.k = IFR.illuminatedFraction2(r, R, DELTA);
+ details.q = (1 - details.k) * details.d;
+ return details;
+};
+
+var CAAPhysicalMars$ = {};
+
+registerType("CAAPhysicalMars", [CAAPhysicalMars, CAAPhysicalMars$, null]);
diff --git a/engine/esm/astrocalc/physical_sun.js b/engine/esm/astrocalc/physical_sun.js
new file mode 100644
index 00000000..0d6ff315
--- /dev/null
+++ b/engine/esm/astrocalc/physical_sun.js
@@ -0,0 +1,83 @@
+// Originally `AAPHYSICALSUN.CPP`
+// "Purpose: Implementation for the algorithms which obtain the physical parameters of the Sun"
+// Last update of original: PJN / 16-06-2004
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+import { CAANutation } from "./nutation.js";
+import { CAAEarth } from "./earth.js";
+
+
+// CAAPhysicalSunDetails
+
+export function CAAPhysicalSunDetails() {
+ this.p = 0;
+ this.b0 = 0;
+ this.l0 = 0;
+ this.p = 0;
+ this.b0 = 0;
+ this.l0 = 0;
+}
+
+var CAAPhysicalSunDetails$ = {};
+
+registerType("CAAPhysicalSunDetails", [CAAPhysicalSunDetails, CAAPhysicalSunDetails$, null]);
+
+
+// CAAPhysicalSun
+
+export function CAAPhysicalSun() { }
+
+CAAPhysicalSun.calculate = function (JD) {
+ var theta = CT.m360((JD - 2398220) * 360 / 25.38);
+ var I = 7.25;
+ var K = 73.6667 + 1.3958333 * (JD - 2396758) / 36525;
+ var L = CAAEarth.eclipticLongitude(JD);
+ var R = CAAEarth.radiusVector(JD);
+ var SunLong = L + 180 - CT.dmS2D(0, 0, 20.4898 / R);
+ var SunLongDash = SunLong + CT.dmS2D(0, 0, CAANutation.nutationInLongitude(JD));
+ var epsilon = CAANutation.trueObliquityOfEcliptic(JD);
+ epsilon = CT.d2R(epsilon);
+ SunLong = CT.d2R(SunLong);
+ SunLongDash = CT.d2R(SunLongDash);
+ K = CT.d2R(K);
+ I = CT.d2R(I);
+ theta = CT.d2R(theta);
+ var x = Math.atan(-Math.cos(SunLong) * Math.tan(epsilon));
+ var y = Math.atan(-Math.cos(SunLong - K) * Math.tan(I));
+ var details = new CAAPhysicalSunDetails();
+ details.p = CT.r2D(x + y);
+ details.b0 = CT.r2D(Math.asin(Math.sin(SunLong - K) * Math.sin(I)));
+ var eta = Math.atan(Math.tan(SunLong - K) * Math.cos(I));
+ details.l0 = CT.m360(CT.r2D(eta - theta));
+ return details;
+};
+
+CAAPhysicalSun.timeOfStartOfRotation = function (C) {
+ var JED = 2398140.227 + 27.2752316 * C;
+ var M = CT.m360(281.96 + 26.882476 * C);
+ M = CT.d2R(M);
+ JED += (0.1454 * Math.sin(M) - 0.0085 * Math.sin(2 * M) - 0.0141 * Math.cos(2 * M));
+ return JED;
+};
+
+var CAAPhysicalSun$ = {};
+
+registerType("CAAPhysicalSun", [CAAPhysicalSun, CAAPhysicalSun$, null]);
diff --git a/engine/esm/astrocalc/pluto.js b/engine/esm/astrocalc/pluto.js
new file mode 100644
index 00000000..5a36ba58
--- /dev/null
+++ b/engine/esm/astrocalc/pluto.js
@@ -0,0 +1,122 @@
+// Originally `AAPLUTO.CPP`
+// "Purpose: Implementation for the algorithms which obtain the heliocentric position of Pluto"
+// Last update of original: PJN / 29-12-2003
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+
+
+// PlutoCoefficient1
+
+export function PlutoCoefficient1(j, s, p) {
+ this.j = 0;
+ this.s = 0;
+ this.p = 0;
+ this.j = j;
+ this.s = s;
+ this.p = p;
+}
+
+var PlutoCoefficient1$ = {};
+
+registerType("PlutoCoefficient1", [PlutoCoefficient1, PlutoCoefficient1$, null]);
+
+
+// PlutoCoefficient2
+
+export function PlutoCoefficient2(a, b) {
+ this.a = 0;
+ this.b = 0;
+ this.a = a;
+ this.b = b;
+}
+
+var PlutoCoefficient2$ = {};
+
+registerType("PlutoCoefficient2", [PlutoCoefficient2, PlutoCoefficient2$, null]);
+
+
+// Coefficients
+
+const g_PlutoArgumentCoefficients = [new PlutoCoefficient1(0, 0, 1), new PlutoCoefficient1(0, 0, 2), new PlutoCoefficient1(0, 0, 3), new PlutoCoefficient1(0, 0, 4), new PlutoCoefficient1(0, 0, 5), new PlutoCoefficient1(0, 0, 6), new PlutoCoefficient1(0, 1, -1), new PlutoCoefficient1(0, 1, 0), new PlutoCoefficient1(0, 1, 1), new PlutoCoefficient1(0, 1, 2), new PlutoCoefficient1(0, 1, 3), new PlutoCoefficient1(0, 2, -2), new PlutoCoefficient1(0, 2, -1), new PlutoCoefficient1(0, 2, 0), new PlutoCoefficient1(1, -1, 0), new PlutoCoefficient1(1, -1, 1), new PlutoCoefficient1(1, 0, -3), new PlutoCoefficient1(1, 0, -2), new PlutoCoefficient1(1, 0, -1), new PlutoCoefficient1(1, 0, 0), new PlutoCoefficient1(1, 0, 1), new PlutoCoefficient1(1, 0, 2), new PlutoCoefficient1(1, 0, 3), new PlutoCoefficient1(1, 0, 4), new PlutoCoefficient1(1, 1, -3), new PlutoCoefficient1(1, 1, -2), new PlutoCoefficient1(1, 1, -1), new PlutoCoefficient1(1, 1, 0), new PlutoCoefficient1(1, 1, 1), new PlutoCoefficient1(1, 1, 3), new PlutoCoefficient1(2, 0, -6), new PlutoCoefficient1(2, 0, -5), new PlutoCoefficient1(2, 0, -4), new PlutoCoefficient1(2, 0, -3), new PlutoCoefficient1(2, 0, -2), new PlutoCoefficient1(2, 0, -1), new PlutoCoefficient1(2, 0, 0), new PlutoCoefficient1(2, 0, 1), new PlutoCoefficient1(2, 0, 2), new PlutoCoefficient1(2, 0, 3), new PlutoCoefficient1(3, 0, -2), new PlutoCoefficient1(3, 0, -1), new PlutoCoefficient1(3, 0, 0)];
+const g_PlutoLongitudeCoefficients = [new PlutoCoefficient2(-19799805, 19850055), new PlutoCoefficient2(897144, -4954829), new PlutoCoefficient2(611149, 1211027), new PlutoCoefficient2(-341243, -189585), new PlutoCoefficient2(129287, -34992), new PlutoCoefficient2(-38164, 30893), new PlutoCoefficient2(20442, -9987), new PlutoCoefficient2(-4063, -5071), new PlutoCoefficient2(-6016, -3336), new PlutoCoefficient2(-3956, 3039), new PlutoCoefficient2(-667, 3572), new PlutoCoefficient2(1276, 501), new PlutoCoefficient2(1152, -917), new PlutoCoefficient2(630, -1277), new PlutoCoefficient2(2571, -459), new PlutoCoefficient2(899, -1449), new PlutoCoefficient2(-1016, 1043), new PlutoCoefficient2(-2343, -1012), new PlutoCoefficient2(7042, 788), new PlutoCoefficient2(1199, -338), new PlutoCoefficient2(418, -67), new PlutoCoefficient2(120, -274), new PlutoCoefficient2(-60, -159), new PlutoCoefficient2(-82, -29), new PlutoCoefficient2(-36, -29), new PlutoCoefficient2(-40, 7), new PlutoCoefficient2(-14, 22), new PlutoCoefficient2(4, 13), new PlutoCoefficient2(5, 2), new PlutoCoefficient2(-1, 0), new PlutoCoefficient2(2, 0), new PlutoCoefficient2(-4, 5), new PlutoCoefficient2(4, -7), new PlutoCoefficient2(14, 24), new PlutoCoefficient2(-49, -34), new PlutoCoefficient2(163, -48), new PlutoCoefficient2(9, -24), new PlutoCoefficient2(-4, 1), new PlutoCoefficient2(-3, 1), new PlutoCoefficient2(1, 3), new PlutoCoefficient2(-3, -1), new PlutoCoefficient2(5, -3), new PlutoCoefficient2(0, 0)];
+const g_PlutoLatitudeCoefficients = [new PlutoCoefficient2(-5452852, -14974862), new PlutoCoefficient2(3527812, 1672790), new PlutoCoefficient2(-1050748, 327647), new PlutoCoefficient2(178690, -292153), new PlutoCoefficient2(18650, 100340), new PlutoCoefficient2(-30697, -25823), new PlutoCoefficient2(4878, 11248), new PlutoCoefficient2(226, -64), new PlutoCoefficient2(2030, -836), new PlutoCoefficient2(69, -604), new PlutoCoefficient2(-247, -567), new PlutoCoefficient2(-57, 1), new PlutoCoefficient2(-122, 175), new PlutoCoefficient2(-49, -164), new PlutoCoefficient2(-197, 199), new PlutoCoefficient2(-25, 217), new PlutoCoefficient2(589, -248), new PlutoCoefficient2(-269, 711), new PlutoCoefficient2(185, 193), new PlutoCoefficient2(315, 807), new PlutoCoefficient2(-130, -43), new PlutoCoefficient2(5, 3), new PlutoCoefficient2(2, 17), new PlutoCoefficient2(2, 5), new PlutoCoefficient2(2, 3), new PlutoCoefficient2(3, 1), new PlutoCoefficient2(2, -1), new PlutoCoefficient2(1, -1), new PlutoCoefficient2(0, -1), new PlutoCoefficient2(0, 0), new PlutoCoefficient2(0, -2), new PlutoCoefficient2(2, 2), new PlutoCoefficient2(-7, 0), new PlutoCoefficient2(10, -8), new PlutoCoefficient2(-3, 20), new PlutoCoefficient2(6, 5), new PlutoCoefficient2(14, 17), new PlutoCoefficient2(-2, 0), new PlutoCoefficient2(0, 0), new PlutoCoefficient2(0, 0), new PlutoCoefficient2(0, 1), new PlutoCoefficient2(0, 0), new PlutoCoefficient2(1, 0)];
+const g_PlutoRadiusCoefficients = [new PlutoCoefficient2(66865439, 68951812), new PlutoCoefficient2(-11827535, -332538), new PlutoCoefficient2(1593179, -1438890), new PlutoCoefficient2(-18444, 483220), new PlutoCoefficient2(-65977, -85431), new PlutoCoefficient2(31174, -6032), new PlutoCoefficient2(-5794, 22161), new PlutoCoefficient2(4601, 4032), new PlutoCoefficient2(-1729, 234), new PlutoCoefficient2(-415, 702), new PlutoCoefficient2(239, 723), new PlutoCoefficient2(67, -67), new PlutoCoefficient2(1034, -451), new PlutoCoefficient2(-129, 504), new PlutoCoefficient2(480, -231), new PlutoCoefficient2(2, -441), new PlutoCoefficient2(-3359, 265), new PlutoCoefficient2(7856, -7832), new PlutoCoefficient2(36, 45763), new PlutoCoefficient2(8663, 8547), new PlutoCoefficient2(-809, -769), new PlutoCoefficient2(263, -144), new PlutoCoefficient2(-126, 32), new PlutoCoefficient2(-35, -16), new PlutoCoefficient2(-19, -4), new PlutoCoefficient2(-15, 8), new PlutoCoefficient2(-4, 12), new PlutoCoefficient2(5, 6), new PlutoCoefficient2(3, 1), new PlutoCoefficient2(6, -2), new PlutoCoefficient2(2, 2), new PlutoCoefficient2(-2, -2), new PlutoCoefficient2(14, 13), new PlutoCoefficient2(-63, 13), new PlutoCoefficient2(136, -236), new PlutoCoefficient2(273, 1065), new PlutoCoefficient2(251, 149), new PlutoCoefficient2(-25, -9), new PlutoCoefficient2(9, -2), new PlutoCoefficient2(-8, 7), new PlutoCoefficient2(2, -10), new PlutoCoefficient2(19, 35), new PlutoCoefficient2(10, 3)];
+
+
+// CAAPluto
+
+export function CAAPluto() { }
+
+CAAPluto.eclipticLongitude = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var J = 34.35 + 3034.9057 * T;
+ var S = 50.08 + 1222.1138 * T;
+ var P = 238.96 + 144.96 * T;
+ var L = 0;
+ var nPlutoCoefficients = g_PlutoArgumentCoefficients.length;
+ for (var i = 0; i < nPlutoCoefficients; i++) {
+ var Alpha = g_PlutoArgumentCoefficients[i].j * J + g_PlutoArgumentCoefficients[i].s * S + g_PlutoArgumentCoefficients[i].p * P;
+ Alpha = CT.d2R(Alpha);
+ L += ((g_PlutoLongitudeCoefficients[i].a * Math.sin(Alpha)) + (g_PlutoLongitudeCoefficients[i].b * Math.cos(Alpha)));
+ }
+ L = L / 1000000;
+ L += (238.958116 + 144.96 * T);
+ L = CT.m360(L);
+ return L;
+};
+
+CAAPluto.eclipticLatitude = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var J = 34.35 + 3034.9057 * T;
+ var S = 50.08 + 1222.1138 * T;
+ var P = 238.96 + 144.96 * T;
+ var L = 0;
+ var nPlutoCoefficients = g_PlutoArgumentCoefficients.length;
+ for (var i = 0; i < nPlutoCoefficients; i++) {
+ var Alpha = g_PlutoArgumentCoefficients[i].j * J + g_PlutoArgumentCoefficients[i].s * S + g_PlutoArgumentCoefficients[i].p * P;
+ Alpha = CT.d2R(Alpha);
+ L += ((g_PlutoLatitudeCoefficients[i].a * Math.sin(Alpha)) + (g_PlutoLatitudeCoefficients[i].b * Math.cos(Alpha)));
+ }
+ L = L / 1000000;
+ L += -3.908239;
+ return L;
+};
+
+CAAPluto.radiusVector = function (JD) {
+ var T = (JD - 2451545) / 36525;
+ var J = 34.35 + 3034.9057 * T;
+ var S = 50.08 + 1222.1138 * T;
+ var P = 238.96 + 144.96 * T;
+ var R = 0;
+ var nPlutoCoefficients = g_PlutoArgumentCoefficients.length;
+ for (var i = 0; i < nPlutoCoefficients; i++) {
+ var Alpha = g_PlutoArgumentCoefficients[i].j * J + g_PlutoArgumentCoefficients[i].s * S + g_PlutoArgumentCoefficients[i].p * P;
+ Alpha = CT.d2R(Alpha);
+ R += ((g_PlutoRadiusCoefficients[i].a * Math.sin(Alpha)) + (g_PlutoRadiusCoefficients[i].b * Math.cos(Alpha)));
+ }
+ R = R / 10000000;
+ R += 40.7241346;
+ return R;
+};
+
+var CAAPluto$ = {};
+
+registerType("CAAPluto", [CAAPluto, CAAPluto$, null]);
diff --git a/engine/esm/astrocalc/precession.js b/engine/esm/astrocalc/precession.js
new file mode 100644
index 00000000..87e7632c
--- /dev/null
+++ b/engine/esm/astrocalc/precession.js
@@ -0,0 +1,154 @@
+// Originally `AAPRECESSION.CPP`
+// "Purpose: Implementation for the algorithms for Precession"
+// Last update of original: PJN / 29-12-2003
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { COR, CT } from "./coordinate_transformation.js";
+
+
+// CAAPrecession
+
+export function CAAPrecession() { }
+
+CAAPrecession.precessEquatorial = function (Alpha, Delta, JD0, JD) {
+ var T = (JD0 - 2451545) / 36525;
+ var Tsquared = T * T;
+ var t = (JD - JD0) / 36525;
+ var tsquared = t * t;
+ var tcubed = tsquared * t;
+ Alpha = CT.h2R(Alpha);
+ Delta = CT.d2R(Delta);
+ var sigma = (2306.2181 + 1.39656 * T - 0.000139 * Tsquared) * t + (0.30188 - 3.44E-05 * T) * tsquared + 0.017988 * tcubed;
+ sigma = CT.d2R(CT.dmS2D(0, 0, sigma));
+ var zeta = (2306.2181 + 1.39656 * T - 0.000138 * Tsquared) * t + (1.09468 + 6.6E-05 * T) * tsquared + 0.018203 * tcubed;
+ zeta = CT.d2R(CT.dmS2D(0, 0, zeta));
+ var phi = (2004.3109 - 0.8533 * T - 0.000217 * Tsquared) * t - (0.42665 + 0.000217 * T) * tsquared - 0.041833 * tcubed;
+ phi = CT.d2R(CT.dmS2D(0, 0, phi));
+ var A = Math.cos(Delta) * Math.sin(Alpha + sigma);
+ var B = Math.cos(phi) * Math.cos(Delta) * Math.cos(Alpha + sigma) - Math.sin(phi) * Math.sin(Delta);
+ var C = Math.sin(phi) * Math.cos(Delta) * Math.cos(Alpha + sigma) + Math.cos(phi) * Math.sin(Delta);
+ var vvalue = new COR();
+ vvalue.x = CT.r2H(Math.atan2(A, B) + zeta);
+ if (vvalue.x < 0) {
+ vvalue.x += 24;
+ }
+ vvalue.y = CT.r2D(Math.asin(C));
+ return vvalue;
+};
+
+CAAPrecession.precessEquatorialFK4 = function (Alpha, Delta, JD0, JD) {
+ var T = (JD0 - 2415020.3135) / 36524.2199;
+ var t = (JD - JD0) / 36524.2199;
+ var tsquared = t * t;
+ var tcubed = tsquared * t;
+ Alpha = CT.h2R(Alpha);
+ Delta = CT.d2R(Delta);
+ var sigma = (2304.25 + 1.396 * T) * t + 0.302 * tsquared + 0.018 * tcubed;
+ sigma = CT.d2R(CT.dmS2D(0, 0, sigma));
+ var zeta = 0.791 * tsquared + 0.001 * tcubed;
+ zeta = CT.d2R(CT.dmS2D(0, 0, zeta));
+ zeta += sigma;
+ var phi = (2004.682 - 0.853 * T) * t - 0.426 * tsquared - 0.042 * tcubed;
+ phi = CT.d2R(CT.dmS2D(0, 0, phi));
+ var A = Math.cos(Delta) * Math.sin(Alpha + sigma);
+ var B = Math.cos(phi) * Math.cos(Delta) * Math.cos(Alpha + sigma) - Math.sin(phi) * Math.sin(Delta);
+ var C = Math.sin(phi) * Math.cos(Delta) * Math.cos(Alpha + sigma) + Math.cos(phi) * Math.sin(Delta);
+ var vvalue = new COR();
+ vvalue.x = CT.r2H(Math.atan2(A, B) + zeta);
+ if (vvalue.x < 0) {
+ vvalue.x += 24;
+ }
+ vvalue.y = CT.r2D(Math.asin(C));
+ return vvalue;
+};
+
+CAAPrecession.precessEcliptic = function (Lambda, Beta, JD0, JD) {
+ var T = (JD0 - 2451545) / 36525;
+ var Tsquared = T * T;
+ var t = (JD - JD0) / 36525;
+ var tsquared = t * t;
+ var tcubed = tsquared * t;
+ Lambda = CT.d2R(Lambda);
+ Beta = CT.d2R(Beta);
+ var eta = (47.0029 - 0.06603 * T + 0.000598 * Tsquared) * t + (-0.03302 + 0.000598 * T) * tsquared + 6E-05 * tcubed;
+ eta = CT.d2R(CT.dmS2D(0, 0, eta));
+ var pi = 174.876384 * 3600 + 3289.4789 * T + 0.60622 * Tsquared - (869.8089 + 0.50491 * T) * t + 0.03536 * tsquared;
+ pi = CT.d2R(CT.dmS2D(0, 0, pi));
+ var p = (5029.0966 + 2.22226 * T - 4.2E-05 * Tsquared) * t + (1.11113 - 4.2E-05 * T) * tsquared - 6E-06 * tcubed;
+ p = CT.d2R(CT.dmS2D(0, 0, p));
+ var A = Math.cos(eta) * Math.cos(Beta) * Math.sin(pi - Lambda) - Math.sin(eta) * Math.sin(Beta);
+ var B = Math.cos(Beta) * Math.cos(pi - Lambda);
+ var C = Math.cos(eta) * Math.sin(Beta) + Math.sin(eta) * Math.cos(Beta) * Math.sin(pi - Lambda);
+ var vvalue = new COR();
+ vvalue.x = CT.r2D(p + pi - Math.atan2(A, B));
+ if (vvalue.x < 0) {
+ vvalue.x += 360;
+ }
+ vvalue.y = CT.r2D(Math.asin(C));
+ return vvalue;
+};
+
+CAAPrecession.equatorialPMToEcliptic = function (Alpha, Delta, Beta, PMAlpha, PMDelta, Epsilon) {
+ Epsilon = CT.d2R(Epsilon);
+ Alpha = CT.h2R(Alpha);
+ Delta = CT.d2R(Delta);
+ Beta = CT.d2R(Beta);
+ var cosb = Math.cos(Beta);
+ var sinEpsilon = Math.sin(Epsilon);
+ var vvalue = new COR();
+ vvalue.x = (PMDelta * sinEpsilon * Math.cos(Alpha) + PMAlpha * Math.cos(Delta) * (Math.cos(Epsilon) * Math.cos(Delta) + sinEpsilon * Math.sin(Delta) * Math.sin(Alpha))) / (cosb * cosb);
+ vvalue.y = (PMDelta * (Math.cos(Epsilon) * Math.cos(Delta) + sinEpsilon * Math.sin(Delta) * Math.sin(Alpha)) - PMAlpha * sinEpsilon * Math.cos(Alpha) * Math.cos(Delta)) / cosb;
+ return vvalue;
+};
+
+CAAPrecession.adjustPositionUsingUniformProperMotion = function (t, Alpha, Delta, PMAlpha, PMDelta) {
+ var vvalue = new COR();
+ vvalue.x = Alpha + (PMAlpha * t / 3600);
+ vvalue.y = Delta + (PMDelta * t / 3600);
+ return vvalue;
+};
+
+CAAPrecession.adjustPositionUsingMotionInSpace = function (r, DeltaR, t, Alpha, Delta, PMAlpha, PMDelta) {
+ DeltaR /= 977792;
+ PMAlpha /= 13751;
+ PMDelta /= 206265;
+ Alpha = CT.h2R(Alpha);
+ Delta = CT.d2R(Delta);
+ var x = r * Math.cos(Delta) * Math.cos(Alpha);
+ var y = r * Math.cos(Delta) * Math.sin(Alpha);
+ var z = r * Math.sin(Delta);
+ var DeltaX = x / r * DeltaR - z * PMDelta * Math.cos(Alpha) - y * PMAlpha;
+ var DeltaY = y / r * DeltaR - z * PMDelta * Math.sin(Alpha) + x * PMAlpha;
+ var DeltaZ = z / r * DeltaR + r * PMDelta * Math.cos(Delta);
+ x += t * DeltaX;
+ y += t * DeltaY;
+ z += t * DeltaZ;
+ var vvalue = new COR();
+ vvalue.x = CT.r2H(Math.atan2(y, x));
+ if (vvalue.x < 0) {
+ vvalue.x += 24;
+ }
+ vvalue.y = CT.r2D(Math.atan2(z, Math.sqrt(x * x + y * y)));
+ return vvalue;
+};
+
+var CAAPrecession$ = {};
+
+registerType("CAAPrecession", [CAAPrecession, CAAPrecession$, null]);
diff --git a/engine/esm/astrocalc/rise_transit_set.js b/engine/esm/astrocalc/rise_transit_set.js
new file mode 100644
index 00000000..770b9ce1
--- /dev/null
+++ b/engine/esm/astrocalc/rise_transit_set.js
@@ -0,0 +1,126 @@
+// Originally `AARISETRANSITSET.CPP`
+// "Purpose: Implementation for the algorithms which obtain the Rise, Transit and Set times"
+// Last update of original: PJN / 15-10-2004
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+import { DYT } from "./dynamical_time.js";
+import { INTP } from "./interpolate.js";
+import { CAASidereal } from "./sidereal.js";
+
+
+// CAARiseTransitSetDetails
+
+export function CAARiseTransitSetDetails() {
+ this.bValid = false;
+ this.rise = 0;
+ this.transit = 0;
+ this.set = 0;
+ this.bValid = false;
+ this.rise = 0;
+ this.transit = 0;
+ this.set = 0;
+}
+
+var CAARiseTransitSetDetails$ = {};
+
+registerType("CAARiseTransitSetDetails", [CAARiseTransitSetDetails, CAARiseTransitSetDetails$, null]);
+
+
+// CAARiseTransitSet
+
+export function CAARiseTransitSet() { }
+
+CAARiseTransitSet.rise = function (JD, Alpha1, Delta1, Alpha2, Delta2, Alpha3, Delta3, Longitude, Latitude, h0) {
+ var details = new CAARiseTransitSetDetails();
+ details.bValid = false;
+ var theta0 = CAASidereal.apparentGreenwichSiderealTime(JD);
+ theta0 *= 15;
+ var deltaT = DYT.deltaT(JD);
+ var Delta2Rad = CT.d2R(Delta2);
+ var LatitudeRad = CT.d2R(Latitude);
+ var h0Rad = CT.d2R(h0);
+ var cosH0 = (Math.sin(h0Rad) - Math.sin(LatitudeRad) * Math.sin(Delta2Rad)) / (Math.cos(LatitudeRad) * Math.cos(Delta2Rad));
+ if ((cosH0 > 1) || (cosH0 < -1)) {
+ return details;
+ }
+ var H0 = Math.acos(cosH0);
+ H0 = CT.r2D(H0);
+ var M0 = (Alpha2 * 15 + Longitude - theta0) / 360;
+ var M1 = M0 - H0 / 360;
+ var M2 = M0 + H0 / 360;
+ if (M0 > 1) {
+ M0 -= 1;
+ }
+ else if (M0 < 0) {
+ M0 += 1;
+ }
+ if (M1 > 1) {
+ M1 -= 1;
+ }
+ else if (M1 < 0) {
+ M1 += 1;
+ }
+ if (M2 > 1) {
+ M2 -= 1;
+ }
+ else if (M2 < 0) {
+ M2 += 1;
+ }
+ for (var i = 0; i < 2; i++) {
+ var theta1 = theta0 + 360.985647 * M1;
+ theta1 = CT.m360(theta1);
+ var n = M1 + deltaT / 86400;
+ var Alpha = INTP.interpolate(n, Alpha1, Alpha2, Alpha3);
+ var Delta = INTP.interpolate(n, Delta1, Delta2, Delta3);
+ var H = theta1 - Longitude - Alpha * 15;
+ var Horizontal = CT.eq2H(H / 15, Delta, Latitude);
+ var DeltaM = (Horizontal.y - h0) / (360 * Math.cos(CT.d2R(Delta)) * Math.cos(LatitudeRad) * Math.sin(CT.d2R(H)));
+ M1 += DeltaM;
+ theta1 = theta0 + 360.985647 * M0;
+ theta1 = CT.m360(theta1);
+ n = M0 + deltaT / 86400;
+ Alpha = INTP.interpolate(n, Alpha1, Alpha2, Alpha3);
+ H = theta1 - Longitude - Alpha * 15;
+ if (H < -180) {
+ H += 360;
+ }
+ DeltaM = -H / 360;
+ M0 += DeltaM;
+ theta1 = theta0 + 360.985647 * M2;
+ theta1 = CT.m360(theta1);
+ n = M2 + deltaT / 86400;
+ Alpha = INTP.interpolate(n, Alpha1, Alpha2, Alpha3);
+ Delta = INTP.interpolate(n, Delta1, Delta2, Delta3);
+ H = theta1 - Longitude - Alpha * 15;
+ Horizontal = CT.eq2H(H / 15, Delta, Latitude);
+ DeltaM = (Horizontal.y - h0) / (360 * Math.cos(CT.d2R(Delta)) * Math.cos(LatitudeRad) * Math.sin(CT.d2R(H)));
+ M2 += DeltaM;
+ }
+ details.bValid = true;
+ details.rise = M1 * 24;
+ details.set = M2 * 24;
+ details.transit = M0 * 24;
+ return details;
+};
+
+var CAARiseTransitSet$ = {};
+
+registerType("CAARiseTransitSet", [CAARiseTransitSet, CAARiseTransitSet$, null]);
diff --git a/engine/esm/astrocalc/saturn.js b/engine/esm/astrocalc/saturn.js
new file mode 100644
index 00000000..43a92596
--- /dev/null
+++ b/engine/esm/astrocalc/saturn.js
@@ -0,0 +1,179 @@
+// Originally `AASATURN.CPP`
+// "Purpose: Implementation for the algorithms which obtain the heliocentric position of Saturn"
+// Last update of original: PJN / 31-05-2004
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+import { VSC } from "./earth.js";
+
+
+// Coefficients
+
+const g_L0SaturnCoefficients = [new VSC(87401354, 0, 0), new VSC(11107660, 3.9620509, 213.29909544), new VSC(1414151, 4.5858152, 7.113547), new VSC(398379, 0.52112, 206.185548), new VSC(350769, 3.303299, 426.598191), new VSC(206816, 0.246584, 103.092774), new VSC(79271, 3.84007, 220.41264), new VSC(23990, 4.66977, 110.20632), new VSC(16574, 0.43719, 419.48464), new VSC(15820, 0.93809, 632.78374), new VSC(15054, 2.7167, 639.89729), new VSC(14907, 5.76903, 316.39187), new VSC(14610, 1.56519, 3.93215), new VSC(13160, 4.44891, 14.22709), new VSC(13005, 5.98119, 11.0457), new VSC(10725, 3.1294, 202.2534), new VSC(6126, 1.7633, 277.035), new VSC(5863, 0.2366, 529.691), new VSC(5228, 4.2078, 3.1814), new VSC(5020, 3.1779, 433.7117), new VSC(4593, 0.6198, 199.072), new VSC(4006, 2.2448, 63.7359), new VSC(3874, 3.2228, 138.5175), new VSC(3269, 0.7749, 949.1756), new VSC(2954, 0.9828, 95.9792), new VSC(2461, 2.0316, 735.8765), new VSC(1758, 3.2658, 522.5774), new VSC(1640, 5.505, 846.0828), new VSC(1581, 4.3727, 309.2783), new VSC(1391, 4.0233, 323.5054), new VSC(1124, 2.8373, 415.5525), new VSC(1087, 4.1834, 2.4477), new VSC(1017, 3.717, 227.5262), new VSC(957, 0.507, 1265.567), new VSC(853, 3.421, 175.166), new VSC(849, 3.191, 209.367), new VSC(789, 5.007, 0.963), new VSC(749, 2.144, 853.196), new VSC(744, 5.253, 224.345), new VSC(687, 1.747, 1052.268), new VSC(654, 1.599, 0.048), new VSC(634, 2.299, 412.371), new VSC(625, 0.97, 210.118), new VSC(580, 3.093, 74.782), new VSC(546, 2.127, 350.332), new VSC(543, 1.518, 9.561), new VSC(530, 4.449, 117.32), new VSC(478, 2.965, 137.033), new VSC(474, 5.475, 742.99), new VSC(452, 1.044, 490.334), new VSC(449, 1.29, 127.472), new VSC(372, 2.278, 217.231), new VSC(355, 3.013, 838.969), new VSC(347, 1.539, 340.771), new VSC(343, 0.246, 0.521), new VSC(330, 0.247, 1581.959), new VSC(322, 0.961, 203.738), new VSC(322, 2.572, 647.011), new VSC(309, 3.495, 216.48), new VSC(287, 2.37, 351.817), new VSC(278, 0.4, 211.815), new VSC(249, 1.47, 1368.66), new VSC(227, 4.91, 12.53), new VSC(220, 4.204, 200.769), new VSC(209, 1.345, 625.67), new VSC(208, 0.483, 1162.475), new VSC(208, 1.283, 39.357), new VSC(204, 6.011, 265.989), new VSC(185, 3.503, 149.563), new VSC(184, 0.973, 4.193), new VSC(182, 5.491, 2.921), new VSC(174, 1.863, 0.751), new VSC(165, 0.44, 5.417), new VSC(149, 5.736, 52.69), new VSC(148, 1.535, 5.629), new VSC(146, 6.231, 195.14), new VSC(140, 4.295, 21.341), new VSC(131, 4.068, 10.295), new VSC(125, 6.277, 1898.351), new VSC(122, 1.976, 4.666), new VSC(118, 5.341, 554.07), new VSC(117, 2.679, 1155.361), new VSC(114, 5.594, 1059.382), new VSC(112, 1.105, 191.208), new VSC(110, 0.166, 1.484), new VSC(109, 3.438, 536.805), new VSC(107, 4.012, 956.289), new VSC(104, 2.192, 88.866), new VSC(103, 1.197, 1685.052), new VSC(101, 4.965, 269.921)];
+const g_L1SaturnCoefficients = [new VSC(21354295596, 0, 0), new VSC(1296855, 1.8282054, 213.2990954), new VSC(564348, 2.885001, 7.113547), new VSC(107679, 2.277699, 206.185548), new VSC(98323, 1.0807, 426.59819), new VSC(40255, 2.04128, 220.41264), new VSC(19942, 1.27955, 103.09277), new VSC(10512, 2.7488, 14.22709), new VSC(6939, 0.4049, 639.8973), new VSC(4803, 2.4419, 419.4846), new VSC(4056, 2.9217, 110.2063), new VSC(3769, 3.6497, 3.9322), new VSC(3385, 2.4169, 3.1814), new VSC(3302, 1.2626, 433.7117), new VSC(3071, 2.3274, 199.072), new VSC(1953, 3.5639, 11.0457), new VSC(1249, 2.628, 95.9792), new VSC(922, 1.961, 227.526), new VSC(706, 4.417, 529.691), new VSC(650, 6.174, 202.253), new VSC(628, 6.111, 309.278), new VSC(487, 6.04, 853.196), new VSC(479, 4.988, 522.577), new VSC(468, 4.617, 63.736), new VSC(417, 2.117, 323.505), new VSC(408, 1.299, 209.367), new VSC(352, 2.317, 632.784), new VSC(344, 3.959, 412.371), new VSC(340, 3.634, 316.392), new VSC(336, 3.772, 735.877), new VSC(332, 2.861, 210.118), new VSC(289, 2.733, 117.32), new VSC(281, 5.744, 2.448), new VSC(266, 0.543, 647.011), new VSC(230, 1.644, 216.48), new VSC(192, 2.965, 224.345), new VSC(173, 4.077, 846.083), new VSC(167, 2.597, 21.341), new VSC(136, 2.286, 10.295), new VSC(131, 3.441, 742.99), new VSC(128, 4.095, 217.231), new VSC(109, 6.161, 415.552), new VSC(98, 4.73, 838.97), new VSC(94, 3.48, 1052.27), new VSC(92, 3.95, 88.87), new VSC(87, 1.22, 440.83), new VSC(83, 3.11, 625.67), new VSC(78, 6.24, 302.16), new VSC(67, 0.29, 4.67), new VSC(66, 5.65, 9.56), new VSC(62, 4.29, 127.47), new VSC(62, 1.83, 195.14), new VSC(58, 2.48, 191.96), new VSC(57, 5.02, 137.03), new VSC(55, 0.28, 74.78), new VSC(54, 5.13, 490.33), new VSC(51, 1.46, 536.8), new VSC(47, 1.18, 149.56), new VSC(47, 5.15, 515.46), new VSC(46, 2.23, 956.29), new VSC(44, 2.71, 5.42), new VSC(40, 0.41, 269.92), new VSC(40, 3.89, 728.76), new VSC(38, 0.65, 422.67), new VSC(38, 2.53, 12.53), new VSC(37, 3.78, 2.92), new VSC(35, 6.08, 5.63), new VSC(34, 3.21, 1368.66), new VSC(33, 4.64, 277.03), new VSC(33, 5.43, 1066.5), new VSC(33, 0.3, 351.82), new VSC(32, 4.39, 1155.36), new VSC(31, 2.43, 52.69), new VSC(30, 2.84, 203), new VSC(30, 6.19, 284.15), new VSC(30, 3.39, 1059.38), new VSC(29, 2.03, 330.62), new VSC(28, 2.74, 265.99), new VSC(26, 4.51, 340.77)];
+const g_L2SaturnCoefficients = [new VSC(116441, 1.179879, 7.113547), new VSC(91921, 0.07425, 213.2991), new VSC(90592, 0, 0), new VSC(15277, 4.06492, 206.18555), new VSC(10631, 0.25778, 220.41264), new VSC(10605, 5.40964, 426.59819), new VSC(4265, 1.046, 14.2271), new VSC(1216, 2.9186, 103.0928), new VSC(1165, 4.6094, 639.8973), new VSC(1082, 5.6913, 433.7117), new VSC(1045, 4.0421, 199.072), new VSC(1020, 0.6337, 3.1814), new VSC(634, 4.388, 419.485), new VSC(549, 5.573, 3.932), new VSC(457, 1.268, 110.206), new VSC(425, 0.209, 227.526), new VSC(274, 4.288, 95.979), new VSC(162, 1.381, 11.046), new VSC(129, 1.566, 309.278), new VSC(117, 3.881, 853.196), new VSC(105, 4.9, 647.011), new VSC(101, 0.893, 21.341), new VSC(96, 2.91, 316.39), new VSC(95, 5.63, 412.37), new VSC(85, 5.73, 209.37), new VSC(83, 6.05, 216.48), new VSC(82, 1.02, 117.32), new VSC(75, 4.76, 210.12), new VSC(67, 0.46, 522.58), new VSC(66, 0.48, 10.29), new VSC(64, 0.35, 323.51), new VSC(61, 4.88, 632.78), new VSC(53, 2.75, 529.69), new VSC(46, 5.69, 440.83), new VSC(45, 1.67, 202.25), new VSC(42, 5.71, 88.87), new VSC(32, 0.07, 63.74), new VSC(32, 1.67, 302.16), new VSC(31, 4.16, 191.96), new VSC(27, 0.83, 224.34), new VSC(25, 5.66, 735.88), new VSC(20, 5.94, 217.23), new VSC(18, 4.9, 625.67), new VSC(17, 1.63, 742.99), new VSC(16, 0.58, 515.46), new VSC(14, 0.21, 838.97), new VSC(14, 3.76, 195.14), new VSC(12, 4.72, 203), new VSC(12, 0.13, 234.64), new VSC(12, 3.12, 846.08), new VSC(11, 5.92, 536.8), new VSC(11, 5.6, 728.76), new VSC(11, 3.2, 1066.5), new VSC(10, 4.99, 422.67), new VSC(10, 0.26, 330.62), new VSC(10, 4.15, 860.31), new VSC(9, 0.46, 956.29), new VSC(8, 2.14, 269.92), new VSC(8, 5.25, 429.78), new VSC(8, 4.03, 9.56), new VSC(7, 5.4, 1052.27), new VSC(6, 4.46, 284.15), new VSC(6, 5.93, 405.26)];
+const g_L3SaturnCoefficients = [new VSC(16039, 5.73945, 7.11355), new VSC(4250, 4.5854, 213.2991), new VSC(1907, 4.7608, 220.4126), new VSC(1466, 5.9133, 206.1855), new VSC(1162, 5.6197, 14.2271), new VSC(1067, 3.6082, 426.5982), new VSC(239, 3.861, 433.712), new VSC(237, 5.768, 199.072), new VSC(166, 5.116, 3.181), new VSC(151, 2.736, 639.897), new VSC(131, 4.743, 227.526), new VSC(63, 0.23, 419.48), new VSC(62, 4.74, 103.09), new VSC(40, 5.47, 21.34), new VSC(40, 5.96, 95.98), new VSC(39, 5.83, 110.21), new VSC(28, 3.01, 647.01), new VSC(25, 0.99, 3.93), new VSC(19, 1.92, 853.2), new VSC(18, 4.97, 10.29), new VSC(18, 1.03, 412.37), new VSC(18, 4.2, 216.48), new VSC(18, 3.32, 309.28), new VSC(16, 3.9, 440.83), new VSC(16, 5.62, 117.32), new VSC(13, 1.18, 88.87), new VSC(11, 5.58, 11.05), new VSC(11, 5.93, 191.96), new VSC(10, 3.95, 209.37), new VSC(9, 3.39, 302.16), new VSC(8, 4.88, 323.51), new VSC(7, 0.38, 632.78), new VSC(6, 2.25, 522.58), new VSC(6, 1.06, 210.12), new VSC(5, 4.64, 234.64), new VSC(4, 3.14, 0), new VSC(4, 2.31, 515.46), new VSC(3, 2.2, 860.31), new VSC(3, 0.59, 529.69), new VSC(3, 4.93, 224.34), new VSC(3, 0.42, 625.67), new VSC(2, 4.77, 330.62), new VSC(2, 3.35, 429.78), new VSC(2, 3.2, 202.25), new VSC(2, 1.19, 1066.5), new VSC(2, 1.35, 405.26), new VSC(2, 4.16, 223.59), new VSC(2, 3.07, 654.12)];
+const g_L4SaturnCoefficients = [new VSC(1662, 3.9983, 7.1135), new VSC(257, 2.984, 220.413), new VSC(236, 3.902, 14.227), new VSC(149, 2.741, 213.299), new VSC(114, 3.142, 0), new VSC(110, 1.515, 206.186), new VSC(68, 1.72, 426.6), new VSC(40, 2.05, 433.71), new VSC(38, 1.24, 199.07), new VSC(31, 3.01, 227.53), new VSC(15, 0.83, 639.9), new VSC(9, 3.71, 21.34), new VSC(6, 2.42, 419.48), new VSC(6, 1.16, 647.01), new VSC(4, 1.45, 95.98), new VSC(4, 2.12, 440.83), new VSC(3, 4.09, 110.21), new VSC(3, 2.77, 412.37), new VSC(3, 3.01, 88.87), new VSC(3, 0, 853.2), new VSC(3, 0.39, 103.09), new VSC(2, 3.78, 117.32), new VSC(2, 2.83, 234.64), new VSC(2, 5.08, 309.28), new VSC(2, 2.24, 216.48), new VSC(2, 5.19, 302.16), new VSC(1, 1.55, 191.96)];
+const g_L5SaturnCoefficients = [new VSC(124, 2.259, 7.114), new VSC(34, 2.16, 14.23), new VSC(28, 1.2, 220.41), new VSC(6, 1.22, 227.53), new VSC(5, 0.24, 433.71), new VSC(4, 6.23, 426.6), new VSC(3, 2.97, 199.07), new VSC(3, 4.29, 206.19), new VSC(2, 6.25, 213.3), new VSC(1, 5.28, 639.9), new VSC(1, 0.24, 440.83), new VSC(1, 3.14, 0)];
+const g_B0SaturnCoefficients = [new VSC(4330678, 3.6028443, 213.2990954), new VSC(240348, 2.852385, 426.598191), new VSC(84746, 0, 0), new VSC(34116, 0.57297, 206.18555), new VSC(30863, 3.48442, 220.41264), new VSC(14734, 2.11847, 639.89729), new VSC(9917, 5.79, 419.4846), new VSC(6994, 4.736, 7.1135), new VSC(4808, 5.4331, 316.3919), new VSC(4788, 4.9651, 110.2063), new VSC(3432, 2.7326, 433.7117), new VSC(1506, 6.013, 103.0928), new VSC(1060, 5.631, 529.691), new VSC(969, 5.204, 632.784), new VSC(942, 1.396, 853.196), new VSC(708, 3.803, 323.505), new VSC(552, 5.131, 202.253), new VSC(400, 3.359, 227.526), new VSC(319, 3.626, 209.367), new VSC(316, 1.997, 647.011), new VSC(314, 0.465, 217.231), new VSC(284, 4.886, 224.345), new VSC(236, 2.139, 11.046), new VSC(215, 5.95, 846.083), new VSC(209, 2.12, 415.552), new VSC(207, 0.73, 199.072), new VSC(179, 2.954, 63.736), new VSC(141, 0.644, 490.334), new VSC(139, 4.595, 14.227), new VSC(139, 1.998, 735.877), new VSC(135, 5.245, 742.99), new VSC(122, 3.115, 522.577), new VSC(116, 3.109, 216.48), new VSC(114, 0.963, 210.118)];
+const g_B1SaturnCoefficients = [new VSC(397555, 5.3329, 213.299095), new VSC(49479, 3.14159, 0), new VSC(18572, 6.09919, 426.59819), new VSC(14801, 2.30586, 206.18555), new VSC(9644, 1.6967, 220.4126), new VSC(3757, 1.2543, 419.4846), new VSC(2717, 5.9117, 639.8973), new VSC(1455, 0.8516, 433.7117), new VSC(1291, 2.9177, 7.1135), new VSC(853, 0.436, 316.392), new VSC(298, 0.919, 632.784), new VSC(292, 5.316, 853.196), new VSC(284, 1.619, 227.526), new VSC(275, 3.889, 103.093), new VSC(172, 0.052, 647.011), new VSC(166, 2.444, 199.072), new VSC(158, 5.209, 110.206), new VSC(128, 1.207, 529.691), new VSC(110, 2.457, 217.231), new VSC(82, 2.76, 210.12), new VSC(81, 2.86, 14.23), new VSC(69, 1.66, 202.25), new VSC(65, 1.26, 216.48), new VSC(61, 1.25, 209.37), new VSC(59, 1.82, 323.51), new VSC(46, 0.82, 440.83), new VSC(36, 1.82, 224.34), new VSC(34, 2.84, 117.32), new VSC(33, 1.31, 412.37), new VSC(32, 1.19, 846.08), new VSC(27, 4.65, 1066.5), new VSC(27, 4.44, 11.05)];
+const g_B2SaturnCoefficients = [new VSC(20630, 0.50482, 213.2991), new VSC(3720, 3.9983, 206.1855), new VSC(1627, 6.1819, 220.4126), new VSC(1346, 0, 0), new VSC(706, 3.039, 419.485), new VSC(365, 5.099, 426.598), new VSC(330, 5.279, 433.712), new VSC(219, 3.828, 639.897), new VSC(139, 1.043, 7.114), new VSC(104, 6.157, 227.526), new VSC(93, 1.98, 316.39), new VSC(71, 4.15, 199.07), new VSC(52, 2.88, 632.78), new VSC(49, 4.43, 647.01), new VSC(41, 3.16, 853.2), new VSC(29, 4.53, 210.12), new VSC(24, 1.12, 14.23), new VSC(21, 4.35, 217.23), new VSC(20, 5.31, 440.83), new VSC(18, 0.85, 110.21), new VSC(17, 5.68, 216.48), new VSC(16, 4.26, 103.09), new VSC(14, 3, 412.37), new VSC(12, 2.53, 529.69), new VSC(8, 3.32, 202.25), new VSC(7, 5.56, 209.37), new VSC(7, 0.29, 323.51), new VSC(6, 1.16, 117.32), new VSC(6, 3.61, 869.31)];
+const g_B3SaturnCoefficients = [new VSC(666, 1.99, 213.299), new VSC(632, 5.698, 206.186), new VSC(398, 0, 0), new VSC(188, 4.338, 220.413), new VSC(92, 4.84, 419.48), new VSC(52, 3.42, 433.71), new VSC(42, 2.38, 426.6), new VSC(26, 4.4, 227.53), new VSC(21, 5.85, 199.07), new VSC(18, 1.99, 639.9), new VSC(11, 5.37, 7.11), new VSC(10, 2.55, 647.01), new VSC(7, 3.46, 316.39), new VSC(6, 4.8, 632.78), new VSC(6, 0.02, 210.12), new VSC(6, 3.52, 440.83), new VSC(5, 5.64, 14.23), new VSC(5, 1.22, 853.2), new VSC(4, 4.71, 412.37), new VSC(3, 0.63, 103.09), new VSC(2, 3.72, 216.48)];
+const g_B4SaturnCoefficients = [new VSC(80, 1.12, 206.19), new VSC(32, 3.12, 213.3), new VSC(17, 2.48, 220.41), new VSC(12, 3.14, 0), new VSC(9, 0.38, 419.48), new VSC(6, 1.56, 433.71), new VSC(5, 2.63, 227.53), new VSC(5, 1.28, 199.07), new VSC(1, 1.43, 426.6), new VSC(1, 0.67, 647.01), new VSC(1, 1.72, 440.83), new VSC(1, 6.18, 639.9)];
+const g_B5SaturnCoefficients = [new VSC(8, 2.82, 206.19), new VSC(1, 0.51, 220.41)];
+const g_R0SaturnCoefficients = [new VSC(955758136, 0, 0), new VSC(52921382, 2.3922622, 213.29909544), new VSC(1873680, 5.2354961, 206.1855484), new VSC(1464664, 1.6476305, 426.5981909), new VSC(821891, 5.9352, 316.39187), new VSC(547507, 5.015326, 103.092774), new VSC(371684, 2.271148, 220.412642), new VSC(361778, 3.139043, 7.113547), new VSC(140618, 5.704067, 632.783739), new VSC(108975, 3.293136, 110.206321), new VSC(69007, 5.941, 419.48464), new VSC(61053, 0.94038, 639.89729), new VSC(48913, 1.55733, 202.2534), new VSC(34144, 0.19519, 277.03499), new VSC(32402, 5.47085, 949.17561), new VSC(20937, 0.46349, 735.87651), new VSC(20839, 1.52103, 433.71174), new VSC(20747, 5.33256, 199.072), new VSC(15298, 3.05944, 529.69097), new VSC(14296, 2.60434, 323.50542), new VSC(12884, 1.64892, 138.5175), new VSC(11993, 5.98051, 846.08283), new VSC(11380, 1.73106, 522.57742), new VSC(9796, 5.2048, 1265.5675), new VSC(7753, 5.8519, 95.9792), new VSC(6771, 3.0043, 14.2271), new VSC(6466, 0.1773, 1052.2684), new VSC(5850, 1.4552, 415.5525), new VSC(5307, 0.5974, 63.7359), new VSC(4696, 2.1492, 227.5262), new VSC(4044, 1.6401, 209.3669), new VSC(3688, 0.7802, 412.3711), new VSC(3461, 1.8509, 175.1661), new VSC(3420, 4.9455, 1581.9593), new VSC(3401, 0.5539, 350.3321), new VSC(3376, 3.6953, 224.3448), new VSC(2976, 5.6847, 210.1177), new VSC(2885, 1.3876, 838.9693), new VSC(2881, 0.1796, 853.1964), new VSC(2508, 3.5385, 742.9901), new VSC(2448, 6.1841, 1368.6603), new VSC(2406, 2.9656, 117.3199), new VSC(2174, 0.0151, 340.7709), new VSC(2024, 5.0541, 11.0457)];
+const g_R1SaturnCoefficients = [new VSC(6182981, 0.2584352, 213.2990954), new VSC(506578, 0.711147, 206.185548), new VSC(341394, 5.796358, 426.598191), new VSC(188491, 0.472157, 220.412642), new VSC(186262, 3.141593, 0), new VSC(143891, 1.407449, 7.113547), new VSC(49621, 6.01744, 103.09277), new VSC(20928, 5.09246, 639.89729), new VSC(19953, 1.1756, 419.48464), new VSC(18840, 1.6082, 110.20632), new VSC(13877, 0.75886, 199.072), new VSC(12893, 5.9433, 433.71174), new VSC(5397, 1.2885, 14.2271), new VSC(4869, 0.8679, 323.5054), new VSC(4247, 0.393, 227.5262), new VSC(3252, 1.2585, 95.9792), new VSC(3081, 3.4366, 522.5774), new VSC(2909, 4.6068, 202.2534), new VSC(2856, 2.1673, 735.8765), new VSC(1988, 2.4505, 412.3711), new VSC(1941, 6.0239, 209.3669), new VSC(1581, 1.2919, 210.1177), new VSC(1340, 4.308, 853.1964), new VSC(1316, 1.253, 117.3199), new VSC(1203, 1.8665, 316.3919), new VSC(1091, 0.0753, 216.4805), new VSC(966, 0.48, 632.784), new VSC(954, 5.152, 647.011), new VSC(898, 0.983, 529.691), new VSC(882, 1.885, 1052.268), new VSC(874, 1.402, 224.345), new VSC(785, 3.064, 838.969), new VSC(740, 1.382, 625.67), new VSC(658, 4.144, 309.278), new VSC(650, 1.725, 742.99), new VSC(613, 3.033, 63.736), new VSC(599, 2.549, 217.231), new VSC(503, 2.13, 3.932)];
+const g_R2SaturnCoefficients = [new VSC(436902, 4.786717, 213.299095), new VSC(71923, 2.5007, 206.18555), new VSC(49767, 4.97168, 220.41264), new VSC(43221, 3.8694, 426.59819), new VSC(29646, 5.9631, 7.11355), new VSC(4721, 2.4753, 199.072), new VSC(4142, 4.1067, 433.7117), new VSC(3789, 3.0977, 639.8973), new VSC(2964, 1.3721, 103.0928), new VSC(2556, 2.8507, 419.4846), new VSC(2327, 0, 0), new VSC(2208, 6.2759, 110.2063), new VSC(2188, 5.8555, 14.2271), new VSC(1957, 4.9245, 227.5262), new VSC(924, 5.464, 323.505), new VSC(706, 2.971, 95.979), new VSC(546, 4.129, 412.371), new VSC(431, 5.178, 522.577), new VSC(405, 4.173, 209.367), new VSC(391, 4.481, 216.48), new VSC(374, 5.834, 117.32), new VSC(361, 3.277, 647.011), new VSC(356, 3.192, 210.118), new VSC(326, 2.269, 853.196), new VSC(207, 4.022, 735.877), new VSC(204, 0.088, 202.253), new VSC(180, 3.597, 632.784), new VSC(178, 4.097, 440.825), new VSC(154, 3.135, 625.67), new VSC(148, 0.136, 302.165), new VSC(133, 2.594, 191.958), new VSC(132, 5.933, 309.278)];
+const g_R3SaturnCoefficients = [new VSC(20315, 3.02187, 213.2991), new VSC(8924, 3.1914, 220.4126), new VSC(6909, 4.3517, 206.1855), new VSC(4087, 4.2241, 7.1135), new VSC(3879, 2.0106, 426.5982), new VSC(1071, 4.2036, 199.072), new VSC(907, 2.283, 433.712), new VSC(606, 3.175, 227.526), new VSC(597, 4.135, 14.227), new VSC(483, 1.173, 639.897), new VSC(393, 0, 0), new VSC(229, 4.698, 419.485), new VSC(188, 4.59, 110.206), new VSC(150, 3.202, 103.093), new VSC(121, 3.768, 323.505), new VSC(102, 4.71, 95.979), new VSC(101, 5.819, 412.371), new VSC(93, 1.44, 647.01), new VSC(84, 2.63, 216.48), new VSC(73, 4.15, 117.32), new VSC(62, 2.31, 440.83), new VSC(55, 0.31, 853.2), new VSC(50, 2.39, 209.37), new VSC(45, 4.37, 191.96), new VSC(41, 0.69, 522.58), new VSC(40, 1.84, 302.16), new VSC(38, 5.94, 88.87), new VSC(32, 4.01, 21.34)];
+const g_R4SaturnCoefficients = [new VSC(1202, 1.415, 220.4126), new VSC(708, 1.162, 213.299), new VSC(516, 6.24, 206.186), new VSC(427, 2.469, 7.114), new VSC(268, 0.187, 426.598), new VSC(170, 5.959, 199.072), new VSC(150, 0.48, 433.712), new VSC(145, 1.442, 227.526), new VSC(121, 2.405, 14.227), new VSC(47, 5.57, 639.9), new VSC(19, 5.86, 647.01), new VSC(17, 0.53, 440.83), new VSC(16, 2.9, 110.21), new VSC(15, 0.3, 419.48), new VSC(14, 1.3, 412.37), new VSC(13, 2.09, 323.51), new VSC(11, 0.22, 95.98), new VSC(11, 2.46, 117.32), new VSC(10, 3.14, 0), new VSC(9, 1.56, 88.87), new VSC(9, 2.28, 21.34), new VSC(9, 0.68, 216.48), new VSC(8, 1.27, 234.64)];
+const g_R5SaturnCoefficients = [new VSC(129, 5.913, 220.413), new VSC(32, 0.69, 7.11), new VSC(27, 5.91, 227.53), new VSC(20, 4.95, 433.71), new VSC(20, 0.67, 14.23), new VSC(14, 2.67, 206.19), new VSC(14, 1.46, 199.07), new VSC(13, 4.59, 426.6), new VSC(7, 4.63, 213.3), new VSC(5, 3.61, 639.9), new VSC(4, 4.9, 440.83), new VSC(3, 4.07, 647.01), new VSC(3, 4.66, 191.96), new VSC(3, 0.49, 323.51), new VSC(3, 3.18, 419.48), new VSC(2, 3.7, 88.87), new VSC(2, 3.32, 95.98), new VSC(2, 0.56, 117.32)];
+
+
+// CAASaturn
+
+export function CAASaturn() { }
+
+CAASaturn.eclipticLongitude = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var rho5 = rho4 * rho;
+ var nL0Coefficients = g_L0SaturnCoefficients.length;
+ var L0 = 0;
+ var i;
+ for (i = 0; i < nL0Coefficients; i++) {
+ L0 += g_L0SaturnCoefficients[i].a * Math.cos(g_L0SaturnCoefficients[i].b + g_L0SaturnCoefficients[i].c * rho);
+ }
+ var nL1Coefficients = g_L1SaturnCoefficients.length;
+ var L1 = 0;
+ for (i = 0; i < nL1Coefficients; i++) {
+ L1 += g_L1SaturnCoefficients[i].a * Math.cos(g_L1SaturnCoefficients[i].b + g_L1SaturnCoefficients[i].c * rho);
+ }
+ var nL2Coefficients = g_L2SaturnCoefficients.length;
+ var L2 = 0;
+ for (i = 0; i < nL2Coefficients; i++) {
+ L2 += g_L2SaturnCoefficients[i].a * Math.cos(g_L2SaturnCoefficients[i].b + g_L2SaturnCoefficients[i].c * rho);
+ }
+ var nL3Coefficients = g_L3SaturnCoefficients.length;
+ var L3 = 0;
+ for (i = 0; i < nL3Coefficients; i++) {
+ L3 += g_L3SaturnCoefficients[i].a * Math.cos(g_L3SaturnCoefficients[i].b + g_L3SaturnCoefficients[i].c * rho);
+ }
+ var nL4Coefficients = g_L4SaturnCoefficients.length;
+ var L4 = 0;
+ for (i = 0; i < nL4Coefficients; i++) {
+ L4 += g_L4SaturnCoefficients[i].a * Math.cos(g_L4SaturnCoefficients[i].b + g_L4SaturnCoefficients[i].c * rho);
+ }
+ var nL5Coefficients = g_L5SaturnCoefficients.length;
+ var L5 = 0;
+ for (i = 0; i < nL5Coefficients; i++) {
+ L5 += g_L5SaturnCoefficients[i].a * Math.cos(g_L5SaturnCoefficients[i].b + g_L5SaturnCoefficients[i].c * rho);
+ }
+ var vvalue = (L0 + L1 * rho + L2 * rhosquared + L3 * rhocubed + L4 * rho4 + L5 * rho5) / 100000000;
+ vvalue = CT.m360(CT.r2D(vvalue));
+ return vvalue;
+};
+
+CAASaturn.eclipticLatitude = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var rho5 = rho4 * rho;
+ var nB0Coefficients = g_B0SaturnCoefficients.length;
+ var B0 = 0;
+ var i;
+ for (i = 0; i < nB0Coefficients; i++) {
+ B0 += g_B0SaturnCoefficients[i].a * Math.cos(g_B0SaturnCoefficients[i].b + g_B0SaturnCoefficients[i].c * rho);
+ }
+ var nB1Coefficients = g_B1SaturnCoefficients.length;
+ var B1 = 0;
+ for (i = 0; i < nB1Coefficients; i++) {
+ B1 += g_B1SaturnCoefficients[i].a * Math.cos(g_B1SaturnCoefficients[i].b + g_B1SaturnCoefficients[i].c * rho);
+ }
+ var nB2Coefficients = g_B2SaturnCoefficients.length;
+ var B2 = 0;
+ for (i = 0; i < nB2Coefficients; i++) {
+ B2 += g_B2SaturnCoefficients[i].a * Math.cos(g_B2SaturnCoefficients[i].b + g_B2SaturnCoefficients[i].c * rho);
+ }
+ var nB3Coefficients = g_B3SaturnCoefficients.length;
+ var B3 = 0;
+ for (i = 0; i < nB3Coefficients; i++) {
+ B3 += g_B3SaturnCoefficients[i].a * Math.cos(g_B3SaturnCoefficients[i].b + g_B3SaturnCoefficients[i].c * rho);
+ }
+ var nB4Coefficients = g_B4SaturnCoefficients.length;
+ var B4 = 0;
+ for (i = 0; i < nB4Coefficients; i++) {
+ B4 += g_B4SaturnCoefficients[i].a * Math.cos(g_B4SaturnCoefficients[i].b + g_B4SaturnCoefficients[i].c * rho);
+ }
+ var nB5Coefficients = g_B5SaturnCoefficients.length;
+ var B5 = 0;
+ for (i = 0; i < nB5Coefficients; i++) {
+ B5 += g_B5SaturnCoefficients[i].a * Math.cos(g_B5SaturnCoefficients[i].b + g_B5SaturnCoefficients[i].c * rho);
+ }
+ var vvalue = (B0 + B1 * rho + B2 * rhosquared + B3 * rhocubed + B4 * rho4 + B5 * rho5) / 100000000;
+ vvalue = CT.r2D(vvalue);
+ return vvalue;
+};
+
+CAASaturn.radiusVector = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var rho5 = rho4 * rho;
+ var nR0Coefficients = g_R0SaturnCoefficients.length;
+ var R0 = 0;
+ var i;
+ for (i = 0; i < nR0Coefficients; i++) {
+ R0 += g_R0SaturnCoefficients[i].a * Math.cos(g_R0SaturnCoefficients[i].b + g_R0SaturnCoefficients[i].c * rho);
+ }
+ var nR1Coefficients = g_R1SaturnCoefficients.length;
+ var R1 = 0;
+ for (i = 0; i < nR1Coefficients; i++) {
+ R1 += g_R1SaturnCoefficients[i].a * Math.cos(g_R1SaturnCoefficients[i].b + g_R1SaturnCoefficients[i].c * rho);
+ }
+ var nR2Coefficients = g_R2SaturnCoefficients.length;
+ var R2 = 0;
+ for (i = 0; i < nR2Coefficients; i++) {
+ R2 += g_R2SaturnCoefficients[i].a * Math.cos(g_R2SaturnCoefficients[i].b + g_R2SaturnCoefficients[i].c * rho);
+ }
+ var nR3Coefficients = g_R3SaturnCoefficients.length;
+ var R3 = 0;
+ for (i = 0; i < nR3Coefficients; i++) {
+ R3 += g_R3SaturnCoefficients[i].a * Math.cos(g_R3SaturnCoefficients[i].b + g_R3SaturnCoefficients[i].c * rho);
+ }
+ var nR4Coefficients = g_R4SaturnCoefficients.length;
+ var R4 = 0;
+ for (i = 0; i < nR4Coefficients; i++) {
+ R4 += g_R4SaturnCoefficients[i].a * Math.cos(g_R4SaturnCoefficients[i].b + g_R4SaturnCoefficients[i].c * rho);
+ }
+ var nR5Coefficients = g_R5SaturnCoefficients.length;
+ var R5 = 0;
+ for (i = 0; i < nR5Coefficients; i++) {
+ R5 += g_R5SaturnCoefficients[i].a * Math.cos(g_R5SaturnCoefficients[i].b + g_R5SaturnCoefficients[i].c * rho);
+ }
+ return (R0 + R1 * rho + R2 * rhosquared + R3 * rhocubed + R4 * rho4 + R5 * rho5) / 100000000;
+};
+
+var CAASaturn$ = {};
+
+registerType("CAASaturn", [CAASaturn, CAASaturn$, null]);
diff --git a/engine/esm/astrocalc/saturn_rings.js b/engine/esm/astrocalc/saturn_rings.js
new file mode 100644
index 00000000..37cf6042
--- /dev/null
+++ b/engine/esm/astrocalc/saturn_rings.js
@@ -0,0 +1,141 @@
+// Originally `AASATURNRINGS.CPP`
+// "Purpose: Implementation for the algorithms which calculate various parameters related to the Rings of Saturn"
+// Last update of original: PJN / 08-01-2004
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+import { CAAFK5 } from "./fk5.js";
+import { ELL } from "./elliptical.js";
+import { CAANutation } from "./nutation.js";
+import { CAAEarth } from "./earth.js";
+import { CAASaturn } from "./saturn.js";
+
+// CAASaturnRingDetails
+
+export function CAASaturnRingDetails() {
+ this.b = 0;
+ this.bdash = 0;
+ this.p = 0;
+ this.a = 0;
+ this.b = 0;
+ this.deltaU = 0;
+ this.b = 0;
+ this.bdash = 0;
+ this.p = 0;
+ this.a = 0;
+ this.b = 0;
+ this.deltaU = 0;
+}
+
+var CAASaturnRingDetails$ = {};
+
+registerType("CAASaturnRingDetails", [CAASaturnRingDetails, CAASaturnRingDetails$, null]);
+
+
+// CAASaturnRings
+
+export function CAASaturnRings() { }
+
+CAASaturnRings.calculate = function (JD) {
+ var details = new CAASaturnRingDetails();
+ var T = (JD - 2451545) / 36525;
+ var T2 = T * T;
+ var i = 28.075216 - 0.012998 * T + 4E-06 * T2;
+ var irad = CT.d2R(i);
+ var omega = 169.50847 + 1.394681 * T + 0.000412 * T2;
+ var omegarad = CT.d2R(omega);
+ var l0 = CAAEarth.eclipticLongitude(JD);
+ var b0 = CAAEarth.eclipticLatitude(JD);
+ l0 += CAAFK5.correctionInLongitude(l0, b0, JD);
+ var l0rad = CT.d2R(l0);
+ b0 += CAAFK5.correctionInLatitude(l0, JD);
+ var b0rad = CT.d2R(b0);
+ var R = CAAEarth.radiusVector(JD);
+ var DELTA = 9;
+ var PreviousEarthLightTravelTime = 0;
+ var EarthLightTravelTime = ELL.distanceToLightTime(DELTA);
+ var JD1 = JD - EarthLightTravelTime;
+ var bIterate = true;
+ var x = 0;
+ var y = 0;
+ var z = 0;
+ var l = 0;
+ var b = 0;
+ var r = 0;
+ while (bIterate) {
+ l = CAASaturn.eclipticLongitude(JD1);
+ b = CAASaturn.eclipticLatitude(JD1);
+ l += CAAFK5.correctionInLongitude(l, b, JD1);
+ b += CAAFK5.correctionInLatitude(l, JD1);
+ var lrad = CT.d2R(l);
+ var brad = CT.d2R(b);
+ r = CAASaturn.radiusVector(JD1);
+ x = r * Math.cos(brad) * Math.cos(lrad) - R * Math.cos(l0rad);
+ y = r * Math.cos(brad) * Math.sin(lrad) - R * Math.sin(l0rad);
+ z = r * Math.sin(brad) - R * Math.sin(b0rad);
+ DELTA = Math.sqrt(x * x + y * y + z * z);
+ EarthLightTravelTime = ELL.distanceToLightTime(DELTA);
+ bIterate = (Math.abs(EarthLightTravelTime - PreviousEarthLightTravelTime) > 2E-06);
+ if (bIterate) {
+ JD1 = JD - EarthLightTravelTime;
+ PreviousEarthLightTravelTime = EarthLightTravelTime;
+ }
+ }
+ var lambda = Math.atan2(y, x);
+ var beta = Math.atan2(z, Math.sqrt(x * x + y * y));
+ details.b = Math.asin(Math.sin(irad) * Math.cos(beta) * Math.sin(lambda - omegarad) - Math.cos(irad) * Math.sin(beta));
+ details.a = 375.35 / DELTA;
+ details.b = details.a * Math.sin(Math.abs(details.b));
+ details.b = CT.r2D(details.b);
+ var N = 113.6655 + 0.8771 * T;
+ var Nrad = CT.d2R(N);
+ var ldash = l - 0.01759 / r;
+ var ldashrad = CT.d2R(ldash);
+ var bdash = b - 0.000764 * Math.cos(ldashrad - Nrad) / r;
+ var bdashrad = CT.d2R(bdash);
+ details.bdash = CT.r2D(Math.asin(Math.sin(irad) * Math.cos(bdashrad) * Math.sin(ldashrad - omegarad) - Math.cos(irad) * Math.sin(bdashrad)));
+ var U1 = Math.atan2(Math.sin(irad) * Math.sin(bdashrad) + Math.cos(irad) * Math.cos(bdashrad) * Math.sin(ldashrad - omegarad), Math.cos(bdashrad) * Math.cos(ldashrad - omegarad));
+ var U2 = Math.atan2(Math.sin(irad) * Math.sin(beta) + Math.cos(irad) * Math.cos(beta) * Math.sin(lambda - omegarad), Math.cos(beta) * Math.cos(lambda - omegarad));
+ details.deltaU = CT.r2D(Math.abs(U1 - U2));
+ var Obliquity = CAANutation.trueObliquityOfEcliptic(JD);
+ var NutationInLongitude = CAANutation.nutationInLongitude(JD);
+ var lambda0 = omega - 90;
+ var beta0 = 90 - i;
+ lambda += CT.d2R(0.005693 * Math.cos(l0rad - lambda) / Math.cos(beta));
+ beta += CT.d2R(0.005693 * Math.sin(l0rad - lambda) * Math.sin(beta));
+ lambda = CT.r2D(lambda);
+ lambda += NutationInLongitude / 3600;
+ lambda = CT.m360(lambda);
+ lambda0 += NutationInLongitude / 3600;
+ lambda0 = CT.m360(lambda0);
+ beta = CT.r2D(beta);
+ var GeocentricEclipticSaturn = CT.ec2Eq(lambda, beta, Obliquity);
+ var alpha = CT.h2R(GeocentricEclipticSaturn.x);
+ var delta = CT.d2R(GeocentricEclipticSaturn.y);
+ var GeocentricEclipticNorthPole = CT.ec2Eq(lambda0, beta0, Obliquity);
+ var alpha0 = CT.h2R(GeocentricEclipticNorthPole.x);
+ var delta0 = CT.d2R(GeocentricEclipticNorthPole.y);
+ details.p = CT.r2D(Math.atan2(Math.cos(delta0) * Math.sin(alpha0 - alpha), Math.sin(delta0) * Math.cos(delta) - Math.cos(delta0) * Math.sin(delta) * Math.cos(alpha0 - alpha)));
+ return details;
+};
+
+var CAASaturnRings$ = {};
+
+registerType("CAASaturnRings", [CAASaturnRings, CAASaturnRings$, null]);
diff --git a/engine/esm/astrocalc/sidereal.js b/engine/esm/astrocalc/sidereal.js
new file mode 100644
index 00000000..33ba1de8
--- /dev/null
+++ b/engine/esm/astrocalc/sidereal.js
@@ -0,0 +1,64 @@
+// Originally `AASIDEREAL.CPP`
+// "Purpose: Implementation for the algorithms which obtain sidereal time"
+// Last update of original: PJN / 28-01-2007
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { ss } from "../ss.js";
+import { DT } from "./date.js";
+import { CT } from "./coordinate_transformation.js";
+import { CAANutation } from "./nutation.js";
+
+
+// CAASidereal
+
+export function CAASidereal() { }
+
+CAASidereal.meanGreenwichSiderealTime = function (JD) {
+ var date = new DT();
+ date.setJD(JD, DT.afterPapalReformJD(JD));
+ var D = date.get();
+ var Year = ss.truncate(D[0]);
+ var Month = ss.truncate(D[1]);
+ var Day = ss.truncate(D[2]);
+ var Hour = ss.truncate(D[3]);
+ var Minute = ss.truncate(D[4]);
+ var Second = D[5];
+ date.set(Year, Month, Day, 0, 0, 0, date.inGregorianCalendar());
+ var JDMidnight = date.julian();
+ var T = (JDMidnight - 2451545) / 36525;
+ var TSquared = T * T;
+ var TCubed = TSquared * T;
+ var Value = 100.46061837 + (36000.770053608 * T) + (0.000387933 * TSquared) - (TCubed / 38710000);
+ Value += (((Hour * 15) + (Minute * 0.25) + (Second * 0.00416666666666667)) * 1.00273790935);
+ Value = CT.d2H(Value);
+ return CT.m24(Value);
+};
+
+CAASidereal.apparentGreenwichSiderealTime = function (JD) {
+ var MeanObliquity = CAANutation.meanObliquityOfEcliptic(JD);
+ var TrueObliquity = MeanObliquity + CAANutation.nutationInObliquity(JD) / 3600;
+ var NutationInLongitude = CAANutation.nutationInLongitude(JD);
+ var Value = CAASidereal.meanGreenwichSiderealTime(JD) + (NutationInLongitude * Math.cos(CT.d2R(TrueObliquity)) / 54000);
+ return CT.m24(Value);
+};
+
+var CAASidereal$ = {};
+
+registerType("CAASidereal", [CAASidereal, CAASidereal$, null]);
diff --git a/engine/esm/astrocalc/stellar_magnitudes.js b/engine/esm/astrocalc/stellar_magnitudes.js
new file mode 100644
index 00000000..6126d3b7
--- /dev/null
+++ b/engine/esm/astrocalc/stellar_magnitudes.js
@@ -0,0 +1,54 @@
+// Originally `AASTELLARMAGNITUDES.CPP`
+// "Purpose: Implementation for the algorithms which operate on the stellar magntidue system"
+// Last update of original: PJN / 12-02-2004
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { Util } from "../baseutil.js";
+
+
+// CAAStellarMagnitudes
+
+export function CAAStellarMagnitudes() { }
+
+CAAStellarMagnitudes.combinedMagnitude = function (m1, m2) {
+ var x = 0.4 * (m2 - m1);
+ return m2 - 2.5 * Util.log10(Math.pow(10, x) + 1);
+};
+
+CAAStellarMagnitudes.combinedMagnitude2 = function (Magnitudes, pMagnitudes) {
+ var vvalue = 0;
+ for (var i = 0; i < Magnitudes; i++) {
+ vvalue += Math.pow(10, -0.4 * pMagnitudes[i]);
+ }
+ return -2.5 * Util.log10(vvalue);
+};
+
+CAAStellarMagnitudes.brightnessRatio = function (m1, m2) {
+ var x = 0.4 * (m2 - m1);
+ return Math.pow(10, x);
+};
+
+CAAStellarMagnitudes.magnitudeDifference = function (brightnessRatio) {
+ return 2.5 * Util.log10(brightnessRatio);
+};
+
+var CAAStellarMagnitudes$ = {};
+
+registerType("CAAStellarMagnitudes", [CAAStellarMagnitudes, CAAStellarMagnitudes$, null]);
diff --git a/engine/esm/astrocalc/sun.js b/engine/esm/astrocalc/sun.js
new file mode 100644
index 00000000..d28b2132
--- /dev/null
+++ b/engine/esm/astrocalc/sun.js
@@ -0,0 +1,120 @@
+// Originally `AASUN.CPP`
+// "Purpose: Implementation for the algorithms which calculate the position of Earth"
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { C3D, CT } from "./coordinate_transformation.js";
+import { CAAEarth } from "./earth.js";
+import { CAAFK5 } from "./fk5.js";
+import { CAANutation } from "./nutation.js";
+
+// CAASun
+
+export function CAASun() { }
+
+CAASun.geometricEclipticLongitude = function (JD) {
+ return CT.m360(CAAEarth.eclipticLongitude(JD) + 180);
+};
+
+CAASun.geometricEclipticLatitude = function (JD) {
+ return -CAAEarth.eclipticLatitude(JD);
+};
+
+CAASun.geometricEclipticLongitudeJ2000 = function (JD) {
+ return CT.m360(CAAEarth.eclipticLongitudeJ2000(JD) + 180);
+};
+
+CAASun.geometricEclipticLatitudeJ2000 = function (JD) {
+ return -CAAEarth.eclipticLatitudeJ2000(JD);
+};
+
+CAASun.geometricFK5EclipticLongitude = function (JD) {
+ var Longitude = CAASun.geometricEclipticLongitude(JD);
+ var Latitude = CAASun.geometricEclipticLatitude(JD);
+ Longitude += CAAFK5.correctionInLongitude(Longitude, Latitude, JD);
+ return Longitude;
+};
+
+CAASun.geometricFK5EclipticLatitude = function (JD) {
+ var Longitude = CAASun.geometricEclipticLongitude(JD);
+ var Latitude = CAASun.geometricEclipticLatitude(JD);
+ var SunLatCorrection = CAAFK5.correctionInLatitude(Longitude, JD);
+ Latitude += SunLatCorrection;
+ return Latitude;
+};
+
+CAASun.apparentEclipticLongitude = function (JD) {
+ var Longitude = CAASun.geometricFK5EclipticLongitude(JD);
+ Longitude += CT.dmS2D(0, 0, CAANutation.nutationInLongitude(JD));
+ var R = CAAEarth.radiusVector(JD);
+ Longitude -= CT.dmS2D(0, 0, 20.4898 / R);
+ return Longitude;
+};
+
+CAASun.apparentEclipticLatitude = function (JD) {
+ return CAASun.geometricFK5EclipticLatitude(JD);
+};
+
+CAASun.eclipticRectangularCoordinatesMeanEquinox = function (JD) {
+ var Longitude = CT.d2R(CAASun.geometricFK5EclipticLongitude(JD));
+ var Latitude = CT.d2R(CAASun.geometricFK5EclipticLatitude(JD));
+ var R = CAAEarth.radiusVector(JD);
+ var epsilon = CT.d2R(CAANutation.meanObliquityOfEcliptic(JD));
+ var vvalue = new C3D();
+ vvalue.x = R * Math.cos(Latitude) * Math.cos(Longitude);
+ vvalue.y = R * (Math.cos(Latitude) * Math.sin(Longitude) * Math.cos(epsilon) - Math.sin(Latitude) * Math.sin(epsilon));
+ vvalue.z = R * (Math.cos(Latitude) * Math.sin(Longitude) * Math.sin(epsilon) + Math.sin(Latitude) * Math.cos(epsilon));
+ return vvalue;
+};
+
+CAASun.eclipticRectangularCoordinatesJ2000 = function (JD) {
+ var Longitude = CAASun.geometricEclipticLongitudeJ2000(JD);
+ Longitude = CT.d2R(Longitude);
+ var Latitude = CAASun.geometricEclipticLatitudeJ2000(JD);
+ Latitude = CT.d2R(Latitude);
+ var R = CAAEarth.radiusVector(JD);
+ var vvalue = new C3D();
+ var coslatitude = Math.cos(Latitude);
+ vvalue.x = R * coslatitude * Math.cos(Longitude);
+ vvalue.y = R * coslatitude * Math.sin(Longitude);
+ vvalue.z = R * Math.sin(Latitude);
+ return vvalue;
+};
+
+CAASun.equatorialRectangularCoordinatesJ2000 = function (JD) {
+ var vvalue = CAASun.eclipticRectangularCoordinatesJ2000(JD);
+ vvalue = CAAFK5.convertVSOPToFK5J2000(vvalue);
+ return vvalue;
+};
+
+CAASun.equatorialRectangularCoordinatesB1950 = function (JD) {
+ var vvalue = CAASun.eclipticRectangularCoordinatesJ2000(JD);
+ vvalue = CAAFK5.convertVSOPToFK5B1950(vvalue);
+ return vvalue;
+};
+
+CAASun.equatorialRectangularCoordinatesAnyEquinox = function (JD, JDEquinox) {
+ var vvalue = CAASun.equatorialRectangularCoordinatesJ2000(JD);
+ vvalue = CAAFK5.convertVSOPToFK5AnyEquinox(vvalue, JDEquinox);
+ return vvalue;
+};
+
+var CAASun$ = {};
+
+registerType("CAASun", [CAASun, CAASun$, null]);
diff --git a/engine/esm/astrocalc/uranus.js b/engine/esm/astrocalc/uranus.js
new file mode 100644
index 00000000..47e6c404
--- /dev/null
+++ b/engine/esm/astrocalc/uranus.js
@@ -0,0 +1,159 @@
+// Originally `AAURANUS.CPP`
+// "Purpose: Implementation for the algorithms which obtain the heliocentric position of Uranus"
+// Last update of original: PJN / 29-12-2003
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+import { VSC } from "./earth.js";
+
+
+// Coefficients
+
+const g_L0UranusCoefficients = [new VSC(548129294, 0, 0), new VSC(9260408, 0.8910642, 74.7815986), new VSC(1504248, 3.6271926, 1.4844727), new VSC(365982, 1.899622, 73.297126), new VSC(272328, 3.358237, 149.563197), new VSC(70328, 5.39254, 63.7359), new VSC(68893, 6.09292, 76.26607), new VSC(61999, 2.26952, 2.96895), new VSC(61951, 2.85099, 11.0457), new VSC(26469, 3.14152, 71.81265), new VSC(25711, 6.1138, 454.90937), new VSC(21079, 4.36059, 148.07872), new VSC(17819, 1.74437, 36.64856), new VSC(14613, 4.73732, 3.93215), new VSC(11163, 5.82682, 224.3448), new VSC(10998, 0.48865, 138.5175), new VSC(9527, 2.9552, 35.1641), new VSC(7546, 5.2363, 109.9457), new VSC(4220, 3.2333, 70.8494), new VSC(4052, 2.2775, 151.0477), new VSC(3490, 5.4831, 146.5943), new VSC(3355, 1.0655, 4.4534), new VSC(3144, 4.752, 77.7505), new VSC(2927, 4.629, 9.5612), new VSC(2922, 5.3524, 85.8273), new VSC(2273, 4.366, 70.3282), new VSC(2149, 0.6075, 38.133), new VSC(2051, 1.5177, 0.1119), new VSC(1992, 4.9244, 277.035), new VSC(1667, 3.6274, 380.1278), new VSC(1533, 2.5859, 52.6902), new VSC(1376, 2.0428, 65.2204), new VSC(1372, 4.1964, 111.4302), new VSC(1284, 3.1135, 202.2534), new VSC(1282, 0.5427, 222.8603), new VSC(1244, 0.9161, 2.4477), new VSC(1221, 0.199, 108.4612), new VSC(1151, 4.179, 33.6796), new VSC(1150, 0.9334, 3.1814), new VSC(1090, 1.775, 12.5302), new VSC(1072, 0.2356, 62.2514), new VSC(946, 1.192, 127.472), new VSC(708, 5.183, 213.299), new VSC(653, 0.966, 78.714), new VSC(628, 0.182, 984.6), new VSC(607, 5.432, 529.691), new VSC(559, 3.358, 0.521), new VSC(524, 2.013, 299.126), new VSC(483, 2.106, 0.963), new VSC(471, 1.407, 184.727), new VSC(467, 0.415, 145.11), new VSC(434, 5.521, 183.243), new VSC(405, 5.987, 8.077), new VSC(399, 0.338, 415.552), new VSC(396, 5.87, 351.817), new VSC(379, 2.35, 56.622), new VSC(310, 5.833, 145.631), new VSC(300, 5.644, 22.091), new VSC(294, 5.839, 39.618), new VSC(252, 1.637, 221.376), new VSC(249, 4.746, 225.829), new VSC(239, 2.35, 137.033), new VSC(224, 0.516, 84.343), new VSC(223, 2.843, 0.261), new VSC(220, 1.922, 67.668), new VSC(217, 6.142, 5.938), new VSC(216, 4.778, 340.771), new VSC(208, 5.58, 68.844), new VSC(202, 1.297, 0.048), new VSC(199, 0.956, 152.532), new VSC(194, 1.888, 456.394), new VSC(193, 0.916, 453.425), new VSC(187, 1.319, 0.16), new VSC(182, 3.536, 79.235), new VSC(173, 1.539, 160.609), new VSC(172, 5.68, 219.891), new VSC(170, 3.677, 5.417), new VSC(169, 5.879, 18.159), new VSC(165, 1.424, 106.977), new VSC(163, 3.05, 112.915), new VSC(158, 0.738, 54.175), new VSC(147, 1.263, 59.804), new VSC(143, 1.3, 35.425), new VSC(139, 5.386, 32.195), new VSC(139, 4.26, 909.819), new VSC(124, 1.374, 7.114), new VSC(110, 2.027, 554.07), new VSC(109, 5.706, 77.963), new VSC(104, 5.028, 0.751), new VSC(104, 1.458, 24.379), new VSC(103, 0.681, 14.978)];
+const g_L1UranusCoefficients = [new VSC(7502543122, 0, 0), new VSC(154458, 5.242017, 74.781599), new VSC(24456, 1.71256, 1.48447), new VSC(9258, 0.4284, 11.0457), new VSC(8266, 1.5022, 63.7359), new VSC(7842, 1.3198, 149.5632), new VSC(3899, 0.4648, 3.9322), new VSC(2284, 4.1737, 76.2661), new VSC(1927, 0.5301, 2.9689), new VSC(1233, 1.5863, 70.8494), new VSC(791, 5.436, 3.181), new VSC(767, 1.996, 73.297), new VSC(482, 2.984, 85.827), new VSC(450, 4.138, 138.517), new VSC(446, 3.723, 224.345), new VSC(427, 4.731, 71.813), new VSC(354, 2.583, 148.079), new VSC(348, 2.454, 9.561), new VSC(317, 5.579, 52.69), new VSC(206, 2.363, 2.448), new VSC(189, 4.202, 56.622), new VSC(184, 0.284, 151.048), new VSC(180, 5.684, 12.53), new VSC(171, 3.001, 78.714), new VSC(158, 2.909, 0.963), new VSC(155, 5.591, 4.453), new VSC(154, 4.652, 35.164), new VSC(152, 2.942, 77.751), new VSC(143, 2.59, 62.251), new VSC(121, 4.148, 127.472), new VSC(116, 3.732, 65.22), new VSC(102, 4.188, 145.631), new VSC(102, 6.034, 0.112), new VSC(88, 3.99, 18.16), new VSC(88, 6.16, 202.25), new VSC(81, 2.64, 22.09), new VSC(72, 6.05, 70.33), new VSC(69, 4.05, 77.96), new VSC(59, 3.7, 67.67), new VSC(47, 3.54, 351.82), new VSC(44, 5.91, 7.11), new VSC(43, 5.72, 5.42), new VSC(39, 4.92, 222.86), new VSC(36, 5.9, 33.68), new VSC(36, 3.29, 8.08), new VSC(36, 3.33, 71.6), new VSC(35, 5.08, 38.13), new VSC(31, 5.62, 984.6), new VSC(31, 5.5, 59.8), new VSC(31, 5.46, 160.61), new VSC(30, 1.66, 447.8), new VSC(29, 1.15, 462.02), new VSC(29, 4.52, 84.34), new VSC(27, 5.54, 131.4), new VSC(27, 6.15, 299.13), new VSC(26, 4.99, 137.03), new VSC(25, 5.74, 380.13)];
+const g_L2UranusCoefficients = [new VSC(53033, 0, 0), new VSC(2358, 2.2601, 74.7816), new VSC(769, 4.526, 11.046), new VSC(552, 3.258, 63.736), new VSC(542, 2.276, 3.932), new VSC(529, 4.923, 1.484), new VSC(258, 3.691, 3.181), new VSC(239, 5.858, 149.563), new VSC(182, 6.218, 70.849), new VSC(54, 1.44, 76.27), new VSC(49, 6.03, 56.62), new VSC(45, 3.91, 2.45), new VSC(45, 0.81, 85.83), new VSC(38, 1.78, 52.69), new VSC(37, 4.46, 2.97), new VSC(33, 0.86, 9.56), new VSC(29, 5.1, 73.3), new VSC(24, 2.11, 18.16), new VSC(22, 5.99, 138.52), new VSC(22, 4.82, 78.71), new VSC(21, 2.4, 77.96), new VSC(21, 2.17, 224.34), new VSC(17, 2.54, 145.63), new VSC(17, 3.47, 12.53), new VSC(12, 0.02, 22.09), new VSC(11, 0.08, 127.47), new VSC(10, 5.16, 71.6), new VSC(10, 4.46, 62.25), new VSC(9, 4.26, 7.11), new VSC(8, 5.5, 67.67), new VSC(7, 1.25, 5.42), new VSC(6, 3.36, 447.8), new VSC(6, 5.45, 65.22), new VSC(6, 4.52, 151.05), new VSC(6, 5.73, 462.02)];
+const g_L3UranusCoefficients = [new VSC(121, 0.024, 74.782), new VSC(68, 4.12, 3.93), new VSC(53, 2.39, 11.05), new VSC(46, 0, 0), new VSC(45, 2.04, 3.18), new VSC(44, 2.96, 1.48), new VSC(25, 4.89, 63.74), new VSC(21, 4.55, 70.85), new VSC(20, 2.31, 149.56), new VSC(9, 1.58, 56.62), new VSC(4, 0.23, 18.16), new VSC(4, 5.39, 76.27), new VSC(4, 0.95, 77.96), new VSC(3, 4.98, 85.83), new VSC(3, 4.13, 52.69), new VSC(3, 0.37, 78.71), new VSC(2, 0.86, 145.63), new VSC(2, 5.66, 9.56)];
+const g_L4UranusCoefficients = [new VSC(114, 3.142, 0), new VSC(6, 4.58, 74.78), new VSC(3, 0.35, 11.05), new VSC(1, 3.42, 56.62)];
+const g_B0UranusCoefficients = [new VSC(1346278, 2.6187781, 74.7815986), new VSC(62341, 5.08111, 149.5632), new VSC(61601, 3.14159, 0), new VSC(9964, 1.616, 76.2661), new VSC(9926, 0.5763, 73.2971), new VSC(3259, 1.2612, 224.3448), new VSC(2972, 2.2437, 1.4845), new VSC(2010, 6.0555, 148.0787), new VSC(1522, 0.2796, 63.7359), new VSC(924, 4.038, 151.048), new VSC(761, 6.14, 71.813), new VSC(522, 3.321, 138.517), new VSC(463, 0.743, 85.827), new VSC(437, 3.381, 529.691), new VSC(435, 0.341, 77.751), new VSC(431, 3.554, 213.299), new VSC(420, 5.213, 11.046), new VSC(245, 0.788, 2.969), new VSC(233, 2.257, 222.86), new VSC(216, 1.591, 38.133), new VSC(180, 3.725, 299.126), new VSC(175, 1.236, 146.594), new VSC(174, 1.937, 380.128), new VSC(160, 5.336, 111.43), new VSC(144, 5.962, 35.164), new VSC(116, 5.739, 70.849), new VSC(106, 0.941, 70.328), new VSC(102, 2.619, 78.714)];
+const g_B1UranusCoefficients = [new VSC(206366, 4.123943, 74.781599), new VSC(8563, 0.3382, 149.5632), new VSC(1726, 2.1219, 73.2971), new VSC(1374, 0, 0), new VSC(1369, 3.0686, 76.2661), new VSC(451, 3.777, 1.484), new VSC(400, 2.848, 224.345), new VSC(307, 1.255, 148.079), new VSC(154, 3.786, 63.736), new VSC(112, 5.573, 151.048), new VSC(111, 5.329, 138.517), new VSC(83, 3.59, 71.81), new VSC(56, 3.4, 85.83), new VSC(54, 1.7, 77.75), new VSC(42, 1.21, 11.05), new VSC(41, 4.45, 78.71), new VSC(32, 3.77, 222.86), new VSC(30, 2.56, 2.97), new VSC(27, 5.34, 213.3), new VSC(26, 0.42, 380.13)];
+const g_B2UranusCoefficients = [new VSC(9212, 5.8004, 74.7816), new VSC(557, 0, 0), new VSC(286, 2.177, 149.563), new VSC(95, 3.84, 73.3), new VSC(45, 4.88, 76.27), new VSC(20, 5.46, 1.48), new VSC(15, 0.88, 138.52), new VSC(14, 2.85, 148.08), new VSC(14, 5.07, 63.74), new VSC(10, 5, 224.34), new VSC(8, 6.27, 78.71)];
+const g_B3UranusCoefficients = [new VSC(268, 1.251, 74.782), new VSC(11, 3.14, 0), new VSC(6, 4.01, 149.56), new VSC(3, 5.78, 73.3)];
+const g_B4UranusCoefficients = [new VSC(6, 2.85, 74.78)];
+const g_R0UranusCoefficients = [new VSC(1921264848, 0, 0), new VSC(88784984, 5.60377527, 74.78159857), new VSC(3440836, 0.328361, 73.2971259), new VSC(2055653, 1.7829517, 149.5631971), new VSC(649322, 4.522473, 76.266071), new VSC(602248, 3.860038, 63.735898), new VSC(496404, 1.401399, 454.909367), new VSC(338526, 1.580027, 138.517497), new VSC(243508, 1.570866, 71.812653), new VSC(190522, 1.998094, 1.484473), new VSC(161858, 2.791379, 148.078724), new VSC(143706, 1.383686, 11.0457), new VSC(93192, 0.17437, 36.64856), new VSC(89806, 3.66105, 109.94569), new VSC(71424, 4.24509, 224.3448), new VSC(46677, 1.39977, 35.16409), new VSC(39026, 3.36235, 277.03499), new VSC(39010, 1.66971, 70.84945), new VSC(36755, 3.88649, 146.59425), new VSC(30349, 0.701, 151.04767), new VSC(29156, 3.18056, 77.75054), new VSC(25786, 3.78538, 85.8273), new VSC(25620, 5.25656, 380.12777), new VSC(22637, 0.72519, 529.69097), new VSC(20473, 2.7964, 70.32818), new VSC(20472, 1.55589, 202.2534), new VSC(17901, 0.55455, 2.96895), new VSC(15503, 5.35405, 38.13304), new VSC(14702, 4.90434, 108.46122), new VSC(12897, 2.62154, 111.43016), new VSC(12328, 5.96039, 127.4718), new VSC(11959, 1.75044, 984.60033), new VSC(11853, 0.99343, 52.6902), new VSC(11696, 3.29826, 3.93215), new VSC(11495, 0.43774, 65.22037), new VSC(10793, 1.42105, 213.2991), new VSC(9111, 4.9964, 62.2514), new VSC(8421, 5.2535, 222.8603), new VSC(8402, 5.0388, 415.5525), new VSC(7449, 0.7949, 351.8166), new VSC(7329, 3.9728, 183.2428), new VSC(6046, 5.6796, 78.7138), new VSC(5524, 3.115, 9.5612), new VSC(5445, 5.1058, 145.1098), new VSC(5238, 2.6296, 33.6796), new VSC(4079, 3.2206, 340.7709), new VSC(3919, 4.2502, 39.6175), new VSC(3802, 6.1099, 184.7273), new VSC(3781, 3.4584, 456.3938), new VSC(3687, 2.4872, 453.4249), new VSC(3102, 4.1403, 219.8914), new VSC(2963, 0.8298, 56.6224), new VSC(2942, 0.4239, 299.1264), new VSC(2940, 2.1464, 137.033), new VSC(2938, 3.6766, 140.002), new VSC(2865, 0.31, 12.5302), new VSC(2538, 4.8546, 131.4039), new VSC(2364, 0.4425, 554.07), new VSC(2183, 2.9404, 305.3462)];
+const g_R1UranusCoefficients = [new VSC(1479896, 3.6720571, 74.7815986), new VSC(71212, 6.22601, 63.7359), new VSC(68627, 6.13411, 149.5632), new VSC(24060, 3.14159, 0), new VSC(21468, 2.60177, 76.26607), new VSC(20857, 5.24625, 11.0457), new VSC(11405, 0.01848, 70.84945), new VSC(7497, 0.4236, 73.2971), new VSC(4244, 1.4169, 85.8273), new VSC(3927, 3.1551, 71.8127), new VSC(3578, 2.3116, 224.3448), new VSC(3506, 2.5835, 138.5175), new VSC(3229, 5.255, 3.9322), new VSC(3060, 0.1532, 1.4845), new VSC(2564, 0.9808, 148.0787), new VSC(2429, 3.9944, 52.6902), new VSC(1645, 2.6535, 127.4718), new VSC(1584, 1.4305, 78.7138), new VSC(1508, 5.06, 151.0477), new VSC(1490, 2.6756, 56.6224), new VSC(1413, 4.5746, 202.2534), new VSC(1403, 1.3699, 77.7505), new VSC(1228, 1.047, 62.2514), new VSC(1033, 0.2646, 131.4039), new VSC(992, 2.172, 65.22), new VSC(862, 5.055, 351.817), new VSC(744, 3.076, 35.164), new VSC(687, 2.499, 77.963), new VSC(647, 4.473, 70.328), new VSC(624, 0.863, 9.561), new VSC(604, 0.907, 984.6), new VSC(575, 3.231, 447.796), new VSC(562, 2.718, 462.023), new VSC(530, 5.917, 213.299), new VSC(528, 5.151, 2.969)];
+const g_R2UranusCoefficients = [new VSC(22440, 0.69953, 74.7816), new VSC(4727, 1.699, 63.7359), new VSC(1682, 4.6483, 70.8494), new VSC(1650, 3.0966, 11.0457), new VSC(1434, 3.5212, 149.5632), new VSC(770, 0, 0), new VSC(500, 6.172, 76.266), new VSC(461, 0.767, 3.932), new VSC(390, 4.496, 56.622), new VSC(390, 5.527, 85.827), new VSC(292, 0.204, 52.69), new VSC(287, 3.534, 73.297), new VSC(273, 3.847, 138.517), new VSC(220, 1.964, 131.404), new VSC(216, 0.848, 77.963), new VSC(205, 3.248, 78.714), new VSC(149, 4.898, 127.472), new VSC(129, 2.081, 3.181)];
+const g_R3UranusCoefficients = [new VSC(1164, 4.7345, 74.7816), new VSC(212, 3.343, 63.736), new VSC(196, 2.98, 70.849), new VSC(105, 0.958, 11.046), new VSC(73, 1, 149.56), new VSC(72, 0.03, 56.62), new VSC(55, 2.59, 3.93), new VSC(36, 5.65, 77.96), new VSC(34, 3.82, 76.27), new VSC(32, 3.6, 131.4)];
+const g_R4UranusCoefficients = [new VSC(53, 3.01, 74.78), new VSC(10, 1.91, 56.62)];
+
+
+// CAAUranus
+
+export function CAAUranus() { }
+
+CAAUranus.eclipticLongitude = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var nL0Coefficients = g_L0UranusCoefficients.length;
+ var L0 = 0;
+ var i;
+ for (i = 0; i < nL0Coefficients; i++) {
+ L0 += g_L0UranusCoefficients[i].a * Math.cos(g_L0UranusCoefficients[i].b + g_L0UranusCoefficients[i].c * rho);
+ }
+ var nL1Coefficients = g_L1UranusCoefficients.length;
+ var L1 = 0;
+ for (i = 0; i < nL1Coefficients; i++) {
+ L1 += g_L1UranusCoefficients[i].a * Math.cos(g_L1UranusCoefficients[i].b + g_L1UranusCoefficients[i].c * rho);
+ }
+ var nL2Coefficients = g_L2UranusCoefficients.length;
+ var L2 = 0;
+ for (i = 0; i < nL2Coefficients; i++) {
+ L2 += g_L2UranusCoefficients[i].a * Math.cos(g_L2UranusCoefficients[i].b + g_L2UranusCoefficients[i].c * rho);
+ }
+ var nL3Coefficients = g_L3UranusCoefficients.length;
+ var L3 = 0;
+ for (i = 0; i < nL3Coefficients; i++) {
+ L3 += g_L3UranusCoefficients[i].a * Math.cos(g_L3UranusCoefficients[i].b + g_L3UranusCoefficients[i].c * rho);
+ }
+ var nL4Coefficients = g_L4UranusCoefficients.length;
+ var L4 = 0;
+ for (i = 0; i < nL4Coefficients; i++) {
+ L4 += g_L4UranusCoefficients[i].a * Math.cos(g_L4UranusCoefficients[i].b + g_L4UranusCoefficients[i].c * rho);
+ }
+ var vvalue = (L0 + L1 * rho + L2 * rhosquared + L3 * rhocubed + L4 * rho4) / 100000000;
+ vvalue = CT.m360(CT.r2D(vvalue));
+ return vvalue;
+};
+
+CAAUranus.eclipticLatitude = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var nB0Coefficients = g_B0UranusCoefficients.length;
+ var B0 = 0;
+ var i;
+ for (i = 0; i < nB0Coefficients; i++) {
+ B0 += g_B0UranusCoefficients[i].a * Math.cos(g_B0UranusCoefficients[i].b + g_B0UranusCoefficients[i].c * rho);
+ }
+ var nB1Coefficients = g_B1UranusCoefficients.length;
+ var B1 = 0;
+ for (i = 0; i < nB1Coefficients; i++) {
+ B1 += g_B1UranusCoefficients[i].a * Math.cos(g_B1UranusCoefficients[i].b + g_B1UranusCoefficients[i].c * rho);
+ }
+ var nB2Coefficients = g_B2UranusCoefficients.length;
+ var B2 = 0;
+ for (i = 0; i < nB2Coefficients; i++) {
+ B2 += g_B2UranusCoefficients[i].a * Math.cos(g_B2UranusCoefficients[i].b + g_B2UranusCoefficients[i].c * rho);
+ }
+ var nB3Coefficients = g_B3UranusCoefficients.length;
+ var B3 = 0;
+ for (i = 0; i < nB3Coefficients; i++) {
+ B3 += g_B3UranusCoefficients[i].a * Math.cos(g_B3UranusCoefficients[i].b + g_B3UranusCoefficients[i].c * rho);
+ }
+ var nB4Coefficients = g_B4UranusCoefficients.length;
+ var B4 = 0;
+ for (i = 0; i < nB4Coefficients; i++) {
+ B4 += g_B4UranusCoefficients[i].a * Math.cos(g_B4UranusCoefficients[i].b + g_B4UranusCoefficients[i].c * rho);
+ }
+ var vvalue = (B0 + B1 * rho + B2 * rhosquared + B3 * rhocubed + B4 * rho4) / 100000000;
+ vvalue = CT.r2D(vvalue);
+ return vvalue;
+};
+
+CAAUranus.radiusVector = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var nR0Coefficients = g_R0UranusCoefficients.length;
+ var R0 = 0;
+ var i;
+ for (i = 0; i < nR0Coefficients; i++) {
+ R0 += g_R0UranusCoefficients[i].a * Math.cos(g_R0UranusCoefficients[i].b + g_R0UranusCoefficients[i].c * rho);
+ }
+ var nR1Coefficients = g_R1UranusCoefficients.length;
+ var R1 = 0;
+ for (i = 0; i < nR1Coefficients; i++) {
+ R1 += g_R1UranusCoefficients[i].a * Math.cos(g_R1UranusCoefficients[i].b + g_R1UranusCoefficients[i].c * rho);
+ }
+ var nR2Coefficients = g_R2UranusCoefficients.length;
+ var R2 = 0;
+ for (i = 0; i < nR2Coefficients; i++) {
+ R2 += g_R2UranusCoefficients[i].a * Math.cos(g_R2UranusCoefficients[i].b + g_R2UranusCoefficients[i].c * rho);
+ }
+ var nR3Coefficients = g_R3UranusCoefficients.length;
+ var R3 = 0;
+ for (i = 0; i < nR3Coefficients; i++) {
+ R3 += g_R3UranusCoefficients[i].a * Math.cos(g_R3UranusCoefficients[i].b + g_R3UranusCoefficients[i].c * rho);
+ }
+ var nR4Coefficients = g_R4UranusCoefficients.length;
+ var R4 = 0;
+ for (i = 0; i < nR4Coefficients; i++) {
+ R4 += g_R4UranusCoefficients[i].a * Math.cos(g_R4UranusCoefficients[i].b + g_R4UranusCoefficients[i].c * rho);
+ }
+ return (R0 + R1 * rho + R2 * rhosquared + R3 * rhocubed + R4 * rho4) / 100000000;
+};
+
+var CAAUranus$ = {};
+
+registerType("CAAUranus", [CAAUranus, CAAUranus$, null]);
+
diff --git a/engine/esm/astrocalc/venus.js b/engine/esm/astrocalc/venus.js
new file mode 100644
index 00000000..9b62ce41
--- /dev/null
+++ b/engine/esm/astrocalc/venus.js
@@ -0,0 +1,165 @@
+// Originally `AAVENUS.CPP`
+// "Purpose: Implementation for the algorithms which obtain the heliocentric position of Venus"
+// Last update of original: PJN / 29-12-2003
+//
+// Translated into C# and released by Microsoft, then transpiled into JavaScript
+// by ScriptSharp, for the WorldWide Telescope project.
+//
+// The legal notices in the original code are as follows:
+//
+// Copyright (c) 2003 - 2007 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)
+//
+// All rights reserved.
+//
+// Copyright / Usage Details:
+//
+// You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
+// when your product is released in binary form. You are allowed to modify the source code in any way you want
+// except you cannot modify the copyright details at the top of each module. If you want to distribute source
+// code with your application, then you are only allowed to distribute versions released by the author. This is
+// to maintain a single distribution point for the source code.
+
+import { registerType } from "../typesystem.js";
+import { CT } from "./coordinate_transformation.js";
+import { VSC } from "./earth.js";
+
+
+// Coefficients
+
+const g_L0VenusCoefficients = [new VSC(317614667, 0, 0), new VSC(1353968, 5.5931332, 10213.2855462), new VSC(89892, 5.3065, 20426.57109), new VSC(5477, 4.4163, 7860.4194), new VSC(3456, 2.6996, 11790.6291), new VSC(2372, 2.9938, 3930.2097), new VSC(1664, 4.2502, 1577.3435), new VSC(1438, 4.1575, 9683.5946), new VSC(1317, 5.1867, 26.2983), new VSC(1201, 6.1536, 30639.8566), new VSC(769, 0.816, 9437.763), new VSC(761, 1.95, 529.691), new VSC(708, 1.065, 775.523), new VSC(585, 3.998, 191.448), new VSC(500, 4.123, 15720.839), new VSC(429, 3.586, 19367.189), new VSC(327, 5.677, 5507.553), new VSC(326, 4.591, 10404.734), new VSC(232, 3.163, 9153.904), new VSC(180, 4.653, 1109.379), new VSC(155, 5.57, 19651.048), new VSC(128, 4.226, 20.775), new VSC(128, 0.962, 5661.332), new VSC(106, 1.537, 801.821)];
+const g_L1VenusCoefficients = [new VSC(1021352943053, 0, 0), new VSC(95708, 2.46424, 10213.28555), new VSC(14445, 0.51625, 20426.57109), new VSC(213, 1.795, 30639.857), new VSC(174, 2.655, 26.298), new VSC(152, 6.106, 1577.344), new VSC(82, 5.7, 191.45), new VSC(70, 2.68, 9437.76), new VSC(52, 3.6, 775.52), new VSC(38, 1.03, 529.69), new VSC(30, 1.25, 5507.55), new VSC(25, 6.11, 10404.73)];
+const g_L2VenusCoefficients = [new VSC(54127, 0, 0), new VSC(3891, 0.3451, 10213.2855), new VSC(1338, 2.0201, 20426.5711), new VSC(24, 2.05, 26.3), new VSC(19, 3.54, 30639.86), new VSC(10, 3.97, 775.52), new VSC(7, 1.52, 1577.34), new VSC(6, 1, 191.45)];
+const g_L3VenusCoefficients = [new VSC(136, 4.804, 10213.286), new VSC(78, 3.67, 20426.57), new VSC(26, 0, 0)];
+const g_L4VenusCoefficients = [new VSC(114, 3.1416, 0), new VSC(3, 5.21, 20426.57), new VSC(2, 2.51, 10213.29)];
+const g_L5VenusCoefficients = [new VSC(1, 3.14, 0)];
+const g_B0VenusCoefficients = [new VSC(5923638, 0.2670278, 10213.2855462), new VSC(40108, 1.14737, 20426.57109), new VSC(32815, 3.14737, 0), new VSC(1011, 1.0895, 30639.8566), new VSC(149, 6.254, 18073.705), new VSC(138, 0.86, 1577.344), new VSC(130, 3.672, 9437.763), new VSC(120, 3.705, 2352.866), new VSC(108, 4.539, 22003.915)];
+const g_B1VenusCoefficients = [new VSC(513348, 1.803643, 10213.285546), new VSC(4380, 3.3862, 20426.5711), new VSC(199, 0, 0), new VSC(197, 2.53, 30639.857)];
+const g_B2VenusCoefficients = [new VSC(22378, 3.38509, 10213.28555), new VSC(282, 0, 0), new VSC(173, 5.256, 20426.571), new VSC(27, 3.87, 30639.86)];
+const g_B3VenusCoefficients = [new VSC(647, 4.992, 10213.286), new VSC(20, 3.14, 0), new VSC(6, 0.77, 20426.57), new VSC(3, 5.44, 30639.86)];
+const g_B4VenusCoefficients = [new VSC(14, 0.32, 10213.29)];
+const g_R0VenusCoefficients = [new VSC(72334821, 0, 0), new VSC(489824, 4.021518, 10213.285546), new VSC(1658, 4.9021, 20426.5711), new VSC(1632, 2.8455, 7860.4194), new VSC(1378, 1.1285, 11790.6291), new VSC(498, 2.587, 9683.595), new VSC(374, 1.423, 3930.21), new VSC(264, 5.529, 9437.763), new VSC(237, 2.551, 15720.839), new VSC(222, 2.013, 19367.189), new VSC(126, 2.728, 1577.344), new VSC(119, 3.02, 10404.734)];
+const g_R1VenusCoefficients = [new VSC(34551, 0.89199, 10213.28555), new VSC(234, 1.772, 20426.571), new VSC(234, 3.142, 0)];
+const g_R2VenusCoefficients = [new VSC(1407, 5.0637, 10213.2855), new VSC(16, 5.47, 20426.57), new VSC(13, 0, 0)];
+const g_R3VenusCoefficients = [new VSC(50, 3.22, 10213.29)];
+const g_R4VenusCoefficients = [new VSC(1, 0.92, 10213.29)];
+
+
+// CAAVenus
+
+export function CAAVenus() { }
+
+CAAVenus.eclipticLongitude = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var rho5 = rho4 * rho;
+ var nL0Coefficients = g_L0VenusCoefficients.length;
+ var L0 = 0;
+ var i;
+ for (i = 0; i < nL0Coefficients; i++) {
+ L0 += g_L0VenusCoefficients[i].a * Math.cos(g_L0VenusCoefficients[i].b + g_L0VenusCoefficients[i].c * rho);
+ }
+ var nL1Coefficients = g_L1VenusCoefficients.length;
+ var L1 = 0;
+ for (i = 0; i < nL1Coefficients; i++) {
+ L1 += g_L1VenusCoefficients[i].a * Math.cos(g_L1VenusCoefficients[i].b + g_L1VenusCoefficients[i].c * rho);
+ }
+ var nL2Coefficients = g_L2VenusCoefficients.length;
+ var L2 = 0;
+ for (i = 0; i < nL2Coefficients; i++) {
+ L2 += g_L2VenusCoefficients[i].a * Math.cos(g_L2VenusCoefficients[i].b + g_L2VenusCoefficients[i].c * rho);
+ }
+ var nL3Coefficients = g_L3VenusCoefficients.length;
+ var L3 = 0;
+ for (i = 0; i < nL3Coefficients; i++) {
+ L3 += g_L3VenusCoefficients[i].a * Math.cos(g_L3VenusCoefficients[i].b + g_L3VenusCoefficients[i].c * rho);
+ }
+ var nL4Coefficients = g_L4VenusCoefficients.length;
+ var L4 = 0;
+ for (i = 0; i < nL4Coefficients; i++) {
+ L4 += g_L4VenusCoefficients[i].a * Math.cos(g_L4VenusCoefficients[i].b + g_L4VenusCoefficients[i].c * rho);
+ }
+ var nL5Coefficients = g_L5VenusCoefficients.length;
+ var L5 = 0;
+ for (i = 0; i < nL5Coefficients; i++) {
+ L5 += g_L5VenusCoefficients[i].a * Math.cos(g_L5VenusCoefficients[i].b + g_L5VenusCoefficients[i].c * rho);
+ }
+ var vvalue = (L0 + L1 * rho + L2 * rhosquared + L3 * rhocubed + L4 * rho4 + L5 * rho5) / 100000000;
+ vvalue = CT.m360(CT.r2D(vvalue));
+ return vvalue;
+};
+
+CAAVenus.eclipticLatitude = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var nB0Coefficients = g_B0VenusCoefficients.length;
+ var B0 = 0;
+ var i;
+ for (i = 0; i < nB0Coefficients; i++) {
+ B0 += g_B0VenusCoefficients[i].a * Math.cos(g_B0VenusCoefficients[i].b + g_B0VenusCoefficients[i].c * rho);
+ }
+ var nB1Coefficients = g_B1VenusCoefficients.length;
+ var B1 = 0;
+ for (i = 0; i < nB1Coefficients; i++) {
+ B1 += g_B1VenusCoefficients[i].a * Math.cos(g_B1VenusCoefficients[i].b + g_B1VenusCoefficients[i].c * rho);
+ }
+ var nB2Coefficients = g_B2VenusCoefficients.length;
+ var B2 = 0;
+ for (i = 0; i < nB2Coefficients; i++) {
+ B2 += g_B2VenusCoefficients[i].a * Math.cos(g_B2VenusCoefficients[i].b + g_B2VenusCoefficients[i].c * rho);
+ }
+ var nB3Coefficients = g_B3VenusCoefficients.length;
+ var B3 = 0;
+ for (i = 0; i < nB3Coefficients; i++) {
+ B3 += g_B3VenusCoefficients[i].a * Math.cos(g_B3VenusCoefficients[i].b + g_B3VenusCoefficients[i].c * rho);
+ }
+ var nB4Coefficients = g_B4VenusCoefficients.length;
+ var B4 = 0;
+ for (i = 0; i < nB4Coefficients; i++) {
+ B4 += g_B4VenusCoefficients[i].a * Math.cos(g_B4VenusCoefficients[i].b + g_B4VenusCoefficients[i].c * rho);
+ }
+ var vvalue = (B0 + B1 * rho + B2 * rhosquared + B3 * rhocubed + B4 * rho4) / 100000000;
+ vvalue = CT.r2D(vvalue);
+ return vvalue;
+};
+
+CAAVenus.radiusVector = function (JD) {
+ var rho = (JD - 2451545) / 365250;
+ var rhosquared = rho * rho;
+ var rhocubed = rhosquared * rho;
+ var rho4 = rhocubed * rho;
+ var nR0Coefficients = g_R0VenusCoefficients.length;
+ var R0 = 0;
+ var i;
+ for (i = 0; i < nR0Coefficients; i++) {
+ R0 += g_R0VenusCoefficients[i].a * Math.cos(g_R0VenusCoefficients[i].b + g_R0VenusCoefficients[i].c * rho);
+ }
+ var nR1Coefficients = g_R1VenusCoefficients.length;
+ var R1 = 0;
+ for (i = 0; i < nR1Coefficients; i++) {
+ R1 += g_R1VenusCoefficients[i].a * Math.cos(g_R1VenusCoefficients[i].b + g_R1VenusCoefficients[i].c * rho);
+ }
+ var nR2Coefficients = g_R2VenusCoefficients.length;
+ var R2 = 0;
+ for (i = 0; i < nR2Coefficients; i++) {
+ R2 += g_R2VenusCoefficients[i].a * Math.cos(g_R2VenusCoefficients[i].b + g_R2VenusCoefficients[i].c * rho);
+ }
+ var nR3Coefficients = g_R3VenusCoefficients.length;
+ var R3 = 0;
+ for (i = 0; i < nR3Coefficients; i++) {
+ R3 += g_R3VenusCoefficients[i].a * Math.cos(g_R3VenusCoefficients[i].b + g_R3VenusCoefficients[i].c * rho);
+ }
+ var nR4Coefficients = g_R4VenusCoefficients.length;
+ var R4 = 0;
+ for (i = 0; i < nR4Coefficients; i++) {
+ R4 += g_R4VenusCoefficients[i].a * Math.cos(g_R4VenusCoefficients[i].b + g_R4VenusCoefficients[i].c * rho);
+ }
+ return (R0 + R1 * rho + R2 * rhosquared + R3 * rhocubed + R4 * rho4) / 100000000;
+};
+
+var CAAVenus$ = {};
+
+registerType("CAAVenus", [CAAVenus, CAAVenus$, null]);
diff --git a/engine/esm/baseplanets.js b/engine/esm/baseplanets.js
new file mode 100644
index 00000000..d0259371
--- /dev/null
+++ b/engine/esm/baseplanets.js
@@ -0,0 +1,51 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Planet-related code that can come lower in the dependency graph.
+
+import { registerType } from "./typesystem.js";
+import { Vector3d } from "./double3d.js";
+import { Dates, PointList } from "./graphics/primitives3d.js";
+
+
+// BasePlanets
+
+export function BasePlanets() { }
+
+BasePlanets.drawPointPlanet = function (renderContext, location, size, color, zOrder) {
+ var center = location;
+ var rad = size / 2;
+ if (renderContext.gl != null) {
+ var ppList = new PointList(renderContext);
+ ppList.minSize = 20;
+ ppList.addPoint(location.copy(), color._clone(), new Dates(0, 1), size / 100);
+ ppList.depthBuffered = true;
+ ppList.draw(renderContext, 1, false);
+ }
+ else {
+ var screenSpacePnt = renderContext.WVP.transform(center);
+ if (screenSpacePnt.z < 0) {
+ return;
+ }
+ if (!zOrder) {
+ if (Vector3d.dot(renderContext.get_viewPoint(), center) < 0.55) {
+ return;
+ }
+ }
+ var ctx = renderContext.device;
+ ctx.save();
+ ctx.beginPath();
+ ctx.arc(screenSpacePnt.x, screenSpacePnt.y, rad, 0, Math.PI * 2, true);
+ ctx.lineWidth = 1;
+ ctx.fillStyle = color.toString();
+ if (true) {
+ ctx.fill();
+ }
+ ctx.globalAlpha = 1;
+ ctx.strokeStyle = color.toString();
+ ctx.stroke();
+ ctx.restore();
+ }
+};
+
+registerType("BasePlanets", [BasePlanets, {}, null]);
diff --git a/engine/esm/baseutil.js b/engine/esm/baseutil.js
new file mode 100644
index 00000000..4b65f185
--- /dev/null
+++ b/engine/esm/baseutil.js
@@ -0,0 +1,207 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Miscellaneous utilities.
+
+import { registerType } from "./typesystem.js";
+import { ss } from "./ss.js";
+
+// wwtlib.Util
+
+export function Util() {
+}
+
+Util.splitString = function (target, split) {
+ var parts = [];
+ var start = 0;
+ var end = 0;
+ for (var i = 0; i < target.length; i++) {
+ var found = false;
+ for (var j = 0; j < split.length; j++) {
+ if (target[i] === split[j]) {
+ parts.push(target.substring(start, end - start));
+ found = true;
+ continue;
+ }
+ start = i + 1;
+ end = i + 1;
+ }
+ if (!found) {
+ end++;
+ }
+ }
+ if (end > start) {
+ parts.push(target.substring(start, end - start));
+ }
+ return parts;
+};
+
+Util.stringContains = function (target, chars) {
+ for (var i = 0; i < chars.length; i++) {
+ if (target.indexOf(chars[i]) > -1) {
+ return true;
+ }
+ }
+ return false;
+};
+
+Util.getHashCode = function (target) {
+ var hash = 0;
+ if (!target.length) {
+ return hash;
+ }
+ for (var i = 0; i < target.length; i++) {
+ var c = target.charCodeAt(i);
+ hash = ((hash << 5) - hash) + c;
+ }
+ return hash;
+};
+
+Util.compare = function (l, r) {
+ if (l === r) {
+ return 0;
+ }
+ if (l > r) {
+ return 1;
+ }
+ return -1;
+};
+
+Util.logN = function (num, b) {
+ return Math.log(num) / Math.log(b);
+};
+
+// Parse timespan into int with milliseconds
+Util.parseTimeSpan = function (timespan) {
+ var val = 0;
+ var parts = timespan.split(':');
+ if (parts.length === 3) {
+ val += parseInt(parts[0]) * 3600000;
+ val += parseInt(parts[1]) * 60000;
+ val += ss.truncate((parseFloat(parts[2]) * 1000));
+ }
+ return val;
+};
+
+// convert duration to HH:MM:SS.S
+Util.xmlDuration = function (duration) {
+ var s = duration / 1000;
+ var hours = Math.floor(s / 3600);
+ var min = Math.floor(s / 60) - (hours * 60);
+ var sec = s - ((hours * 3600) + min * 60);
+ return ss.format('{0}:{1}:{2}', hours, min, sec);
+};
+
+Util.xmlDate = function (d) {
+ var hours = d.getHours();
+ var amPm = 'AM';
+ if (hours > 12) {
+ hours -= 12;
+ amPm = 'PM';
+ }
+ return (d.getMonth() + 1).toString() + '/' + d.getDate().toString() + '/' + d.getFullYear().toString() + ' ' + hours.toString() + ':' + d.getMinutes().toString() + ':' + d.getSeconds().toString() + ' ' + amPm;
+};
+
+Util.selectSingleNode = function (parent, name) {
+ var node = null;
+ var $enum1 = ss.enumerate(parent.childNodes);
+ while ($enum1.moveNext()) {
+ var child = $enum1.current;
+ if (child.nodeName === name) {
+ node = child;
+ break;
+ }
+ }
+ return node;
+};
+
+Util.getInnerText = function (node) {
+ if (ss.emptyString(node.text)) {
+ var cn = node;
+ return cn.textContent;
+ }
+ else {
+ return node.text;
+ }
+};
+
+Util.getWrappedText = function (ctx, text, width) {
+ var lines = [];
+ lines.push(text);
+ return lines;
+};
+
+Util.toHex = function (number) {
+ var num = Math.max(0, Math.min(ss.truncate(number), 255));
+ return '0123456789ABCDEF'.substr((num - num % 16) / 16, 1) + '0123456789ABCDEF'.substr(num % 16, 1);
+};
+
+Util.fromHex = function (data) {
+ var val = 0;
+ switch (data.substr(1, 1).toUpperCase()) {
+ case 'A':
+ val += 10;
+ break;
+ case 'B':
+ val += 11;
+ break;
+ case 'C':
+ val += 12;
+ break;
+ case 'D':
+ val += 13;
+ break;
+ case 'E':
+ val += 14;
+ break;
+ case 'F':
+ val += 15;
+ break;
+ default:
+ val += parseInt(data.substr(1, 1));
+ break;
+ }
+ switch (data.substr(0, 1).toUpperCase()) {
+ case 'A':
+ val += 10 * 16;
+ break;
+ case 'B':
+ val += 11 * 16;
+ break;
+ case 'C':
+ val += 12 * 16;
+ break;
+ case 'D':
+ val += 13 * 16;
+ break;
+ case 'E':
+ val += 14 * 16;
+ break;
+ case 'F':
+ val += 15 * 16;
+ break;
+ default:
+ val += parseInt(data.substr(0, 1)) * 16;
+ break;
+ }
+ return val;
+};
+
+Util._openUrl = function (url) {
+ window.open(url);
+};
+
+Util.log10 = function (num) {
+ return Math.log(num) / 2.30258509299405;
+};
+
+Util.sign = function (num) {
+ if (num < 0) {
+ return -1;
+ }
+ return 1;
+};
+
+var Util$ = {};
+
+registerType("Util", [Util, Util$, null]);
diff --git a/engine/esm/blend_state.js b/engine/esm/blend_state.js
new file mode 100644
index 00000000..9ac83e31
--- /dev/null
+++ b/engine/esm/blend_state.js
@@ -0,0 +1,82 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Blend state.
+
+import { ss } from "./ss.js";
+import { registerType } from "./typesystem.js";
+
+
+// wwtlib.BlendState
+
+export function BlendState() {
+ this._switchedTime = new Date(1990, 0, 0, 0, 0, 0, 0);
+ this._state = false;
+ this._targetState = this._state;
+ this._delayTime = 1000;
+}
+
+BlendState.create = function (initialState, delayTime) {
+ var temp = new BlendState();
+ temp._state = initialState;
+ temp._targetState = initialState;
+ temp._delayTime = delayTime;
+ return temp;
+};
+
+var BlendState$ = {
+ get_state: function () {
+ if (this._targetState !== this._state) {
+ var ts = ss.now() - this._switchedTime;
+ if (ts > this._delayTime) {
+ this._state = this._targetState;
+ }
+ return true;
+ }
+ return this._state;
+ },
+
+ set_state: function (value) {
+ this._switchedTime = new Date(1990, 0, 0, 0, 0, 0, 0);
+ this._state = value;
+ this._targetState = this._state;
+ return value;
+ },
+
+ get_targetState: function () {
+ return this._targetState;
+ },
+
+ set_targetState: function (value) {
+ if (this._targetState !== value) {
+ this._switchedTime = ss.now();
+ this._targetState = value;
+ }
+ return value;
+ },
+
+ get_opacity: function () {
+ if (this._targetState !== this._state) {
+ var ts = ss.now() - this._switchedTime;
+ if (ts > this._delayTime) {
+ this._state = this._targetState;
+ }
+ else {
+ var opacity = (ts / this._delayTime);
+ return (this._targetState) ? opacity : 1 - opacity;
+ }
+ }
+ return (this._state) ? 1 : 0;
+ },
+
+ get_delayTime: function () {
+ return this._delayTime;
+ },
+
+ set_delayTime: function (value) {
+ this._delayTime = value;
+ return value;
+ }
+};
+
+registerType("BlendState", [BlendState, BlendState$, null]);
diff --git a/engine/esm/camera_parameters.js b/engine/esm/camera_parameters.js
new file mode 100644
index 00000000..64bdabc3
--- /dev/null
+++ b/engine/esm/camera_parameters.js
@@ -0,0 +1,221 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Camera parameters.
+
+import { registerType, registerEnum } from "./typesystem.js";
+import { ss } from "./ss.js";
+import { Vector3d } from "./double3d.js";
+import { Coordinates } from "./coordinates.js";
+
+
+// wwtlib.SolarSystemObjects
+
+export var SolarSystemObjects = {
+ sun: 0,
+ mercury: 1,
+ venus: 2,
+ mars: 3,
+ jupiter: 4,
+ saturn: 5,
+ uranus: 6,
+ neptune: 7,
+ pluto: 8,
+ moon: 9,
+ io: 10,
+ europa: 11,
+ ganymede: 12,
+ callisto: 13,
+ ioShadow: 14,
+ europaShadow: 15,
+ ganymedeShadow: 16,
+ callistoShadow: 17,
+ sunEclipsed: 18,
+ earth: 19,
+ custom: 20,
+ undefined: 65536
+};
+
+registerType("SolarSystemObjects", SolarSystemObjects);
+registerEnum("SolarSystemObjects", SolarSystemObjects);
+
+
+// wwtlib.InterpolationType
+
+export var InterpolationType = {
+ linear: 0,
+ easeIn: 1,
+ easeOut: 2,
+ easeInOut: 3,
+ exponential: 4,
+ defaultV: 5
+};
+
+registerType("InterpolationType", InterpolationType);
+registerEnum("InterpolationType", InterpolationType);
+
+
+
+// wwtlib.CameraParameters
+
+export function CameraParameters() {
+ this.lat = 0;
+ this.lng = 0;
+ this.zoom = 0;
+ this.rotation = 0;
+ this.angle = 0;
+ this.raDec = false;
+ this.opacity = 0;
+ this.target = 0;
+ this.zoom = 360;
+ this.viewTarget = new Vector3d();
+}
+
+CameraParameters.create = function (lat, lng, zoom, rotation, angle, opactity) {
+ var temp = new CameraParameters();
+ temp.lat = lat;
+ temp.lng = lng;
+ temp.zoom = zoom;
+ temp.rotation = rotation;
+ temp.angle = angle;
+ temp.raDec = false;
+ temp.opacity = opactity;
+ temp.viewTarget = Vector3d.create(0, 0, 0);
+ temp.target = 20;
+ temp.targetReferenceFrame = '';
+ return temp;
+};
+
+CameraParameters.logN = function (num, b) {
+ return Math.log(num) / Math.log(b);
+};
+
+CameraParameters.sinh = function (v) {
+ return (Math.exp(v) - Math.exp(-v)) / 2;
+};
+
+CameraParameters.interpolate = function (from, to, alphaIn, type, fastDirectionMove) {
+ var result = new CameraParameters();
+ var alpha = CameraParameters.easeCurve(alphaIn, type);
+ var alphaBIn = Math.min(1, alphaIn * 2);
+ var alphaB = CameraParameters.easeCurve(alphaBIn, type);
+ result.angle = to.angle * alpha + from.angle * (1 - alpha);
+ result.rotation = to.rotation * alpha + from.rotation * (1 - alpha);
+ if (fastDirectionMove) {
+ result.lat = to.lat * alphaB + from.lat * (1 - alphaB);
+ result.lng = to.lng * alphaB + from.lng * (1 - alphaB);
+ }
+ else {
+ result.lat = to.lat * alpha + from.lat * (1 - alpha);
+ result.lng = to.lng * alpha + from.lng * (1 - alpha);
+ }
+ result.zoom = Math.pow(2, CameraParameters.logN(to.zoom, 2) * alpha + CameraParameters.logN(from.zoom, 2) * (1 - alpha));
+ result.opacity = (to.opacity * alpha + from.opacity * (1 - alpha));
+ result.viewTarget = Vector3d.lerp(from.viewTarget, to.viewTarget, alpha);
+ result.targetReferenceFrame = to.targetReferenceFrame;
+ if (to.target === from.target) {
+ result.target = to.target;
+ }
+ else {
+ result.target = 20;
+ }
+ return result;
+};
+
+CameraParameters.interpolateGreatCircle = function (from, to, alphaIn, type, fastDirectionMove) {
+ var result = new CameraParameters();
+ var alpha = CameraParameters.easeCurve(alphaIn, type);
+ var alphaBIn = Math.min(1, alphaIn * 2);
+ var alphaB = CameraParameters.easeCurve(alphaBIn, type);
+ result.angle = to.angle * alpha + from.angle * (1 - alpha);
+ result.rotation = to.rotation * alpha + from.rotation * (1 - alpha);
+ var left = Coordinates.geoTo3dDouble(from.lat, from.lng);
+ var right = Coordinates.geoTo3dDouble(to.lat, to.lng);
+ var mid = Vector3d.slerp(left, right, alpha);
+ var midV2 = Coordinates.cartesianToLatLng(mid);
+ result.lat = midV2.y;
+ result.lng = midV2.x;
+ result.zoom = Math.pow(2, CameraParameters.logN(to.zoom, 2) * alpha + CameraParameters.logN(from.zoom, 2) * (1 - alpha));
+ result.opacity = (to.opacity * alpha + from.opacity * (1 - alpha));
+ result.viewTarget = Vector3d.lerp(from.viewTarget, to.viewTarget, alpha);
+ result.targetReferenceFrame = to.targetReferenceFrame;
+ if (to.target === from.target) {
+ result.target = to.target;
+ }
+ else {
+ result.target = 20;
+ }
+ return result;
+};
+
+CameraParameters.easeCurve = function (alpha, type) {
+ switch (type) {
+ case 0:
+ return alpha;
+ case 4:
+ return Math.pow(alpha, 2);
+ case 1:
+ return ((1 - alpha) * CameraParameters.sinh(alpha / (0.1085712344 * 2)) / 100) + alpha * alpha;
+ case 2:
+ return (alpha * (1 - CameraParameters.sinh((1 - alpha) / (0.1085712344 * 2)) / 100)) + (1 - alpha) * alpha;
+ case 3:
+ if (alpha < 0.5) {
+ return CameraParameters.sinh(alpha / 0.1085712344) / 100;
+ }
+ else {
+ return 1 - (CameraParameters.sinh((1 - alpha) / 0.1085712344) / 100);
+ }
+ default:
+ return alpha;
+ }
+};
+
+var CameraParameters$ = {
+ copy: function () {
+ var temp = new CameraParameters();
+ temp.lat = this.lat;
+ temp.lng = this.lng;
+ temp.zoom = this.zoom;
+ temp.rotation = this.rotation;
+ temp.angle = this.angle;
+ temp.raDec = this.raDec;
+ temp.opacity = this.opacity;
+ temp.viewTarget = this.viewTarget.copy();
+ temp.target = this.target;
+ temp.targetReferenceFrame = this.targetReferenceFrame;
+ return temp;
+ },
+
+ get_RA: function () {
+ return ((((180 - (this.lng - 180)) / 360) * 24) % 24);
+ },
+
+ set_RA: function (value) {
+ this.lng = 180 - (value / 24 * 360) - 180;
+ this.raDec = true;
+ return value;
+ },
+
+ get_dec: function () {
+ return this.lat;
+ },
+
+ set_dec: function (value) {
+ this.lat = value;
+ return value;
+ },
+
+ equals: function (obj) {
+ if (ss.canCast(obj, CameraParameters)) {
+ var cam = obj;
+ if (Math.abs(cam.angle - this.angle) > 0.01 || Math.abs(cam.lat - this.lat) > (cam.zoom / 10000) || Math.abs(cam.get_RA() - this.get_RA()) > (cam.zoom / 1000) || Math.abs(cam.rotation - this.rotation) > 0.1 || Math.abs(cam.zoom - this.zoom) > (Math.abs(cam.zoom) / 1000)) {
+ return false;
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+};
+
+registerType("CameraParameters", [CameraParameters, CameraParameters$, null]);
diff --git a/engine/esm/color.js b/engine/esm/color.js
new file mode 100644
index 00000000..c9a93da7
--- /dev/null
+++ b/engine/esm/color.js
@@ -0,0 +1,556 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Basic color types.
+
+import { registerType } from "./typesystem.js";
+import { ss } from "./ss.js";
+import { Util } from "./util.js";
+
+// wwtlib.Color
+
+export function Color() {
+ this.a = 255;
+ this.b = 255;
+ this.g = 255;
+ this.r = 255;
+ this.name = '';
+}
+
+Color.fromArgb = function (a, r, g, b) {
+ var temp = new Color();
+ temp.a = a;
+ temp.r = r;
+ temp.g = g;
+ temp.b = b;
+ return temp;
+};
+
+Color._fromArgbColor = function (a, col) {
+ var temp = new Color();
+ temp.a = a;
+ temp.r = col.r;
+ temp.g = col.g;
+ temp.b = col.b;
+ return temp;
+};
+
+Color.fromName = function (name) {
+ var temp = Color.load(name);
+ return temp;
+};
+
+Color.load = function (color) {
+ var a = 255, r = 255, g = 255, b = 255;
+ var pieces = color.split(':');
+ if (pieces.length === 5) {
+ a = parseInt(pieces[1]);
+ r = parseInt(pieces[2]);
+ g = parseInt(pieces[3]);
+ b = parseInt(pieces[4]);
+ }
+ else if (pieces.length === 2) {
+ return Color.fromName(pieces[1].toLowerCase());
+ }
+ else if (pieces.length === 1 && ss.startsWith(pieces[0], '#')) {
+ return Color.fromHex(pieces[0]);
+ }
+ else if (pieces.length === 1 && pieces[0].length === 8) {
+ return Color.fromSimpleHex(pieces[0]);
+ }
+ else if (pieces.length === 1) {
+ return Color._fromWindowsNamedColor(pieces[0]);
+ }
+ return Color.fromArgb(a, r, g, b);
+};
+
+Color._fromWindowsNamedColor = function (color) {
+ switch (color.toLowerCase()) {
+ case 'activeborder':
+ return Color.fromArgb(255, 180, 180, 180);
+ case 'activecaption':
+ return Color.fromArgb(255, 153, 180, 209);
+ case 'activecaptiontext':
+ return Color.fromArgb(255, 0, 0, 0);
+ case 'appworkspace':
+ return Color.fromArgb(255, 171, 171, 171);
+ case 'control':
+ return Color.fromArgb(255, 240, 240, 240);
+ case 'controldark':
+ return Color.fromArgb(255, 160, 160, 160);
+ case 'controldarkdark':
+ return Color.fromArgb(255, 105, 105, 105);
+ case 'controllight':
+ return Color.fromArgb(255, 227, 227, 227);
+ case 'controllightlight':
+ return Color.fromArgb(255, 255, 255, 255);
+ case 'controltext':
+ return Color.fromArgb(255, 0, 0, 0);
+ case 'desktop':
+ return Color.fromArgb(255, 255, 255, 255);
+ case 'graytext':
+ return Color.fromArgb(255, 109, 109, 109);
+ case 'highlight':
+ return Color.fromArgb(255, 51, 153, 255);
+ case 'highlighttext':
+ return Color.fromArgb(255, 255, 255, 255);
+ case 'hottrack':
+ return Color.fromArgb(255, 0, 102, 204);
+ case 'inactiveborder':
+ return Color.fromArgb(255, 244, 247, 252);
+ case 'inactivecaption':
+ return Color.fromArgb(255, 191, 205, 219);
+ case 'inactivecaptiontext':
+ return Color.fromArgb(255, 0, 0, 0);
+ case 'info':
+ return Color.fromArgb(255, 255, 255, 225);
+ case 'infotext':
+ return Color.fromArgb(255, 0, 0, 0);
+ case 'menu':
+ return Color.fromArgb(255, 240, 240, 240);
+ case 'menutext':
+ return Color.fromArgb(255, 0, 0, 0);
+ case 'scrollbar':
+ return Color.fromArgb(255, 200, 200, 200);
+ case 'window':
+ return Color.fromArgb(255, 255, 255, 255);
+ case 'windowframe':
+ return Color.fromArgb(255, 100, 100, 100);
+ case 'windowtext':
+ return Color.fromArgb(255, 0, 0, 0);
+ case 'transparent':
+ return Color.fromArgb(0, 255, 255, 255);
+ case 'aliceblue':
+ return Color.fromArgb(255, 240, 248, 255);
+ case 'antiquewhite':
+ return Color.fromArgb(255, 250, 235, 215);
+ case 'aqua':
+ return Color.fromArgb(255, 0, 255, 255);
+ case 'aquamarine':
+ return Color.fromArgb(255, 127, 255, 212);
+ case 'azure':
+ return Color.fromArgb(255, 240, 255, 255);
+ case 'beige':
+ return Color.fromArgb(255, 245, 245, 220);
+ case 'bisque':
+ return Color.fromArgb(255, 255, 228, 196);
+ case 'black':
+ return Color.fromArgb(255, 0, 0, 0);
+ case 'blanchedalmond':
+ return Color.fromArgb(255, 255, 235, 205);
+ case 'blue':
+ return Color.fromArgb(255, 0, 0, 255);
+ case 'blueviolet':
+ return Color.fromArgb(255, 138, 43, 226);
+ case 'brown':
+ return Color.fromArgb(255, 165, 42, 42);
+ case 'burlywood':
+ return Color.fromArgb(255, 222, 184, 135);
+ case 'cadetblue':
+ return Color.fromArgb(255, 95, 158, 160);
+ case 'chartreuse':
+ return Color.fromArgb(255, 127, 255, 0);
+ case 'chocolate':
+ return Color.fromArgb(255, 210, 105, 30);
+ case 'coral':
+ return Color.fromArgb(255, 255, 127, 80);
+ case 'cornflowerblue':
+ return Color.fromArgb(255, 100, 149, 237);
+ case 'cornsilk':
+ return Color.fromArgb(255, 255, 248, 220);
+ case 'crimson':
+ return Color.fromArgb(255, 220, 20, 60);
+ case 'cyan':
+ return Color.fromArgb(255, 0, 255, 255);
+ case 'darkblue':
+ return Color.fromArgb(255, 0, 0, 139);
+ case 'darkcyan':
+ return Color.fromArgb(255, 0, 139, 139);
+ case 'darkgoldenrod':
+ return Color.fromArgb(255, 184, 134, 11);
+ case 'darkgray':
+ return Color.fromArgb(255, 169, 169, 169);
+ case 'darkgreen':
+ return Color.fromArgb(255, 0, 100, 0);
+ case 'darkkhaki':
+ return Color.fromArgb(255, 189, 183, 107);
+ case 'darkmagenta':
+ return Color.fromArgb(255, 139, 0, 139);
+ case 'darkolivegreen':
+ return Color.fromArgb(255, 85, 107, 47);
+ case 'darkorange':
+ return Color.fromArgb(255, 255, 140, 0);
+ case 'darkorchid':
+ return Color.fromArgb(255, 153, 50, 204);
+ case 'darkred':
+ return Color.fromArgb(255, 139, 0, 0);
+ case 'darksalmon':
+ return Color.fromArgb(255, 233, 150, 122);
+ case 'darkseagreen':
+ return Color.fromArgb(255, 143, 188, 139);
+ case 'darkslateblue':
+ return Color.fromArgb(255, 72, 61, 139);
+ case 'darkslategray':
+ return Color.fromArgb(255, 47, 79, 79);
+ case 'darkturquoise':
+ return Color.fromArgb(255, 0, 206, 209);
+ case 'darkviolet':
+ return Color.fromArgb(255, 148, 0, 211);
+ case 'deeppink':
+ return Color.fromArgb(255, 255, 20, 147);
+ case 'deepskyblue':
+ return Color.fromArgb(255, 0, 191, 255);
+ case 'dimgray':
+ return Color.fromArgb(255, 105, 105, 105);
+ case 'dodgerblue':
+ return Color.fromArgb(255, 30, 144, 255);
+ case 'firebrick':
+ return Color.fromArgb(255, 178, 34, 34);
+ case 'floralwhite':
+ return Color.fromArgb(255, 255, 250, 240);
+ case 'forestgreen':
+ return Color.fromArgb(255, 34, 139, 34);
+ case 'fuchsia':
+ return Color.fromArgb(255, 255, 0, 255);
+ case 'gainsboro':
+ return Color.fromArgb(255, 220, 220, 220);
+ case 'ghostwhite':
+ return Color.fromArgb(255, 248, 248, 255);
+ case 'gold':
+ return Color.fromArgb(255, 255, 215, 0);
+ case 'goldenrod':
+ return Color.fromArgb(255, 218, 165, 32);
+ case 'gray':
+ return Color.fromArgb(255, 128, 128, 128);
+ case 'green':
+ return Color.fromArgb(255, 0, 128, 0);
+ case 'greenyellow':
+ return Color.fromArgb(255, 173, 255, 47);
+ case 'honeydew':
+ return Color.fromArgb(255, 240, 255, 240);
+ case 'hotpink':
+ return Color.fromArgb(255, 255, 105, 180);
+ case 'indianred':
+ return Color.fromArgb(255, 205, 92, 92);
+ case 'indigo':
+ return Color.fromArgb(255, 75, 0, 130);
+ case 'ivory':
+ return Color.fromArgb(255, 255, 255, 240);
+ case 'khaki':
+ return Color.fromArgb(255, 240, 230, 140);
+ case 'lavender':
+ return Color.fromArgb(255, 230, 230, 250);
+ case 'lavenderblush':
+ return Color.fromArgb(255, 255, 240, 245);
+ case 'lawngreen':
+ return Color.fromArgb(255, 124, 252, 0);
+ case 'lemonchiffon':
+ return Color.fromArgb(255, 255, 250, 205);
+ case 'lightblue':
+ return Color.fromArgb(255, 173, 216, 230);
+ case 'lightcoral':
+ return Color.fromArgb(255, 240, 128, 128);
+ case 'lightcyan':
+ return Color.fromArgb(255, 224, 255, 255);
+ case 'lightgoldenrodyellow':
+ return Color.fromArgb(255, 250, 250, 210);
+ case 'lightgray':
+ return Color.fromArgb(255, 211, 211, 211);
+ case 'lightgreen':
+ return Color.fromArgb(255, 144, 238, 144);
+ case 'lightpink':
+ return Color.fromArgb(255, 255, 182, 193);
+ case 'lightsalmon':
+ return Color.fromArgb(255, 255, 160, 122);
+ case 'lightseagreen':
+ return Color.fromArgb(255, 32, 178, 170);
+ case 'lightskyblue':
+ return Color.fromArgb(255, 135, 206, 250);
+ case 'lightslategray':
+ return Color.fromArgb(255, 119, 136, 153);
+ case 'lightsteelblue':
+ return Color.fromArgb(255, 176, 196, 222);
+ case 'lightyellow':
+ return Color.fromArgb(255, 255, 255, 224);
+ case 'lime':
+ return Color.fromArgb(255, 0, 255, 0);
+ case 'limegreen':
+ return Color.fromArgb(255, 50, 205, 50);
+ case 'linen':
+ return Color.fromArgb(255, 250, 240, 230);
+ case 'magenta':
+ return Color.fromArgb(255, 255, 0, 255);
+ case 'maroon':
+ return Color.fromArgb(255, 128, 0, 0);
+ case 'mediumaquamarine':
+ return Color.fromArgb(255, 102, 205, 170);
+ case 'mediumblue':
+ return Color.fromArgb(255, 0, 0, 205);
+ case 'mediumorchid':
+ return Color.fromArgb(255, 186, 85, 211);
+ case 'mediumpurple':
+ return Color.fromArgb(255, 147, 112, 219);
+ case 'mediumseagreen':
+ return Color.fromArgb(255, 60, 179, 113);
+ case 'mediumslateblue':
+ return Color.fromArgb(255, 123, 104, 238);
+ case 'mediumspringgreen':
+ return Color.fromArgb(255, 0, 250, 154);
+ case 'mediumturquoise':
+ return Color.fromArgb(255, 72, 209, 204);
+ case 'mediumvioletred':
+ return Color.fromArgb(255, 199, 21, 133);
+ case 'midnightblue':
+ return Color.fromArgb(255, 25, 25, 112);
+ case 'mintcream':
+ return Color.fromArgb(255, 245, 255, 250);
+ case 'mistyrose':
+ return Color.fromArgb(255, 255, 228, 225);
+ case 'moccasin':
+ return Color.fromArgb(255, 255, 228, 181);
+ case 'navajowhite':
+ return Color.fromArgb(255, 255, 222, 173);
+ case 'navy':
+ return Color.fromArgb(255, 0, 0, 128);
+ case 'oldlace':
+ return Color.fromArgb(255, 253, 245, 230);
+ case 'olive':
+ return Color.fromArgb(255, 128, 128, 0);
+ case 'olivedrab':
+ return Color.fromArgb(255, 107, 142, 35);
+ case 'orange':
+ return Color.fromArgb(255, 255, 165, 0);
+ case 'orangered':
+ return Color.fromArgb(255, 255, 69, 0);
+ case 'orchid':
+ return Color.fromArgb(255, 218, 112, 214);
+ case 'palegoldenrod':
+ return Color.fromArgb(255, 238, 232, 170);
+ case 'palegreen':
+ return Color.fromArgb(255, 152, 251, 152);
+ case 'paleturquoise':
+ return Color.fromArgb(255, 175, 238, 238);
+ case 'palevioletred':
+ return Color.fromArgb(255, 219, 112, 147);
+ case 'papayawhip':
+ return Color.fromArgb(255, 255, 239, 213);
+ case 'peachpuff':
+ return Color.fromArgb(255, 255, 218, 185);
+ case 'peru':
+ return Color.fromArgb(255, 205, 133, 63);
+ case 'pink':
+ return Color.fromArgb(255, 255, 192, 203);
+ case 'plum':
+ return Color.fromArgb(255, 221, 160, 221);
+ case 'powderblue':
+ return Color.fromArgb(255, 176, 224, 230);
+ case 'purple':
+ return Color.fromArgb(255, 128, 0, 128);
+ case 'red':
+ return Color.fromArgb(255, 255, 0, 0);
+ case 'rosybrown':
+ return Color.fromArgb(255, 188, 143, 143);
+ case 'royalblue':
+ return Color.fromArgb(255, 65, 105, 225);
+ case 'saddlebrown':
+ return Color.fromArgb(255, 139, 69, 19);
+ case 'salmon':
+ return Color.fromArgb(255, 250, 128, 114);
+ case 'sandybrown':
+ return Color.fromArgb(255, 244, 164, 96);
+ case 'seagreen':
+ return Color.fromArgb(255, 46, 139, 87);
+ case 'seashell':
+ return Color.fromArgb(255, 255, 245, 238);
+ case 'sienna':
+ return Color.fromArgb(255, 160, 82, 45);
+ case 'silver':
+ return Color.fromArgb(255, 192, 192, 192);
+ case 'skyblue':
+ return Color.fromArgb(255, 135, 206, 235);
+ case 'slateblue':
+ return Color.fromArgb(255, 106, 90, 205);
+ case 'slategray':
+ return Color.fromArgb(255, 112, 128, 144);
+ case 'snow':
+ return Color.fromArgb(255, 255, 250, 250);
+ case 'springgreen':
+ return Color.fromArgb(255, 0, 255, 127);
+ case 'steelblue':
+ return Color.fromArgb(255, 70, 130, 180);
+ case 'tan':
+ return Color.fromArgb(255, 210, 180, 140);
+ case 'teal':
+ return Color.fromArgb(255, 0, 128, 128);
+ case 'thistle':
+ return Color.fromArgb(255, 216, 191, 216);
+ case 'tomato':
+ return Color.fromArgb(255, 255, 99, 71);
+ case 'turquoise':
+ return Color.fromArgb(255, 64, 224, 208);
+ case 'violet':
+ return Color.fromArgb(255, 238, 130, 238);
+ case 'wheat':
+ return Color.fromArgb(255, 245, 222, 179);
+ case 'white':
+ return Color.fromArgb(255, 255, 255, 255);
+ case 'whitesmoke':
+ return Color.fromArgb(255, 245, 245, 245);
+ case 'yellow':
+ return Color.fromArgb(255, 255, 255, 0);
+ case 'yellowgreen':
+ return Color.fromArgb(255, 154, 205, 50);
+ case 'buttonface':
+ return Color.fromArgb(255, 240, 240, 240);
+ case 'buttonhighlight':
+ return Color.fromArgb(255, 255, 255, 255);
+ case 'buttonshadow':
+ return Color.fromArgb(255, 160, 160, 160);
+ case 'gradientactivecaption':
+ return Color.fromArgb(255, 185, 209, 234);
+ case 'gradientinactivecaption':
+ return Color.fromArgb(255, 215, 228, 242);
+ case 'menubar':
+ return Color.fromArgb(255, 240, 240, 240);
+ case 'menuhighlight':
+ return Color.fromArgb(255, 51, 153, 255);
+ }
+ return Color.fromArgb(255, 255, 255, 255);
+};
+
+Color.fromHex = function (data) {
+ var r = Util.fromHex(data.substr(1, 2));
+ var g = Util.fromHex(data.substr(3, 2));
+ var b = Util.fromHex(data.substr(5, 2));
+ var a = 255;
+ return Color.fromArgb(a, r, g, b);
+};
+
+Color.fromSimpleHex = function (data) {
+ var a = Util.fromHex(data.substr(0, 2));
+ var r = Util.fromHex(data.substr(2, 2));
+ var g = Util.fromHex(data.substr(4, 2));
+ var b = Util.fromHex(data.substr(6, 2));
+ return Color.fromArgb(a, r, g, b);
+};
+
+Color.fromInt = function (color) {
+ var r = (color & 4278190080) >>> 24;
+ var g = (color & 16711680) >>> 16;
+ var b = (color & 65280) >>> 8;
+ var a = (color & 255);
+ return Color.fromArgb(a, r, g, b);
+};
+
+var Color$ = {
+ toFormat: function () {
+ if (ss.emptyString(this.name)) {
+ return ss.format('rgb({0},{1},{2})', this.r.toString(), this.g.toString(), this.b.toString());
+ }
+ else {
+ return this.name;
+ }
+ },
+
+ save: function () {
+ if (!ss.emptyString(this.name)) {
+ return ss.format('{0}:{1}', 0, this.name);
+ }
+ else {
+ return ss.format('{0}:{1}:{2}:{3}:{4}', 1, this.a, this.r, this.g, this.b);
+ }
+ },
+
+ toString: function () {
+ if (ss.emptyString(this.name)) {
+ return ss.format('#{0}{1}{2}', Util.toHex(this.r), Util.toHex(this.g), Util.toHex(this.b));
+ }
+ else {
+ return this.name;
+ }
+ },
+
+ toSimpleHex: function () {
+ if (ss.emptyString(this.name)) {
+ return ss.format('{0}{1}{2}{3}', Util.toHex(this.a), Util.toHex(this.r), Util.toHex(this.g), Util.toHex(this.b));
+ }
+ else {
+ return this.name;
+ }
+ },
+
+ _clone: function () {
+ return Color.fromArgb(this.a, this.r, this.g, this.b);
+ }
+};
+
+registerType("Color", [Color, Color$, null]);
+
+
+// wwtlib.Colors
+
+export function Colors() { }
+
+Colors.get_black = function () {
+ return Color.fromArgb(255, 0, 0, 0);
+};
+
+Colors.get_blue = function () {
+ return Color.fromArgb(255, 0, 0, 255);
+};
+
+Colors.get_brown = function () {
+ return Color.fromArgb(255, 165, 42, 42);
+};
+
+Colors.get_cyan = function () {
+ return Color.fromArgb(255, 0, 255, 255);
+};
+
+Colors.get_darkGray = function () {
+ return Color.fromArgb(255, 169, 169, 169);
+};
+
+Colors.get_gray = function () {
+ return Color.fromArgb(255, 128, 128, 128);
+};
+
+Colors.get_green = function () {
+ return Color.fromArgb(255, 0, 255, 0);
+};
+
+Colors.get_lightGray = function () {
+ return Color.fromArgb(255, 211, 211, 211);
+};
+
+Colors.get_magenta = function () {
+ return Color.fromArgb(255, 255, 0, 255);
+};
+
+Colors.get_orange = function () {
+ return Color.fromArgb(255, 255, 165, 0);
+};
+
+Colors.get_purple = function () {
+ return Color.fromArgb(255, 128, 0, 128);
+};
+
+Colors.get_red = function () {
+ return Color.fromArgb(255, 255, 0, 0);
+};
+
+Colors.get_transparent = function () {
+ return Color.fromArgb(0, 255, 255, 255);
+};
+
+Colors.get_white = function () {
+ return Color.fromArgb(255, 255, 255, 255);
+};
+
+Colors.get_yellow = function () {
+ return Color.fromArgb(255, 255, 255, 0);
+};
+
+var Colors$ = {};
+
+registerType("Colors", [Colors, Colors$, null]);
diff --git a/engine/esm/constellation_filter.js b/engine/esm/constellation_filter.js
new file mode 100644
index 00000000..0d36dd32
--- /dev/null
+++ b/engine/esm/constellation_filter.js
@@ -0,0 +1,340 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A filter that can match various sets of constellations.
+
+import { ss } from "./ss.js";
+import { registerType } from "./typesystem.js";
+import { BlendState } from "./blend_state.js";
+
+
+// wwtlib.ConstellationFilter
+//
+// This type was defined in `Constellations.js`, but we've moved it here to
+// break circular dependencies.
+
+export function ConstellationFilter() {
+ this.bits = new Array(3);
+ this.oldBits = new Array(3);
+ this.blendState = BlendState.create(false, 1000);
+ this.internal = false;
+ this.settingsOwned = false;
+ for (var i = 0; i < 3; i++) {
+ this.bits[i] = ~this.bits[i];
+ this.oldBits[i] = this.bits[i];
+ }
+}
+
+ConstellationFilter.families = {};
+
+// These are populated in `Constellations._centroidsReady()`.
+ConstellationFilter.bitIDs = {};
+
+ConstellationFilter.buildConstellationFilters = function () {
+ var all = ConstellationFilter.get_allConstellation();
+ all.internal = true;
+ ConstellationFilter.families['AllConstellation'] = all;
+ ConstellationFilter.families['Zodiacal'] = ConstellationFilter.get_zodiacal();
+ ConstellationFilter.families['Ursa Major Family'] = ConstellationFilter.get_ursaMajorFamily();
+ ConstellationFilter.families['Perseus Family'] = ConstellationFilter.get_perseusFamily();
+ ConstellationFilter.families['Hercules Family'] = ConstellationFilter.get_herculesFamily();
+ ConstellationFilter.families['Orion Family'] = ConstellationFilter.get_orionFamily();
+ ConstellationFilter.families['Heavenly Waters'] = ConstellationFilter.get_heavenlyWaters();
+ ConstellationFilter.families['Bayer Family'] = ConstellationFilter.get_bayerFamily();
+ ConstellationFilter.families['La Caille Family'] = ConstellationFilter.get_laCaileFamily();
+};
+
+ConstellationFilter.saveCustomFilters = function () {
+ var sb = new ss.StringBuilder();
+ var $dict1 = ConstellationFilter.families;
+ for (var $key2 in $dict1) {
+ var kv = { key: $key2, value: $dict1[$key2] };
+ if (!kv.value.internal) {
+ sb.append(kv.key);
+ sb.append(';');
+ sb.appendLine(kv.value.toString());
+ }
+ }
+};
+
+ConstellationFilter.get_allConstellation = function () {
+ var all = new ConstellationFilter();
+ all.setAll(true);
+ return all;
+};
+
+ConstellationFilter.get_zodiacal = function () {
+ var zodiacal = new ConstellationFilter();
+ zodiacal.set('ARI', true);
+ zodiacal.set('TAU', true);
+ zodiacal.set('GEM', true);
+ zodiacal.set('CNC', true);
+ zodiacal.set('LEO', true);
+ zodiacal.set('VIR', true);
+ zodiacal.set('LIB', true);
+ zodiacal.set('SCO', true);
+ zodiacal.set('SGR', true);
+ zodiacal.set('CAP', true);
+ zodiacal.set('AQR', true);
+ zodiacal.set('PSC', true);
+ zodiacal.internal = true;
+ return zodiacal;
+};
+
+ConstellationFilter.get_ursaMajorFamily = function () {
+ var uma = new ConstellationFilter();
+ uma.set('UMA', true);
+ uma.set('UMI', true);
+ uma.set('DRA', true);
+ uma.set('CVN', true);
+ uma.set('BOO', true);
+ uma.set('COM', true);
+ uma.set('CRB', true);
+ uma.set('CAM', true);
+ uma.set('LYN', true);
+ uma.set('LMI', true);
+ uma.internal = true;
+ return uma;
+};
+
+ConstellationFilter.get_perseusFamily = function () {
+ var Perseus = new ConstellationFilter();
+ Perseus.set('CAS', true);
+ Perseus.set('CEP', true);
+ Perseus.set('AND', true);
+ Perseus.set('PER', true);
+ Perseus.set('PEG', true);
+ Perseus.set('CET', true);
+ Perseus.set('AUR', true);
+ Perseus.set('LAC', true);
+ Perseus.set('TRI', true);
+ Perseus.internal = true;
+ return Perseus;
+};
+
+ConstellationFilter.get_herculesFamily = function () {
+ var hercules = new ConstellationFilter();
+ hercules.set('HER', true);
+ hercules.set('SGE', true);
+ hercules.set('AQL', true);
+ hercules.set('LYR', true);
+ hercules.set('CYG', true);
+ hercules.set('VUL', true);
+ hercules.set('HYA', true);
+ hercules.set('SEX', true);
+ hercules.set('CRT', true);
+ hercules.set('CRV', true);
+ hercules.set('OPH', true);
+ hercules.set('SER1', true);
+ hercules.set('SER2', true);
+ hercules.set('SCT', true);
+ hercules.set('CEN', true);
+ hercules.set('LUP', true);
+ hercules.set('CRA', true);
+ hercules.set('ARA', true);
+ hercules.set('TRA', true);
+ hercules.set('CRU', true);
+ hercules.internal = true;
+ return hercules;
+};
+
+ConstellationFilter.get_orionFamily = function () {
+ var orion = new ConstellationFilter();
+ orion.set('ORI', true);
+ orion.set('CMA', true);
+ orion.set('CMI', true);
+ orion.set('MON', true);
+ orion.set('LEP', true);
+ orion.internal = true;
+ return orion;
+};
+
+ConstellationFilter.get_heavenlyWaters = function () {
+ var waters = new ConstellationFilter();
+ waters.set('DEL', true);
+ waters.set('EQU', true);
+ waters.set('ERI', true);
+ waters.set('PSA', true);
+ waters.set('CAR', true);
+ waters.set('PUP', true);
+ waters.set('VEL', true);
+ waters.set('PYX', true);
+ waters.set('COL', true);
+ waters.internal = true;
+ return waters;
+};
+
+ConstellationFilter.get_bayerFamily = function () {
+ var bayer = new ConstellationFilter();
+ bayer.set('HYA', true);
+ bayer.set('DOR', true);
+ bayer.set('VOL', true);
+ bayer.set('APS', true);
+ bayer.set('PAV', true);
+ bayer.set('GRU', true);
+ bayer.set('PHE', true);
+ bayer.set('TUC', true);
+ bayer.set('IND', true);
+ bayer.set('CHA', true);
+ bayer.set('MUS', true);
+ bayer.internal = true;
+ return bayer;
+};
+
+ConstellationFilter.get_laCaileFamily = function () {
+ var LaCaile = new ConstellationFilter();
+ LaCaile.set('NOR', true);
+ LaCaile.set('CIR', true);
+ LaCaile.set('TEL', true);
+ LaCaile.set('MIC', true);
+ LaCaile.set('SCL', true);
+ LaCaile.set('FOR', true);
+ LaCaile.set('CAE', true);
+ LaCaile.set('HOR', true);
+ LaCaile.set('OCT', true);
+ LaCaile.set('MEN', true);
+ LaCaile.set('RET', true);
+ LaCaile.set('PIC', true);
+ LaCaile.set('ANT', true);
+ LaCaile.internal = true;
+ return LaCaile;
+};
+
+ConstellationFilter.parse = function (val) {
+ var parts = (val).split(',');
+ var cf = new ConstellationFilter();
+ try {
+ for (var i = 0; i < 3; i++) {
+ cf.bits[i] = parseInt(parts[i]);
+ }
+ }
+ catch ($e1) { }
+ return cf;
+};
+
+var ConstellationFilter$ = {
+ _saveBits: function () {
+ for (var i = 0; i < 3; i++) {
+ this.oldBits[i] = this.bits[i];
+ }
+ },
+
+ _isChanged: function () {
+ for (var i = 0; i < 3; i++) {
+ if (this.oldBits[i] !== this.bits[i]) {
+ return true;
+ }
+ }
+ return false;
+ },
+
+ _checkChanged: function () {
+ if (this._isChanged()) {
+ this._fireChanged();
+ }
+ },
+
+ isEnabled: function (abbrev) {
+ var bitID = ConstellationFilter.bitIDs[abbrev];
+ var index = bitID / 32;
+ bitID = bitID % 32;
+ return this.blendState.get_state() && !!((1 << bitID) & this.bits[index]);
+ },
+
+ isSet: function (abbrev) {
+ this._saveBits();
+ var bitID = ConstellationFilter.bitIDs[abbrev];
+ var index = ss.truncate((bitID / 32));
+ bitID = bitID % 32;
+ return !!((1 << bitID) & this.bits[index]);
+ },
+
+ set: function (abbrev, state) {
+ this._saveBits();
+ var bitID = ConstellationFilter.bitIDs[abbrev];
+ var index = bitID / 32;
+ bitID = bitID % 32;
+ if (state) {
+ this.bits[index] = this.bits[index] | (1 << bitID);
+ } else {
+ this.bits[index] = this.bits[index] ^ (1 << bitID);
+ }
+ this._checkChanged();
+ },
+
+ setAll: function (state) {
+ this._saveBits();
+ for (var bitID = 0; bitID < 89; bitID++) {
+ var index = bitID / 32;
+ var bit = bitID % 32;
+ if (state) {
+ this.bits[index] = this.bits[index] | (1 << bit);
+ }
+ else {
+ this.bits[index] = this.bits[index] ^ (1 << bit);
+ }
+ }
+ this._checkChanged();
+ },
+
+ setBits: function (bits) {
+ this._saveBits();
+ for (var i = 0; i < 3; i++) {
+ this.bits[i] = (bits[i * 4]) + ((bits[i * 4 + 1]) << 8) + ((bits[i * 4 + 2]) << 16) + ((bits[i * 4 + 3]) << 24);
+ }
+ this._checkChanged();
+ },
+
+ getBits: function () {
+ var bits = new Array(12);
+ var index = 0;
+ for (var i = 0; i < 3; i++) {
+ bits[index++] = this.bits[i];
+ bits[index++] = (this.bits[i] >> 8);
+ bits[index++] = (this.bits[i] >> 16);
+ bits[index++] = (this.bits[i] >> 24);
+ }
+ return bits;
+ },
+
+ cloneFilter: function (filter) {
+ this._saveBits();
+ for (var i = 0; i < 3; i++) {
+ this.bits[i] = filter.bits[i];
+ }
+ this._checkChanged();
+ },
+
+ clone: function () {
+ var newFilter = new ConstellationFilter();
+ newFilter.cloneFilter(this);
+ return newFilter;
+ },
+
+ combine: function (filter) {
+ this._saveBits();
+ for (var i = 0; i < 3; i++) {
+ this.bits[i] = this.bits[i] | filter.bits[i];
+ }
+ this._checkChanged();
+ },
+
+ remove: function (filter) {
+ this._saveBits();
+ for (var i = 0; i < 3; i++) {
+ this.bits[i] = this.bits[i] & ~filter.bits[i];
+ }
+ this._checkChanged();
+ },
+
+ _fireChanged: function () {
+ if (this.settingsOwned) {
+ }
+ },
+
+ toString: function () {
+ return ss.format('{0},{1},{2}', this.bits[0], this.bits[1], this.bits[2]);
+ }
+};
+
+registerType("ConstellationFilter", [ConstellationFilter, ConstellationFilter$, null]);
diff --git a/engine/esm/constellations.js b/engine/esm/constellations.js
new file mode 100644
index 00000000..87e4d225
--- /dev/null
+++ b/engine/esm/constellations.js
@@ -0,0 +1,514 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Constellations in the sky.
+
+import { ss } from "./ss.js";
+import { registerType, registerEnum } from "./typesystem.js";
+import { Vector3d } from "./double3d.js";
+import { createPlace, makeNewFolder } from "./data_globals.js";
+import { SimpleLineList } from "./graphics/primitives3d.js";
+import { BlendState } from "./blend_state.js";
+import { Color } from "./color.js";
+import { ConstellationFilter } from "./constellation_filter.js";
+import { Coordinates } from "./coordinates.js";
+import { Settings } from "./settings.js";
+import { Text3d, Text3dBatch } from "./sky_text.js";
+import { URLHelpers } from "./url_helpers.js";
+import { WebFile } from "./web_file.js";
+
+
+// wwtlib.PointType
+
+export var PointType = {
+ move: 0,
+ line: 1,
+ dash: 2,
+ start: 3
+};
+
+registerType("PointType", PointType);
+registerEnum("PointType", PointType);
+
+
+// wwtlib.Lineset
+
+export function Lineset(name) {
+ this._name = name;
+ this.points = [];
+}
+
+var Lineset$ = {
+ get_name: function () {
+ return this._name;
+ },
+
+ set_name: function (value) {
+ this._name = value;
+ return value;
+ },
+
+ add: function (ra, dec, pointType, name) {
+ this.points.push(new Linepoint(ra, dec, pointType, name));
+ }
+};
+
+registerType("Lineset", [Lineset, Lineset$, null]);
+
+
+// wwtlib.Linepoint
+
+export function Linepoint(ra, dec, type, name) {
+ this.RA = 0;
+ this.dec = 0;
+ this.pointType = 0;
+ this.name = null;
+ this.RA = ra;
+ this.dec = dec;
+ this.pointType = type;
+ this.name = name;
+}
+
+var Linepoint$ = {
+ toString: function () {
+ if (ss.emptyString(this.name)) {
+ return Coordinates.formatDMS((((this.RA / 360) * 24 + 12) % 24)) + ', ' + Coordinates.formatDMS(this.dec) + ', ' + this.pointType.toString();
+ } else {
+ return this.name + ', ' + this.pointType.toString();
+ }
+ }
+};
+
+registerType("Linepoint", [Linepoint, Linepoint$, null]);
+
+
+// wwtlib.Constellations
+
+export function Constellations() {
+ this._pointCount = 0;
+ this._boundry = false;
+ this._noInterpollation = false;
+ this.readOnly = false;
+ this.radius = 1;
+ this._drawCount = 0;
+ this._constellationVertexBuffers = {};
+}
+
+Constellations.RC = 0.017453292519943;
+Constellations._maxSeperation = 0.745;
+Constellations.containment = null; // initialized in InitializeConstellations
+Constellations._constToDraw = '';
+Constellations.selectedSegment = null;
+Constellations._artFile = null;
+Constellations.artwork = null;
+Constellations.boundries = null;
+Constellations.pictureBlendStates = {};
+
+Constellations.createBasic = function (name) {
+ var temp = new Constellations();
+ temp._name = name;
+ temp._url = null;
+ temp.lines = [];
+ var $enum1 = ss.enumerate(ss.keys(Constellations.fullNames));
+ while ($enum1.moveNext()) {
+ var abbrv = $enum1.current;
+ temp.lines.push(new Lineset(abbrv));
+ }
+ return temp;
+};
+
+Constellations.create = function (name, url, boundry, noInterpollation, resource) {
+ var temp = new Constellations();
+ temp._noInterpollation = noInterpollation;
+ temp._boundry = boundry;
+ temp._name = name;
+ temp._url = url;
+ temp.getFile();
+ return temp;
+};
+
+Constellations.drawConstellationNames = function (renderContext, opacity, drawColor) {
+ if (Constellations._namesBatch == null) {
+ Constellations.initializeConstellationNames();
+ if (Constellations._namesBatch == null) {
+ return;
+ }
+ }
+ Constellations._namesBatch.draw(renderContext, opacity, drawColor);
+};
+
+Constellations.initializeConstellationNames = function () {
+ if (Constellations.constellationCentroids == null) {
+ return;
+ }
+ Constellations._namesBatch = new Text3dBatch(Settings.get_active().get_constellationLabelsHeight());
+ var $enum1 = ss.enumerate(ss.keys(Constellations.constellationCentroids));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var centroid = Constellations.constellationCentroids[key];
+ var center = Coordinates.raDecTo3dAu(centroid.get_RA(), centroid.get_dec(), 1);
+ var up = Vector3d.create(0, 1, 0);
+ var name = centroid.get_name();
+ if (centroid.get_name() === 'Triangulum Australe') {
+ name = ss.replaceString(name, ' ', '\n ');
+ }
+ Constellations._namesBatch.add(new Text3d(center, up, name, Settings.get_active().get_constellationLabelsHeight(), 0.000125));
+ }
+};
+
+// The WWTControl driver will not (and should not) call this function in
+// "freestanding mode", because the functionality depends on a
+// worldwidetelescope.org API.
+Constellations.drawArtwork = function (renderContext) {
+ if (Constellations.artwork == null) {
+ if (Constellations._artFile == null) {
+ Constellations._artFile = makeNewFolder();
+ Constellations._artFile.loadFromUrl(URLHelpers.singleton.coreStaticUrl('wwtweb/catalog.aspx?W=hevelius'), Constellations._onArtReady);
+ }
+ return;
+ }
+ Constellations._maxSeperation = Math.max(0.5, Math.cos((renderContext.get_fovAngle() * 2) / 180 * Math.PI));
+ var $enum1 = ss.enumerate(Constellations.artwork);
+ while ($enum1.moveNext()) {
+ var place = $enum1.current;
+ var bs = Constellations.pictureBlendStates[place.get_constellation()];
+ bs.set_targetState(Settings.get_active().get_constellationArtFilter().isSet(place.get_constellation()));
+ if (bs.get_state()) {
+ var reverse = false;
+ var centroid = Constellations.constellationCentroids[place.get_constellation()];
+ if (centroid != null) {
+ var pos = Coordinates.raDecTo3d((reverse) ? -centroid.get_RA() - 6 : centroid.get_RA(), (reverse) ? centroid.get_dec() : centroid.get_dec());
+ if (Vector3d.dot(renderContext.get_viewPoint(), pos) > Constellations._maxSeperation) {
+ renderContext.drawImageSet(place.get_studyImageset(), 100);
+ }
+ }
+ }
+ }
+};
+
+Constellations._onArtReady = function () {
+ Constellations._artFile.childLoadCallback(Constellations._loadArtList);
+};
+
+Constellations._loadArtList = function () {
+ Constellations.artwork = Constellations._artFile.get_places();
+};
+
+// Repeated invocations of this function are OK.
+Constellations.initializeConstellations = function () {
+ if (Constellations.containment == null) {
+ var url = URLHelpers.singleton.engineAssetUrl('ConstellationNamePositions_EN.txt');
+ Constellations._webFileConstNames = new WebFile(url);
+ Constellations._webFileConstNames.onStateChange = Constellations._loadNames;
+ Constellations._webFileConstNames.send();
+ Constellations.containment = Constellations.create(
+ 'Constellations',
+ URLHelpers.singleton.engineAssetUrl('constellations.txt'),
+ true, // "boundry"
+ true, // "noInterpollation"
+ true, // "resource"
+ );
+ }
+};
+
+Constellations._loadNames = function () {
+ if (Constellations._webFileConstNames.get_state() === 2) {
+ alert(Constellations._webFileConstNames.get_message());
+ }
+ else if (Constellations._webFileConstNames.get_state() === 1) {
+ Constellations._centroidsReady(Constellations._webFileConstNames.getText());
+ }
+};
+
+Constellations._centroidsReady = function (file) {
+ Constellations.constellationCentroids = {};
+ Constellations.fullNames = {};
+ Constellations.abbreviations = {};
+ var rows = file.split('\r\n');
+ var id = 0;
+ var line;
+ var $enum1 = ss.enumerate(rows);
+
+ while ($enum1.moveNext()) {
+ var row = $enum1.current;
+ line = row;
+ var data = line.split(',');
+ Constellations.fullNames[data[1]] = data[0];
+ Constellations.abbreviations[data[0]] = data[1];
+ ConstellationFilter.bitIDs[data[1]] = id++;
+ Constellations.pictureBlendStates[data[1]] = BlendState.create(true, 1000);
+ Constellations.constellationCentroids[data[1]] = createPlace(data[0], parseFloat(data[3]), parseFloat(data[2]), 128, data[1], 2, 360);
+ }
+
+ ConstellationFilter.buildConstellationFilters();
+};
+
+Constellations.fullName = function (name) {
+ if (ss.keyExists(Constellations.fullNames, name)) {
+ return Constellations.fullNames[name];
+ }
+ return name;
+};
+
+Constellations.abbreviation = function (name) {
+ if (Constellations.abbreviations != null && !ss.emptyString(name) && ss.keyExists(Constellations.abbreviations, name)) {
+ return Constellations.abbreviations[name];
+ }
+ return name;
+};
+
+var Constellations$ = {
+ get_name: function () {
+ return this._name;
+ },
+
+ set_name: function (value) {
+ this._name = value;
+ return value;
+ },
+
+ getFile: function () {
+ this._webFile = new WebFile(this._url);
+ this._webFile.onStateChange = ss.bind('fileStateChange', this);
+ this._webFile.send();
+ },
+
+ fileStateChange: function () {
+ if (this._webFile.get_state() === 2) {
+ alert(this._webFile.get_message());
+ } else if (this._webFile.get_state() === 1) {
+ this._loadConstellationData(this._webFile.getText());
+ }
+ },
+
+ _loadConstellationData: function (data) {
+ if (this._boundry && !this._noInterpollation) {
+ Constellations.boundries = {};
+ }
+ this.lines = [];
+ var lineSet = null;
+ try {
+ var rows = data.split('\r\n');
+ var abrv;
+ var abrvOld = '';
+ var ra;
+ var dec;
+ var lastRa = 0;
+ var type = 0;
+ var $enum1 = ss.enumerate(rows);
+ while ($enum1.moveNext()) {
+ var row = $enum1.current;
+ var line = row;
+ if (line.substr(11, 2) === '- ') {
+ line = line.substr(0, 11) + ' -' + line.substr(13, (line.length - 13));
+ }
+ if (line.substr(11, 2) === '+ ') {
+ line = line.substr(0, 11) + ' +' + line.substr(13, (line.length - 13));
+ }
+ dec = parseFloat(line.substr(11, 10));
+ if (this._noInterpollation) {
+ ra = parseFloat(line.substr(0, 10));
+ }
+ else {
+ ra = parseFloat(line.substr(0, 10));
+ }
+ abrv = ss.trim(line.substr(23, 4));
+ if (!this._boundry) {
+ if (!!ss.trim(line.substr(28, 1))) {
+ type = parseInt(line.substr(28, 1));
+ }
+ }
+ else {
+ if (this._noInterpollation && line.substr(28, 1) !== 'O') {
+ continue;
+ }
+ }
+ if (abrv !== abrvOld) {
+ type = 3;
+ lineSet = new Lineset(abrv);
+ this.lines.push(lineSet);
+ if (this._boundry && !this._noInterpollation) {
+ Constellations.boundries[abrv] = lineSet;
+ }
+ abrvOld = abrv;
+ lastRa = 0;
+ }
+ if (this._noInterpollation) {
+ if (Math.abs(ra - lastRa) > 12) {
+ ra = ra - (24 * (((ra - lastRa) < 0) ? -1 : 1));
+ }
+ lastRa = ra;
+ }
+ var starName = null;
+ if (line.length > 30) {
+ starName = ss.trim(line.substr(30));
+ }
+ if (starName == null || starName !== 'Empty') {
+ lineSet.add(ra, dec, type, starName);
+ }
+ this._pointCount++;
+ type = 1;
+ }
+ }
+ catch ($e2) {
+ }
+ },
+
+ draw: function (renderContext, showOnlySelected, focusConsteallation, clearExisting) {
+ Constellations._maxSeperation = Math.max(0.6, Math.cos((renderContext.get_fovAngle() * 2) / 180 * Math.PI));
+ this._drawCount = 0;
+ var lsSelected = null;
+ if (this.lines == null || Constellations.constellationCentroids == null) {
+ return;
+ }
+ Constellations._constToDraw = focusConsteallation;
+ var $enum1 = ss.enumerate(this.lines);
+ while ($enum1.moveNext()) {
+ var ls = $enum1.current;
+ if (Constellations._constToDraw === ls.get_name() && this._boundry) {
+ lsSelected = ls;
+ }
+ else if (!showOnlySelected || !this._boundry) {
+ this._drawSingleConstellation(renderContext, ls, 1);
+ }
+ }
+ if (lsSelected != null) {
+ this._drawSingleConstellation(renderContext, lsSelected, 1);
+ }
+ },
+
+ _drawSingleConstellation: function (renderContext, ls, opacity) {
+ var reverse = false;
+ var centroid = Constellations.constellationCentroids[ls.get_name()];
+ if (centroid != null) {
+ var pos = Coordinates.raDecTo3d((reverse) ? -centroid.get_RA() - 6 : centroid.get_RA(), (reverse) ? centroid.get_dec() : centroid.get_dec());
+ if (Vector3d.dot(renderContext.get_viewPoint(), pos) < Constellations._maxSeperation) {
+ return;
+ }
+ }
+ if (!ss.keyExists(this._constellationVertexBuffers, ls.get_name())) {
+ var count = ls.points.length;
+ var linelist = new SimpleLineList();
+ linelist.set_depthBuffered(false);
+ this._constellationVertexBuffers[ls.get_name()] = linelist;
+ var currentPoint = new Vector3d();
+ var temp;
+ for (var i = 0; i < count; i++) {
+ if (!ls.points[i].pointType || !i) {
+ currentPoint = Coordinates.raDecTo3d(ls.points[i].RA, ls.points[i].dec);
+ }
+ else {
+ temp = Coordinates.raDecTo3d(ls.points[i].RA, ls.points[i].dec);
+ linelist.addLine(currentPoint, temp);
+ currentPoint = temp;
+ }
+ }
+ if (this._boundry) {
+ temp = Coordinates.raDecTo3d(ls.points[0].RA, ls.points[0].dec);
+ linelist.addLine(currentPoint, temp);
+ }
+ }
+ var col = 'red';
+ if (this._boundry) {
+ if (Constellations._constToDraw !== ls.get_name()) {
+ col = Settings.get_globalSettings().get_constellationBoundryColor();
+ }
+ else {
+ col = Settings.get_globalSettings().get_constellationSelectionColor();
+ }
+ } else {
+ col = Settings.get_globalSettings().get_constellationFigureColor();
+ }
+ this._constellationVertexBuffers[ls.get_name()].drawLines(renderContext, opacity, Color.load(col));
+ },
+
+ _drawSingleConstellationOld: function (renderContext, ls) {
+ var reverse = false;
+ var centroid = Constellations.constellationCentroids[ls.get_name()];
+ if (centroid != null) {
+ var pos = Coordinates.raDecTo3d((reverse) ? -centroid.get_RA() - 6 : centroid.get_RA(), (reverse) ? centroid.get_dec() : centroid.get_dec());
+ if (Vector3d.dot(renderContext.get_viewPoint(), pos) < Constellations._maxSeperation) {
+ return;
+ }
+ }
+ this._drawCount++;
+ var col;
+ if (this._boundry) {
+ if (Constellations._constToDraw !== ls.get_name()) {
+ col = Settings.get_globalSettings().get_constellationBoundryColor();
+ }
+ else {
+ col = Settings.get_globalSettings().get_constellationSelectionColor();
+ }
+ } else {
+ col = Settings.get_globalSettings().get_constellationFigureColor();
+ }
+ if (renderContext.gl == null) {
+ var ctx = renderContext.device;
+ var count = ls.points.length;
+ var lastPoint = new Vector3d();
+ ctx.save();
+ var linePending = false;
+ ctx.beginPath();
+ ctx.strokeStyle = col;
+ ctx.lineWidth = 2;
+ ctx.globalAlpha = 0.25;
+ for (var i = 0; i < count; i++) {
+ if (!ls.points[i].pointType || !i) {
+ if (linePending) {
+ ctx.stroke();
+ }
+ lastPoint = renderContext.WVP.transform(Coordinates.raDecTo3d(ls.points[i].RA, ls.points[i].dec));
+ ctx.moveTo(lastPoint.x, lastPoint.y);
+ }
+ else {
+ var newPoint = renderContext.WVP.transform(Coordinates.raDecTo3d(ls.points[i].RA, ls.points[i].dec));
+ ctx.lineTo(newPoint.x, newPoint.y);
+ linePending = true;
+ }
+ }
+ if (this._boundry) {
+ ctx.closePath();
+ }
+ ctx.stroke();
+ ctx.restore();
+ } else {
+ //todo add webgl method of drawing
+ }
+ },
+
+ findConstellationForPoint: function (ra, dec) {
+ if (dec > 88.402 || this.lines == null) {
+ return 'UMI';
+ }
+ var $enum1 = ss.enumerate(this.lines);
+ while ($enum1.moveNext()) {
+ var ls = $enum1.current;
+ var count = ls.points.length;
+ var i;
+ var j;
+ var inside = false;
+ for (i = 0, j = count - 1; i < count; j = i++) {
+ if ((((ls.points[i].dec <= dec) && (dec < ls.points[j].dec)) || ((ls.points[j].dec <= dec) && (dec < ls.points[i].dec))) && (ra < (ls.points[j].RA - ls.points[i].RA) * (dec - ls.points[i].dec) / (ls.points[j].dec - ls.points[i].dec) + ls.points[i].RA)) {
+ inside = !inside;
+ }
+ }
+ if (inside) {
+ return ls.get_name();
+ }
+ }
+ if (ra > 0) {
+ return this.findConstellationForPoint(ra - 24, dec);
+ }
+ // Ursa Minor is tricky since it wraps around the poles. It can evade the point in rect test
+ if (dec > 65.5) {
+ return 'UMI';
+ }
+ if (dec < -65.5) {
+ return 'OCT';
+ }
+ return 'Error';
+ }
+};
+
+registerType("Constellations", [Constellations, Constellations$, null]);
diff --git a/engine/esm/coordinates.js b/engine/esm/coordinates.js
new file mode 100644
index 00000000..5293acf5
--- /dev/null
+++ b/engine/esm/coordinates.js
@@ -0,0 +1,582 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Routines for coordinate transformations
+//
+// NB: these functions are redundant in the webclient because we don't have the
+// single-precision `Vector3` type that's distinguished from `Vector3d`. To
+// minimize the code delta from Windows, we keep both names for simplicity. But
+// the `...Rad` functions are added because ScriptSharp can't deal with
+// overloads.
+
+import { registerType } from "./typesystem.js";
+import { ss } from "./ss.js";
+import { Util } from "./baseutil.js";
+import { Vector2d, Vector3d } from "./double3d.js";
+
+
+// wwtlib.Coordinates
+
+export function Coordinates(ascention, declination) {
+ // Held in radians
+ this._ascention = 0;
+ this._declination = 0;
+ this._ascention = ascention + (Math.PI * 80) % (Math.PI * 2);
+ this._declination = declination;
+}
+
+Coordinates.RC = (3.1415927 / 180);
+Coordinates.RCRA = (3.1415927 / 12);
+Coordinates.radius = 1;
+Coordinates._rotationMatrix = null;
+
+Coordinates.geoTo3d = function (lat, lng) {
+ return Vector3d.create(Math.cos(lng * Coordinates.RC) * Math.cos(lat * Coordinates.RC) * 1, Math.sin(lat * Coordinates.RC) * 1, Math.sin(lng * Coordinates.RC) * Math.cos(lat * Coordinates.RC) * 1);
+};
+
+Coordinates.geoTo3dDouble = function (lat, lng) {
+ return Vector3d.create(Math.cos(lng * Coordinates.RC) * Math.cos(lat * Coordinates.RC) * 1, Math.sin(lat * Coordinates.RC) * 1, Math.sin(lng * Coordinates.RC) * Math.cos(lat * Coordinates.RC) * 1);
+};
+
+Coordinates.geoTo3dRad = function (lat, lng, radius) {
+ return Vector3d.create(Math.cos(lng * Coordinates.RC) * Math.cos(lat * Coordinates.RC) * radius, Math.sin(lat * Coordinates.RC) * radius, Math.sin(lng * Coordinates.RC) * Math.cos(lat * Coordinates.RC) * radius);
+};
+
+Coordinates.raDecTo3d = function (ra, dec) {
+ return Vector3d.create(Math.cos(ra * Coordinates.RCRA) * Math.cos(dec * Coordinates.RC) * 1, Math.sin(dec * Coordinates.RC) * 1, Math.sin(ra * Coordinates.RCRA) * Math.cos(dec * Coordinates.RC) * 1);
+};
+
+Coordinates.raDecTo3dAu = function (ra, dec, au) {
+ return Vector3d.create(Math.cos(ra * Coordinates.RCRA) * Math.cos(dec * Coordinates.RC) * au, Math.sin(dec * Coordinates.RC) * au, Math.sin(ra * Coordinates.RCRA) * Math.cos(dec * Coordinates.RC) * au);
+};
+
+Coordinates.raDecTo3dMat = function (ra, dec, mat) {
+ return Vector3d._transformCoordinate(Vector3d.create((Math.cos(ra * Coordinates.RCRA) * Math.cos(dec * Coordinates.RC) * 1), (Math.sin(dec * Coordinates.RC) * 1), (Math.sin(ra * Coordinates.RCRA) * Math.cos(dec * Coordinates.RC) * 1)), mat);
+};
+
+Coordinates.raDecTo3dPointRad = function (point, radius) {
+ point.set_dec(-point.get_dec());
+ return Vector3d.create((Math.cos(point.get_RA() * Coordinates.RCRA) * Math.cos(point.get_dec() * Coordinates.RC) * radius), (Math.sin(point.get_dec() * Coordinates.RC) * radius), (Math.sin(point.get_RA() * Coordinates.RCRA) * Math.cos(point.get_dec() * Coordinates.RC) * radius));
+};
+
+Coordinates.sterographicTo3d = function (x, y, radius, standardLat, meridean, falseEasting, falseNorthing, scale, north) {
+ var lat = 90;
+ var lng = 0;
+ x -= falseEasting;
+ y -= falseNorthing;
+ if (!!x || !!y) {
+ var re = (1 + Math.sin(Math.abs(standardLat) / 180 * Math.PI)) * 6371000 / scale;
+ var rere = re * re;
+ var c1 = 180 / Math.PI;
+ if (!x) {
+ lng = (90 * y < 0) ? -1 : 1;
+ } else {
+ lng = Math.atan2(y, x) * c1;
+ }
+ var len = (x * x) + (y * y);
+ lat = (rere - len) / (rere + len);
+ lat = Math.asin(lat) * c1;
+ if (!north) {
+ lat = -lat;
+ lng = -lng;
+ meridean = -meridean;
+ }
+ }
+ return Coordinates.geoTo3dRad(lat, 90 + lng + meridean, radius);
+};
+
+Coordinates.equitorialToHorizon = function (equitorial, location, utc) {
+ var hourAngle = Coordinates.mstFromUTC2(utc, location.get_lng()) - (equitorial.get_RA() * 15);
+ if (hourAngle < 0) {
+ hourAngle += 360;
+ }
+ var ha = hourAngle * Coordinates.RC;
+ var dec = equitorial.get_dec() * Coordinates.RC;
+ var lat = location.get_lat() * Coordinates.RC;
+ var sinAlt = Math.sin(dec) * Math.sin(lat) + Math.cos(dec) * Math.cos(lat) * Math.cos(ha);
+ var altitude = Math.asin(sinAlt);
+ var cosAzimith = (Math.sin(dec) - Math.sin(altitude) * Math.sin(lat)) / (Math.cos(altitude) * Math.cos(lat));
+ var azimuth = Math.acos(cosAzimith);
+ var altAz = new Coordinates(azimuth, altitude);
+ if (Math.sin(ha) > 0) {
+ altAz.set_az((360 - altAz.get_az()));
+ }
+ return altAz;
+};
+
+Coordinates.horizonToEquitorial = function (altAz, location, utc) {
+ var hourAngle = Coordinates.mstFromUTC2(utc, location.get_lng());
+ var haLocal;
+ var declination;
+ var raDec = Coordinates._altAzToRaDec(altAz.get_alt() * Coordinates.RC, altAz.get_az() * Coordinates.RC, location.get_lat() * Coordinates.RC);
+ haLocal = raDec.x;
+ declination = raDec.y;
+ var ha = (haLocal / Coordinates.RC);
+ hourAngle += ha;
+ if (hourAngle < 0) {
+ hourAngle += 360;
+ }
+ if (hourAngle > 360) {
+ hourAngle -= 360;
+ }
+ return Coordinates.fromRaDec(hourAngle / 15, declination / Coordinates.RC);
+};
+
+Coordinates._altAzToRaDec = function (Altitude, Azimuth, Latitude) {
+ var hrAngle = 0;
+ var dec = 0;
+ Azimuth = Math.PI - Azimuth;
+ if (Azimuth < 0) {
+ Azimuth += Math.PI * 2;
+ }
+ hrAngle = Math.atan2(Math.sin(Azimuth), Math.cos(Azimuth) * Math.sin(Latitude) + Math.tan(Altitude) * Math.cos(Latitude));
+ if (hrAngle < 0) {
+ hrAngle += Math.PI * 2;
+ }
+ dec = Math.asin(Math.sin(Latitude) * Math.sin(Altitude) - Math.cos(Latitude) * Math.cos(Altitude) * Math.cos(Azimuth));
+ return Vector2d.create(hrAngle, dec);
+};
+
+Coordinates.mstFromUTC2 = function (utc, lng) {
+ var year = utc.getUTCFullYear();
+ var month = utc.getUTCMonth() + 1;
+ var day = utc.getUTCDate();
+ var hour = utc.getUTCHours();
+ var minute = utc.getUTCMinutes();
+ var second = utc.getUTCSeconds() + utc.getUTCMilliseconds() / 1000;
+ if (month === 1 || month === 2) {
+ year -= 1;
+ month += 12;
+ }
+ var a = ss.truncate((year / 100));
+ var b = 2 - a + Math.floor((a / 4));
+ var c = Math.floor(365.25 * year);
+ var d = Math.floor(30.6001 * (month + 1));
+ var julianDays;
+ var julianCenturies;
+ var mst;
+ julianDays = b + c + d - 730550.5 + day + (hour + minute / 60 + second / 3600) / 24;
+ julianCenturies = julianDays / 36525;
+ mst = 280.46061837 + 360.98564736629 * julianDays + 0.000387933 * julianCenturies * julianCenturies - julianCenturies * julianCenturies * julianCenturies / 38710000 + lng;
+ if (mst > 0) {
+ while (mst > 360) {
+ mst = mst - 360;
+ }
+ }
+ else {
+ while (mst < 0) {
+ mst = mst + 360;
+ }
+ }
+ return mst;
+};
+
+Coordinates.cartesianToSpherical = function (vector) {
+ var ascention;
+ var declination;
+ var radius = Math.sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z);
+ var XZ = Math.sqrt(vector.x * vector.x + vector.z * vector.z);
+ declination = Math.asin(vector.y / radius);
+ if (0 < vector.x) {
+ ascention = Math.asin(vector.z / XZ);
+ }
+ else if (0 > vector.x) {
+ ascention = Math.PI - Math.asin(vector.z / XZ);
+ }
+ else {
+ ascention = 0;
+ }
+ return new Coordinates(ascention, declination);
+};
+
+Coordinates.cartesianToSpherical2 = function (vector) {
+ var rho = Math.sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z);
+ var longitude = Math.atan2(vector.z, vector.x);
+ var latitude = Math.asin(vector.y / rho);
+ return new Coordinates(longitude, latitude);
+};
+
+Coordinates.cartesianToSphericalSky = function (vector) {
+ var rho = Math.sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z);
+ var ra = Math.atan2(vector.z, vector.x);
+ var dec = Math.asin(-vector.y / rho);
+ return Vector2d.create(ra / Math.PI * 12, dec / Math.PI * 180);
+};
+
+Coordinates.sphericalSkyToCartesian = function (vector) {
+ var ra = vector.x * (Math.PI / 12);
+ var dec = vector.y * (Math.PI / 180);
+ var x = Math.cos(ra) * Math.cos(dec);
+ var y = -Math.sin(dec);
+ var z = Math.sin(ra) * Math.cos(dec);
+ return Vector3d.create(x, y, z);
+};
+
+Coordinates.cartesianToLatLng = function (vector) {
+ var rho = Math.sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z);
+ var longitude = Math.atan2(vector.z, vector.x);
+ var latitude = Math.asin(vector.y / rho);
+ return Vector2d.create(longitude * 180 / Math.PI, latitude * 180 / Math.PI);
+};
+
+Coordinates.cartesianToSpherical3 = function (vector) {
+ var rho = Math.sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z);
+ var longitude = Math.atan2(vector.z, vector.x);
+ var latitude = Math.asin(vector.y / rho);
+ return new Coordinates(longitude, latitude);
+};
+
+Coordinates.sign = function (target) {
+ return (target < 0) ? -1 : 1;
+};
+
+Coordinates.formatDMSSign = function (angle, sign) {
+ try {
+ angle += (Coordinates.sign(angle) * 0.0001388888888889);
+ var degrees = ss.truncate(angle);
+ var minutes = ((angle - ss.truncate(angle)) * 60);
+ var seconds = ((minutes - ss.truncate(minutes)) * 60);
+ if (sign) {
+ var signString = (angle > 0) ? '+' : '-';
+ return ss.format('{3}{0:00;00}:{1:00}:{2:00}', degrees, Math.abs(ss.truncate(minutes)), Math.abs(ss.truncate(seconds)), signString);
+ } else {
+ return ss.format('{0:00}:{1:00}:{2:00}', degrees, Math.abs(ss.truncate(minutes)), Math.abs(ss.truncate(seconds)));
+ }
+ }
+ catch ($e1) {
+ return '';
+ }
+};
+
+Coordinates.twoPlaces = function (val) {
+ var num = val.toString();
+ if (num.length < 2) {
+ num = '0' + num;
+ }
+ return num;
+};
+
+Coordinates.formatDMS = function (angle) {
+ try {
+ angle += (((angle < 0) ? -1 : 1) * 0.0001388888888889);
+ var degrees = Math.abs(ss.truncate(angle));
+ var minutes = ((angle - ss.truncate(angle)) * 60);
+ var seconds = ((minutes - ss.truncate(minutes)) * 60);
+ var sign = (angle < 0) ? '-' : '';
+ return ss.format('{3}{0}:{1}:{2}', Math.abs(degrees), Coordinates.twoPlaces(Math.abs(ss.truncate(minutes))), Coordinates.twoPlaces(Math.abs(ss.truncate(seconds))), sign);
+ }
+ catch ($e1) {
+ return '';
+ }
+};
+
+Coordinates.formatDMSWide = function (angle) {
+ try {
+ angle += (Coordinates.sign(angle) * 0.0001388888888889);
+ var degrees = Math.abs(ss.truncate(angle));
+ var minutes = ((angle - ss.truncate(angle)) * 60);
+ var seconds = ((minutes - ss.truncate(minutes)) * 60);
+ var sign = (angle < 0) ? '-' : '';
+ return ss.format('{3}{0:00} : {1:00} : {2:00}', degrees, Math.abs(ss.truncate(minutes)), Math.abs(ss.truncate(seconds)), sign);
+ }
+ catch ($e1) {
+ return '';
+ }
+};
+
+Coordinates.formatHMS = function (angle) {
+ try {
+ angle += (Coordinates.sign(angle) * 0.0001388888888889);
+ var degrees = ss.truncate(angle);
+ var minutes = ((angle - ss.truncate(angle)) * 60);
+ var seconds = ((minutes - ss.truncate(minutes)) * 60);
+ return ss.format('{0:00}h{1:00}m{2:00}s', degrees, Math.abs(ss.truncate(minutes)), Math.abs(ss.truncate(seconds)));
+ }
+ catch ($e1) {
+ return '';
+ }
+};
+
+Coordinates.parseRA = function (data, degrees) {
+ data = ss.trim(data).toLowerCase();
+ if (data.indexOf('d') > -1 || data.indexOf('\u00b0') > -1) {
+ degrees = true;
+ }
+ if (data.indexOf('h') > -1 || data.indexOf(':') > -1) {
+ degrees = false;
+ }
+ var ra = Coordinates.parse(data) / ((degrees) ? 15 : 1);
+ return Math.max(Math.min(ra, 24), 0);
+};
+
+Coordinates.parseDec = function (data) {
+ var dec = Coordinates.parse(data);
+ return Math.max(Math.min(dec, 90), -90);
+};
+
+Coordinates.parse = function (data) {
+ try {
+ data = ss.trim(data).toLowerCase();
+ data = ss.replaceString(ss.replaceString(ss.replaceString(ss.replaceString(ss.replaceString(ss.replaceString(data, 'd ', 'd'), 'h ', 'h'), 'm ', 'm'), 's ', 's'), "' ", "'"), '" ', '"');
+ if (Util.stringContains(data, [':', ' ', 'd', 'h', 'm', 's', "'", '"', '\u00b0'])) {
+ var hours = 0;
+ var minutes = 0;
+ var seconds = 0;
+ var sign = 0;
+ var parts = Util.splitString(data, [':', ' ', 'd', 'h', 'm', 's', "'", '"', '\u00b0']);
+ if (parts.length > 0) {
+ if (!ss.emptyString(parts[0])) {
+ hours = Math.abs(parseFloat(parts[0]));
+ sign = (parseFloat(parts[0]) < 0) ? -1 : 1;
+ if (parts[0].indexOf('-') > -1) {
+ sign = -1;
+ }
+ }
+ }
+ if (parts.length > 1) {
+ if (!ss.emptyString(parts[1])) {
+ minutes = parseFloat(parts[1]);
+ }
+ }
+ if (parts.length > 2) {
+ if (!ss.emptyString(parts[2])) {
+ seconds = parseFloat(parts[2]);
+ }
+ }
+ if (!sign) {
+ sign = 1;
+ }
+ return sign * (hours + minutes / 60 + seconds / 3600);
+ } else {
+ var val = 0;
+ try {
+ val = parseFloat(data);
+ }
+ catch ($e1) {
+ val = 0;
+ }
+ return val;
+ }
+ }
+ catch ($e2) {
+ return 0;
+ }
+};
+
+Coordinates.fromRaDec = function (ra, dec) {
+ return new Coordinates((ra - 12) * 15 * Coordinates.RC, dec * Coordinates.RC);
+};
+
+Coordinates.fromLatLng = function (lat, lng) {
+ return new Coordinates(lng * Coordinates.RC, lat * Coordinates.RC);
+};
+
+Coordinates.dmsToDegrees = function (Degrees, Minutes, Seconds) {
+ return Degrees + Minutes / 60 + Seconds / 3600;
+};
+
+Coordinates.degreesToRadians = function (Degrees) {
+ return Degrees * 0.0174532925199433;
+};
+
+Coordinates.radiansToDegrees = function (Radians) {
+ return Radians * 57.2957795130823;
+};
+
+Coordinates.radiansToHours = function (Radians) {
+ return Radians * 3.81971863420549;
+};
+
+Coordinates.hoursToRadians = function (Hours) {
+ return Hours * 0.261799387799149;
+};
+
+Coordinates.hoursToDegrees = function (Hours) {
+ return Hours * 15;
+};
+
+Coordinates.degreesToHours = function (Degrees) {
+ return Degrees / 15;
+};
+
+Coordinates.PI = function () {
+ return 3.14159265358979;
+};
+
+Coordinates.mapTo0To360Range = function (Degrees) {
+ var Value = Degrees;
+ while (Value < 0) {
+ Value += 360;
+ }
+ while (Value > 360) {
+ Value -= 360;
+ }
+ return Value;
+};
+
+Coordinates.mapTo0To24Range = function (HourAngle) {
+ var Value = HourAngle;
+ while (Value < 0) {
+ Value += 24;
+ }
+ while (Value > 24) {
+ Value -= 24;
+ }
+ return Value;
+};
+
+Coordinates.meanObliquityOfEcliptic = function (JD) {
+ var U = (JD - 2451545) / 3652500;
+ var Usquared = U * U;
+ var Ucubed = Usquared * U;
+ var U4 = Ucubed * U;
+ var U5 = U4 * U;
+ var U6 = U5 * U;
+ var U7 = U6 * U;
+ var U8 = U7 * U;
+ var U9 = U8 * U;
+ var U10 = U9 * U;
+ return Coordinates.dmsToDegrees(23, 26, 21.448) - Coordinates.dmsToDegrees(0, 0, 4680.93) * U - Coordinates.dmsToDegrees(0, 0, 1.55) * Usquared + Coordinates.dmsToDegrees(0, 0, 1999.25) * Ucubed - Coordinates.dmsToDegrees(0, 0, 51.38) * U4 - Coordinates.dmsToDegrees(0, 0, 249.67) * U5 - Coordinates.dmsToDegrees(0, 0, 39.05) * U6 + Coordinates.dmsToDegrees(0, 0, 7.12) * U7 + Coordinates.dmsToDegrees(0, 0, 27.87) * U8 + Coordinates.dmsToDegrees(0, 0, 5.79) * U9 + Coordinates.dmsToDegrees(0, 0, 2.45) * U10;
+};
+
+Coordinates.j2000toGalactic = function (J2000RA, J2000DEC) {
+ var J2000pos = [Math.cos(J2000RA / 180 * Math.PI) * Math.cos(J2000DEC / 180 * Math.PI), Math.sin(J2000RA / 180 * Math.PI) * Math.cos(J2000DEC / 180 * Math.PI), Math.sin(J2000DEC / 180 * Math.PI)];
+ if (Coordinates._rotationMatrix == null) {
+ Coordinates._rotationMatrix = new Array(3);
+ Coordinates._rotationMatrix[0] = [-0.0548755604, -0.8734370902, -0.4838350155];
+ Coordinates._rotationMatrix[1] = [0.4941094279, -0.44482963, 0.7469822445];
+ Coordinates._rotationMatrix[2] = [-0.867666149, -0.1980763734, 0.4559837762];
+ }
+ var Galacticpos = new Array(3);
+ for (var i = 0; i < 3; i++) {
+ Galacticpos[i] = J2000pos[0] * Coordinates._rotationMatrix[i][0] + J2000pos[1] * Coordinates._rotationMatrix[i][1] + J2000pos[2] * Coordinates._rotationMatrix[i][2];
+ }
+ var GalacticL2 = Math.atan2(Galacticpos[1], Galacticpos[0]);
+ if (GalacticL2 < 0) {
+ GalacticL2 = GalacticL2 + 2 * Math.PI;
+ }
+ if (GalacticL2 > 2 * Math.PI) {
+ GalacticL2 = GalacticL2 - 2 * Math.PI;
+ }
+ var GalacticB2 = Math.atan2(Galacticpos[2], Math.sqrt(Galacticpos[0] * Galacticpos[0] + Galacticpos[1] * Galacticpos[1]));
+ return [GalacticL2 / Math.PI * 180, GalacticB2 / Math.PI * 180];
+};
+
+Coordinates.galacticTo3dDouble = function (l, b) {
+ var result = Coordinates.galactictoJ2000(l, b);
+ return Coordinates.raDecTo3dAu(result[0] / 15, result[1], 1);
+};
+
+Coordinates.galactictoJ2000 = function (GalacticL2, GalacticB2) {
+ var Galacticpos = [Math.cos(GalacticL2 / 180 * Math.PI) * Math.cos(GalacticB2 / 180 * Math.PI), Math.sin(GalacticL2 / 180 * Math.PI) * Math.cos(GalacticB2 / 180 * Math.PI), Math.sin(GalacticB2 / 180 * Math.PI)];
+ if (Coordinates._rotationMatrix == null) {
+ Coordinates._rotationMatrix = new Array(3);
+ Coordinates._rotationMatrix[0] = [-0.0548755604, -0.8734370902, -0.4838350155];
+ Coordinates._rotationMatrix[1] = [0.4941094279, -0.44482963, 0.7469822445];
+ Coordinates._rotationMatrix[2] = [-0.867666149, -0.1980763734, 0.4559837762];
+ }
+ var J2000pos = new Array(3);
+ for (var i = 0; i < 3; i++) {
+ J2000pos[i] = Galacticpos[0] * Coordinates._rotationMatrix[0][i] + Galacticpos[1] * Coordinates._rotationMatrix[1][i] + Galacticpos[2] * Coordinates._rotationMatrix[2][i];
+ }
+ var J2000RA = Math.atan2(J2000pos[1], J2000pos[0]);
+ if (J2000RA < 0) {
+ J2000RA = J2000RA + 2 * Math.PI;
+ }
+ if (J2000RA > 2 * Math.PI) {
+ J2000RA = J2000RA - 2 * Math.PI;
+ }
+ var J2000DEC = Math.atan2(J2000pos[2], Math.sqrt(J2000pos[0] * J2000pos[0] + J2000pos[1] * J2000pos[1]));
+ return [J2000RA / Math.PI * 180, J2000DEC / Math.PI * 180];
+};
+
+var Coordinates$ = {
+ distance: function (pointB) {
+ var y = this.get_lat();
+ var x = this.get_lng() * Math.cos(y * Coordinates.RC);
+ var y1 = pointB.get_lat();
+ var x1 = pointB.get_lng() * Math.cos(y1 * Coordinates.RC);
+ return Math.sqrt((y - y1) * (y - y1) + (x - x1) * (x - x1));
+ },
+
+ distance3d: function (pointB) {
+ var pnt1 = Coordinates.geoTo3dDouble(pointB.get_lat(), pointB.get_lng());
+ var pnt2 = Coordinates.geoTo3dDouble(this.get_lat(), this.get_lng());
+ var pntDiff = Vector3d.subtractVectors(pnt1, pnt2);
+ return pntDiff.length() / Coordinates.RC;
+ },
+
+ angle: function (pointB) {
+ var y = this.get_lat();
+ var x = this.get_lng() * Math.cos(y * Coordinates.RC);
+ var y1 = pointB.get_lat();
+ var x1 = pointB.get_lng() * Math.cos(y1 * Coordinates.RC);
+ return Math.atan2((y1 - y), (x1 - x));
+ },
+
+ get_RA: function () {
+ return (((this._ascention / Math.PI) * 12) + 12) % 24;
+ },
+
+ set_RA: function (value) {
+ this._ascention = (value / 12) * Math.PI;
+ return value;
+ },
+
+ get_dec: function () {
+ return this._declination / Coordinates.RC;
+ },
+
+ set_dec: function (value) {
+ this._declination = value * Coordinates.RC;
+ return value;
+ },
+
+ get_lat: function () {
+ return this._declination / Coordinates.RC;
+ },
+
+ set_lat: function (value) {
+ this._declination = value * Coordinates.RC;
+ return value;
+ },
+
+ get_lng: function () {
+ var lng = this._ascention / Coordinates.RC;
+ if (lng <= 180) {
+ return lng;
+ } else {
+ return (-180 + (180 - lng));
+ }
+ },
+
+ set_lng: function (value) {
+ //todo This was broken check callers to see what effect it had.
+ this._ascention = ((value * Coordinates.RC) + (Math.PI * 2) % (Math.PI * 2));
+ return value;
+ },
+
+ get_alt: function () {
+ return this._declination / Coordinates.RC;
+ },
+
+ set_alt: function (value) {
+ this._declination = value * Coordinates.RC;
+ return value;
+ },
+
+ get_az: function () {
+ return this._ascention / Coordinates.RC;
+ },
+
+ set_az: function (value) {
+ this._ascention = value * Coordinates.RC;
+ return value;
+ },
+
+ toString: function () {
+ return ss.format('Lat: {0}, Lng: {1}', this.get_lat(), this.get_lng());
+ }
+};
+
+registerType("Coordinates", [Coordinates, Coordinates$, null]);
diff --git a/engine/esm/data_globals.js b/engine/esm/data_globals.js
new file mode 100644
index 00000000..8e629d07
--- /dev/null
+++ b/engine/esm/data_globals.js
@@ -0,0 +1,91 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Various global variables associated with data assets.
+//
+// See `render_globals.js` for a general rationale for this kind of module.
+
+// This used to be WWTControl(.singleton).freestandingMode. It sets whether the
+// engine will avoid accessing the central WWT servers.
+export var freestandingMode = false;
+
+export function set_freestandingMode(value) {
+ freestandingMode = !!value;
+}
+
+// This is equivalent to `new HipsProperties(imageset)`. We abstract
+// the function to avoid circular dependencies in the type hierarchy.
+export var makeNewHipsProperties = null;
+
+export function set_makeNewHipsProperties(value) {
+ makeNewHipsProperties = value;
+}
+
+// This is equivalent to `new Folder()`. We abstract
+// the function to avoid circular dependencies in the type hierarchy.
+export var makeNewFolder = null;
+
+export function set_makeNewFolder(value) {
+ makeNewFolder = value;
+}
+
+// This is equivalent to `Place.create(name, lat, lng, classification,
+// constellation, type, zoomFactor)`. We abstract the function to avoid circular
+// dependencies in the type hierarchy.
+export var createPlace = null;
+
+export function set_createPlace(value) {
+ createPlace = value;
+}
+
+// This is another way to access `WWTControl.singleton`. It's the
+// global singleton WWTControl instance.
+export var globalWWTControl = null;
+
+export function set_globalWWTControl(value) {
+ globalWWTControl = value;
+}
+
+// This is another way to access the `WWTControl.scriptInterface` singleton. It's
+// the global singleton ScriptInterface instance.
+export var globalScriptInterface = null;
+
+export function set_globalScriptInterface(value) {
+ globalScriptInterface = value;
+}
+
+// This is another way to access `LayerManager.setVisibleLayerList()`. Once
+// again, we need this to break some circular dependencies in the module
+// structure.
+export var setManagerVisibleLayerList = null;
+
+export function set_setManagerVisibleLayerList(value) {
+ setManagerVisibleLayerList = value;
+}
+
+// This is another way to access `TourDocument.fromUrlRaw()`. Once again, we
+// need this to break some circular dependencies in the module structure.
+
+export var tourDocumentFromUrlRaw = null;
+
+export function set_tourDocumentFromUrlRaw(value) {
+ tourDocumentFromUrlRaw = value;
+}
+
+// This is another way to access `LayerManager.getAllMaps()`. Once again, we
+// need this to break some circular dependencies in the module structure.
+
+export var layerManagerGetAllMaps = null;
+
+export function set_layerManagerGetAllMaps(value) {
+ layerManagerGetAllMaps = value;
+}
+
+// This is another way to access `Wtml.getWtmlFile()`. Once again, we
+// need this to break some circular dependencies in the module structure.
+
+export var loadWtmlFile = null;
+
+export function set_loadWtmlFile(value) {
+ loadWtmlFile = value;
+}
diff --git a/engine/esm/double3d.js b/engine/esm/double3d.js
new file mode 100644
index 00000000..be1516f2
--- /dev/null
+++ b/engine/esm/double3d.js
@@ -0,0 +1,2326 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Basic vector datatypes and the like.
+
+import { registerType } from "./typesystem.js";
+import { ss } from "./ss.js";
+import { Color } from "./color.js";
+import { tileUvMultiple } from "./render_globals.js";
+
+
+// Break some circular dependencies
+//
+// `Vector2d.cartesianToSpherical2` is almost the same as
+// `Coordinates.cartesianToSpherical2`, but the resulting angles are measured in
+// degrees rather than radians, and the Coordinates class applies some
+// transformations in various places. Out of an abundance of caution we
+// reproduce its calculations rotely.
+
+const RC = (3.1415927 / 180); // not thrilled about the low precision!
+
+function geoTo3dDouble(lat, lng) {
+ return Vector3d.create(
+ Math.cos(lng * RC) * Math.cos(lat * RC) * 1,
+ Math.sin(lat * RC) * 1,
+ Math.sin(lng * RC) * Math.cos(lat * RC) * 1
+ );
+}
+
+function coords_cartesianToSpherical2(vector) {
+ var rho = Math.sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z);
+ var longitude = Math.atan2(vector.z, vector.x);
+ var latitude = Math.asin(vector.y / rho);
+
+ // I don't love this approach but it's what the Coords constructor does
+ longitude = longitude + (Math.PI * 80) % (Math.PI * 2);
+
+ // Coordinates.get_lng():
+ var lng = longitude / RC;
+ if (lng > 180) {
+ lng = (-180 + (180 - lng));
+ }
+
+ // Coordinates.get_lat():
+ var lat = latitude / RC;
+
+ return [lat, lng];
+}
+
+
+// wwtlib.LocationHint
+//
+// Summary:
+// Describes a custom vertex format structure that contains position and one
+// set of texture coordinates.
+
+export var LocationHint = {
+ slash: 0,
+ backslash: 1,
+ top: 2
+};
+
+registerType("LocationHint", LocationHint);
+
+
+// wwtlib.PositionTexture
+
+export function PositionTexture() {
+ this.tu = 0;
+ this.tv = 0;
+ this.position = new Vector3d();
+}
+
+// Summary:
+// Initializes a new instance of the Microsoft.DirectX.Direct3D.CustomVertex.PositionTextured
+// class.
+//
+// Parameters:
+// pos:
+// A Microsoft.DirectX.Vector3d object that contains the vertex position.
+//
+// u:
+// Floating-point value that represents the Microsoft.DirectX.Direct3D.CustomVertex.PositionTextured.#ctor()
+// component of the texture coordinate.
+//
+// v:
+// Floating-point value that represents the Microsoft.DirectX.Direct3D.CustomVertex.PositionTextured.#ctor()
+// component of the texture coordinate.
+PositionTexture.createPos = function (pos, u, v) {
+ var temp = new PositionTexture();
+ temp.tu = u * tileUvMultiple;
+ temp.tv = v * tileUvMultiple;
+ temp.position = pos;
+ return temp;
+};
+
+PositionTexture.createPosRaw = function (pos, u, v) {
+ var temp = new PositionTexture();
+ temp.tu = u;
+ temp.tv = v;
+ temp.position = pos;
+ return temp;
+};
+
+PositionTexture.createPosSize = function (pos, u, v, width, height) {
+ var temp = new PositionTexture();
+ temp.tu = u * width;
+ temp.tv = v * height;
+ temp.position = pos;
+ return temp;
+};
+
+// Summary:
+// Initializes a new instance of the Microsoft.DirectX.Direct3D.CustomVertex.PositionTextured
+// class.
+//
+// Parameters:
+// xvalue:
+// Floating-point value that represents the x coordinate of the position.
+//
+// yvalue:
+// Floating-point value that represents the y coordinate of the position.
+//
+// zvalue:
+// Floating-point value that represents the z coordinate of the position.
+//
+// u:
+// Floating-point value that represents the Microsoft.DirectX.Direct3D.CustomVertex.PositionTextured.#ctor()
+// component of the texture coordinate.
+//
+// v:
+// Floating-point value that represents the Microsoft.DirectX.Direct3D.CustomVertex.PositionTextured.#ctor()
+// component of the texture coordinate.
+PositionTexture.create = function (xvalue, yvalue, zvalue, u, v) {
+ var temp = new PositionTexture();
+ temp.position = Vector3d.create(xvalue, yvalue, zvalue);
+ temp.tu = u * tileUvMultiple;
+ temp.tv = v * tileUvMultiple;
+ return temp;
+};
+
+var PositionTexture$ = {
+ copy: function () {
+ var temp = new PositionTexture();
+ temp.position = Vector3d.makeCopy(this.position);
+ temp.tu = this.tu;
+ temp.tv = this.tv;
+ return temp;
+ },
+
+ toString: function () {
+ return ss.format('{0}, {1}, {2}, {3}, {4}', this.position.x, this.position.y, this.position.z, this.tu, this.tv);
+ }
+};
+
+registerType("PositionTexture", [PositionTexture, PositionTexture$, null]);
+
+
+// wwtlib.PositionColoredTextured
+
+export function PositionColoredTextured() {
+ this.tu = 0;
+ this.tv = 0;
+ this.color = new Color();
+ this.position = new Vector3d();
+}
+
+// Summary:
+// Initializes a new instance of the Microsoft.DirectX.Direct3D.CustomVertex.PositionTextured
+// class.
+//
+// Parameters:
+// pos:
+// A Microsoft.DirectX.Vector3d object that contains the vertex position.
+//
+// u:
+// Floating-point value that represents the Microsoft.DirectX.Direct3D.CustomVertex.PositionTextured.#ctor()
+// component of the texture coordinate.
+//
+// v:
+// Floating-point value that represents the Microsoft.DirectX.Direct3D.CustomVertex.PositionTextured.#ctor()
+// component of the texture coordinate.
+PositionColoredTextured.createPos = function (pos, u, v) {
+ var temp = new PositionColoredTextured();
+ temp.tu = u * tileUvMultiple;
+ temp.tv = v * tileUvMultiple;
+ temp.position = pos;
+ return temp;
+};
+
+PositionColoredTextured.createPosRaw = function (pos, u, v) {
+ var temp = new PositionColoredTextured();
+ temp.tu = u;
+ temp.tv = v;
+ temp.position = pos;
+ return temp;
+};
+
+PositionColoredTextured.createPosSize = function (pos, u, v, width, height) {
+ var temp = new PositionColoredTextured();
+ temp.tu = u * width;
+ temp.tv = v * height;
+ temp.position = pos;
+ return temp;
+};
+
+// ** Is it a mistake that this is creating a PositionTexture, not PositionColoredTextured? **
+//
+// Summary:
+// Initializes a new instance of the Microsoft.DirectX.Direct3D.CustomVertex.PositionTextured
+// class.
+//
+// Parameters:
+// xvalue:
+// Floating-point value that represents the x coordinate of the position.
+//
+// yvalue:
+// Floating-point value that represents the y coordinate of the position.
+//
+// zvalue:
+// Floating-point value that represents the z coordinate of the position.
+//
+// u:
+// Floating-point value that represents the Microsoft.DirectX.Direct3D.CustomVertex.PositionTextured.#ctor()
+// component of the texture coordinate.
+//
+// v:
+// Floating-point value that represents the Microsoft.DirectX.Direct3D.CustomVertex.PositionTextured.#ctor()
+// component of the texture coordinate.
+PositionColoredTextured.create = function (xvalue, yvalue, zvalue, u, v) {
+ var temp = new PositionTexture();
+ temp.position = Vector3d.create(xvalue, yvalue, zvalue);
+ temp.tu = u * tileUvMultiple;
+ temp.tv = v * tileUvMultiple;
+ return temp;
+};
+
+var PositionColoredTextured$ = {
+ copy: function () {
+ var temp = new PositionTexture();
+ temp.position = Vector3d.makeCopy(this.position);
+ temp.tu = this.tu;
+ temp.tv = this.tv;
+ return temp;
+ },
+ toString: function () {
+ return ss.format('{0}, {1}, {2}, {3}, {4}', this.position.x, this.position.y, this.position.z, this.tu, this.tv);
+ }
+};
+
+registerType("PositionColoredTextured", [PositionColoredTextured, PositionColoredTextured$, null]);
+
+
+// wwtlib.PositionColored
+
+export function PositionColored(pos, color) {
+ this.color = new Color();
+ this.color = color._clone();
+ this.position = pos.copy();
+}
+
+var PositionColored$ = {
+ copy: function () {
+ var temp = new PositionColored(this.position, this.color);
+ return temp;
+ },
+
+ toString: function () {
+ return ss.format('{0}, {1}, {2}, {3}', this.position.x, this.position.y, this.position.z, this.color.toString());
+ }
+};
+
+registerType("PositionColored", [PositionColored, PositionColored$, null]);
+
+
+// wwtlib.PositionNormalTexturedTangent
+//
+// Summary:
+// Custom vertex format with position, normal, texture coordinate, and tangent vector. The
+// tangent vector is stored in the second texture coordinate.
+
+export function PositionNormalTexturedTangent(position, normal, texCoord, tangent) {
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+ this.nx = 0;
+ this.ny = 0;
+ this.nz = 0;
+ this.tu = 0;
+ this.tv = 0;
+ this.tanx = 0;
+ this.tany = 0;
+ this.tanz = 0;
+ this.x = position.x;
+ this.y = position.y;
+ this.z = position.z;
+ this.nx = normal.x;
+ this.ny = normal.y;
+ this.nz = normal.z;
+ this.tu = texCoord.x;
+ this.tv = texCoord.y;
+ this.tanx = tangent.x;
+ this.tany = tangent.y;
+ this.tanz = tangent.z;
+}
+
+var PositionNormalTexturedTangent$ = {
+ get_normal: function () {
+ return Vector3d.create(this.nx, this.ny, this.nz);
+ },
+
+ set_normal: function (value) {
+ this.nx = value.x;
+ this.ny = value.y;
+ this.nz = value.z;
+ return value;
+ },
+
+ get_position: function () {
+ return Vector3d.create(this.x, this.y, this.z);
+ },
+
+ set_position: function (value) {
+ this.x = value.x;
+ this.y = value.y;
+ this.z = value.z;
+ return value;
+ },
+
+ get_texCoord: function () {
+ return Vector2d.create(this.tu, this.tv);
+ },
+
+ set_texCoord: function (value) {
+ this.tu = value.x;
+ this.tv = value.y;
+ return value;
+ },
+
+ get_tangent: function () {
+ return Vector3d.create(this.tanx, this.tany, this.tanz);
+ },
+
+ set_tangent: function (value) {
+ this.tanx = value.x;
+ this.tany = value.y;
+ this.tanz = value.z;
+ return value;
+ },
+
+ toString: function () {
+ return ss.format('X={0}, Y={1}, Z={2}, Nx={3}, Ny={4}, Nz={5}, U={6}, V={7}, TanX={8}, TanY={9}, TanZ={10}', this.x, this.y, this.z, this.nx, this.ny, this.nz, this.tu, this.tv, this.tanx, this.tany, this.tanz);
+ }
+};
+
+registerType("PositionNormalTexturedTangent", [PositionNormalTexturedTangent, PositionNormalTexturedTangent$, null]);
+
+
+// wwtlib.Vector3d
+
+export function Vector3d() {
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+}
+
+Vector3d.create = function (valueX, valueY, valueZ) {
+ var temp = new Vector3d();
+ temp.x = valueX;
+ temp.y = valueY;
+ temp.z = valueZ;
+ return temp;
+};
+
+Vector3d.makeCopy = function (value) {
+ var temp = new Vector3d();
+ temp.x = value.x;
+ temp.y = value.y;
+ temp.z = value.z;
+ return temp;
+};
+
+Vector3d.negate = function (vec) {
+ return Vector3d.create(-vec.x, -vec.y, -vec.z);
+};
+
+Vector3d.midPoint = function (left, right) {
+ var result = Vector3d.create((left.x + right.x) / 2, (left.y + right.y) / 2, (left.z + right.z) / 2);
+ return result;
+};
+
+Vector3d.midPointByLength = function (left, right) {
+ var result = Vector3d.create((left.x + right.x) / 2, (left.y + right.y) / 2, (left.z + right.z) / 2);
+ result.normalize();
+ result.multiply(left.length());
+ return result;
+};
+
+Vector3d.get_empty = function () {
+ return Vector3d.create(0, 0, 0);
+};
+
+Vector3d.addVectors = function (left, right) {
+ return Vector3d.create(left.x + right.x, left.y + right.y, left.z + right.z);
+};
+
+Vector3d.cross = function (left, right) {
+ return Vector3d.create(left.y * right.z - left.z * right.y, left.z * right.x - left.x * right.z, left.x * right.y - left.y * right.x);
+};
+
+Vector3d.dot = function (left, right) {
+ return left.x * right.x + left.y * right.y + left.z * right.z;
+};
+
+Vector3d.getLength = function (source) {
+ return Math.sqrt(source.x * source.x + source.y * source.y + source.z * source.z);
+};
+
+Vector3d.getLengthSq = function (source) {
+ return source.x * source.x + source.y * source.y + source.z * source.z;
+};
+
+// Summary:
+// Performs a linear interpolation between two 3-D vectors.
+//
+// Parameters:
+// left:
+// Source Microsoft.DirectX.Vector3d structure.
+//
+// right:
+// Source Microsoft.DirectX.Vector3d structure.
+//
+// interpolater:
+// Parameter that linearly interpolates between the vectors.
+//
+// Returns:
+// A Microsoft.DirectX.Vector3d structure that is the result of the linear interpolation.
+Vector3d.lerp = function (left, right, interpolater) {
+ return Vector3d.create(left.x * (1 - interpolater) + right.x * interpolater, left.y * (1 - interpolater) + right.y * interpolater, left.z * (1 - interpolater) + right.z * interpolater);
+};
+
+Vector3d.midpoint = function (left, right) {
+ var tmp = Vector3d.create(left.x * (0.5) + right.x * 0.5, left.y * (0.5) + right.y * 0.5, left.z * (0.5) + right.z * 0.5);
+ tmp.normalize();
+ return tmp;
+};
+
+Vector3d.slerp = function (left, right, interpolater) {
+ var dot = Vector3d.dot(left, right);
+ while (dot < 0.98) {
+ var middle = Vector3d.midpoint(left, right);
+ if (interpolater > 0.5) {
+ left = middle;
+ interpolater -= 0.5;
+ interpolater *= 2;
+ }
+ else {
+ right = middle;
+ interpolater *= 2;
+ }
+ dot = Vector3d.dot(left, right);
+ }
+ var tmp = Vector3d.lerp(left, right, interpolater);
+ tmp.normalize();
+ return tmp;
+};
+
+Vector3d.multiplyScalar = function (source, f) {
+ var result = source.copy();
+ result.multiply(f);
+ return result;
+};
+
+Vector3d.scale = function (source, scalingFactor) {
+ var result = source;
+ result.multiply(scalingFactor);
+ return result;
+};
+
+Vector3d.subtractVectors = function (left, right) {
+ var result = left.copy();
+ result.subtract(right);
+ return result;
+};
+
+Vector3d.parse = function (data) {
+ var newVector = new Vector3d();
+ var list = data.split(',');
+ if (list.length === 3) {
+ newVector.x = parseFloat(list[0]);
+ newVector.y = parseFloat(list[1]);
+ newVector.z = parseFloat(list[2]);
+ }
+ return newVector;
+};
+
+Vector3d._transformCoordinate = function (vector3d, mat) {
+ return mat.transform(vector3d);
+};
+
+var Vector3d$ = {
+ set: function (valueX, valueY, valueZ) {
+ this.x = valueX;
+ this.y = valueY;
+ this.z = valueZ;
+ },
+
+ copy: function () {
+ var temp = new Vector3d();
+ temp.x = this.x;
+ temp.y = this.y;
+ temp.z = this.z;
+ return temp;
+ },
+
+ round: function () {
+ this.x = ss.truncate((this.x * 65536)) / 65536;
+ this.y = ss.truncate((this.y * 65536)) / 65536;
+ this.z = ss.truncate((this.z * 65536)) / 65536;
+ },
+
+ add: function (source) {
+ this.x += source.x;
+ this.y += source.y;
+ this.z += source.z;
+ },
+
+ length: function () {
+ return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
+ },
+
+ lengthSq: function () {
+ return this.x * this.x + this.y * this.y + this.z * this.z;
+ },
+
+ multiply: function (s) {
+ this.x *= s;
+ this.y *= s;
+ this.z *= s;
+ },
+
+ normalize: function () {
+ var length = this.length();
+ if (!!length) {
+ this.x /= length;
+ this.y /= length;
+ this.z /= length;
+ }
+ },
+
+ rotateX: function (radians) {
+ var zTemp;
+ var yTemp;
+ yTemp = this.y * Math.cos(radians) - this.z * Math.sin(radians);
+ zTemp = this.y * Math.sin(radians) + this.z * Math.cos(radians);
+ this.z = zTemp;
+ this.y = yTemp;
+ },
+
+ rotateZ: function (radians) {
+ var xTemp;
+ var yTemp;
+ xTemp = this.x * Math.cos(radians) - this.y * Math.sin(radians);
+ yTemp = this.x * Math.sin(radians) + this.y * Math.cos(radians);
+ this.y = yTemp;
+ this.x = xTemp;
+ },
+
+ rotateY: function (radians) {
+ var zTemp;
+ var xTemp;
+ zTemp = this.z * Math.cos(radians) - this.x * Math.sin(radians);
+ xTemp = this.z * Math.sin(radians) + this.x * Math.cos(radians);
+ this.x = xTemp;
+ this.z = zTemp;
+ },
+
+ subtract: function (source) {
+ this.x -= source.x;
+ this.y -= source.y;
+ this.z -= source.z;
+ return this;
+ },
+
+ toString: function () {
+ return ss.format('{0}, {1}, {2}', this.x, this.y, this.z);
+ },
+
+ toSpherical: function () {
+ var ascention;
+ var declination;
+ var radius = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
+ var XZ = Math.sqrt(this.x * this.x + this.z * this.z);
+ declination = Math.asin(this.y / radius);
+ if (!XZ) {
+ ascention = 0;
+ }
+ else if (0 <= this.x) {
+ ascention = Math.asin(this.z / XZ);
+ }
+ else {
+ ascention = Math.PI - Math.asin(this.z / XZ);
+ }
+ return Vector2d.create(((ascention + Math.PI) % (2 * Math.PI)), (declination + (Math.PI / 2)));
+ },
+
+ toRaDec: function () {
+ var point = this.toSpherical();
+ point.x = point.x / Math.PI * 12;
+ point.y = (point.y / Math.PI * 180) - 90;
+ return point;
+ },
+
+ distanceToLine: function (x1, x2) {
+ var t1 = Vector3d.subtractVectors(x2, x1);
+ var t2 = Vector3d.subtractVectors(x1, this);
+ var t3 = Vector3d.cross(t1, t2);
+ var d1 = t3.length();
+ var t4 = Vector3d.subtractVectors(x2, x1);
+ var d2 = t4.length();
+ return d1 / d2;
+ },
+
+ _transformByMatrics: function (lookAtAdjust) {
+ var temp = lookAtAdjust.transform(this);
+ this.x = temp.x;
+ this.y = temp.y;
+ this.z = temp.z;
+ }
+};
+
+registerType("Vector3d", [Vector3d, Vector3d$, null]);
+
+Vector3d.zero = new Vector3d();
+
+
+// wwtlib.Vector2d
+
+export function Vector2d() {
+ this.x = 0;
+ this.y = 0;
+}
+
+Vector2d.lerp = function (left, right, interpolater) {
+ return Vector2d.create(left.x * (1 - interpolater) + right.x * interpolater, left.y * (1 - interpolater) + right.y * interpolater);
+};
+
+Vector2d.cartesianToSpherical2 = function (vector) {
+ var rho = Math.sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z);
+ var longitude = Math.atan2(vector.z, vector.x);
+ var latitude = Math.asin(vector.y / rho);
+ return Vector2d.create(longitude / Math.PI * 180, latitude / Math.PI * 180);
+};
+
+Vector2d.average3d = function (left, right) {
+ var pntLeft = geoTo3dDouble(left.y, left.x);
+ var pntRight = geoTo3dDouble(right.y, right.x);
+ var pntOut = Vector3d.addVectors(pntLeft, pntRight);
+ pntOut.multiply(0.5);
+ pntOut.normalize();
+ return Vector2d.cartesianToSpherical2(pntOut);
+};
+
+Vector2d.create = function (x, y) {
+ var temp = new Vector2d();
+ temp.x = x;
+ temp.y = y;
+ return temp;
+};
+
+Vector2d.subtract = function (left, right) {
+ return Vector2d.create(left.x - right.x, left.y - right.y);
+};
+
+var Vector2d$ = {
+ distance3d: function (pointB) {
+ var pnt1 = geoTo3dDouble(pointB.y, pointB.x);
+ var pnt2 = geoTo3dDouble(this.y, this.x);
+ var pntDiff = Vector3d.subtractVectors(pnt1, pnt2);
+ return pntDiff.length() / Math.PI * 180;
+ },
+
+ get_length: function () {
+ return Math.sqrt(this.x * this.x + this.y * this.y);
+ },
+
+ normalize: function () {
+ var length = this.get_length();
+ if (!!length) {
+ this.x /= length;
+ this.y /= length;
+ }
+ },
+
+ extend: function (factor) {
+ this.x = this.x * factor;
+ this.y = this.y * factor;
+ }
+};
+
+registerType("Vector2d", [Vector2d, Vector2d$, null]);
+
+
+// wwtlib.Matrix3d
+
+export function Matrix3d() {
+ this._m11 = 0;
+ this._m12 = 0;
+ this._m13 = 0;
+ this._m14 = 0;
+ this._m21 = 0;
+ this._m22 = 0;
+ this._m23 = 0;
+ this._m24 = 0;
+ this._m31 = 0;
+ this._m32 = 0;
+ this._m33 = 0;
+ this._m34 = 0;
+ this._offsetX = 0;
+ this._offsetY = 0;
+ this._offsetZ = 0;
+ this._m44 = 0;
+ this._isNotKnownToBeIdentity = false;
+}
+
+Matrix3d.create = function (m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, offsetX, offsetY, offsetZ, m44) {
+ var temp = new Matrix3d();
+ temp._m11 = m11;
+ temp._m12 = m12;
+ temp._m13 = m13;
+ temp._m14 = m14;
+ temp._m21 = m21;
+ temp._m22 = m22;
+ temp._m23 = m23;
+ temp._m24 = m24;
+ temp._m31 = m31;
+ temp._m32 = m32;
+ temp._m33 = m33;
+ temp._m34 = m34;
+ temp._offsetX = offsetX;
+ temp._offsetY = offsetY;
+ temp._offsetZ = offsetZ;
+ temp._m44 = m44;
+ temp._isNotKnownToBeIdentity = true;
+ return temp;
+};
+
+Matrix3d.get_identity = function () {
+ var temp = new Matrix3d();
+ temp.set(Matrix3d._s_identity);
+ return temp;
+};
+
+Matrix3d.multiplyMatrix = function (matrix1, matrix2) {
+ if (matrix1.get__isDistinguishedIdentity()) {
+ return matrix2;
+ }
+ if (matrix2.get__isDistinguishedIdentity()) {
+ return matrix1;
+ }
+ return Matrix3d.create((((matrix1._m11 * matrix2._m11) + (matrix1._m12 * matrix2._m21)) + (matrix1._m13 * matrix2._m31)) + (matrix1._m14 * matrix2._offsetX), (((matrix1._m11 * matrix2._m12) + (matrix1._m12 * matrix2._m22)) + (matrix1._m13 * matrix2._m32)) + (matrix1._m14 * matrix2._offsetY), (((matrix1._m11 * matrix2._m13) + (matrix1._m12 * matrix2._m23)) + (matrix1._m13 * matrix2._m33)) + (matrix1._m14 * matrix2._offsetZ), (((matrix1._m11 * matrix2._m14) + (matrix1._m12 * matrix2._m24)) + (matrix1._m13 * matrix2._m34)) + (matrix1._m14 * matrix2._m44), (((matrix1._m21 * matrix2._m11) + (matrix1._m22 * matrix2._m21)) + (matrix1._m23 * matrix2._m31)) + (matrix1._m24 * matrix2._offsetX), (((matrix1._m21 * matrix2._m12) + (matrix1._m22 * matrix2._m22)) + (matrix1._m23 * matrix2._m32)) + (matrix1._m24 * matrix2._offsetY), (((matrix1._m21 * matrix2._m13) + (matrix1._m22 * matrix2._m23)) + (matrix1._m23 * matrix2._m33)) + (matrix1._m24 * matrix2._offsetZ), (((matrix1._m21 * matrix2._m14) + (matrix1._m22 * matrix2._m24)) + (matrix1._m23 * matrix2._m34)) + (matrix1._m24 * matrix2._m44), (((matrix1._m31 * matrix2._m11) + (matrix1._m32 * matrix2._m21)) + (matrix1._m33 * matrix2._m31)) + (matrix1._m34 * matrix2._offsetX), (((matrix1._m31 * matrix2._m12) + (matrix1._m32 * matrix2._m22)) + (matrix1._m33 * matrix2._m32)) + (matrix1._m34 * matrix2._offsetY), (((matrix1._m31 * matrix2._m13) + (matrix1._m32 * matrix2._m23)) + (matrix1._m33 * matrix2._m33)) + (matrix1._m34 * matrix2._offsetZ), (((matrix1._m31 * matrix2._m14) + (matrix1._m32 * matrix2._m24)) + (matrix1._m33 * matrix2._m34)) + (matrix1._m34 * matrix2._m44), (((matrix1._offsetX * matrix2._m11) + (matrix1._offsetY * matrix2._m21)) + (matrix1._offsetZ * matrix2._m31)) + (matrix1._m44 * matrix2._offsetX), (((matrix1._offsetX * matrix2._m12) + (matrix1._offsetY * matrix2._m22)) + (matrix1._offsetZ * matrix2._m32)) + (matrix1._m44 * matrix2._offsetY), (((matrix1._offsetX * matrix2._m13) + (matrix1._offsetY * matrix2._m23)) + (matrix1._offsetZ * matrix2._m33)) + (matrix1._m44 * matrix2._offsetZ), (((matrix1._offsetX * matrix2._m14) + (matrix1._offsetY * matrix2._m24)) + (matrix1._offsetZ * matrix2._m34)) + (matrix1._m44 * matrix2._m44));
+};
+
+Matrix3d.lookAtLH = function (cameraPosition, cameraTarget, cameraUpVector) {
+ var zaxis = Vector3d.subtractVectors(cameraTarget, cameraPosition);
+ zaxis.normalize();
+ var xaxis = Vector3d.cross(cameraUpVector, zaxis);
+ xaxis.normalize();
+ var yaxis = Vector3d.cross(zaxis, xaxis);
+ var mat = Matrix3d.create(xaxis.x, yaxis.x, zaxis.x, 0, xaxis.y, yaxis.y, zaxis.y, 0, xaxis.z, yaxis.z, zaxis.z, 0, -Vector3d.dot(xaxis, cameraPosition), -Vector3d.dot(yaxis, cameraPosition), -Vector3d.dot(zaxis, cameraPosition), 1);
+ return mat;
+};
+
+Matrix3d._createIdentity = function () {
+ var matrixd = Matrix3d.create(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+ matrixd.set__isDistinguishedIdentity(true);
+ return matrixd;
+};
+
+Matrix3d.equals = function (matrix1, matrix2) {
+ if (matrix1.get__isDistinguishedIdentity() || matrix2.get__isDistinguishedIdentity()) {
+ return (matrix1.get_isIdentity() === matrix2.get_isIdentity());
+ }
+ if ((((matrix1.get_m11() === matrix2.get_m11() && matrix1.get_m12() === matrix2.get_m12()) && (matrix1.get_m13() === matrix2.get_m13() && matrix1.get_m14() === matrix2.get_m14())) && ((matrix1.get_m21() === matrix2.get_m21() && matrix1.get_m22() === matrix2.get_m22()) && (matrix1.get_m23() === matrix2.get_m23() && matrix1.get_m24() === matrix2.get_m24()))) && (((matrix1.get_m31() === matrix2.get_m31() && matrix1.get_m32() === matrix2.get_m32()) && (matrix1.get_m33() === matrix2.get_m33() && matrix1.get_m34() === matrix2.get_m34())) && ((matrix1.get_offsetX() === matrix2.get_offsetX() && matrix1.get_offsetY() === matrix2.get_offsetY()) && matrix1.get_offsetZ() === matrix2.get_offsetZ()))) {
+ return matrix1.get_m44() === matrix2.get_m44();
+ }
+ return false;
+};
+
+Matrix3d.fromMatrix2d = function (mat) {
+ var mat3d = Matrix3d._createIdentity();
+ mat3d.set_m11(mat.m11);
+ mat3d.set_m12(mat.m12);
+ mat3d.set_m13(mat.m13);
+ mat3d.set_m21(mat.m21);
+ mat3d.set_m22(mat.m22);
+ mat3d.set_m23(mat.m23);
+ mat3d.set_m31(mat.m31);
+ mat3d.set_m32(mat.m32);
+ mat3d.set_m33(mat.m33);
+ mat3d._isNotKnownToBeIdentity = true;
+ return mat3d;
+};
+
+Matrix3d.rotationYawPitchRoll = function (heading, pitch, roll) {
+ var matX = Matrix3d._rotationX(pitch);
+ var matY = Matrix3d._rotationY(heading);
+ var matZ = Matrix3d._rotationZ(roll);
+ return Matrix3d.multiplyMatrix(Matrix3d.multiplyMatrix(matY, matX), matZ);
+};
+
+Matrix3d._rotationY = function (p) {
+ var v = p;
+ var matNew = Matrix3d.get_identity();
+ matNew._m11 = Math.cos(v);
+ matNew._m22 = 1;
+ matNew._m31 = Math.sin(v);
+ matNew._m13 = -Math.sin(v);
+ matNew._m33 = Math.cos(v);
+ matNew._isNotKnownToBeIdentity = true;
+ return matNew;
+};
+
+Matrix3d._rotationX = function (p) {
+ var v = p;
+ var matNew = Matrix3d.get_identity();
+ matNew._m11 = 1;
+ matNew._m22 = Math.cos(v);
+ matNew._m32 = -Math.sin(v);
+ matNew._m23 = Math.sin(v);
+ matNew._m33 = Math.cos(v);
+ matNew._isNotKnownToBeIdentity = true;
+ return matNew;
+};
+
+Matrix3d._rotationZ = function (p) {
+ var v = p;
+ var matNew = Matrix3d.get_identity();
+ matNew._m11 = Math.cos(v);
+ matNew._m21 = -Math.sin(v);
+ matNew._m12 = Math.sin(v);
+ matNew._m22 = Math.cos(v);
+ matNew._m33 = 1;
+ matNew._isNotKnownToBeIdentity = true;
+ return matNew;
+};
+
+Matrix3d._scaling = function (x, y, z) {
+ var matNew = Matrix3d.get_identity();
+ matNew._m11 = x;
+ matNew._m22 = y;
+ matNew._m33 = z;
+ matNew._isNotKnownToBeIdentity = true;
+ return matNew;
+};
+
+Matrix3d._translationXYZ = function (x, y, z) {
+ var matNew = Matrix3d.get_identity();
+ matNew.set_offsetX(x);
+ matNew.set_offsetY(y);
+ matNew.set_offsetZ(z);
+ matNew._isNotKnownToBeIdentity = true;
+ return matNew;
+};
+
+Matrix3d.perspectiveFovLH = function (fieldOfViewY, aspectRatio, znearPlane, zfarPlane) {
+ var h = 1 / Math.tan(fieldOfViewY / 2);
+ var w = h / aspectRatio;
+ return Matrix3d.create(w, 0, 0, 0, 0, h, 0, 0, 0, 0, zfarPlane / (zfarPlane - znearPlane), 1, 0, 0, -znearPlane * zfarPlane / (zfarPlane - znearPlane), 0);
+};
+
+Matrix3d.perspectiveOffCenterLH = function (left, right, bottom, top, znearPlane, zfarPlane) {
+ return Matrix3d.create(2 * znearPlane / (right - left), 0, 0, 0, 0, 2 * znearPlane / (top - bottom), 0, 0, (left + right) / (left - right), (top + bottom) / (bottom - top), zfarPlane / (zfarPlane - znearPlane), 1, 0, 0, znearPlane * zfarPlane / (znearPlane - zfarPlane), 0);
+};
+
+Matrix3d.invertMatrix = function (matrix3d) {
+ var mat = matrix3d.clone();
+ mat.invert();
+ return mat;
+};
+
+Matrix3d.translation = function (vector3d) {
+ return Matrix3d._translationXYZ(vector3d.x, vector3d.y, vector3d.z);
+};
+
+Matrix3d.getMapMatrix = function (center, fieldWidth, fieldHeight, rotation) {
+ var offsetX = 0;
+ var offsetY = 0;
+ offsetX = -((center.get_lng() + 180 - (fieldWidth / 2)) / 360);
+ offsetY = -(1 - ((center.get_lat() + 90 + (fieldHeight / 2)) / 180));
+ var mat = new Matrix2d();
+ var scaleX = 0;
+ var scaleY = 0;
+ scaleX = 360 / fieldWidth;
+ scaleY = 180 / fieldHeight;
+ mat = Matrix2d.multiply(mat, Matrix2d.translation(offsetX, offsetY));
+ mat = Matrix2d.multiply(mat, Matrix2d.scaling(scaleX, scaleY));
+ if (!!rotation) {
+ mat = Matrix2d.multiply(mat, Matrix2d.translation(-0.5, -0.5));
+ mat = Matrix2d.multiply(mat, Matrix2d.rotation(rotation));
+ mat = Matrix2d.multiply(mat, Matrix2d.translation(0.5, 0.5));
+ }
+ return Matrix3d.fromMatrix2d(mat);
+};
+
+var Matrix3d$ = {
+ clone: function () {
+ var tmp = new Matrix3d();
+ tmp.set(this);
+ return tmp;
+ },
+
+ setIdentity: function () {
+ this.set(Matrix3d._s_identity);
+ },
+
+ set: function (mat) {
+ this._m11 = mat._m11;
+ this._m12 = mat._m12;
+ this._m13 = mat._m13;
+ this._m14 = mat._m14;
+ this._m21 = mat._m21;
+ this._m22 = mat._m22;
+ this._m23 = mat._m23;
+ this._m24 = mat._m24;
+ this._m31 = mat._m31;
+ this._m32 = mat._m32;
+ this._m33 = mat._m33;
+ this._m34 = mat._m34;
+ this._offsetX = mat._offsetX;
+ this._offsetY = mat._offsetY;
+ this._offsetZ = mat._offsetZ;
+ this._m44 = mat._m44;
+ this._isNotKnownToBeIdentity = true;
+ },
+
+ floatArray: function () {
+ var array = new Array(16);
+ array[0] = this._m11;
+ array[1] = this._m12;
+ array[2] = this._m13;
+ array[3] = this._m14;
+ array[4] = this._m21;
+ array[5] = this._m22;
+ array[6] = this._m23;
+ array[7] = this._m24;
+ array[8] = this._m31;
+ array[9] = this._m32;
+ array[10] = this._m33;
+ array[11] = this._m34;
+ array[12] = this._offsetX;
+ array[13] = this._offsetY;
+ array[14] = this._offsetZ;
+ array[15] = this._m44;
+ return array;
+ },
+
+ get_isIdentity: function () {
+ if (this.get__isDistinguishedIdentity()) {
+ return true;
+ }
+ if (((((this._m11 === 1) && (!this._m12)) && ((!this._m13) && (!this._m14))) && (((!this._m21) && (this._m22 === 1)) && ((!this._m23) && (!this._m24)))) && ((((!this._m31) && (!this._m32)) && ((this._m33 === 1) && (!this._m34))) && (((!this._offsetX) && (!this._offsetY)) && ((!this._offsetZ) && (this._m44 === 1))))) {
+ this.set__isDistinguishedIdentity(true);
+ return true;
+ }
+ return false;
+ },
+
+ prepend: function (matrix) {
+ this.set(Matrix3d.multiplyMatrix(matrix, this));
+ },
+
+ append: function (matrix) {
+ this._multiply(matrix);
+ },
+
+ scale: function (scale) {
+ if (this.get__isDistinguishedIdentity()) {
+ this._setScaleMatrix(scale);
+ }
+ else {
+ this._m11 *= scale.x;
+ this._m12 *= scale.y;
+ this._m13 *= scale.z;
+ this._m21 *= scale.x;
+ this._m22 *= scale.y;
+ this._m23 *= scale.z;
+ this._m31 *= scale.x;
+ this._m32 *= scale.y;
+ this._m33 *= scale.z;
+ this._offsetX *= scale.x;
+ this._offsetY *= scale.y;
+ this._offsetZ *= scale.z;
+ }
+ },
+
+ scalePrepend: function (scale) {
+ if (this.get__isDistinguishedIdentity()) {
+ this._setScaleMatrix(scale);
+ }
+ else {
+ this._m11 *= scale.x;
+ this._m12 *= scale.x;
+ this._m13 *= scale.x;
+ this._m14 *= scale.x;
+ this._m21 *= scale.y;
+ this._m22 *= scale.y;
+ this._m23 *= scale.y;
+ this._m24 *= scale.y;
+ this._m31 *= scale.z;
+ this._m32 *= scale.z;
+ this._m33 *= scale.z;
+ this._m34 *= scale.z;
+ }
+ },
+
+ scaleAt: function (scale, center) {
+ if (this.get__isDistinguishedIdentity()) {
+ this._setScaleMatrixCenter(scale, center);
+ }
+ else {
+ var num = this._m14 * center.x;
+ this._m11 = num + (scale.x * (this._m11 - num));
+ num = this._m14 * center.y;
+ this._m12 = num + (scale.y * (this._m12 - num));
+ num = this._m14 * center.z;
+ this._m13 = num + (scale.z * (this._m13 - num));
+ num = this._m24 * center.x;
+ this._m21 = num + (scale.x * (this._m21 - num));
+ num = this._m24 * center.y;
+ this._m22 = num + (scale.y * (this._m22 - num));
+ num = this._m24 * center.z;
+ this._m23 = num + (scale.z * (this._m23 - num));
+ num = this._m34 * center.x;
+ this._m31 = num + (scale.x * (this._m31 - num));
+ num = this._m34 * center.y;
+ this._m32 = num + (scale.y * (this._m32 - num));
+ num = this._m34 * center.z;
+ this._m33 = num + (scale.z * (this._m33 - num));
+ num = this._m44 * center.x;
+ this._offsetX = num + (scale.x * (this._offsetX - num));
+ num = this._m44 * center.y;
+ this._offsetY = num + (scale.y * (this._offsetY - num));
+ num = this._m44 * center.z;
+ this._offsetZ = num + (scale.z * (this._offsetZ - num));
+ }
+ },
+
+ scaleAtPrepend: function (scale, center) {
+ if (this.get__isDistinguishedIdentity()) {
+ this._setScaleMatrixCenter(scale, center);
+ }
+ else {
+ var num3 = center.x - (center.x * scale.x);
+ var num2 = center.y - (center.y * scale.y);
+ var num = center.z - (center.z * scale.z);
+ this._offsetX += ((this._m11 * num3) + (this._m21 * num2)) + (this._m31 * num);
+ this._offsetY += ((this._m12 * num3) + (this._m22 * num2)) + (this._m32 * num);
+ this._offsetZ += ((this._m13 * num3) + (this._m23 * num2)) + (this._m33 * num);
+ this._m44 += ((this._m14 * num3) + (this._m24 * num2)) + (this._m34 * num);
+ this._m11 *= scale.x;
+ this._m12 *= scale.x;
+ this._m13 *= scale.x;
+ this._m14 *= scale.x;
+ this._m21 *= scale.y;
+ this._m22 *= scale.y;
+ this._m23 *= scale.y;
+ this._m24 *= scale.y;
+ this._m31 *= scale.z;
+ this._m32 *= scale.z;
+ this._m33 *= scale.z;
+ this._m34 *= scale.z;
+ }
+ },
+
+ translate: function (offset) {
+ if (this.get__isDistinguishedIdentity()) {
+ this._setTranslationMatrix(offset);
+ }
+ else {
+ this._m11 += this._m14 * offset.x;
+ this._m12 += this._m14 * offset.y;
+ this._m13 += this._m14 * offset.z;
+ this._m21 += this._m24 * offset.x;
+ this._m22 += this._m24 * offset.y;
+ this._m23 += this._m24 * offset.z;
+ this._m31 += this._m34 * offset.x;
+ this._m32 += this._m34 * offset.y;
+ this._m33 += this._m34 * offset.z;
+ this._offsetX += this._m44 * offset.x;
+ this._offsetY += this._m44 * offset.y;
+ this._offsetZ += this._m44 * offset.z;
+ }
+ },
+
+ translatePrepend: function (offset) {
+ if (this.get__isDistinguishedIdentity()) {
+ this._setTranslationMatrix(offset);
+ }
+ else {
+ this._offsetX += ((this._m11 * offset.x) + (this._m21 * offset.y)) + (this._m31 * offset.z);
+ this._offsetY += ((this._m12 * offset.x) + (this._m22 * offset.y)) + (this._m32 * offset.z);
+ this._offsetZ += ((this._m13 * offset.x) + (this._m23 * offset.y)) + (this._m33 * offset.z);
+ this._m44 += ((this._m14 * offset.x) + (this._m24 * offset.y)) + (this._m34 * offset.z);
+ }
+ },
+
+ transform: function (point) {
+ var temp = new Vector3d();
+ if (!this.get__isDistinguishedIdentity()) {
+ var x = point.x;
+ var y = point.y;
+ var z = point.z;
+ temp.x = (((x * this._m11) + (y * this._m21)) + (z * this._m31)) + this._offsetX;
+ temp.y = (((x * this._m12) + (y * this._m22)) + (z * this._m32)) + this._offsetY;
+ temp.z = (((x * this._m13) + (y * this._m23)) + (z * this._m33)) + this._offsetZ;
+ if (!this.get_isAffine()) {
+ var num4 = (((x * this._m14) + (y * this._m24)) + (z * this._m34)) + this._m44;
+ temp.x /= num4;
+ temp.y /= num4;
+ temp.z /= num4;
+ }
+ }
+ return temp;
+ },
+
+ _transformTo: function (input, output) {
+ output.x = (((input.x * this._m11) + (input.y * this._m21)) + (input.z * this._m31)) + this._offsetX;
+ output.y = (((input.x * this._m12) + (input.y * this._m22)) + (input.z * this._m32)) + this._offsetY;
+ output.z = (((input.x * this._m13) + (input.y * this._m23)) + (input.z * this._m33)) + this._offsetZ;
+ var num4 = (((input.x * this._m14) + (input.y * this._m24)) + (input.z * this._m34)) + this._m44;
+ output.x /= num4;
+ output.y /= num4;
+ output.z /= num4;
+ },
+
+ transformArray: function (points) {
+ if (points != null) {
+ for (var i = 0; i < points.length; i++) {
+ this._multiplyPoint(points[i]);
+ }
+ }
+ },
+
+ projectArrayToScreen: function (input, output) {
+ if (input != null && output != null) {
+ var affine = this.get_isAffine();
+ for (var i = 0; i < input.length; i++) {
+ var x = input[i].x;
+ var y = input[i].y;
+ var z = input[i].z;
+ if (affine) {
+ output[i].x = ((((x * this._m11) + (y * this._m21)) + (z * this._m31)) + this._offsetX);
+ output[i].y = ((((x * this._m12) + (y * this._m22)) + (z * this._m32)) + this._offsetY);
+ output[i].z = (((x * this._m13) + (y * this._m23)) + (z * this._m33)) + this._offsetZ;
+ }
+ else {
+ var num4 = (((x * this._m14) + (y * this._m24)) + (z * this._m34)) + this._m44;
+ output[i].x = (((((x * this._m11) + (y * this._m21)) + (z * this._m31)) + this._offsetX) / num4);
+ output[i].y = (((((x * this._m12) + (y * this._m22)) + (z * this._m32)) + this._offsetY) / num4);
+ output[i].z = ((((x * this._m13) + (y * this._m23)) + (z * this._m33)) + this._offsetZ) / num4;
+ }
+ }
+ }
+ },
+
+ projectToScreen: function (input, width, height) {
+ var output = new Vector3d();
+ var x = input.x;
+ var y = input.y;
+ var z = input.z;
+ if (this.get_isAffine()) {
+ output.x = (((((x * this._m11) + (y * this._m21)) + (z * this._m31)) + this._offsetX) + 0.5) * width;
+ output.y = (-((((x * this._m12) + (y * this._m22)) + (z * this._m32)) + this._offsetY) + 0.5) * height;
+ output.z = (((x * this._m13) + (y * this._m23)) + (z * this._m33)) + this._offsetZ;
+ }
+ else {
+ var num4 = (((x * this._m14) + (y * this._m24)) + (z * this._m34)) + this._m44;
+ output.x = ((((((x * this._m11) + (y * this._m21)) + (z * this._m31)) + this._offsetX) / num4) + 0.5) * width;
+ output.y = (-(((((x * this._m12) + (y * this._m22)) + (z * this._m32)) + this._offsetY) / num4) + 0.5) * height;
+ output.z = ((((x * this._m13) + (y * this._m23)) + (z * this._m33)) + this._offsetZ) / num4;
+ }
+ return output;
+ },
+
+ get_isAffine: function () {
+ if (this.get__isDistinguishedIdentity()) {
+ return true;
+ }
+ if (((!this._m14) && (!this._m24)) && (!this._m34)) {
+ return (this._m44 === 1);
+ }
+ return false;
+ },
+
+ get_determinant: function () {
+ if (this.get__isDistinguishedIdentity()) {
+ return 1;
+ }
+ if (this.get_isAffine()) {
+ return this._getNormalizedAffineDeterminant();
+ }
+ var num6 = (this._m13 * this._m24) - (this._m23 * this._m14);
+ var num5 = (this._m13 * this._m34) - (this._m33 * this._m14);
+ var num4 = (this._m13 * this._m44) - (this._offsetZ * this._m14);
+ var num3 = (this._m23 * this._m34) - (this._m33 * this._m24);
+ var num2 = (this._m23 * this._m44) - (this._offsetZ * this._m24);
+ var num = (this._m33 * this._m44) - (this._offsetZ * this._m34);
+ var num10 = ((this._m22 * num5) - (this._m32 * num6)) - (this._m12 * num3);
+ var num9 = ((this._m12 * num2) - (this._m22 * num4)) + (this._offsetY * num6);
+ var num8 = ((this._m32 * num4) - (this._offsetY * num5)) - (this._m12 * num);
+ var num7 = ((this._m22 * num) - (this._m32 * num2)) + (this._offsetY * num3);
+ return ((((this._offsetX * num10) + (this._m31 * num9)) + (this._m21 * num8)) + (this._m11 * num7));
+ },
+
+ get_hasInverse: function () {
+ return !DoubleUtilities.isZero(this.get_determinant());
+ },
+
+ invert: function () {
+ if (!this._invertCore()) {
+ return;
+ }
+ },
+
+ transpose: function () {
+ var that = new Matrix3d();
+ that.set(this);
+ this._m12 = that._m21;
+ this._m13 = that._m31;
+ this._m14 = that._offsetX;
+ this._m23 = that._m32;
+ this._m24 = that._offsetY;
+ this._m34 = that._offsetZ;
+ this._m21 = that._m12;
+ this._m31 = that._m13;
+ this._offsetX = that._m14;
+ this._m32 = that._m23;
+ this._offsetY = that._m24;
+ this._offsetZ = that._m34;
+ },
+
+ get_m11: function () {
+ if (this.get__isDistinguishedIdentity()) {
+ return 1;
+ }
+ return this._m11;
+ },
+
+ set_m11: function (value) {
+ if (this.get__isDistinguishedIdentity()) {
+ this.set(Matrix3d._s_identity);
+ this.set__isDistinguishedIdentity(false);
+ }
+ this._m11 = value;
+ return value;
+ },
+
+ get_m12: function () {
+ return this._m12;
+ },
+
+ set_m12: function (value) {
+ if (this.get__isDistinguishedIdentity()) {
+ this.set(Matrix3d._s_identity);
+ this.set__isDistinguishedIdentity(false);
+ }
+ this._m12 = value;
+ return value;
+ },
+
+ get_m13: function () {
+ return this._m13;
+ },
+
+ set_m13: function (value) {
+ if (this.get__isDistinguishedIdentity()) {
+ this.set(Matrix3d._s_identity);
+ this.set__isDistinguishedIdentity(false);
+ }
+ this._m13 = value;
+ return value;
+ },
+
+ get_m14: function () {
+ return this._m14;
+ },
+
+ set_m14: function (value) {
+ if (this.get__isDistinguishedIdentity()) {
+ this.set(Matrix3d._s_identity);
+ this.set__isDistinguishedIdentity(false);
+ }
+ this._m14 = value;
+ return value;
+ },
+
+ get_m21: function () {
+ return this._m21;
+ },
+
+ set_m21: function (value) {
+ if (this.get__isDistinguishedIdentity()) {
+ this.set(Matrix3d._s_identity);
+ this.set__isDistinguishedIdentity(false);
+ }
+ this._m21 = value;
+ return value;
+ },
+
+ get_m22: function () {
+ if (this.get__isDistinguishedIdentity()) {
+ return 1;
+ }
+ return this._m22;
+ },
+
+ set_m22: function (value) {
+ if (this.get__isDistinguishedIdentity()) {
+ this.set(Matrix3d._s_identity);
+ this.set__isDistinguishedIdentity(false);
+ }
+ this._m22 = value;
+ return value;
+ },
+
+ get_m23: function () {
+ return this._m23;
+ },
+
+ set_m23: function (value) {
+ if (this.get__isDistinguishedIdentity()) {
+ this.set(Matrix3d._s_identity);
+ this.set__isDistinguishedIdentity(false);
+ }
+ this._m23 = value;
+ return value;
+ },
+
+ get_m24: function () {
+ return this._m24;
+ },
+
+ set_m24: function (value) {
+ if (this.get__isDistinguishedIdentity()) {
+ this.set(Matrix3d._s_identity);
+ this.set__isDistinguishedIdentity(false);
+ }
+ this._m24 = value;
+ return value;
+ },
+
+ get_m31: function () {
+ return this._m31;
+ },
+
+ set_m31: function (value) {
+ if (this.get__isDistinguishedIdentity()) {
+ this.set(Matrix3d._s_identity);
+ this.set__isDistinguishedIdentity(false);
+ }
+ this._m31 = value;
+ return value;
+ },
+
+ get_m32: function () {
+ return this._m32;
+ },
+
+ set_m32: function (value) {
+ if (this.get__isDistinguishedIdentity()) {
+ this.set(Matrix3d._s_identity);
+ this.set__isDistinguishedIdentity(false);
+ }
+ this._m32 = value;
+ return value;
+ },
+
+ get_m33: function () {
+ if (this.get__isDistinguishedIdentity()) {
+ return 1;
+ }
+ return this._m33;
+ },
+
+ set_m33: function (value) {
+ if (this.get__isDistinguishedIdentity()) {
+ this.set(Matrix3d._s_identity);
+ this.set__isDistinguishedIdentity(false);
+ }
+ this._m33 = value;
+ return value;
+ },
+
+ get_m34: function () {
+ return this._m34;
+ },
+
+ set_m34: function (value) {
+ if (this.get__isDistinguishedIdentity()) {
+ this.set(Matrix3d._s_identity);
+ this.set__isDistinguishedIdentity(false);
+ }
+ this._m34 = value;
+ return value;
+ },
+
+ get_m41: function () {
+ return this.get_offsetX();
+ },
+
+ set_m41: function (value) {
+ this.set_offsetX(value);
+ return value;
+ },
+
+ get_m42: function () {
+ return this.get_offsetY();
+ },
+
+ set_m42: function (value) {
+ this.set_offsetY(value);
+ return value;
+ },
+
+ get_m43: function () {
+ return this.get_offsetZ();
+ },
+
+ set_m43: function (value) {
+ this.set_offsetZ(value);
+ return value;
+ },
+
+ get_offsetX: function () {
+ return this._offsetX;
+ },
+
+ set_offsetX: function (value) {
+ if (this.get__isDistinguishedIdentity()) {
+ this.set(Matrix3d._s_identity);
+ this.set__isDistinguishedIdentity(false);
+ }
+ this._offsetX = value;
+ return value;
+ },
+
+ get_offsetY: function () {
+ return this._offsetY;
+ },
+
+ set_offsetY: function (value) {
+ if (this.get__isDistinguishedIdentity()) {
+ this.set(Matrix3d._s_identity);
+ this.set__isDistinguishedIdentity(false);
+ }
+ this._offsetY = value;
+ return value;
+ },
+
+ get_offsetZ: function () {
+ return this._offsetZ;
+ },
+
+ set_offsetZ: function (value) {
+ if (this.get__isDistinguishedIdentity()) {
+ this.set(Matrix3d._s_identity);
+ this.set__isDistinguishedIdentity(false);
+ }
+ this._offsetZ = value;
+ return value;
+ },
+
+ get_m44: function () {
+ if (this.get__isDistinguishedIdentity()) {
+ return 1;
+ }
+ return this._m44;
+ },
+
+ set_m44: function (value) {
+ if (this.get__isDistinguishedIdentity()) {
+ this.set(Matrix3d._s_identity);
+ this.set__isDistinguishedIdentity(false);
+ }
+ this._m44 = value;
+ return value;
+ },
+
+ _setScaleMatrix: function (scale) {
+ this._m11 = scale.x;
+ this._m22 = scale.y;
+ this._m33 = scale.z;
+ this._m44 = 1;
+ this.set__isDistinguishedIdentity(false);
+ },
+
+ _setScaleMatrixCenter: function (scale, center) {
+ this._m11 = scale.x;
+ this._m22 = scale.y;
+ this._m33 = scale.z;
+ this._m44 = 1;
+ this._offsetX = center.x - (center.x * scale.x);
+ this._offsetY = center.y - (center.y * scale.y);
+ this._offsetZ = center.z - (center.z * scale.z);
+ this.set__isDistinguishedIdentity(false);
+ },
+
+ _setTranslationMatrix: function (offset) {
+ this._m11 = this._m22 = this._m33 = this._m44 = 1;
+ this._offsetX = offset.x;
+ this._offsetY = offset.y;
+ this._offsetZ = offset.z;
+ this.set__isDistinguishedIdentity(false);
+ },
+
+ _multiplyPoint: function (point) {
+ if (!this.get__isDistinguishedIdentity()) {
+ var x = point.x;
+ var y = point.y;
+ var z = point.z;
+ point.x = (((x * this._m11) + (y * this._m21)) + (z * this._m31)) + this._offsetX;
+ point.y = (((x * this._m12) + (y * this._m22)) + (z * this._m32)) + this._offsetY;
+ point.z = (((x * this._m13) + (y * this._m23)) + (z * this._m33)) + this._offsetZ;
+ if (!this.get_isAffine()) {
+ var num4 = (((x * this._m14) + (y * this._m24)) + (z * this._m34)) + this._m44;
+ point.x /= num4;
+ point.y /= num4;
+ point.z /= num4;
+ }
+ }
+ },
+
+ multiplyVector: function (vector) {
+ if (!this.get__isDistinguishedIdentity()) {
+ var x = vector.x;
+ var y = vector.y;
+ var z = vector.z;
+ vector.x = ((x * this._m11) + (y * this._m21)) + (z * this._m31);
+ vector.y = ((x * this._m12) + (y * this._m22)) + (z * this._m32);
+ vector.z = ((x * this._m13) + (y * this._m23)) + (z * this._m33);
+ }
+ },
+
+ _getNormalizedAffineDeterminant: function () {
+ var num3 = (this._m12 * this._m23) - (this._m22 * this._m13);
+ var num2 = (this._m32 * this._m13) - (this._m12 * this._m33);
+ var num = (this._m22 * this._m33) - (this._m32 * this._m23);
+ return (((this._m31 * num3) + (this._m21 * num2)) + (this._m11 * num));
+ },
+
+ _normalizedAffineInvert: function () {
+ var num11 = (this._m12 * this._m23) - (this._m22 * this._m13);
+ var num10 = (this._m32 * this._m13) - (this._m12 * this._m33);
+ var num9 = (this._m22 * this._m33) - (this._m32 * this._m23);
+ var num8 = ((this._m31 * num11) + (this._m21 * num10)) + (this._m11 * num9);
+ if (DoubleUtilities.isZero(num8)) {
+ return false;
+ }
+ var num20 = (this._m21 * this._m13) - (this._m11 * this._m23);
+ var num19 = (this._m11 * this._m33) - (this._m31 * this._m13);
+ var num18 = (this._m31 * this._m23) - (this._m21 * this._m33);
+ var num7 = (this._m11 * this._m22) - (this._m21 * this._m12);
+ var num6 = (this._m11 * this._m32) - (this._m31 * this._m12);
+ var num5 = (this._m11 * this._offsetY) - (this._offsetX * this._m12);
+ var num4 = (this._m21 * this._m32) - (this._m31 * this._m22);
+ var num3 = (this._m21 * this._offsetY) - (this._offsetX * this._m22);
+ var num2 = (this._m31 * this._offsetY) - (this._offsetX * this._m32);
+ var num17 = ((this._m23 * num5) - (this._offsetZ * num7)) - (this._m13 * num3);
+ var num16 = ((this._m13 * num2) - (this._m33 * num5)) + (this._offsetZ * num6);
+ var num15 = ((this._m33 * num3) - (this._offsetZ * num4)) - (this._m23 * num2);
+ var num14 = num7;
+ var num13 = -num6;
+ var num12 = num4;
+ var num = 1 / num8;
+ this._m11 = num9 * num;
+ this._m12 = num10 * num;
+ this._m13 = num11 * num;
+ this._m21 = num18 * num;
+ this._m22 = num19 * num;
+ this._m23 = num20 * num;
+ this._m31 = num12 * num;
+ this._m32 = num13 * num;
+ this._m33 = num14 * num;
+ this._offsetX = num15 * num;
+ this._offsetY = num16 * num;
+ this._offsetZ = num17 * num;
+ return true;
+ },
+
+ _invertCore: function () {
+ if (!this.get__isDistinguishedIdentity()) {
+ if (this.get_isAffine()) {
+ return this._normalizedAffineInvert();
+ }
+ var num7 = (this._m13 * this._m24) - (this._m23 * this._m14);
+ var num6 = (this._m13 * this._m34) - (this._m33 * this._m14);
+ var num5 = (this._m13 * this._m44) - (this._offsetZ * this._m14);
+ var num4 = (this._m23 * this._m34) - (this._m33 * this._m24);
+ var num3 = (this._m23 * this._m44) - (this._offsetZ * this._m24);
+ var num2 = (this._m33 * this._m44) - (this._offsetZ * this._m34);
+ var num12 = ((this._m22 * num6) - (this._m32 * num7)) - (this._m12 * num4);
+ var num11 = ((this._m12 * num3) - (this._m22 * num5)) + (this._offsetY * num7);
+ var num10 = ((this._m32 * num5) - (this._offsetY * num6)) - (this._m12 * num2);
+ var num9 = ((this._m22 * num2) - (this._m32 * num3)) + (this._offsetY * num4);
+ var num8 = (((this._offsetX * num12) + (this._m31 * num11)) + (this._m21 * num10)) + (this._m11 * num9);
+ if (DoubleUtilities.isZero(num8)) {
+ return false;
+ }
+ var num24 = ((this._m11 * num4) - (this._m21 * num6)) + (this._m31 * num7);
+ var num23 = ((this._m21 * num5) - (this._offsetX * num7)) - (this._m11 * num3);
+ var num22 = ((this._m11 * num2) - (this._m31 * num5)) + (this._offsetX * num6);
+ var num21 = ((this._m31 * num3) - (this._offsetX * num4)) - (this._m21 * num2);
+ num7 = (this._m11 * this._m22) - (this._m21 * this._m12);
+ num6 = (this._m11 * this._m32) - (this._m31 * this._m12);
+ num5 = (this._m11 * this._offsetY) - (this._offsetX * this._m12);
+ num4 = (this._m21 * this._m32) - (this._m31 * this._m22);
+ num3 = (this._m21 * this._offsetY) - (this._offsetX * this._m22);
+ num2 = (this._m31 * this._offsetY) - (this._offsetX * this._m32);
+ var num20 = ((this._m13 * num4) - (this._m23 * num6)) + (this._m33 * num7);
+ var num19 = ((this._m23 * num5) - (this._offsetZ * num7)) - (this._m13 * num3);
+ var num18 = ((this._m13 * num2) - (this._m33 * num5)) + (this._offsetZ * num6);
+ var num17 = ((this._m33 * num3) - (this._offsetZ * num4)) - (this._m23 * num2);
+ var num16 = ((this._m24 * num6) - (this._m34 * num7)) - (this._m14 * num4);
+ var num15 = ((this._m14 * num3) - (this._m24 * num5)) + (this._m44 * num7);
+ var num14 = ((this._m34 * num5) - (this._m44 * num6)) - (this._m14 * num2);
+ var num13 = ((this._m24 * num2) - (this._m34 * num3)) + (this._m44 * num4);
+ var num = 1 / num8;
+ this._m11 = num9 * num;
+ this._m12 = num10 * num;
+ this._m13 = num11 * num;
+ this._m14 = num12 * num;
+ this._m21 = num21 * num;
+ this._m22 = num22 * num;
+ this._m23 = num23 * num;
+ this._m24 = num24 * num;
+ this._m31 = num13 * num;
+ this._m32 = num14 * num;
+ this._m33 = num15 * num;
+ this._m34 = num16 * num;
+ this._offsetX = num17 * num;
+ this._offsetY = num18 * num;
+ this._offsetZ = num19 * num;
+ this._m44 = num20 * num;
+ }
+ return true;
+ },
+
+ get__isDistinguishedIdentity: function () {
+ return !this._isNotKnownToBeIdentity;
+ },
+
+ set__isDistinguishedIdentity: function (value) {
+ this._isNotKnownToBeIdentity = !value;
+ return value;
+ },
+
+ _multiply: function (mat) {
+ this.set(Matrix3d.multiplyMatrix(this, mat));
+ }
+};
+
+registerType("Matrix3d", [Matrix3d, Matrix3d$, null]);
+
+Matrix3d._s_identity = Matrix3d._createIdentity();
+
+
+// wwtlib.Matrix2d
+
+export function Matrix2d() {
+ this.m11 = 1;
+ this.m12 = 0;
+ this.m13 = 0;
+ this.m21 = 0;
+ this.m22 = 1;
+ this.m23 = 0;
+ this.m31 = 0;
+ this.m32 = 0;
+ this.m33 = 1;
+}
+
+Matrix2d.create = function (m11, m12, m13, m21, m22, m23, m31, m32, m33) {
+ var mat = new Matrix2d();
+ mat.m11 = m11;
+ mat.m12 = m12;
+ mat.m13 = m13;
+ mat.m21 = m21;
+ mat.m22 = m22;
+ mat.m23 = m23;
+ mat.m31 = m31;
+ mat.m32 = m32;
+ mat.m33 = m33;
+ return mat;
+};
+
+Matrix2d.rotation = function (angle) {
+ var mat = new Matrix2d();
+ mat.m11 = Math.cos(angle);
+ mat.m21 = -Math.sin(angle);
+ mat.m12 = Math.sin(angle);
+ mat.m22 = Math.cos(angle);
+ return mat;
+};
+
+Matrix2d.translation = function (x, y) {
+ var mat = new Matrix2d();
+ mat.m31 = x;
+ mat.m32 = y;
+ return mat;
+};
+
+Matrix2d.scaling = function (x, y) {
+ var mat = new Matrix2d();
+ mat.m11 = x;
+ mat.m22 = y;
+ return mat;
+};
+
+Matrix2d.multiply = function (matrix1, matrix2) {
+ return Matrix2d.create((((matrix1.m11 * matrix2.m11) + (matrix1.m12 * matrix2.m21)) + (matrix1.m13 * matrix2.m31)), (((matrix1.m11 * matrix2.m12) + (matrix1.m12 * matrix2.m22)) + (matrix1.m13 * matrix2.m32)), (((matrix1.m11 * matrix2.m13) + (matrix1.m12 * matrix2.m23)) + (matrix1.m13 * matrix2.m33)), (((matrix1.m21 * matrix2.m11) + (matrix1.m22 * matrix2.m21)) + (matrix1.m23 * matrix2.m31)), (((matrix1.m21 * matrix2.m12) + (matrix1.m22 * matrix2.m22)) + (matrix1.m23 * matrix2.m32)), (((matrix1.m21 * matrix2.m13) + (matrix1.m22 * matrix2.m23)) + (matrix1.m23 * matrix2.m33)), (((matrix1.m31 * matrix2.m11) + (matrix1.m32 * matrix2.m21)) + (matrix1.m33 * matrix2.m31)), (((matrix1.m31 * matrix2.m12) + (matrix1.m32 * matrix2.m22)) + (matrix1.m33 * matrix2.m32)), (((matrix1.m31 * matrix2.m13) + (matrix1.m32 * matrix2.m23)) + (matrix1.m33 * matrix2.m33)));
+};
+
+Matrix2d.rotateAt = function (angle, pnt) {
+ var matT0 = Matrix2d.translation(-pnt.x, -pnt.y);
+ var matR = Matrix2d.rotation(angle);
+ var matT1 = Matrix2d.translation(pnt.x, pnt.y);
+ return Matrix2d.multiply(Matrix2d.multiply(matT0, matR), matT1);
+};
+
+var Matrix2d$ = {
+ _transformPoints: function (points) {
+ var $enum1 = ss.enumerate(points);
+ while ($enum1.moveNext()) {
+ var pnt = $enum1.current;
+ this.multiplyPoint(pnt);
+ }
+ },
+
+ multiplyPoint: function (point) {
+ var x = point.x;
+ var y = point.y;
+ point.x = (((x * this.m11) + (y * this.m21)) + this.m31);
+ point.y = (((x * this.m12) + (y * this.m22)) + this.m32);
+ }
+};
+
+registerType("Matrix2d", [Matrix2d, Matrix2d$, null]);
+
+
+// wwtlib.DoubleUtilities
+
+export function DoubleUtilities() { }
+
+DoubleUtilities.isZero = function (value) {
+ return (Math.abs(value) < 2.22044604925031E-50);
+};
+
+DoubleUtilities.isOne = function (value) {
+ return (Math.abs(value - 1) < 2.22044604925031E-50);
+};
+
+DoubleUtilities.radiansToDegrees = function (radians) {
+ return radians * 180 / Math.PI;
+};
+
+DoubleUtilities.degreesToRadians = function (degrees) {
+ return degrees * Math.PI / 180;
+};
+
+DoubleUtilities.clamp = function (x, min, max) {
+ return Math.max(min, Math.min(x, max));
+};
+
+registerType("DoubleUtilities", [DoubleUtilities, null, null]);
+
+
+// wwtlib.PlaneD
+
+export function PlaneD(valuePointA, valuePointB, valuePointC, valuePointD) {
+ this.a = 0;
+ this.b = 0;
+ this.c = 0;
+ this.d = 0;
+ this.a = valuePointA;
+ this.b = valuePointB;
+ this.c = valuePointC;
+ this.d = valuePointD;
+}
+
+var PlaneD$ = {
+ normalize: function () {
+ var length = Math.sqrt(this.a * this.a + this.b * this.b + this.c * this.c);
+ this.a /= length;
+ this.b /= length;
+ this.c /= length;
+ this.d /= length;
+ },
+
+ dot: function (v) {
+ return this.b * v.y + this.c * v.z + this.d * v.w + this.a * v.x;
+ }
+};
+
+registerType("PlaneD", [PlaneD, PlaneD$, null]);
+
+
+// wwtlib.Vector4d
+
+export function Vector4d(valueX, valueY, valueZ, valueW) {
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+ this.w = 0;
+ this.x = valueX;
+ this.y = valueY;
+ this.z = valueZ;
+ this.w = valueW;
+}
+
+var Vector4d$ = {};
+
+registerType("Vector4d", [Vector4d, Vector4d$, null]);
+
+
+// wwtlib.PositionNormalTexturedX2
+
+// Summary:
+// Initializes a new instance of the PositionNormalTexturedX2
+// class.
+//
+// Parameters:
+// pos:
+// A Microsoft.DirectX.Vector3 object that contains the vertex position.
+//
+// nor:
+// A Microsoft.DirectX.Vector3 object that contains the vertex normal data.
+//
+// u:
+// Floating-point value that represents the PositionNormalTexturedX2.#ctor()
+// component of the texture coordinate.
+//
+// v:
+// Floating-point value that represents the PositionNormalTexturedX2.#ctor()
+// component of the texture coordinate.
+export function PositionNormalTexturedX2() {
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+ this.nx = 0;
+ this.ny = 0;
+ this.nz = 0;
+ this.tu = 0;
+ this.tv = 0;
+ this.tu1 = 0;
+ this.tv1 = 0;
+}
+
+PositionNormalTexturedX2.create2UV = function (pos, nor, u, v, u1, v1) {
+ var temp = new PositionNormalTexturedX2();
+ temp.x = pos.x;
+ temp.y = pos.y;
+ temp.z = pos.z;
+ temp.nx = nor.x;
+ temp.ny = nor.y;
+ temp.nz = nor.z;
+ temp.tu = u;
+ temp.tv = v;
+ temp.tu1 = u1;
+ temp.tv1 = v1;
+ return temp;
+};
+
+PositionNormalTexturedX2.create = function (pos, nor, u, v) {
+ var temp = new PositionNormalTexturedX2();
+ temp.x = pos.x;
+ temp.y = pos.y;
+ temp.z = pos.z;
+ temp.nx = nor.x;
+ temp.ny = nor.y;
+ temp.nz = nor.z;
+ temp.tu = u;
+ temp.tv = v;
+ var result = coords_cartesianToSpherical2(nor);
+ temp.tu1 = ((result[1] + 180) / 360);
+ temp.tv1 = (1 - ((result[0] + 90) / 180));
+ return temp;
+};
+
+// Summary:
+// Initializes a new instance of the PositionNormalTexturedX2
+// class.
+//
+// Parameters:
+// xvalue:
+// Floating-point value that represents the x coordinate of the position.
+//
+// yvalue:
+// Floating-point value that represents the y coordinate of the position.
+//
+// zvalue:
+// Floating-point value that represents the z coordinate of the position.
+//
+// nxvalue:
+// Floating-point value that represents the nx coordinate of the vertex normal.
+//
+// nyvalue:
+// Floating-point value that represents the ny coordinate of the vertex normal.
+//
+// nzvalue:
+// Floating-point value that represents the nz coordinate of the vertex normal.
+//
+// u:
+// Floating-point value that represents the PositionNormalTexturedX2.#ctor()
+// component of the texture coordinate.
+//
+// v:
+// Floating-point value that represents the PositionNormalTexturedX2.#ctor()
+// component of the texture coordinate.
+PositionNormalTexturedX2.createLong2UV = function (xvalue, yvalue, zvalue, nxvalue, nyvalue, nzvalue, u, v, u1, v1) {
+ var temp = new PositionNormalTexturedX2();
+ temp.x = xvalue;
+ temp.y = yvalue;
+ temp.z = zvalue;
+ temp.nx = nxvalue;
+ temp.ny = nyvalue;
+ temp.nz = nzvalue;
+ temp.tu = u;
+ temp.tv = v;
+ temp.tu1 = u1;
+ temp.tv1 = v1;
+ return temp;
+};
+
+PositionNormalTexturedX2.get_strideSize = function () {
+ return 40;
+};
+
+var PositionNormalTexturedX2$ = {
+ get_lat: function () {
+ return (1 - this.tv1) * 180 - 90;
+ },
+
+ set_lat: function (value) {
+ this.tv1 = (1 - ((value + 90) / 180));
+ return value;
+ },
+
+ get_lng: function () {
+ return this.tu1 * 360 - 180;
+ },
+
+ set_lng: function (value) {
+ this.tu1 = ((value + 180) / 360);
+ return value;
+ },
+
+ createLong: function (xvalue, yvalue, zvalue, nxvalue, nyvalue, nzvalue, u, v) {
+ var temp = new PositionNormalTexturedX2();
+ temp.x = xvalue;
+ temp.y = yvalue;
+ temp.z = zvalue;
+ temp.nx = nxvalue;
+ temp.ny = nyvalue;
+ temp.nz = nzvalue;
+ temp.tu = u;
+ temp.tv = v;
+ var result = coords_cartesianToSpherical2(Vector3d.create(this.nx, this.ny, this.nz));
+ temp.tu1 = ((result[1] + 180) / 360);
+ temp.tv1 = (1 - ((result[0] + 90) / 180));
+ return temp;
+ },
+
+ get_normal: function () {
+ return Vector3d.create(this.nx, this.ny, this.nz);
+ },
+
+ set_normal: function (value) {
+ this.nx = value.x;
+ this.ny = value.y;
+ this.nz = value.z;
+ return value;
+ },
+
+ get_position: function () {
+ return Vector3d.create(this.x, this.y, this.y);
+ },
+
+ set_position: function (value) {
+ this.x = value.x;
+ this.y = value.y;
+ this.z = value.z;
+ return value;
+ },
+
+ toString: function () {
+ return ss.format('X={0}, Y={1}, Z={2}, Nx={3}, Ny={4}, Nz={5}, U={6}, V={7}, U1={8}, U2={9}', this.x, this.y, this.z, this.nx, this.ny, this.nz, this.tu, this.tv, this.tu1, this.tv1);
+ }
+};
+
+registerType("PositionNormalTexturedX2", [PositionNormalTexturedX2, PositionNormalTexturedX2$, null]);
+
+
+// wwtlib.PositionNormalTextured
+
+// Summary:
+// Initializes a new instance of the PositionNormalTextured
+// class.
+//
+// Parameters:
+// pos:
+// A Microsoft.DirectX.Vector3 object that contains the vertex position.
+//
+// nor:
+// A Microsoft.DirectX.Vector3 object that contains the vertex normal data.
+//
+// u:
+// Floating-point value that represents the PositionNormalTextured.#ctor()
+// component of the texture coordinate.
+//
+// v:
+// Floating-point value that represents the PositionNormalTextured.#ctor()
+// component of the texture coordinate.
+export function PositionNormalTextured() {
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+ this.nx = 0;
+ this.ny = 0;
+ this.nz = 0;
+ this.tu = 0;
+ this.tv = 0;
+}
+
+PositionNormalTextured.createShort = function (pos, nor, u, v) {
+ var temp = new PositionNormalTextured();
+ temp.x = pos.x;
+ temp.y = pos.y;
+ temp.z = pos.z;
+ temp.nx = nor.x;
+ temp.ny = nor.y;
+ temp.nz = nor.z;
+ temp.tu = u;
+ temp.tv = v;
+ return temp;
+};
+
+PositionNormalTextured._create = function (x, y, z, nx, ny, nz, tu, tv) {
+ var temp = new PositionNormalTextured();
+ temp.x = x;
+ temp.y = y;
+ temp.z = z;
+ temp.nx = nx;
+ temp.ny = ny;
+ temp.nz = nz;
+ temp.tu = tu;
+ temp.tv = tv;
+ return temp;
+};
+
+PositionNormalTextured.createUV = function (pos, nor, uv) {
+ var temp = new PositionNormalTextured();
+ temp.x = pos.x;
+ temp.y = pos.y;
+ temp.z = pos.z;
+ temp.nx = nor.x;
+ temp.ny = nor.y;
+ temp.nz = nor.z;
+ temp.tu = uv.x;
+ temp.tv = uv.y;
+ return temp;
+};
+
+var PositionNormalTextured$ = {
+ // ** is it a mistake that this returns an X2 class? almost surely! **
+ //
+ // Summary:
+ // Initializes a new instance of the PositionNormalTextured
+ // class.
+ //
+ // Parameters:
+ // xvalue:
+ // Floating-point value that represents the x coordinate of the position.
+ //
+ // yvalue:
+ // Floating-point value that represents the y coordinate of the position.
+ //
+ // zvalue:
+ // Floating-point value that represents the z coordinate of the position.
+ //
+ // nxvalue:
+ // Floating-point value that represents the nx coordinate of the vertex normal.
+ //
+ // nyvalue:
+ // Floating-point value that represents the ny coordinate of the vertex normal.
+ //
+ // nzvalue:
+ // Floating-point value that represents the nz coordinate of the vertex normal.
+ //
+ // u:
+ // Floating-point value that represents the PositionNormalTexturedX2.#ctor()
+ // component of the texture coordinate.
+ //
+ // v:
+ // Floating-point value that represents the PositionNormalTexturedX2.#ctor()
+ // component of the texture coordinate.
+ createLong: function (xvalue, yvalue, zvalue, nxvalue, nyvalue, nzvalue, u, v) {
+ var temp = new PositionNormalTexturedX2();
+ temp.x = xvalue;
+ temp.y = yvalue;
+ temp.z = zvalue;
+ temp.nx = nxvalue;
+ temp.ny = nyvalue;
+ temp.nz = nzvalue;
+ temp.tu = u;
+ temp.tv = v;
+ return temp;
+ },
+
+ get_normal: function () {
+ return Vector3d.create(this.nx, this.ny, this.nz);
+ },
+
+ set_normal: function (value) {
+ this.nx = value.x;
+ this.ny = value.y;
+ this.nz = value.z;
+ return value;
+ },
+
+ get_position: function () {
+ return Vector3d.create(this.x, this.y, this.z);
+ },
+
+ set_position: function (value) {
+ this.x = value.x;
+ this.y = value.y;
+ this.z = value.z;
+ return value;
+ },
+
+ toString: function () {
+ return ss.format('X={0}, Y={1}, Z={2}, Nx={3}, Ny={4}, Nz={5}, U={6}, V={7}, U1={8}, U2={9}', this.x, this.y, this.z, this.nx, this.ny, this.nz, this.tu, this.tv);
+ }
+};
+
+registerType("PositionNormalTextured", [PositionNormalTextured, PositionNormalTextured$, null]);
+
+
+// wwtlib.SphereHull
+
+export function SphereHull() {
+ this.radius = 0;
+}
+
+SphereHull._create = function (Center, Radius) {
+ var temp = new SphereHull();
+ temp.center = Center;
+ temp.radius = Radius;
+ return temp;
+};
+
+var SphereHull$ = {};
+
+registerType("SphereHull", [SphereHull, SphereHull$, null]);
+
+
+
+// wwtlib.ConvexHull
+
+export function ConvexHull() {
+}
+
+ConvexHull.findEnclosingSphereFast = function (points) {
+ var result = new SphereHull();
+
+ //Find the center of all points.
+
+ var count = points.length;
+ var center = Vector3d.zero;
+ for (var i = 0; i < count; ++i) {
+ center.add(points[i]);
+ }
+
+ //This is the center of our sphere.
+ center.multiply(1 / count);
+
+ //Find the radius of the sphere
+ var radius = 0;
+ for (var i = 0; i < count; ++i) {
+ //We are doing a relative distance comparison to find the maximum
+ //distance from the center of our sphere.
+ var distance = Vector3d.getLengthSq(Vector3d.subtractVectors(points[i], center));
+ if (distance > radius) {
+ radius = distance;
+ }
+ }
+
+ //Find the real distance from the DistanceSquared.
+ radius = Math.sqrt(radius);
+
+ //Construct the sphere.
+ result.center = center;
+ result.radius = radius;
+ return result;
+};
+
+ConvexHull.findEnclosingSphere = function (list) {
+ var Center = new Vector3d();
+ var Radius = 0;
+ var count = list.length;
+ var i;
+ var dx;
+ var dy;
+ var dz;
+ var rad_sq;
+ var xspan;
+ var yspan;
+ var zspan;
+ var maxspan;
+ var old_to_p;
+ var old_to_p_sq;
+ var old_to_new;
+ var xmin = new Vector3d();
+ var xmax = new Vector3d();
+ var ymin = new Vector3d();
+ var ymax = new Vector3d();
+ var zmin = new Vector3d();
+ var zmax = new Vector3d();
+ var dia1 = new Vector3d();
+ var dia2 = new Vector3d();
+
+ // FIRST PASS: find 6 minima/maxima points
+ xmin.x = ymin.y = zmin.z = 100000000;
+ xmax.x = ymax.y = zmax.z = -1000000000;
+ for (i = 0; i < count; i++) {
+ var current = list[i];
+ if (current.x < xmin.x) {
+ xmin = current;
+ }
+ if (current.x > xmax.x) {
+ xmax = current;
+ }
+ if (current.y < ymin.y) {
+ ymin = current;
+ }
+ if (current.y > ymax.y) {
+ ymax = current;
+ }
+ if (current.z < zmin.z) {
+ zmin = current;
+ }
+ if (current.z > zmax.z) {
+ zmax = current;
+ }
+ }
+
+ // Set xspan = distance between the 2 points xmin & xmax (squared)
+ dx = xmax.x - xmin.x;
+ dy = xmax.y - xmin.y;
+ dz = xmax.z - xmin.z;
+ xspan = dx * dx + dy * dy + dz * dz;
+
+ // Same for y & z spans
+ dx = ymax.x - ymin.x;
+ dy = ymax.y - ymin.y;
+ dz = ymax.z - ymin.z;
+ yspan = dx * dx + dy * dy + dz * dz;
+ dx = zmax.x - zmin.x;
+ dy = zmax.y - zmin.y;
+ dz = zmax.z - zmin.z;
+ zspan = dx * dx + dy * dy + dz * dz;
+ dia1 = xmin;
+ dia2 = xmax;
+ maxspan = xspan;
+ if (yspan > maxspan) {
+ maxspan = yspan;
+ dia1 = ymin;
+ dia2 = ymax;
+ }
+ if (zspan > maxspan) {
+ dia1 = zmin;
+ dia2 = zmax;
+ }
+
+ // dia1,dia2 is a diameter of initial sphere
+ // calc initial center
+ Center.x = (dia1.x + dia2.x) / 2;
+ Center.y = (dia1.y + dia2.y) / 2;
+ Center.z = (dia1.z + dia2.z) / 2;
+
+ // calculate initial radius**2 and radius
+ dx = dia2.x - Center.x;
+ dy = dia2.y - Center.y;
+ dz = dia2.z - Center.z;
+ rad_sq = dx * dx + dy * dy + dz * dz;
+ Radius = Math.sqrt(rad_sq);
+
+ // SECOND PASS: increment current sphere
+ for (i = 0; i < count; i++) {
+ var current = list[i];
+ dx = current.x - Center.x;
+ dy = current.y - Center.y;
+ dz = current.z - Center.z;
+ old_to_p_sq = dx * dx + dy * dy + dz * dz;
+ if (old_to_p_sq > rad_sq) {
+ // this point is outside of current sphere
+ old_to_p = Math.sqrt(old_to_p_sq);
+
+ // calc radius of new sphere
+ Radius = (Radius + old_to_p) / 2;
+ rad_sq = Radius * Radius;
+ old_to_new = old_to_p - Radius;
+
+ // calc center of new sphere
+ Center.x = (Radius * Center.x + old_to_new * current.x) / old_to_p;
+ Center.y = (Radius * Center.y + old_to_new * current.y) / old_to_p;
+ Center.z = (Radius * Center.z + old_to_new * current.z) / old_to_p;
+ }
+ }
+
+ return SphereHull._create(Center, Radius);
+};
+
+var ConvexHull$ = {};
+
+registerType("ConvexHull", [ConvexHull, ConvexHull$, null]);
diff --git a/engine/esm/equirectangular_tile.js b/engine/esm/equirectangular_tile.js
new file mode 100644
index 00000000..629fd59a
--- /dev/null
+++ b/engine/esm/equirectangular_tile.js
@@ -0,0 +1,309 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A tile in a pyramid that uses an equirectangular projection.
+
+import { ss } from "./ss.js";
+import { registerType } from "./typesystem.js";
+import { tilePrepDevice } from "./render_globals.js";
+import { PositionTexture } from "./double3d.js";
+import { WEBGL } from "./graphics/webgl_constants.js";
+import { RenderTriangle } from "./render_triangle.js";
+import { Tile } from "./tile.js";
+
+
+// wwtlib.EquirectangularTile
+
+export function EquirectangularTile() {
+ this._tileDegrees$1 = 0;
+ this._topDown$1 = true;
+ this._subDivisionLevel$1 = 1;
+ Tile.call(this);
+}
+
+EquirectangularTile.create = function (level, x, y, dataset, parent) {
+ var temp = new EquirectangularTile();
+ temp.parent = parent;
+ temp.level = level;
+ temp.tileX = x;
+ temp.tileY = y;
+ temp.dataset = dataset;
+ temp._topDown$1 = !dataset.get_bottomsUp();
+ temp.computeBoundingSphere();
+ return temp;
+};
+
+var EquirectangularTile$ = {
+ computeBoundingSphere: function () {
+ if (!this._topDown$1) {
+ this.computeBoundingSphereBottomsUp();
+ return;
+ }
+ this._tileDegrees$1 = this.dataset.get_baseTileDegrees() / Math.pow(2, this.level);
+ var latMin = (90 - ((this.tileY) * this._tileDegrees$1));
+ var latMax = (90 - (((this.tileY + 1)) * this._tileDegrees$1));
+ var lngMin = ((this.tileX * this._tileDegrees$1) - 180);
+ var lngMax = ((((this.tileX + 1)) * this._tileDegrees$1) - 180);
+ var latCenter = (latMin + latMax) / 2;
+ var lngCenter = (lngMin + lngMax) / 2;
+ this.sphereCenter = this.geoTo3d(latCenter, lngCenter, false);
+ this.topLeft = this.geoTo3d(latMin, lngMin, false);
+ this.bottomRight = this.geoTo3d(latMax, lngMax, false);
+ this.topRight = this.geoTo3d(latMin, lngMax, false);
+ this.bottomLeft = this.geoTo3d(latMax, lngMin, false);
+ var distVect = this.geoTo3d(latMin, lngMin, false);
+ distVect.subtract(this.sphereCenter);
+ this.sphereRadius = distVect.length();
+ this._tileDegrees$1 = lngMax - lngMin;
+ },
+
+ computeBoundingSphereBottomsUp: function () {
+ var tileDegrees = this.dataset.get_baseTileDegrees() / (Math.pow(2, this.level));
+ var latMin = (-90 + (((this.tileY + 1)) * tileDegrees));
+ var latMax = (-90 + ((this.tileY) * tileDegrees));
+ var lngMin = ((this.tileX * tileDegrees) - 180);
+ var lngMax = ((((this.tileX + 1)) * tileDegrees) - 180);
+ var latCenter = (latMin + latMax) / 2;
+ var lngCenter = (lngMin + lngMax) / 2;
+ this.sphereCenter = this.geoTo3d(latCenter, lngCenter, false);
+ this.topLeft = this.geoTo3d(latMin, lngMin, false);
+ this.bottomRight = this.geoTo3d(latMax, lngMax, false);
+ this.topRight = this.geoTo3d(latMin, lngMax, false);
+ this.bottomLeft = this.geoTo3d(latMax, lngMin, false);
+ var distVect = this.topLeft;
+ distVect.subtract(this.sphereCenter);
+ this.sphereRadius = distVect.length();
+ tileDegrees = lngMax - lngMin;
+ },
+
+ createGeometry: function (renderContext) {
+ Tile.prototype.createGeometry.call(this, renderContext);
+ if (renderContext.gl == null) {
+ if (!this.dataset.get_dataSetType() || this.dataset.get_dataSetType() === 1) {
+ this._subDivisionLevel$1 = Math.max(2, (4 - this.level) * 2);
+ }
+ } else {
+ this._subDivisionLevel$1 = 32;
+ }
+ try {
+ for (var i = 0; i < 4; i++) {
+ this._renderTriangleLists[i] = [];
+ }
+ if (!this._topDown$1) {
+ return this._createGeometryBottomsUp$1(renderContext);
+ }
+ var lat, lng;
+ var index = 0;
+ var tileDegrees = this.dataset.get_baseTileDegrees() / Math.pow(2, this.level);
+ var latMin = (90 - ((this.tileY) * tileDegrees));
+ var latMax = (90 - (((this.tileY + 1)) * tileDegrees));
+ var lngMin = ((this.tileX * tileDegrees) - 180);
+ var lngMax = ((((this.tileX + 1)) * tileDegrees) - 180);
+ var tileDegreesX = lngMax - lngMin;
+ var tileDegreesY = latMax - latMin;
+ this.topLeft = this.geoTo3d(latMin, lngMin, false);
+ this.bottomRight = this.geoTo3d(latMax, lngMax, false);
+ this.topRight = this.geoTo3d(latMin, lngMax, false);
+ this.bottomLeft = this.geoTo3d(latMax, lngMin, false);
+
+ // Create a vertex buffer
+ var verts = new Array((this._subDivisionLevel$1 + 1) * (this._subDivisionLevel$1 + 1));
+ var x, y;
+ var textureStep = 1 / this._subDivisionLevel$1;
+ for (y = 0; y <= this._subDivisionLevel$1; y++) {
+ if (y !== this._subDivisionLevel$1) {
+ lat = latMin + (textureStep * tileDegreesY * y);
+ }
+ else {
+ lat = latMax;
+ }
+ for (x = 0; x <= this._subDivisionLevel$1; x++) {
+ if (x !== this._subDivisionLevel$1) {
+ lng = lngMin + (textureStep * tileDegreesX * x);
+ }
+ else {
+ lng = lngMax;
+ }
+ index = y * (this._subDivisionLevel$1 + 1) + x;
+ verts[index] = PositionTexture.createPos(this.geoTo3d(lat, lng, false), x * textureStep, y * textureStep);
+ }
+ }
+ this.triangleCount = this._subDivisionLevel$1 * this._subDivisionLevel$1 * 2;
+ var quarterDivisions = this._subDivisionLevel$1 / 2;
+ var part = 0;
+ if (renderContext.gl == null) {
+ for (var y2 = 0; y2 < 2; y2++) {
+ for (var x2 = 0; x2 < 2; x2++) {
+ index = 0;
+ for (var y1 = (quarterDivisions * y2); y1 < (quarterDivisions * (y2 + 1)); y1++) {
+ for (var x1 = (quarterDivisions * x2); x1 < (quarterDivisions * (x2 + 1)); x1++) {
+ var p1;
+ var p2;
+ var p3;
+
+ // First triangle in quad
+ p1 = verts[(y1 * (this._subDivisionLevel$1 + 1) + x1)];
+ p2 = verts[((y1 + 1) * (this._subDivisionLevel$1 + 1) + x1)];
+ p3 = verts[(y1 * (this._subDivisionLevel$1 + 1) + (x1 + 1))];
+ this._renderTriangleLists[part].push(RenderTriangle.create(p1, p3, p2, this.texture, this.level));
+
+ // Second triangle in quad
+ p1 = verts[(y1 * (this._subDivisionLevel$1 + 1) + (x1 + 1))];
+ p2 = verts[((y1 + 1) * (this._subDivisionLevel$1 + 1) + x1)];
+ p3 = verts[((y1 + 1) * (this._subDivisionLevel$1 + 1) + (x1 + 1))];
+ this._renderTriangleLists[part].push(RenderTriangle.create(p1, p3, p2, this.texture, this.level));
+ }
+ }
+ part++;
+ }
+ }
+ } else {
+ //process vertex list
+ this._vertexBuffer = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ARRAY_BUFFER, this._vertexBuffer);
+ var f32array = new Float32Array(verts.length * 5);
+ var buffer = f32array;
+ index = 0;
+ var $enum1 = ss.enumerate(verts);
+ while ($enum1.moveNext()) {
+ var pt = $enum1.current;
+ index = this.addVertex(buffer, index, pt);
+ }
+ tilePrepDevice.bufferData(WEBGL.ARRAY_BUFFER, f32array, WEBGL.STATIC_DRAW);
+ for (var y2 = 0; y2 < 2; y2++) {
+ for (var x2 = 0; x2 < 2; x2++) {
+ var ui16array = new Uint16Array(this.triangleCount * 3);
+ var indexArray = ui16array;
+ index = 0;
+ for (var y1 = (quarterDivisions * y2); y1 < (quarterDivisions * (y2 + 1)); y1++) {
+ for (var x1 = (quarterDivisions * x2); x1 < (quarterDivisions * (x2 + 1)); x1++) {
+ // First triangle in quad
+ indexArray[index++] = (y1 * (this._subDivisionLevel$1 + 1) + x1);
+ indexArray[index++] = ((y1 + 1) * (this._subDivisionLevel$1 + 1) + x1);
+ indexArray[index++] = (y1 * (this._subDivisionLevel$1 + 1) + (x1 + 1));
+
+ // Second triangle in quad
+ indexArray[index++] = (y1 * (this._subDivisionLevel$1 + 1) + (x1 + 1));
+ indexArray[index++] = ((y1 + 1) * (this._subDivisionLevel$1 + 1) + x1);
+ indexArray[index++] = ((y1 + 1) * (this._subDivisionLevel$1 + 1) + (x1 + 1));
+ }
+ }
+ this._indexBuffers[part] = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, this._indexBuffers[part]);
+ tilePrepDevice.bufferData(WEBGL.ELEMENT_ARRAY_BUFFER, ui16array, WEBGL.STATIC_DRAW);
+ part++;
+ }
+ }
+ }
+ }
+ catch ($e2) {
+ }
+ return true;
+ },
+
+ _createGeometryBottomsUp$1: function (renderContext) {
+ var lat, lng;
+ var index = 0;
+ var tileDegrees = this.dataset.get_baseTileDegrees() / Math.pow(2, this.level);
+ var latMin = (-90 + (((this.tileY + 1)) * tileDegrees));
+ var latMax = (-90 + ((this.tileY) * tileDegrees));
+ var lngMin = ((this.tileX * tileDegrees) - 180);
+ var lngMax = ((((this.tileX + 1)) * tileDegrees) - 180);
+ var tileDegreesX = lngMax - lngMin;
+ var tileDegreesY = latMax - latMin;
+
+ // Create a vertex buffer
+ var verts = new Array((this._subDivisionLevel$1 + 1) * (this._subDivisionLevel$1 + 1));
+ var x, y;
+ var textureStep = 1 / this._subDivisionLevel$1;
+ for (y = 0; y <= this._subDivisionLevel$1; y++) {
+ if (y !== this._subDivisionLevel$1) {
+ lat = latMin + (textureStep * tileDegreesY * y);
+ }
+ else {
+ lat = latMax;
+ }
+ for (x = 0; x <= this._subDivisionLevel$1; x++) {
+ if (x !== this._subDivisionLevel$1) {
+ lng = lngMin + (textureStep * tileDegreesX * x);
+ }
+ else {
+ lng = lngMax;
+ }
+ index = y * (this._subDivisionLevel$1 + 1) + x;
+ verts[index] = PositionTexture.createPos(this.geoTo3d(lat, lng, false), x * textureStep, y * textureStep);
+ }
+ }
+ this.triangleCount = this._subDivisionLevel$1 * this._subDivisionLevel$1 * 2;
+ var quarterDivisions = this._subDivisionLevel$1 / 2;
+ var part = 0;
+ if (renderContext.gl == null) {
+ for (var y2 = 0; y2 < 2; y2++) {
+ for (var x2 = 0; x2 < 2; x2++) {
+ index = 0;
+ for (var y1 = (quarterDivisions * y2); y1 < (quarterDivisions * (y2 + 1)); y1++) {
+ for (var x1 = (quarterDivisions * x2); x1 < (quarterDivisions * (x2 + 1)); x1++) {
+ var p1;
+ var p2;
+ var p3;
+
+ // First triangle in quad
+ p1 = verts[(y1 * (this._subDivisionLevel$1 + 1) + x1)];
+ p2 = verts[((y1 + 1) * (this._subDivisionLevel$1 + 1) + x1)];
+ p3 = verts[(y1 * (this._subDivisionLevel$1 + 1) + (x1 + 1))];
+ this._renderTriangleLists[part].push(RenderTriangle.create(p1, p3, p2, this.texture, this.level));
+
+ // Second triangle in quad
+ p1 = verts[(y1 * (this._subDivisionLevel$1 + 1) + (x1 + 1))];
+ p2 = verts[((y1 + 1) * (this._subDivisionLevel$1 + 1) + x1)];
+ p3 = verts[((y1 + 1) * (this._subDivisionLevel$1 + 1) + (x1 + 1))];
+ this._renderTriangleLists[part].push(RenderTriangle.create(p1, p3, p2, this.texture, this.level));
+ }
+ }
+ part++;
+ }
+ }
+ } else {
+ //process vertex list
+ this._vertexBuffer = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ARRAY_BUFFER, this._vertexBuffer);
+ var f32array = new Float32Array(verts.length * 5);
+ var buffer = f32array;
+ index = 0;
+ var $enum1 = ss.enumerate(verts);
+ while ($enum1.moveNext()) {
+ var pt = $enum1.current;
+ index = this.addVertex(buffer, index, pt);
+ }
+ tilePrepDevice.bufferData(WEBGL.ARRAY_BUFFER, f32array, WEBGL.STATIC_DRAW);
+ for (var y2 = 0; y2 < 2; y2++) {
+ for (var x2 = 0; x2 < 2; x2++) {
+ var ui16array = new Uint16Array(this.triangleCount * 3);
+ var indexArray = ui16array;
+ index = 0;
+ for (var y1 = (quarterDivisions * y2); y1 < (quarterDivisions * (y2 + 1)); y1++) {
+ for (var x1 = (quarterDivisions * x2); x1 < (quarterDivisions * (x2 + 1)); x1++) {
+ // First triangle in quad
+ indexArray[index++] = (y1 * (this._subDivisionLevel$1 + 1) + x1);
+ indexArray[index++] = ((y1 + 1) * (this._subDivisionLevel$1 + 1) + x1);
+ indexArray[index++] = (y1 * (this._subDivisionLevel$1 + 1) + (x1 + 1));
+
+ // Second triangle in quad
+ indexArray[index++] = (y1 * (this._subDivisionLevel$1 + 1) + (x1 + 1));
+ indexArray[index++] = ((y1 + 1) * (this._subDivisionLevel$1 + 1) + x1);
+ indexArray[index++] = ((y1 + 1) * (this._subDivisionLevel$1 + 1) + (x1 + 1));
+ }
+ }
+ this._indexBuffers[part] = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, this._indexBuffers[part]);
+ tilePrepDevice.bufferData(WEBGL.ELEMENT_ARRAY_BUFFER, ui16array, WEBGL.STATIC_DRAW);
+ part++;
+ }
+ }
+ }
+
+ return true;
+ }
+};
+
+registerType("EquirectangularTile", [EquirectangularTile, EquirectangularTile$, Tile]);
diff --git a/engine/esm/fast_math.js b/engine/esm/fast_math.js
new file mode 100644
index 00000000..b521e155
--- /dev/null
+++ b/engine/esm/fast_math.js
@@ -0,0 +1,176 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// "Fast math" routines "from Healpix Java package"
+
+import { registerType } from "./typesystem.js";
+
+
+// wwtlib.FastMath
+
+export function FastMath() { }
+
+const pI4_A = 0.785398155450821;
+const pI4_B = 7.94662735614793E-09;
+const pI4_C = 3.06161699786838E-17;
+const m_1_PI = 0.318309886183791;
+
+FastMath._mulsign = function (x, y) {
+ return FastMath._sign(y) * x;
+};
+
+FastMath._isnan = function (d) {
+ return d !== d;
+};
+
+FastMath._isinf = function (d) {
+ // TODO: this was documented as checking for negative infinity as well, and
+ // almost surely should do that!
+ return Math.abs(d) === Number.POSITIVE_INFINITY;
+};
+
+FastMath._sign = function (d) {
+ if (!d) {
+ return 0;
+ }
+ return (d > 0) ? 1 : -1;
+};
+
+FastMath._atanhelper = function (s) {
+ var t = s * s;
+ var u = -1.88796008463073E-05;
+ u = u * t + (0.000209850076645817);
+ u = u * t + (-0.00110611831486672);
+ u = u * t + (0.00370026744188713);
+ u = u * t + (-0.00889896195887655);
+ u = u * t + (0.0165993297735292);
+ u = u * t + (-0.0254517624932313);
+ u = u * t + (0.0337852580001353);
+ u = u * t + (-0.0407629191276837);
+ u = u * t + (0.0466667150077841);
+ u = u * t + (-0.0523674852303482);
+ u = u * t + (0.0587666392926674);
+ u = u * t + (-0.0666573579361081);
+ u = u * t + (0.076921953831177);
+ u = u * t + (-0.090908995008245);
+ u = u * t + (0.111111105648261);
+ u = u * t + (-0.142857142667713);
+ u = u * t + (0.199999999996591);
+ u = u * t + (-0.333333333333311);
+ return u * t * s + s;
+};
+
+FastMath._atan2k = function (y, x) {
+ var q = 0;
+ if (x < 0) {
+ x = -x;
+ q = -2;
+ }
+ if (y > x) {
+ var t = x;
+ x = y;
+ y = -t;
+ q += 1;
+ }
+ return FastMath._atanhelper(y / x) + q * (Math.PI / 2);
+};
+
+// This method calculates the arc tangent of y/x in radians, using the signs of
+// the two arguments to determine the quadrant of the result. The results may
+// have maximum error of 2 ulps.
+FastMath.atan2 = function (y, x) {
+ var r = FastMath._atan2k(Math.abs(y), x);
+ r = FastMath._mulsign(r, x);
+ if (FastMath._isinf(x) || !x) {
+ r = Math.PI / 2 - ((FastMath._isinf(x)) ? (FastMath._sign(x) * (Math.PI / 2)) : 0);
+ }
+ if (FastMath._isinf(y)) {
+ r = Math.PI / 2 - ((FastMath._isinf(x)) ? (FastMath._sign(x) * (Math.PI * 1 / 4)) : 0);
+ }
+ if (!y) {
+ r = ((FastMath._sign(x) === -1) ? Math.PI : 0);
+ }
+ return (FastMath._isnan(x) || FastMath._isnan(y)) ? Number.NaN : FastMath._mulsign(r, y);
+};
+
+// This method calculates the arc sine of x in radians. The return value is in
+// the range [-pi/2, pi/2]. The results may have maximum error of 3 ulps.
+FastMath.asin = function (d) {
+ return FastMath._mulsign(FastMath._atan2k(Math.abs(d), Math.sqrt((1 + d) * (1 - d))), d);
+};
+
+// This method calculates the arc cosine of x in radians. The return value is in
+// the range [0, pi]. The results may have maximum error of 3 ulps.
+FastMath.acos = function (d) {
+ return FastMath._mulsign(FastMath._atan2k(Math.sqrt((1 + d) * (1 - d)), Math.abs(d)), d) + ((d < 0) ? Math.PI : 0);
+};
+
+// Returns the arc tangent of an angle. The results may have maximum error of 2
+// ulps.
+FastMath.atan = function (s) {
+ var q = 0;
+ if (s < 0) {
+ s = -s;
+ q = 2;
+ }
+ if (s > 1) {
+ s = 1 / s;
+ q |= 1;
+ }
+ var t = FastMath._atanhelper(s);
+ if (!!(q & 1)) {
+ t = 1.5707963267949 - t;
+ }
+ if (!!(q & 2)) {
+ t = -t;
+ }
+ return t;
+};
+
+FastMath._sincoshelper = function (d) {
+ var s = d * d;
+ var u = -7.97255955009038E-18;
+ u = u * s + 2.81009972710863E-15;
+ u = u * s - 7.64712219118159E-13;
+ u = u * s + 1.60590430605665E-10;
+ u = u * s - 2.50521083763502E-08;
+ u = u * s + 2.75573192239199E-06;
+ u = u * s - 0.000198412698412696;
+ u = u * s + 0.00833333333333333;
+ u = u * s - 0.166666666666667;
+ return s * u * d + d;
+};
+
+// Returns the trigonometric sine of an angle. The results may have maximum
+// error of 2 ulps.
+FastMath.sin = function (d) {
+ var u = d * m_1_PI;
+ var q = Math.floor((u < 0) ? u - 0.5 : u + 0.5);
+ var x = 4 * q;
+ d -= x * pI4_A;
+ d -= x * pI4_B;
+ d -= x * pI4_C;
+ if (!!(q & 1)) {
+ d = -d;
+ }
+ return FastMath._sincoshelper(d);
+};
+
+// Returns the trigonometric cosine of an angle. The results may have maximum
+// error of 2 ulps.
+FastMath.cos = function (d) {
+ var u = d * m_1_PI - 0.5;
+ var q = 1 + 2 * Math.floor((u < 0) ? u - 0.5 : u + 0.5);
+ var x = 2 * q;
+ d -= x * pI4_A;
+ d -= x * pI4_B;
+ d -= x * pI4_C;
+ if (!(q & 2)) {
+ d = -d;
+ }
+ return FastMath._sincoshelper(d);
+};
+
+var FastMath$ = {};
+
+registerType("FastMath", [FastMath, FastMath$, null]);
diff --git a/engine/esm/fits_properties.js b/engine/esm/fits_properties.js
new file mode 100644
index 00000000..b58f02ba
--- /dev/null
+++ b/engine/esm/fits_properties.js
@@ -0,0 +1,74 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Properties about FITS data.
+
+import { registerType, registerEnum } from "./typesystem.js";
+
+
+// wwtlib.ScaleTypes
+
+export var ScaleTypes = {
+ linear: 0,
+ log: 1,
+ power: 2,
+ squareRoot: 3,
+ histogramEqualization: 4
+};
+
+registerType("ScaleTypes", ScaleTypes);
+registerEnum("ScaleTypes", ScaleTypes);
+
+
+// wwtlib.FitsProperties
+
+export function FitsProperties() {
+ this.bZero = 0;
+ this.bScale = 1;
+ this.containsBlanks = false;
+ this.blankValue = Number.MIN_VALUE;
+ this.maxVal = Number.MIN_VALUE;
+ this.minVal = Number.MAX_VALUE;
+ this.upperCut = Number.MIN_VALUE;
+ this.lowerCut = Number.MAX_VALUE;
+ this.transparentBlack = false;
+ this.colorMapName = 'viridis';
+ this.scaleType = 0;
+
+ // This field exists to support non-HiPS tiled FITS imagesets. We need a
+ // mechanism to notify callers when the top-level tile is loaded,
+ // because only after that has happened is it possible to set up
+ // trustworthy values for properties like LowerCut here. *HiPS* tiled
+ // FITS imagesets don't need this because they have a separate top-level
+ // "properties" file that can be used to trigger a callback.
+ //
+ // We need to load the top-level tile to properly set up the properties
+ // here because (1) they can't be determined well from the level-0 tile
+ // data alone, (2) we want to give the dataset author a chance to
+ // customize them, and (3) the tiled FITS data-loaders don't calculate
+ // min/max from the data for performance reasons. And we'd prefer not to
+ // add the relevant values to the ImageSet XML definition.
+ //
+ // Anyway, the tangent tile image loading code will cause this action to
+ // be triggered when the level-0 tile loads successfully. It would make
+ // sense to also trigger this action for when a non-tiled FITS file is
+ // loaded, but in that use case the existing WcsLoaded callback
+ // suffices. The tiling framework already uses WcsLoaded so for that
+ // case we need to add this extra hook.
+ this.onMainImageLoaded = null;
+ this.mainImageLoadedEventHasFired = false;
+}
+
+var FitsProperties$ = {
+ // See description of the onMainImageLoaded field. This method exists to
+ // help non-HiPS tiled FITS datasets notify callers when the initial
+ // data have loaded and these FitsProperties can be trusted.
+ _fireMainImageLoaded: function (image) {
+ if (this.onMainImageLoaded != null && !this.mainImageLoadedEventHasFired) {
+ this.mainImageLoadedEventHasFired = true;
+ this.onMainImageLoaded(image);
+ }
+ }
+};
+
+registerType("FitsProperties", [FitsProperties, FitsProperties$, null]);
diff --git a/engine/esm/folder.js b/engine/esm/folder.js
new file mode 100644
index 00000000..0222d266
--- /dev/null
+++ b/engine/esm/folder.js
@@ -0,0 +1,524 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A WTML folder of different kinds of WWT content.
+
+import { ss } from "./ss.js";
+import { registerType, registerEnum } from "./typesystem.js";
+import { set_makeNewFolder } from "./data_globals.js";
+import { Util } from "./baseutil.js";
+import { IThumbnail } from "./interfaces.js";
+import { URLHelpers } from "./url_helpers.js";
+import { FolderUp } from "./folder_up.js";
+import { Imageset } from "./imageset.js";
+import { Place } from "./place.js";
+import { Tour } from "./tour.js";
+import { WebFile } from "./web_file.js";
+
+
+// wwtlib.FolderGroup
+
+export var FolderGroup = {
+ explorer: 0,
+ tour: 1,
+ search: 2,
+ constellation: 3,
+ view: 4,
+ goTo: 5,
+ community: 6,
+ context: 7,
+ voTable: 8,
+ imageStack: 9
+};
+
+registerType("FolderGroup", FolderGroup);
+registerEnum("FolderGroup", FolderGroup);
+
+
+// wwtlib.FolderRefreshType
+
+export var FolderRefreshType = {
+ interval: 0,
+ conditionalGet: 1,
+ viewChange: 2
+};
+
+registerType("FolderRefreshType", FolderRefreshType);
+registerEnum("FolderRefreshType", FolderRefreshType);
+
+
+// wwtlib.FolderType
+
+export var FolderType = {
+ earth: 0,
+ planet: 1,
+ sky: 2,
+ panorama: 3
+};
+
+registerType("FolderType", FolderType);
+registerEnum("FolderType", FolderType);
+
+
+// wwtlib.Folder
+
+export function Folder() {
+ this.parent = null;
+ this.isProxy = false;
+ this._versionDependent = false;
+ this._readOnly = true;
+ this._dirty = false;
+ this._thumbnail = null;
+ this._proxyFolder = null;
+ this._lastUpdate = new Date();
+ this._childList = [];
+ this._itemsField = [];
+ this._imagesets = [];
+ this._tours = [];
+ this._folders = [];
+ this._places = [];
+ this._groupField = 0;
+ this._refreshTypeField = 0;
+ this._refreshTypeFieldSpecified = false;
+ this._browseableField = true;
+ this._browseableFieldSpecified = false;
+ this._searchableField = false;
+ this._typeField = 0;
+ this._communityIdField = 0;
+ this._componentIdField = 0;
+ this._permissionField = 0;
+}
+
+var Folder$ = {
+ toString: function () {
+ return this._nameField;
+ },
+
+ get_versionDependent: function () {
+ return this._versionDependent;
+ },
+
+ set_versionDependent: function (value) {
+ this._versionDependent = value;
+ var $enum1 = ss.enumerate(this._folders);
+ while ($enum1.moveNext()) {
+ var folder = $enum1.current;
+ folder.set_versionDependent(this._versionDependent);
+ }
+ return value;
+ },
+
+ get_readOnly: function () {
+ return this._readOnly;
+ },
+
+ set_readOnly: function (value) {
+ this._readOnly = value;
+ return value;
+ },
+
+ get_dirty: function () {
+ return this._dirty;
+ },
+
+ set_dirty: function (value) {
+ this._dirty = value;
+ return value;
+ },
+
+ loadFromUrlWithErrorCallback: function (url, complete, onError) {
+ this._onError = onError;
+ this.loadFromUrl(url, complete);
+ },
+
+ loadFromUrl: function (url, complete) {
+ this._onComplete = complete;
+ this._webFile = new WebFile(URLHelpers.singleton.rewrite(url, 1));
+ this._webFile.onStateChange = ss.bind('_loadData', this);
+ this._webFile.send();
+ },
+
+ _loadData: function () {
+ if (this._webFile.get_state() === 2) {
+ console.error(this._webFile.get_message());
+ if (this._onError != null) {
+ this._onError();
+ }
+ } else if (this._webFile.get_state() === 1) {
+ var node = Util.selectSingleNode(this._webFile.getXml(), 'Folder');
+ if (node == null) {
+ var doc = this._webFile.getXml();
+ if (doc != null) {
+ node = Util.selectSingleNode(doc, 'Folder');
+ }
+ }
+ if (node != null) {
+ this._clearChildren();
+ this._parseXML(node);
+ }
+ if (this._onComplete != null) {
+ this._onComplete();
+ }
+ }
+ },
+
+ _clearChildren: function () {
+ this._folders.length = 0;
+ this._tours.length = 0;
+ this._places.length = 0;
+ this.get_imagesets().length = 0;
+ },
+
+ _parseXML: function (node) {
+ if (node.attributes.getNamedItem('Name') != null) {
+ this._nameField = node.attributes.getNamedItem('Name').nodeValue;
+ } else {
+ this._nameField = '';
+ }
+ if (node.attributes.getNamedItem('Url') != null) {
+ this._urlField = node.attributes.getNamedItem('Url').nodeValue;
+ }
+ if (node.attributes.getNamedItem('Thumbnail') != null) {
+ this._thumbnailUrlField = node.attributes.getNamedItem('Thumbnail').nodeValue;
+ }
+
+ // load Children
+
+ var $enum1 = ss.enumerate(node.childNodes);
+ while ($enum1.moveNext()) {
+ var child = $enum1.current;
+ switch (child.nodeName) {
+ case 'Folder':
+ var temp = new Folder();
+ temp.parent = this;
+ temp._parseXML(child);
+ this._folders.push(temp);
+ break;
+ case 'Place':
+ this._places.push(Place._fromXml(child));
+ break;
+ case 'ImageSet':
+ this.get_imagesets().push(Imageset.fromXMLNode(child));
+ break;
+ case 'Tour':
+ this.get_tours().push(Tour._fromXml(child));
+ break;
+ }
+ }
+ },
+
+ addChildFolder: function (child) {
+ this._folders.push(child);
+ this._dirty = true;
+ },
+
+ removeChildFolder: function (child) {
+ ss.remove(this._folders, child);
+ this._dirty = true;
+ },
+
+ addChildPlace: function (child) {
+ this._places.push(child);
+ this._dirty = true;
+ },
+
+ removeChildPlace: function (child) {
+ ss.remove(this._places, child);
+ this._dirty = true;
+ },
+
+ get_thumbnail: function () {
+ return this._thumbnail;
+ },
+
+ set_thumbnail: function (value) {
+ this._thumbnail = value;
+ return value;
+ },
+
+ get_bounds: function () {
+ return this._bounds;
+ },
+
+ set_bounds: function (value) {
+ this._bounds = value;
+ return value;
+ },
+
+ get_isImage: function () {
+ return false;
+ },
+
+ get_isTour: function () {
+ return false;
+ },
+
+ get_isFolder: function () {
+ return true;
+ },
+
+ get_isCloudCommunityItem: function () {
+ return !!this._communityIdField || this._permissionField > 0;
+ },
+
+ refresh: function () {
+ if (this._proxyFolder == null) {
+ this._proxyFolder = new Folder();
+ this._proxyFolder.isProxy = true;
+ this._proxyFolder.parent = this.parent;
+ }
+
+ //Also listening to errors, to make sure clients do not wait forever in
+ //the case of a 404 or similar. Especially useful for recursive
+ //downloads, where potentially dozens of URL's are downloaded. In case
+ //of errors during downloads, the clients will have an empty folder
+ //during the callback.
+ this._proxyFolder.loadFromUrlWithErrorCallback(this._urlField, this._childReadyCallback, this._childReadyCallback);
+ this._childReadyCallback = null;
+ },
+
+ childLoadCallback: function (callback) {
+ this._childReadyCallback = callback;
+ var temp = this.get_children();
+ if (this._proxyFolder == null) {
+ callback();
+ }
+ },
+
+ get_children: function () {
+ if (ss.emptyString(this._urlField)) {
+ this._childList.length = 0;
+ if (this.parent != null) {
+ var folderUp = new FolderUp();
+ folderUp.parent = this.parent;
+ this._childList.push(folderUp);
+ }
+ if (this.get_folders() != null) {
+ var $enum1 = ss.enumerate(this.get_folders());
+ while ($enum1.moveNext()) {
+ var folder = $enum1.current;
+ this._childList.push(folder);
+ }
+ }
+ if (this.get_imagesets() != null) {
+ var $enum2 = ss.enumerate(this.get_imagesets());
+ while ($enum2.moveNext()) {
+ var imset = $enum2.current;
+ this._childList.push(imset);
+ }
+ }
+ if (this.get_places() != null) {
+ var $enum3 = ss.enumerate(this.get_places());
+ while ($enum3.moveNext()) {
+ var place = $enum3.current;
+ this._childList.push(place);
+ }
+ }
+ if (this.get_tours() != null) {
+ var $enum4 = ss.enumerate(this.get_tours());
+ while ($enum4.moveNext()) {
+ var tour = $enum4.current;
+ this._childList.push(tour);
+ }
+ }
+ return this._childList;
+ } else {
+ var ts = (this._lastUpdate - ss.now()) / 1000;
+ if (this.get_refreshType() === 1 || this._proxyFolder == null || (!this.get_refreshType() && (parseInt(this._refreshIntervalField) < ts))) {
+ this.refresh();
+ }
+ if (this._proxyFolder != null) {
+ return this._proxyFolder.get_children();
+ }
+ else {
+ return null;
+ }
+ }
+ },
+
+ get_msrCommunityId: function () {
+ return this._communityIdField;
+ },
+
+ set_msrCommunityId: function (value) {
+ this._communityIdField = value;
+ return value;
+ },
+
+ get_msrComponentId: function () {
+ return this._componentIdField;
+ },
+
+ set_msrComponentId: function (value) {
+ this._componentIdField = value;
+ return value;
+ },
+
+ get_permission: function () {
+ return this._permissionField;
+ },
+
+ set_permission: function (value) {
+ this._permissionField = value;
+ return value;
+ },
+
+ get_folders: function () {
+ return this._folders;
+ },
+
+ set_folders: function (value) {
+ this._folders = value;
+ return value;
+ },
+
+ get_places: function () {
+ return this._places;
+ },
+
+ set_places: function (value) {
+ this._places = value;
+ return value;
+ },
+
+ get_imagesets: function () {
+ return this._imagesets;
+ },
+
+ set_imagesets: function (value) {
+ this._imagesets = value;
+ return value;
+ },
+
+ get_tours: function () {
+ return this._tours;
+ },
+
+ set_tours: function (value) {
+ this._tours = value;
+ return value;
+ },
+
+ get_name: function () {
+ if (this._nameField == null) {
+ return '';
+ } else {
+ return this._nameField;
+ }
+ },
+
+ set_name: function (value) {
+ this._nameField = value;
+ return value;
+ },
+
+ get_group: function () {
+ return this._groupField;
+ },
+
+ set_group: function (value) {
+ this._groupField = value;
+ return value;
+ },
+
+ get_url: function () {
+ return this._urlField;
+ },
+
+ set_url: function (value) {
+ this._urlField = value;
+ return value;
+ },
+
+ get_thumbnailUrl: function () {
+ if (ss.emptyString(this._thumbnailUrlField)) {
+ return URLHelpers.singleton.engineAssetUrl('thumb_folder.jpg');
+ }
+ return this._thumbnailUrlField;
+ },
+
+ set_thumbnailUrl: function (value) {
+ this._thumbnailUrlField = value;
+ return value;
+ },
+
+ get_refreshType: function () {
+ return this._refreshTypeField;
+ },
+
+ set_refreshType: function (value) {
+ this._refreshTypeField = value;
+ this.set_refreshTypeSpecified(true);
+ return value;
+ },
+
+ get_refreshTypeSpecified: function () {
+ return this._refreshTypeFieldSpecified;
+ },
+
+ set_refreshTypeSpecified: function (value) {
+ this._refreshTypeFieldSpecified = value;
+ return value;
+ },
+
+ get_refreshInterval: function () {
+ return this._refreshIntervalField;
+ },
+
+ set_refreshInterval: function (value) {
+ this._refreshIntervalField = value;
+ return value;
+ },
+
+ get_browseable: function () {
+ return this._browseableField;
+ },
+
+ set_browseable: function (value) {
+ this._browseableField = value;
+ this._browseableFieldSpecified = true;
+ return value;
+ },
+
+ get_browseableSpecified: function () {
+ return this._browseableFieldSpecified;
+ },
+
+ set_browseableSpecified: function (value) {
+ this._browseableFieldSpecified = value;
+ return value;
+ },
+
+ get_searchable: function () {
+ return this._searchableField;
+ },
+
+ set_searchable: function (value) {
+ this._searchableField = value;
+ return value;
+ },
+
+ get_type: function () {
+ return this._typeField;
+ },
+
+ set_type: function (value) {
+ this._typeField = value;
+ return value;
+ },
+
+ get_subType: function () {
+ return this._subTypeField;
+ },
+
+ set_subType: function (value) {
+ this._subTypeField = value;
+ return value;
+ }
+};
+
+registerType("Folder", [Folder, Folder$, null, IThumbnail]);
+
+set_makeNewFolder(function () {
+ return new Folder();
+});
diff --git a/engine/esm/folder_browser.js b/engine/esm/folder_browser.js
new file mode 100644
index 00000000..3b955db7
--- /dev/null
+++ b/engine/esm/folder_browser.js
@@ -0,0 +1,483 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Infrastructure for browsing the WWT folder structure.
+
+import { ss } from "./ss.js";
+import { registerType, registerEnum } from "./typesystem.js";
+import { globalWWTControl } from "./data_globals.js";
+import { globalRenderContext } from "./render_globals.js";
+import { Vector2d } from "./double3d.js";
+import { Folder } from "./folder.js";
+import { FolderUp } from "./folder_up.js";
+import { Imageset } from "./imageset.js";
+import { Place } from "./place.js";
+import { RenderTriangle } from "./render_triangle.js";
+import { Tour } from "./tour.js";
+import { Mouse, Rectangle } from "./util.js";
+
+
+// wwtlib.ThumbnailSize
+
+export var ThumbnailSize = {
+ small: 0,
+ big: 1
+};
+
+registerType("ThumbnailSize", ThumbnailSize);
+registerEnum("ThumbnailSize", ThumbnailSize);
+
+
+// wwtlib.FolderBrowser
+
+export function FolderBrowser() {
+ this._items = [];
+ this.top = 10;
+ this.left = 10;
+ this._indexTouchDown = -1;
+ this._mouseDown = false;
+ this._lastX = 0;
+ this._lastY = 0;
+ this._ignoreClick = false;
+ this._thumbnailSize = 0;
+ this._horzSpacing = 110;
+ this._vertSpacing = 75;
+ this._thumbHeight = 65;
+ this._thumbWidth = 110;
+ this._horzMultiple = 110;
+ this._rowCount = 1;
+ this._colCount = 6;
+ this._dragging = false;
+ this._startIndex = 0;
+ this._startOffset = 0;
+ this._selectedItem = -1;
+ this._hoverItem = -1;
+ this.showAddButton = false;
+ this.width = 0;
+ this.height = 0;
+ this._addButtonHover = false;
+ this.imageClicked = false;
+}
+
+FolderBrowser._downloading = false;
+FolderBrowser._imagesLoaded = false;
+FolderBrowser._imageLoadCount = 0;
+
+FolderBrowser.create = function () {
+ var temp = new FolderBrowser();
+ temp.height = 85;
+ temp.width = 1920;
+ temp.canvas = document.createElement('canvas');
+ temp.canvas.width = temp.width;
+ temp.canvas.height = temp.height;
+ temp.setup();
+ temp.loadImages();
+ return temp;
+};
+
+var FolderBrowser$ = {
+ setup: function () {
+ this.canvas.addEventListener('click', ss.bind('onClick', this), false);
+ this.canvas.addEventListener('dblclick', ss.bind('onDoubleClick', this), false);
+ this.canvas.addEventListener('mousemove', ss.bind('onMouseMove', this), false);
+ this.canvas.addEventListener('mouseup', ss.bind('onMouseUp', this), false);
+ this.canvas.addEventListener('mousedown', ss.bind('onMouseDown', this), false);
+ this.canvas.addEventListener('touchstart', ss.bind('onTouchStart', this), false);
+ this.canvas.addEventListener('touchmove', ss.bind('onTouchMove', this), false);
+ this.canvas.addEventListener('touchend', ss.bind('onTouchEnd', this), false);
+ this.canvas.addEventListener('mouseout', ss.bind('onMouseUp', this), false);
+ },
+
+ onTouchStart: function (e) {
+ var ev = e;
+ ev.preventDefault();
+ this._mouseDown = true;
+ this._lastX = ev.targetTouches[0].pageX;
+ this._lastY = ev.targetTouches[0].pageY;
+ this._indexTouchDown = this._getItemIndexFromCursor(Vector2d.create(ev.targetTouches[0].pageX, ev.targetTouches[0].pageY));
+ },
+
+ onTouchMove: function (e) {
+ var ev = e;
+ ev.preventDefault();
+ if (this._mouseDown) {
+ var curX = ev.targetTouches[0].pageX - this._lastX;
+ var curY = ev.targetTouches[0].pageY - this._lastY;
+ if (this._mouseDown) {
+ this._dragging = true;
+ }
+ if (!this._dragging) {
+ var newHover = this._getItemIndexFromCursor(Vector2d.create(ev.targetTouches[0].pageX, ev.targetTouches[0].pageY));
+ if (this._hoverItem !== newHover) {
+ this._hoverItem = newHover;
+ }
+ }
+ else {
+ var tiles = Math.round(((ev.targetTouches[0].pageX - this._lastX) + this._startOffset) / this._horzSpacing);
+ var offset = Math.round(((ev.targetTouches[0].pageX - this._lastX) + this._startOffset) - (tiles * this._horzSpacing));
+ this._startOffset = offset;
+ this._startIndex -= tiles;
+ if (this._startIndex < 0) {
+ this._startOffset -= (this._horzSpacing * this._startIndex);
+ this._startIndex = 0;
+ }
+ this._lastX = ev.targetTouches[0].pageX;
+ this._lastY = ev.targetTouches[0].pageY;
+ }
+ this.refresh();
+ }
+ },
+
+ onTouchEnd: function (e) {
+ var ev = e;
+ ev.preventDefault();
+ if (this._dragging) {
+ this._dragging = false;
+ this._ignoreClick = true;
+ } else if (this._indexTouchDown > -1 && this._mouseDown) {
+ this._handleClick(this._indexTouchDown);
+ }
+ this._startOffset = 0;
+ this._mouseDown = false;
+ this.refresh();
+ },
+
+ onClick: function (e) {
+ if (!this._ignoreClick) {
+ var index = this._getItemIndexFromCursor(Vector2d.create(e.offsetX, e.offsetY));
+ this._handleClick(index);
+ } else {
+ this._ignoreClick = false;
+ }
+ },
+
+ _handleClick: function (index) {
+ var $this = this;
+
+ if (index > -1) {
+ if (ss.canCast(this._items[index], Place)) {
+ var place = this._items[index];
+ globalWWTControl.gotoTarget(place, false, false, true);
+ return;
+ }
+ if (ss.canCast(this._items[index], Imageset)) {
+ var imageset = this._items[index];
+ globalRenderContext.set_backgroundImageset(imageset);
+ return;
+ }
+ if (ss.canCast(this._items[index], Tour)) {
+ var tour = this._items[index];
+ globalWWTControl.playTour(tour.get_tourUrl());
+ return;
+ }
+ if (ss.canCast(this._items[index], Folder)) {
+ var folder = this._items[index];
+ this._startIndex = 0;
+ folder.childLoadCallback(function () {
+ $this._items = folder.get_children();
+ $this.refresh();
+ });
+ return;
+ }
+ if (ss.canCast(this._items[index], FolderUp)) {
+ var folderUp = this._items[index];
+ if (folderUp.parent != null) {
+ this._startIndex = 0;
+ folderUp.parent.childLoadCallback(function () {
+ $this._items = folderUp.parent.get_children();
+ $this.refresh();
+ });
+ }
+ return;
+ }
+ }
+ return;
+ },
+
+ onDoubleClick: function (e) {
+ RenderTriangle.renderingOn = !RenderTriangle.renderingOn;
+ },
+
+ onGestureChange: function (e) {
+ var g = e;
+ this._mouseDown = false;
+ var delta = g.scale;
+ },
+
+ onMouseDown: function (e) {
+ this._mouseDown = true;
+ this._lastX = Mouse.offsetX(this.canvas, e);
+ this._lastY = Mouse.offsetY(this.canvas, e);
+ },
+
+ onMouseMove: function (e) {
+ if (this._mouseDown) {
+ this._dragging = true;
+ }
+ if (!this._dragging) {
+ var newHover = this._getItemIndexFromCursor(Vector2d.create(Mouse.offsetX(this.canvas, e), Mouse.offsetY(this.canvas, e)));
+ if (this._hoverItem !== newHover) {
+ this._hoverItem = newHover;
+ }
+ } else {
+ var tiles = Math.round(((Mouse.offsetX(this.canvas, e) - this._lastX) + this._startOffset) / this._horzSpacing);
+ var offset = Math.round(((Mouse.offsetX(this.canvas, e) - this._lastX) + this._startOffset) - (tiles * this._horzSpacing));
+ this._startOffset = offset;
+ this._startIndex -= tiles;
+ if (this._startIndex < 0) {
+ this._startOffset -= (this._horzSpacing * this._startIndex);
+ this._startIndex = 0;
+ }
+ this._lastX = Mouse.offsetX(this.canvas, e);
+ this._lastY = Mouse.offsetY(this.canvas, e);
+ }
+ this.refresh();
+ },
+
+ onMouseUp: function (e) {
+ if (this._dragging) {
+ this._startOffset = 0;
+ this._dragging = false;
+ this._ignoreClick = true;
+ }
+ this._mouseDown = false;
+ this.refresh();
+ },
+
+ loadImages: function () {
+ var $this = this;
+
+ if (!FolderBrowser._imagesLoaded && !FolderBrowser._downloading) {
+ FolderBrowser._imageLoadCount = 0;
+ FolderBrowser._imagesLoaded = false;
+ FolderBrowser._downloading = true;
+ FolderBrowser._bmpBackground = document.createElement('img');
+ FolderBrowser._bmpBackground.src = 'images/thumbBackground.png';
+ FolderBrowser._bmpBackground.addEventListener('load', function (e) {
+ FolderBrowser._imageLoadCount++;
+ if (FolderBrowser._imageLoadCount === 5) {
+ FolderBrowser._downloading = false;
+ FolderBrowser._imagesLoaded = true;
+ $this.refresh();
+ }
+ }, false);
+ FolderBrowser._bmpBackgroundHover = document.createElement('img');
+ FolderBrowser._bmpBackgroundHover.src = 'images/thumbBackgroundHover.png';
+ FolderBrowser._bmpBackgroundHover.addEventListener('load', function (e) {
+ FolderBrowser._imageLoadCount++;
+ if (FolderBrowser._imageLoadCount === 5) {
+ FolderBrowser._downloading = false;
+ FolderBrowser._imagesLoaded = true;
+ $this.refresh();
+ }
+ }, false);
+ FolderBrowser._bmpBackgroundWide = document.createElement('img');
+ FolderBrowser._bmpBackgroundWide.src = 'images/thumbBackgroundWide.png';
+ FolderBrowser._bmpBackgroundWide.addEventListener('load', function (e) {
+ FolderBrowser._imageLoadCount++;
+ if (FolderBrowser._imageLoadCount === 5) {
+ FolderBrowser._downloading = false;
+ FolderBrowser._imagesLoaded = true;
+ $this.refresh();
+ }
+ }, false);
+ FolderBrowser._bmpBackgroundWideHover = document.createElement('img');
+ FolderBrowser._bmpBackgroundWideHover.src = 'images/thumbBackgroundWideHover.png';
+ FolderBrowser._bmpBackgroundWideHover.addEventListener('load', function (e) {
+ FolderBrowser._imageLoadCount++;
+ if (FolderBrowser._imageLoadCount === 5) {
+ FolderBrowser._downloading = false;
+ FolderBrowser._imagesLoaded = true;
+ $this.refresh();
+ }
+ }, false);
+ FolderBrowser._bmpDropInsertMarker = document.createElement('img');
+ FolderBrowser._bmpDropInsertMarker.src = 'images/dragInsertMarker.png';
+ FolderBrowser._bmpDropInsertMarker.addEventListener('load', function (e) {
+ FolderBrowser._imageLoadCount++;
+ if (FolderBrowser._imageLoadCount === 5) {
+ FolderBrowser._downloading = false;
+ FolderBrowser._imagesLoaded = true;
+ $this.refresh();
+ }
+ }, false);
+ }
+ },
+
+ get_thumbnailSize: function () {
+ return this._thumbnailSize;
+ },
+
+ set_thumbnailSize: function (value) {
+ this._thumbnailSize = value;
+ switch (value) {
+ case 1:
+ this._horzSpacing = 180;
+ this._vertSpacing = 75;
+ this._thumbHeight = 65;
+ this._thumbWidth = 180;
+ break;
+ case 0:
+ this._horzSpacing = 110;
+ this._vertSpacing = 75;
+ this._thumbHeight = 65;
+ this._thumbWidth = 110;
+ break;
+ }
+ this._updatePaginator();
+ this.refresh();
+ return value;
+ },
+
+ refresh: function () {
+ if (this.width !== window.innerWidth) {
+ this.width = window.innerWidth;
+ }
+ this.paint();
+ },
+
+ get_rowCount: function () {
+ return this._rowCount;
+ },
+
+ set_rowCount: function (value) {
+ if (this._rowCount !== value) {
+ this._rowCount = value;
+ this._updatePaginator();
+ }
+ return value;
+ },
+
+ _updatePaginator: function () { },
+
+ get_colCount: function () {
+ return this._colCount;
+ },
+
+ set_colCount: function (value) {
+ if (this._colCount !== value) {
+ this._colCount = value;
+ this._updatePaginator();
+ }
+ return value;
+ },
+
+ get_itemsPerPage: function () {
+ return this._rowCount * this._colCount;
+ },
+
+ get_currentPage: function () {
+ return this._startIndex / this.get_itemsPerPage();
+ },
+
+ get_pageCount: function () {
+ return Math.max(1, ((this._items.length + this.get_itemsPerPage() - 1) + ((this.showAddButton) ? 1 : 0)) / this.get_itemsPerPage());
+ },
+
+ paint: function () {
+ var $this = this;
+
+ var g = this.canvas.getContext('2d');
+ g.fillStyle = 'rgb(20, 22, 31)';
+ g.fillRect(0, 0, this.width, this.height);
+ if (!FolderBrowser._imagesLoaded) {
+ return;
+ }
+ var netHeight = (this.height - 10 * 2);
+ var netWidth = (this.width - 10 * 2);
+ this.set_rowCount(Math.round(Math.max(netHeight / this._thumbHeight, 1)));
+ this.set_colCount(Math.round(Math.max(netWidth / this._horzSpacing, 1)));
+ this._horzMultiple = (netWidth + 13) / this.get_colCount();
+ this._startIndex = Math.round((this._startIndex / this.get_itemsPerPage()) * this.get_itemsPerPage());
+ var rectf;
+ var index = this._startIndex;
+ for (var y = 0; y < this._rowCount; y++) {
+ for (var x = 0; x < this._colCount; x++) {
+ if (index >= this._items.length) {
+ if (!this._items.length || this.showAddButton) {
+ rectf = Rectangle.create(this.left + x * this._horzMultiple + 3 + this._startOffset, this.top + y * this._vertSpacing, this._thumbWidth - 10, 60);
+ g.drawImage((this._thumbnailSize === 1) ? FolderBrowser._bmpBackgroundWide : FolderBrowser._bmpBackground, ss.truncate((x * this._horzMultiple)) + this._startOffset, y * this._vertSpacing);
+ }
+ break;
+ }
+ rectf = Rectangle.create(this.left + x * this._horzMultiple + 3 + this._startOffset, this.top + y * this._vertSpacing, this._thumbWidth - 14, 60);
+ var textBrush = 'white';
+ if (index === this._hoverItem || (index === this._selectedItem && this._hoverItem === -1)) {
+ g.drawImage((this._thumbnailSize === 1) ? FolderBrowser._bmpBackgroundWideHover : FolderBrowser._bmpBackgroundHover, this.left + ss.truncate((x * this._horzMultiple)) + this._startOffset, this.top + y * this._vertSpacing);
+ textBrush = 'yellow';
+ }
+ else {
+ g.drawImage((this._thumbnailSize === 1) ? FolderBrowser._bmpBackgroundWide : FolderBrowser._bmpBackground, this.left + ss.truncate((x * this._horzMultiple)) + this._startOffset, this.top + y * this._vertSpacing);
+ }
+ this._items[index].set_bounds(Rectangle.create((this.left + x * this._horzMultiple) + this._startOffset, this.top + (y * this._vertSpacing), ss.truncate(this._horzMultiple), this._vertSpacing));
+ try {
+ var bmpThumb = this._items[index].get_thumbnail();
+ if (bmpThumb != null) {
+ g.drawImage(bmpThumb, this.left + (x * this._horzMultiple) + 2 + this._startOffset, this.top + y * this._vertSpacing + 3);
+ g.strokeStyle = 'rgb(0,0,0)';
+ g.rect(this.left + ss.truncate((x * this._horzMultiple)) + 2 + this._startOffset, this.top + y * this._vertSpacing + 3, this._items[index].get_thumbnail().width, this._items[index].get_thumbnail().height);
+ }
+ else {
+ this._items[index].set_thumbnail(document.createElement('img'));
+ this._items[index].get_thumbnail().src = this._items[index].get_thumbnailUrl();
+ this._items[index].get_thumbnail().addEventListener('load', function (e) {
+ $this.refresh();
+ }, false);
+ }
+ }
+ catch ($e1) {
+ }
+ g.fillStyle = textBrush;
+ g.strokeStyle = textBrush;
+ g.lineWidth = 1;
+ g.font = 'normal 8pt Arial';
+ g.fillText(this._items[index].get_name(), rectf.x, rectf.y + rectf.height, rectf.width);
+ index++;
+ }
+ if (index >= this._items.length) {
+ break;
+ }
+ }
+ },
+
+ _getItemIndexFromCursor: function (testPointIn) {
+ var testPoint = Vector2d.create(testPointIn.x + this.left, testPointIn.y + this.top);
+ this.imageClicked = false;
+ var index = -1;
+ var xpos = ss.truncate((testPoint.x / this._horzMultiple));
+ var xPart = ss.truncate((testPoint.x % this._horzMultiple));
+ if (xpos >= this._colCount) {
+ return -1;
+ }
+ if (xpos < 0) {
+ return -1;
+ }
+ var ypos = ss.truncate((testPoint.y / this._vertSpacing));
+ var yPart = ss.truncate((testPoint.y % this._vertSpacing));
+ if (ypos >= this._rowCount) {
+ return -1;
+ }
+ if (ypos < 0) {
+ return -1;
+ }
+ index = this._startIndex + ypos * this._colCount + xpos;
+ if (index === this._items.length) {
+ this._addButtonHover = true;
+ } else {
+ this._addButtonHover = false;
+ }
+ if (index > this._items.length - 1) {
+ return -1;
+ }
+ if ((this._items[index]).get_isImage() && yPart < 16 && xPart > 78) {
+ this.imageClicked = true;
+ }
+ return index;
+ },
+
+ _addItems: function (list) {
+ this._items = list;
+ }
+};
+
+registerType("FolderBrowser", [FolderBrowser, FolderBrowser$, null]);
diff --git a/engine/esm/folder_up.js b/engine/esm/folder_up.js
new file mode 100644
index 00000000..eeba5050
--- /dev/null
+++ b/engine/esm/folder_up.js
@@ -0,0 +1,79 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// An icon for a "move up one folder" item.
+
+import { registerType } from "./typesystem.js";
+import { IThumbnail } from "./interfaces.js";
+import { URLHelpers } from "./url_helpers.js";
+import { Rectangle } from "./util.js";
+
+
+// wwtlib.FolderUp
+
+export function FolderUp() {
+ this.parent = null;
+ this._bounds = new Rectangle();
+}
+
+var FolderUp$ = {
+ get_name: function () {
+ return 'Up Level';
+ },
+
+ get_thumbnail: function () {
+ return this._thumbnail;
+ },
+
+ set_thumbnail: function (value) {
+ this._thumbnail = value;
+ return value;
+ },
+
+ get_thumbnailUrl: function () {
+ return URLHelpers.singleton.engineAssetUrl('thumb_folderup.jpg');
+ },
+
+ set_thumbnailUrl: function (value) {
+ return value;
+ },
+
+ get_bounds: function () {
+ return this._bounds;
+ },
+
+ set_bounds: function (value) {
+ this._bounds = value;
+ return value;
+ },
+
+ get_isImage: function () {
+ return false;
+ },
+
+ get_isTour: function () {
+ return false;
+ },
+
+ get_isFolder: function () {
+ return false;
+ },
+
+ get_isCloudCommunityItem: function () {
+ return false;
+ },
+
+ get_readOnly: function () {
+ return false;
+ },
+
+ get_children: function () {
+ if (this.parent == null) {
+ return [];
+ } else {
+ return this.parent.get_children();
+ }
+ }
+};
+
+registerType("FolderUp", [FolderUp, FolderUp$, null, IThumbnail]);
diff --git a/engine/esm/fxyf.js b/engine/esm/fxyf.js
new file mode 100644
index 00000000..72124bea
--- /dev/null
+++ b/engine/esm/fxyf.js
@@ -0,0 +1,132 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Numerical routines supporting the Healpix implementation.
+
+import { registerType } from "./typesystem.js";
+import { ss } from "./ss.js";
+import { HealpixTables } from "./healpix_tables.js";
+import { HealpixUtils } from "./healpix_utils.js";
+import { Hploc } from "./hploc.js";
+
+
+// wwtlib.Fxyf
+
+export function Fxyf() {
+ // x-coordinate within the basis pixel, range [0.0;1.0]
+ this.fx = 0;
+
+ // y-coordinate within the basis pixel, range [0.0;1.0]
+ this.fy = 0;
+
+ // index of the HEALPix basis pixel, range [0;11]
+ this.face = 0;
+ HealpixTables.call(this);
+}
+
+Fxyf._halfpi$1 = Math.PI / 2;
+Fxyf._inv_halfpi$1 = 2 / Math.PI;
+Fxyf._twothird$1 = 2 / 3;
+
+Fxyf.create = function (x, y, f) {
+ var temp = new Fxyf();
+ temp.fx = x;
+ temp.fy = y;
+ temp.face = f;
+ return temp;
+};
+
+Fxyf._fromHploc$1 = function (loc) {
+ var temp = new Fxyf();
+ var z = loc.z, phi = loc.phi;
+ var za = Math.abs(z);
+ var tt = HealpixUtils.fmodulo((phi * Fxyf._inv_halfpi$1), 4); // in [0,4)
+
+ if (za <= Fxyf._twothird$1) { // Equatorial region
+ var temp1 = 0.5 + tt;
+ var temp2 = z * 0.75;
+ var jp = temp1 - temp2; // index of ascending edge line
+ var jm = temp1 + temp2; // index of descending edge line
+ var ifp = jp; // in {0,4}
+ var ifm = jm;
+ var face_num = (ifp === ifm) ? (ifp | 4) : ((ifp < ifm) ? ifp : (ifm + 8));
+ temp.fx = HealpixUtils.fmodulo(jm, 1);
+ temp.fy = 1 - HealpixUtils.fmodulo(jp, 1);
+ temp.face = face_num;
+ } else { // polar region, za > 2/3
+ var ntt = Math.min(3, ss.truncate(tt));
+ var tp = tt - ntt;
+ var tmp;
+ if ((za < 0.99) || (!loc.have_sth)) {
+ tmp = Math.sqrt(3 * (1 - za));
+ } else {
+ tmp = loc.sth / Math.sqrt((1 + za) / 3);
+ }
+ var jp = tp * tmp; // increasing edge line index
+ var jm = (1 - tp) * tmp; // decreasing edge line index
+ if (jp >= 1) {
+ jp = 1; // for points too close to the boundary
+ }
+ if (jm >= 1) {
+ jm = 1;
+ }
+ if (z >= 0) {
+ temp.fx = 1 - jm;
+ temp.fy = 1 - jp;
+ temp.face = ntt;
+ } else {
+ temp.fx = jp;
+ temp.fy = jm;
+ temp.face = ntt + 8;
+ }
+ }
+ return temp;
+};
+
+Fxyf.fromVector = function (v) {
+ return Fxyf._fromHploc$1(Hploc.create(v));
+};
+
+var Fxyf$ = {
+ toHploc: function () {
+ var loc = new Hploc();
+ var jr = HealpixTables.jrll[this.face] - this.fx - this.fy;
+ var nr;
+ var tmp;
+ if (jr < 1) {
+ nr = jr;
+ tmp = nr * nr / 3;
+ loc.z = 1 - tmp;
+ if (loc.z > 0.99) {
+ loc.sth = Math.sqrt(tmp * (2 - tmp));
+ loc.have_sth = true;
+ }
+ } else if (jr > 3) {
+ nr = 4 - jr;
+ tmp = nr * nr / 3;
+ loc.z = tmp - 1;
+ if (loc.z < -0.99) {
+ loc.sth = Math.sqrt(tmp * (2 - tmp));
+ loc.have_sth = true;
+ }
+ } else {
+ nr = 1;
+ loc.z = (2 - jr) * 2 / 3;
+ }
+ tmp = HealpixTables.jpll[this.face] * nr + this.fx - this.fy;
+ if (tmp < 0) {
+ tmp += 8;
+ }
+ if (tmp >= 8) {
+ tmp -= 8;
+ }
+ loc.phi = (nr < 1E-15) ? 0 : (0.5 * Fxyf._halfpi$1 * tmp) / nr;
+ return loc;
+ },
+
+ toVec3: function () {
+ return this.toHploc().toVec3();
+ }
+};
+
+registerType("Fxyf", [Fxyf, Fxyf$, HealpixTables]);
diff --git a/engine/esm/graphics/gl_buffers.js b/engine/esm/graphics/gl_buffers.js
new file mode 100644
index 00000000..b4e943c4
--- /dev/null
+++ b/engine/esm/graphics/gl_buffers.js
@@ -0,0 +1,458 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// WebGL buffer types.
+
+import { registerType } from "../typesystem.js";
+import { ss } from "../ss.js";
+import { tilePrepDevice } from "../render_globals.js";
+import { WEBGL } from "./webgl_constants.js";
+
+
+// wwtlib.ShortIndexBuffer
+
+export function ShortIndexBuffer(indexes) {
+ this.buffer = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, this.buffer);
+ tilePrepDevice.bufferData(WEBGL.ELEMENT_ARRAY_BUFFER, indexes, WEBGL.STATIC_DRAW);
+}
+
+var ShortIndexBuffer$ = {};
+
+registerType("ShortIndexBuffer", [ShortIndexBuffer, ShortIndexBuffer$, null]);
+
+
+// wwtlib.IndexBuffer
+
+export function IndexBuffer(indexes) {
+ this.buffer = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, this.buffer);
+ tilePrepDevice.bufferData(WEBGL.ELEMENT_ARRAY_BUFFER, indexes, WEBGL.STATIC_DRAW);
+}
+
+var IndexBuffer$ = {
+ dispose: function () {
+ tilePrepDevice.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, null);
+ tilePrepDevice.deleteBuffer(this.buffer);
+ this.buffer = null;
+ }
+};
+
+registerType("IndexBuffer", [IndexBuffer, IndexBuffer$, null, ss.IDisposable]);
+
+
+// wwtlib.VertexBufferBase
+
+export function VertexBufferBase() { }
+
+var VertexBufferBase$ = {
+ dispose: function () {
+ tilePrepDevice.bindBuffer(WEBGL.ARRAY_BUFFER, null);
+ tilePrepDevice.deleteBuffer(this.vertexBuffer);
+ this.vertexBuffer = null;
+ }
+};
+
+registerType("VertexBufferBase", [VertexBufferBase, VertexBufferBase$, null, ss.IDisposable]);
+
+
+// wwtlib.PositionVertexBuffer
+
+export function PositionVertexBuffer(count) {
+ this.count = 0;
+ this._verts$1 = null;
+ VertexBufferBase.call(this);
+ this.count = count;
+}
+
+var PositionVertexBuffer$ = {
+ lock: function () {
+ this._verts$1 = new Array(this.count);
+ return this._verts$1;
+ },
+
+ unlock: function () {
+ this.vertexBuffer = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ARRAY_BUFFER, this.vertexBuffer);
+ var f32array = new Float32Array(this.count * 3);
+ var buffer = f32array;
+ var index = 0;
+ var $enum1 = ss.enumerate(this._verts$1);
+ while ($enum1.moveNext()) {
+ var pt = $enum1.current;
+ buffer[index++] = pt.x;
+ buffer[index++] = pt.y;
+ buffer[index++] = pt.z;
+ }
+ tilePrepDevice.bufferData(WEBGL.ARRAY_BUFFER, f32array, WEBGL.STATIC_DRAW);
+ }
+};
+
+registerType("PositionVertexBuffer", [PositionVertexBuffer, PositionVertexBuffer$, VertexBufferBase]);
+
+
+// wwtlib.PositionTextureVertexBuffer
+
+export function PositionTextureVertexBuffer(count) {
+ this.count = 0;
+ this._verts$1 = null;
+ VertexBufferBase.call(this);
+ this.count = count;
+}
+
+PositionTextureVertexBuffer.create = function (data) {
+ var buffer = new PositionTextureVertexBuffer(data.length);
+ buffer._verts$1 = data;
+ buffer.unlock();
+ return buffer;
+};
+
+var PositionTextureVertexBuffer$ = {
+ lock: function () {
+ this._verts$1 = new Array(this.count);
+ return this._verts$1;
+ },
+
+ unlock: function () {
+ this.vertexBuffer = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ARRAY_BUFFER, this.vertexBuffer);
+ var f32array = new Float32Array(this.count * 5);
+ var buffer = f32array;
+ var index = 0;
+ var $enum1 = ss.enumerate(this._verts$1);
+ while ($enum1.moveNext()) {
+ var pt = $enum1.current;
+ buffer[index++] = pt.position.x;
+ buffer[index++] = pt.position.y;
+ buffer[index++] = pt.position.z;
+ buffer[index++] = pt.tu;
+ buffer[index++] = pt.tv;
+ }
+ tilePrepDevice.bufferData(WEBGL.ARRAY_BUFFER, f32array, WEBGL.STATIC_DRAW);
+ }
+};
+
+registerType("PositionTextureVertexBuffer", [PositionTextureVertexBuffer, PositionTextureVertexBuffer$, VertexBufferBase]);
+
+
+// wwtlib.PositionNormalTexturedVertexBuffer
+
+export function PositionNormalTexturedVertexBuffer(count) {
+ this.count = 0;
+ this._verts$1 = null;
+ VertexBufferBase.call(this);
+ this.count = count;
+}
+
+PositionNormalTexturedVertexBuffer.create = function (data) {
+ var buffer = new PositionNormalTexturedVertexBuffer(data.length);
+ buffer._verts$1 = data;
+ buffer.unlock();
+ return buffer;
+};
+
+var PositionNormalTexturedVertexBuffer$ = {
+ lock: function () {
+ this._verts$1 = new Array(this.count);
+ return this._verts$1;
+ },
+
+ unlock: function () {
+ this.vertexBuffer = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ARRAY_BUFFER, this.vertexBuffer);
+ var f32array = new Float32Array(this.count * 8);
+ var buffer = f32array;
+ var index = 0;
+ var $enum1 = ss.enumerate(this._verts$1);
+ while ($enum1.moveNext()) {
+ var pt = $enum1.current;
+ buffer[index++] = pt.x;
+ buffer[index++] = pt.y;
+ buffer[index++] = pt.z;
+ buffer[index++] = pt.nx;
+ buffer[index++] = pt.ny;
+ buffer[index++] = pt.nz;
+ buffer[index++] = pt.tu;
+ buffer[index++] = pt.tv;
+ }
+ tilePrepDevice.bufferData(WEBGL.ARRAY_BUFFER, f32array, WEBGL.STATIC_DRAW);
+ }
+};
+
+registerType("PositionNormalTexturedVertexBuffer", [PositionNormalTexturedVertexBuffer, PositionNormalTexturedVertexBuffer$, VertexBufferBase]);
+
+
+// wwtlib.PositionNormalTexturedTangentVertexBuffer
+
+export function PositionNormalTexturedTangentVertexBuffer(count) {
+ this.count = 0;
+ this._verts$1 = null;
+ VertexBufferBase.call(this);
+ this.count = count;
+}
+
+PositionNormalTexturedTangentVertexBuffer.create = function (data) {
+ var buffer = new PositionNormalTexturedTangentVertexBuffer(data.length);
+ buffer._verts$1 = data;
+ buffer.unlock();
+ return buffer;
+};
+
+var PositionNormalTexturedTangentVertexBuffer$ = {
+ lock: function () {
+ this._verts$1 = new Array(this.count);
+ return this._verts$1;
+ },
+
+ unlock: function () {
+ this.vertexBuffer = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ARRAY_BUFFER, this.vertexBuffer);
+ var f32array = new Float32Array(this.count * 11);
+ var buffer = f32array;
+ var index = 0;
+ var $enum1 = ss.enumerate(this._verts$1);
+ while ($enum1.moveNext()) {
+ var pt = $enum1.current;
+ buffer[index++] = pt.x;
+ buffer[index++] = pt.y;
+ buffer[index++] = pt.z;
+ buffer[index++] = pt.nx;
+ buffer[index++] = pt.ny;
+ buffer[index++] = pt.nz;
+ buffer[index++] = pt.tanx;
+ buffer[index++] = pt.tany;
+ buffer[index++] = pt.tanz;
+ buffer[index++] = pt.tu;
+ buffer[index++] = pt.tv;
+ }
+ tilePrepDevice.bufferData(WEBGL.ARRAY_BUFFER, f32array, WEBGL.STATIC_DRAW);
+ }
+};
+
+registerType("PositionNormalTexturedTangentVertexBuffer", [PositionNormalTexturedTangentVertexBuffer, PositionNormalTexturedTangentVertexBuffer$, VertexBufferBase]);
+
+
+// wwtlib.KeplerVertexBuffer
+
+export function KeplerVertexBuffer(count) {
+ this.count = 0;
+ this._verts$1 = null;
+ VertexBufferBase.call(this);
+ this.count = count;
+}
+
+KeplerVertexBuffer.create = function (items) {
+ var tmp = new KeplerVertexBuffer(items.length);
+ tmp._verts$1 = items;
+ return tmp;
+};
+
+var KeplerVertexBuffer$ = {
+ lock: function () {
+ this._verts$1 = new Array(this.count);
+ return this._verts$1;
+ },
+
+ unlock: function () {
+ this.vertexBuffer = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ARRAY_BUFFER, this.vertexBuffer);
+ var f32array = new Float32Array(this.count * 19);
+ var buffer = f32array;
+ var index = 0;
+ var $enum1 = ss.enumerate(this._verts$1);
+ while ($enum1.moveNext()) {
+ var pt = $enum1.current;
+ buffer[index++] = pt.ABC.x;
+ buffer[index++] = pt.ABC.y;
+ buffer[index++] = pt.ABC.z;
+ buffer[index++] = pt.abc1.x;
+ buffer[index++] = pt.abc1.y;
+ buffer[index++] = pt.abc1.z;
+ buffer[index++] = pt.pointSize;
+ buffer[index++] = pt.color.r / 255;
+ buffer[index++] = pt.color.g / 255;
+ buffer[index++] = pt.color.b / 255;
+ buffer[index++] = pt.color.a / 255;
+ buffer[index++] = pt.w;
+ buffer[index++] = pt.e;
+ buffer[index++] = pt.n;
+ buffer[index++] = pt.t;
+ buffer[index++] = pt.a;
+ buffer[index++] = pt.z;
+ buffer[index++] = pt.orbitPos;
+ buffer[index++] = pt.orbits;
+ }
+ tilePrepDevice.bufferData(WEBGL.ARRAY_BUFFER, f32array, WEBGL.STATIC_DRAW);
+ }
+};
+
+registerType("KeplerVertexBuffer", [KeplerVertexBuffer, KeplerVertexBuffer$, VertexBufferBase]);
+
+
+// wwtlib.TimeSeriesLineVertexBuffer
+
+export function TimeSeriesLineVertexBuffer(count) {
+ this.count = 0;
+ this._verts$1 = null;
+ VertexBufferBase.call(this);
+ this.count = count;
+}
+
+var TimeSeriesLineVertexBuffer$ = {
+ lock: function () {
+ this._verts$1 = new Array(this.count);
+ return this._verts$1;
+ },
+
+ unlock: function () {
+ this.vertexBuffer = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ARRAY_BUFFER, this.vertexBuffer);
+ var f32array = new Float32Array(this.count * 9);
+ var buffer = f32array;
+ var index = 0;
+ var $enum1 = ss.enumerate(this._verts$1);
+ while ($enum1.moveNext()) {
+ var pt = $enum1.current;
+ buffer[index++] = pt.position.x;
+ buffer[index++] = pt.position.y;
+ buffer[index++] = pt.position.z;
+ buffer[index++] = pt.get_color().r / 255;
+ buffer[index++] = pt.get_color().g / 255;
+ buffer[index++] = pt.get_color().b / 255;
+ buffer[index++] = pt.get_color().a / 255;
+ buffer[index++] = pt.tu;
+ buffer[index++] = pt.tv;
+ }
+ tilePrepDevice.bufferData(WEBGL.ARRAY_BUFFER, f32array, WEBGL.STATIC_DRAW);
+ }
+};
+
+registerType("TimeSeriesLineVertexBuffer", [TimeSeriesLineVertexBuffer, TimeSeriesLineVertexBuffer$, VertexBufferBase]);
+
+
+// wwtlib.TimeSeriesPointVertexBuffer
+
+export function TimeSeriesPointVertexBuffer(count) {
+ this.count = 0;
+ this._verts$1 = null;
+ VertexBufferBase.call(this);
+ this.count = count;
+}
+
+var TimeSeriesPointVertexBuffer$ = {
+ lock: function () {
+ this._verts$1 = new Array(this.count);
+ return this._verts$1;
+ },
+
+ unlock: function () {
+ this.vertexBuffer = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ARRAY_BUFFER, this.vertexBuffer);
+ var f32array = new Float32Array(this.count * 10);
+ var buffer = f32array;
+ var index = 0;
+ var $enum1 = ss.enumerate(this._verts$1);
+ while ($enum1.moveNext()) {
+ var pt = $enum1.current;
+ buffer[index++] = pt.position.x;
+ buffer[index++] = pt.position.y;
+ buffer[index++] = pt.position.z;
+ buffer[index++] = pt.get_color().r / 255;
+ buffer[index++] = pt.get_color().g / 255;
+ buffer[index++] = pt.get_color().b / 255;
+ buffer[index++] = pt.get_color().a / 255;
+ buffer[index++] = pt.tu;
+ buffer[index++] = pt.tv;
+ buffer[index++] = pt.pointSize;
+ }
+ tilePrepDevice.bufferData(WEBGL.ARRAY_BUFFER, f32array, WEBGL.STATIC_DRAW);
+ },
+
+ dispose: function () {
+ tilePrepDevice.bindBuffer(WEBGL.ARRAY_BUFFER, null);
+ tilePrepDevice.deleteBuffer(this.vertexBuffer);
+ this.vertexBuffer = null;
+ }
+};
+
+registerType("TimeSeriesPointVertexBuffer", [TimeSeriesPointVertexBuffer, TimeSeriesPointVertexBuffer$, VertexBufferBase]);
+
+
+// wwtlib.PositionColoredVertexBuffer
+
+export function PositionColoredVertexBuffer(count) {
+ this.count = 0;
+ this._verts$1 = null;
+ VertexBufferBase.call(this);
+ this.count = count;
+}
+
+var PositionColoredVertexBuffer$ = {
+ lock: function () {
+ this._verts$1 = new Array(this.count);
+ return this._verts$1;
+ },
+
+ unlock: function () {
+ this.vertexBuffer = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ARRAY_BUFFER, this.vertexBuffer);
+ var f32array = new Float32Array(this.count * 7);
+ var buffer = f32array;
+ var index = 0;
+ var $enum1 = ss.enumerate(this._verts$1);
+ while ($enum1.moveNext()) {
+ var pt = $enum1.current;
+ buffer[index++] = pt.position.x;
+ buffer[index++] = pt.position.y;
+ buffer[index++] = pt.position.z;
+ buffer[index++] = pt.color.r / 255;
+ buffer[index++] = pt.color.g / 255;
+ buffer[index++] = pt.color.b / 255;
+ buffer[index++] = pt.color.a / 255;
+ }
+ tilePrepDevice.bufferData(WEBGL.ARRAY_BUFFER, f32array, WEBGL.STATIC_DRAW);
+ }
+};
+
+registerType("PositionColoredVertexBuffer", [PositionColoredVertexBuffer, PositionColoredVertexBuffer$, VertexBufferBase]);
+
+
+// wwtlib.PositionColoredTexturedVertexBuffer
+
+export function PositionColoredTexturedVertexBuffer(count) {
+ this.count = 0;
+ this._verts$1 = null;
+ VertexBufferBase.call(this);
+ this.count = count;
+}
+
+var PositionColoredTexturedVertexBuffer$ = {
+ lock: function () {
+ this._verts$1 = new Array(this.count);
+ return this._verts$1;
+ },
+
+ unlock: function () {
+ this.vertexBuffer = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ARRAY_BUFFER, this.vertexBuffer);
+ var f32array = new Float32Array(this.count * 9);
+ var buffer = f32array;
+ var index = 0;
+ var $enum1 = ss.enumerate(this._verts$1);
+ while ($enum1.moveNext()) {
+ var pt = $enum1.current;
+ buffer[index++] = pt.position.x;
+ buffer[index++] = pt.position.y;
+ buffer[index++] = pt.position.z;
+ buffer[index++] = pt.color.r / 255;
+ buffer[index++] = pt.color.g / 255;
+ buffer[index++] = pt.color.b / 255;
+ buffer[index++] = pt.color.a / 255;
+ buffer[index++] = pt.tu;
+ buffer[index++] = pt.tv;
+ }
+ tilePrepDevice.bufferData(WEBGL.ARRAY_BUFFER, f32array, WEBGL.STATIC_DRAW);
+ }
+};
+
+registerType("PositionColoredTexturedVertexBuffer", [PositionColoredTexturedVertexBuffer, PositionColoredTexturedVertexBuffer$, VertexBufferBase]);
diff --git a/engine/esm/graphics/primitives3d.js b/engine/esm/graphics/primitives3d.js
new file mode 100644
index 00000000..aa19410a
--- /dev/null
+++ b/engine/esm/graphics/primitives3d.js
@@ -0,0 +1,929 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Various GL primitives.
+
+import { registerType, registerEnum } from "../typesystem.js";
+import { ss } from "../ss.js";
+import { Matrix3d, Vector3d, PositionColored } from "../double3d.js";
+import { Color } from "../color.js";
+import { URLHelpers } from "../url_helpers.js";
+import { WEBGL } from "./webgl_constants.js";
+import {
+ PositionVertexBuffer,
+ PositionColoredVertexBuffer,
+ TimeSeriesLineVertexBuffer,
+ TimeSeriesPointVertexBuffer,
+} from "./gl_buffers.js";
+import { Texture } from "./texture.js";
+import {
+ SimpleLineShader,
+ SimpleLineShader2D,
+ OrbitLineShader,
+ LineShaderNormalDates,
+ TimeSeriesPointSpriteShader,
+} from "./shaders.js";
+
+
+// wwtlib.CullMode
+
+export var CullMode = {
+ none: 0,
+ counterClockwise: 2,
+ clockwise: 1
+};
+
+registerType("CullMode", CullMode);
+registerEnum("CullMode", CullMode);
+
+
+// wwtlib.PointScaleTypes
+
+export var PointScaleTypes = {
+ linear: 0,
+ power: 1,
+ log: 2,
+ constant: 3,
+ stellarMagnitude: 4
+};
+
+registerType("PointScaleTypes", PointScaleTypes);
+registerEnum("PointScaleTypes", PointScaleTypes);
+
+
+// wwtlib.DataItem
+//
+// This type was originally defined in VizLayer.cs, but it's quite simple
+// and is used here.
+
+export function DataItem() {
+ this.size = 0;
+}
+
+var DataItem$ = {
+ getColor: function () {
+ return 'Red';
+ }
+};
+
+registerType("DataItem", [DataItem, DataItem$, null]);
+
+
+// wwtlib.Dates
+
+export function Dates(start, end) {
+ this.startDate = 0;
+ this.endDate = 0;
+ this.startDate = start;
+ this.endDate = end;
+}
+
+Dates.empty = function () {
+ return new Dates(0, 0);
+};
+
+var Dates$ = {
+ copy: function () {
+ return new Dates(this.startDate, this.endDate);
+ }
+};
+
+registerType("Dates", [Dates, Dates$, null]);
+
+
+// wwtlib.SimpleLineList
+
+export function SimpleLineList() {
+ this._zBuffer = true;
+ this._linePoints = [];
+ this._usingLocalCenter = false;
+ this.sky = true;
+ this.aaFix = true;
+ this.pure2D = false;
+ this.viewTransform = Matrix3d.get_identity();
+ this._lineBuffers = [];
+ this._lineBufferCounts = [];
+ this.useLocalCenters = false;
+}
+
+var SimpleLineList$ = {
+ get_depthBuffered: function () {
+ return this._zBuffer;
+ },
+
+ set_depthBuffered: function (value) {
+ this._zBuffer = value;
+ return value;
+ },
+
+ addLine: function (v1, v2) {
+ this._linePoints.push(v1);
+ this._linePoints.push(v2);
+ this._emptyLineBuffer();
+ },
+
+ clear: function () {
+ this._linePoints.length = 0;
+ this._emptyLineBuffer();
+ },
+
+ drawLines: function (renderContext, opacity, color) {
+ if (this._linePoints.length < 2) {
+ return;
+ }
+ this._initLineBuffer(renderContext);
+ var count = this._linePoints.length;
+ if (renderContext.gl == null) {
+ var viewPoint = Vector3d._transformCoordinate(renderContext.get_viewPoint(), this.viewTransform);
+ var ctx = renderContext.device;
+ ctx.save();
+ ctx.strokeStyle = color.toString();
+ ctx.lineWidth = 2;
+ ctx.globalAlpha = 0.25;
+ var firstPoint = new Vector3d();
+ var secondPoint = new Vector3d();
+ for (var i = 0; i < count; i += 2) {
+ firstPoint = renderContext.WVP.transform(this._linePoints[i]);
+ secondPoint = renderContext.WVP.transform(this._linePoints[i + 1]);
+ if (Vector3d.dot(this._linePoints[i], viewPoint) > 0.6) {
+ ctx.beginPath();
+ ctx.moveTo(firstPoint.x, firstPoint.y);
+ ctx.lineTo(secondPoint.x, secondPoint.y);
+ ctx.stroke();
+ }
+ }
+ ctx.restore();
+ } else {
+ var $enum1 = ss.enumerate(this._lineBuffers);
+ while ($enum1.moveNext()) {
+ var lineBuffer = $enum1.current;
+ if (this.pure2D) {
+ SimpleLineShader2D.use(renderContext, lineBuffer.vertexBuffer, color, this._zBuffer);
+ }
+ else {
+ SimpleLineShader.use(renderContext, lineBuffer.vertexBuffer, color, this._zBuffer);
+ }
+ renderContext.gl.drawArrays(WEBGL.LINES, 0, lineBuffer.count);
+ }
+ }
+ },
+
+ _initLineBuffer: function (renderContext) {
+ if (renderContext.gl != null) {
+ if (!this._lineBuffers.length) {
+ var count = this._linePoints.length;
+ var lineBuffer = null;
+ var linePointList = null;
+ this._localCenter = new Vector3d();
+ if (this.get_depthBuffered()) {
+ var $enum1 = ss.enumerate(this._linePoints);
+
+ // compute the local center
+ while ($enum1.moveNext()) {
+ var point = $enum1.current;
+ this._localCenter.add(point);
+ }
+ this._localCenter.x /= count;
+ this._localCenter.y /= count;
+ this._localCenter.z /= count;
+ }
+ var countLeft = count;
+ var index = 0;
+ var counter = 0;
+ var temp;
+ var $enum2 = ss.enumerate(this._linePoints);
+ while ($enum2.moveNext()) {
+ var point = $enum2.current;
+ if (counter >= 100000 || linePointList == null) {
+ if (lineBuffer != null) {
+ lineBuffer.unlock();
+ }
+ var thisCount = Math.min(100000, countLeft);
+ countLeft -= thisCount;
+ lineBuffer = new PositionVertexBuffer(thisCount);
+ linePointList = lineBuffer.lock(); // Lock the buffer (which will return our structs)
+ this._lineBuffers.push(lineBuffer);
+ this._lineBufferCounts.push(thisCount);
+ counter = 0;
+ }
+ if (this.useLocalCenters) {
+ temp = Vector3d.subtractVectors(point, this._localCenter);
+ linePointList[counter] = temp;
+ }
+ else {
+ linePointList[counter] = point;
+ }
+ index++;
+ counter++;
+ }
+ if (lineBuffer != null) {
+ lineBuffer.unlock();
+ }
+ }
+ }
+ },
+
+ _emptyLineBuffer: function () { }
+};
+
+registerType("SimpleLineList", [SimpleLineList, SimpleLineList$, null]);
+
+
+// wwtlib.OrbitLineList
+
+export function OrbitLineList() {
+ this._zBuffer = true;
+ this._linePoints = [];
+ this._lineColors = [];
+ this.sky = true;
+ this.aaFix = true;
+ this.viewTransform = Matrix3d.get_identity();
+ this._lineBuffers = [];
+ this._lineBufferCounts = [];
+ this.useLocalCenters = false;
+}
+
+var OrbitLineList$ = {
+ get_depthBuffered: function () {
+ return this._zBuffer;
+ },
+
+ set_depthBuffered: function (value) {
+ this._zBuffer = value;
+ return value;
+ },
+
+ addLine: function (v1, v2, c1, c2) {
+ this._linePoints.push(v1);
+ this._lineColors.push(c1);
+ this._linePoints.push(v2);
+ this._lineColors.push(c2);
+ this._emptyLineBuffer();
+ },
+
+ clear: function () {
+ this._linePoints.length = 0;
+ this._emptyLineBuffer();
+ },
+
+ drawLines: function (renderContext, opacity, color) {
+ if (this._linePoints.length < 2) {
+ return;
+ }
+ this._initLineBuffer(renderContext);
+ var count = this._linePoints.length;
+ var $enum1 = ss.enumerate(this._lineBuffers);
+ while ($enum1.moveNext()) {
+ var lineBuffer = $enum1.current;
+ OrbitLineShader.use(renderContext, lineBuffer.vertexBuffer, color);
+ renderContext.gl.drawArrays(WEBGL.LINES, 0, lineBuffer.count);
+ }
+ },
+
+ _initLineBuffer: function (renderContext) {
+ if (renderContext.gl != null) {
+ if (!this._lineBuffers.length) {
+ var count = this._linePoints.length;
+ var lineBuffer = null;
+ var linePointList = null;
+ this._localCenter = new Vector3d();
+ if (this.get_depthBuffered()) {
+ var $enum1 = ss.enumerate(this._linePoints);
+
+ // compute the local center
+ while ($enum1.moveNext()) {
+ var point = $enum1.current;
+ this._localCenter.add(point);
+ }
+ this._localCenter.x /= count;
+ this._localCenter.y /= count;
+ this._localCenter.z /= count;
+ }
+ var countLeft = count;
+ var index = 0;
+ var counter = 0;
+ var temp;
+ var $enum2 = ss.enumerate(this._linePoints);
+ while ($enum2.moveNext()) {
+ var point = $enum2.current;
+ if (counter >= 100000 || linePointList == null) {
+ if (lineBuffer != null) {
+ lineBuffer.unlock();
+ }
+ var thisCount = Math.min(100000, countLeft);
+ countLeft -= thisCount;
+ lineBuffer = new PositionColoredVertexBuffer(thisCount);
+ linePointList = lineBuffer.lock(); // Lock the buffer (which will return our structs)
+ this._lineBuffers.push(lineBuffer);
+ this._lineBufferCounts.push(thisCount);
+ counter = 0;
+ }
+ if (this.useLocalCenters) {
+ temp = Vector3d.subtractVectors(point, this._localCenter);
+ linePointList[counter] = new PositionColored(temp, this._lineColors[index]);
+ }
+ else {
+ linePointList[counter] = new PositionColored(point, this._lineColors[index]);
+ }
+ index++;
+ counter++;
+ }
+ if (lineBuffer != null) {
+ lineBuffer.unlock();
+ }
+ }
+ }
+ },
+
+ _emptyLineBuffer: function () {
+ var $enum1 = ss.enumerate(this._lineBuffers);
+ while ($enum1.moveNext()) {
+ var lineBuffer = $enum1.current;
+ lineBuffer.dispose();
+ }
+ this._lineBuffers.length = 0;
+ }
+};
+
+registerType("OrbitLineList", [OrbitLineList, OrbitLineList$, null]);
+
+
+// wwtlib.LineList
+
+export function LineList() {
+ this._zBuffer = true;
+ this.timeSeries = false;
+ this.showFarSide = true;
+ this.sky = false;
+ this.decay = 0;
+ this.useNonRotatingFrame = false;
+ this.jNow = 0;
+ this._linePoints = [];
+ this._lineColors = [];
+ this._lineDates = [];
+ this._usingLocalCenter = true;
+ this._lineBuffers = [];
+ this._lineBufferCounts = [];
+}
+
+var LineList$ = {
+ get_depthBuffered: function () {
+ return this._zBuffer;
+ },
+
+ set_depthBuffered: function (value) {
+ this._zBuffer = value;
+ return value;
+ },
+
+ addLine: function (v1, v2, color, date) {
+ this._linePoints.push(v1);
+ this._linePoints.push(v2);
+ this._lineColors.push(color);
+ this._lineDates.push(date);
+ this._emptyLineBuffer();
+ },
+
+ addLineNoDate: function (v1, v2, color) {
+ this._linePoints.push(v1);
+ this._linePoints.push(v2);
+ this._lineColors.push(color);
+ this._lineDates.push(new Dates(0, 0));
+ this._emptyLineBuffer();
+ },
+
+ clear: function () {
+ this._linePoints.length = 0;
+ this._lineColors.length = 0;
+ this._lineDates.length = 0;
+ },
+
+ drawLines: function (renderContext, opacity) {
+ if (this._linePoints.length < 2 || opacity <= 0) {
+ return;
+ }
+ if (renderContext.gl == null) {
+ //todo draw with HTML5
+ } else {
+ this._initLineBuffer();
+ var $enum1 = ss.enumerate(this._lineBuffers);
+ while ($enum1.moveNext()) {
+ var lineBuffer = $enum1.current;
+ LineShaderNormalDates.use(renderContext, lineBuffer.vertexBuffer, Color.fromArgb(255, 255, 255, 255), this._zBuffer, this.jNow, (this.timeSeries) ? this.decay : 0);
+ renderContext.gl.drawArrays(WEBGL.LINES, 0, lineBuffer.count);
+ }
+ }
+ },
+
+ _initLineBuffer: function () {
+ if (!this._lineBuffers.length) {
+ var count = this._linePoints.length;
+ var lineBuffer = null;
+ var linePointList = null;
+ var countLeft = count;
+ var index = 0;
+ var counter = 0;
+ var temp;
+ var $enum1 = ss.enumerate(this._linePoints);
+ while ($enum1.moveNext()) {
+ var point = $enum1.current;
+ if (counter >= 100000 || linePointList == null) {
+ if (lineBuffer != null) {
+ lineBuffer.unlock();
+ }
+ var thisCount = Math.min(100000, countLeft);
+ countLeft -= thisCount;
+ lineBuffer = new TimeSeriesLineVertexBuffer(thisCount);
+ linePointList = lineBuffer.lock(); // Lock the buffer (which will return our structs)
+ this._lineBuffers.push(lineBuffer);
+ this._lineBufferCounts.push(thisCount);
+ counter = 0;
+ }
+ var div2 = ss.truncate((index / 2));
+ temp = point; // -localCenter;
+ linePointList[counter] = new TimeSeriesLineVertex();
+ linePointList[counter].position = temp;
+ linePointList[counter].normal = point;
+ linePointList[counter].tu = this._lineDates[div2].startDate;
+ linePointList[counter].tv = this._lineDates[div2].endDate;
+ linePointList[counter].set_color(this._lineColors[div2]);
+ index++;
+ counter++;
+ }
+ if (lineBuffer != null) {
+ lineBuffer.unlock();
+ }
+ }
+ },
+
+ _emptyLineBuffer: function () { }
+};
+
+registerType("LineList", [LineList, LineList$, null]);
+
+
+// wwtlib.TriangleList
+
+export function TriangleList() {
+ this._trianglePoints = [];
+ this._triangleColors = [];
+ this._triangleDates = [];
+ this.timeSeries = false;
+ this.showFarSide = false;
+ this.sky = false;
+ this.depthBuffered = true;
+ this.writeZbuffer = false;
+ this.decay = 0;
+ this.autoTime = true;
+ this.jNow = 0;
+ this._dataToDraw = false;
+ this._triangleBuffers = [];
+ this._triangleBufferCounts = [];
+}
+
+var TriangleList$ = {
+ addTriangle: function (v1, v2, v3, color, date) {
+ this._trianglePoints.push(v1);
+ this._trianglePoints.push(v2);
+ this._trianglePoints.push(v3);
+ this._triangleColors.push(color);
+ this._triangleDates.push(date);
+ this._emptyTriangleBuffer();
+ },
+
+ addSubdividedTriangles: function (v1, v2, v3, color, date, subdivisions) {
+ subdivisions--;
+ if (subdivisions < 0) {
+ this.addTriangle(v1, v2, v3, color, date);
+ } else {
+ var v12;
+ var v23;
+ var v31;
+ v12 = Vector3d.midPointByLength(v1, v2);
+ v23 = Vector3d.midPointByLength(v2, v3);
+ v31 = Vector3d.midPointByLength(v3, v1);
+ this.addSubdividedTriangles(v1, v12, v31, color, date, subdivisions);
+ this.addSubdividedTriangles(v12, v23, v31, color, date, subdivisions);
+ this.addSubdividedTriangles(v12, v2, v23, color, date, subdivisions);
+ this.addSubdividedTriangles(v23, v3, v31, color, date, subdivisions);
+ }
+ },
+
+ addQuad: function (v1, v2, v3, v4, color, date) {
+ this._trianglePoints.push(v1);
+ this._trianglePoints.push(v3);
+ this._trianglePoints.push(v2);
+ this._trianglePoints.push(v2);
+ this._trianglePoints.push(v3);
+ this._trianglePoints.push(v4);
+ this._triangleColors.push(color);
+ this._triangleDates.push(date);
+ this._triangleColors.push(color);
+ this._triangleDates.push(date);
+ this._emptyTriangleBuffer();
+ },
+
+ clear: function () {
+ this._triangleColors.length = 0;
+ this._trianglePoints.length = 0;
+ this._triangleDates.length = 0;
+ this._emptyTriangleBuffer();
+ },
+
+ _emptyTriangleBuffer: function () { },
+
+ _initTriangleBuffer: function () {
+ if (!this._triangleBuffers.length) {
+ var count = this._trianglePoints.length;
+ var triangleBuffer = null;
+ var triPointList = null;
+ var countLeft = count;
+ var index = 0;
+ var counter = 0;
+ var $enum1 = ss.enumerate(this._trianglePoints);
+ while ($enum1.moveNext()) {
+ var point = $enum1.current;
+ if (counter >= 90000 || triangleBuffer == null) {
+ if (triangleBuffer != null) {
+ triangleBuffer.unlock();
+ }
+ var thisCount = Math.min(90000, countLeft);
+ countLeft -= thisCount;
+ triangleBuffer = new TimeSeriesLineVertexBuffer(thisCount);
+ this._triangleBuffers.push(triangleBuffer);
+ this._triangleBufferCounts.push(thisCount);
+ triPointList = triangleBuffer.lock(); // Lock the buffer (which will return our structs)
+ counter = 0;
+ }
+ triPointList[counter] = new TimeSeriesLineVertex();
+ triPointList[counter].position = point;
+ triPointList[counter].normal = point;
+ var div3 = ss.truncate((index / 3));
+ triPointList[counter].set_color(this._triangleColors[div3]);
+ triPointList[counter].tu = this._triangleDates[div3].startDate;
+ triPointList[counter].tv = this._triangleDates[div3].endDate;
+ index++;
+ counter++;
+ }
+ if (triangleBuffer != null) {
+ triangleBuffer.unlock();
+ }
+ this._triangleColors.length = 0;
+ this._triangleDates.length = 0;
+ this._trianglePoints.length = 0;
+ this._dataToDraw = true;
+ }
+ },
+
+ draw: function (renderContext, opacity, cull) {
+ if (this._trianglePoints.length < 1 && !this._dataToDraw) {
+ return;
+ }
+ if (renderContext.gl == null) {
+ //todo implement HTML5 version
+ } else {
+ this._initTriangleBuffer();
+ var $enum1 = ss.enumerate(this._triangleBuffers);
+ while ($enum1.moveNext()) {
+ var triBuffer = $enum1.current;
+ LineShaderNormalDates.use(renderContext, triBuffer.vertexBuffer, Color.fromArgb(255, 255, 255, 255), this.depthBuffered, this.jNow, (this.timeSeries) ? this.decay : 0);
+ renderContext.gl.drawArrays(WEBGL.TRIANGLES, 0, triBuffer.count);
+ }
+ }
+ }
+};
+
+registerType("TriangleList", [TriangleList, TriangleList$, null]);
+
+
+// wwtlib.TriangleFanList
+
+export function TriangleFanList() {
+ this._zBuffer = true;
+ this.timeSeries = false;
+ this.decay = 0;
+ this.jNow = 0;
+ this._shapes = [];
+ this._colors = [];
+ this._dates = [];
+ this._buffers = [];
+ this._bufferCounts = [];
+}
+
+var TriangleFanList$ = {
+ get_depthBuffered: function () {
+ return this._zBuffer;
+ },
+
+ set_depthBuffered: function (value) {
+ this._zBuffer = value;
+ return value;
+ },
+
+ addShape: function (shapePoints, color, date) {
+ this._shapes.push(shapePoints);
+ this._colors.push(color);
+ this._dates.push(date);
+ },
+
+ draw: function (renderContext, opacity) {
+ if (opacity <= 0) {
+ return;
+ }
+ if (renderContext.gl != null) {
+ this._initBuffer();
+ var $enum1 = ss.enumerate(this._buffers);
+ while ($enum1.moveNext()) {
+ var buffer = $enum1.current;
+ LineShaderNormalDates.use(renderContext, buffer.vertexBuffer, Color.fromArgb(255, 255, 255, 255), this._zBuffer, this.jNow, (this.timeSeries) ? this.decay : 0);
+ renderContext.gl.drawArrays(WEBGL.TRIANGLE_FAN, 0, buffer.count);
+ }
+ }
+ },
+
+ _initBuffer: function () {
+ if (this._buffers.length !== this._shapes.length) {
+ this._buffers.length = 0;
+ var index = 0;
+ var $enum1 = ss.enumerate(this._shapes);
+ while ($enum1.moveNext()) {
+ var shape = $enum1.current;
+ var buffer = new TimeSeriesLineVertexBuffer(shape.length);
+ var pointList = buffer.lock(); // Lock the buffer (which will return our structs)
+ this._buffers.push(buffer);
+ this._bufferCounts.push(shape.length);
+ var counter = 0;
+ var $enum2 = ss.enumerate(shape);
+ while ($enum2.moveNext()) {
+ var point = $enum2.current;
+ pointList[counter] = new TimeSeriesLineVertex();
+ pointList[counter].position = point;
+ pointList[counter].tu = this._dates[index].startDate;
+ pointList[counter].tv = this._dates[index].endDate;
+ pointList[counter].set_color(this._colors[index]);
+ counter++;
+ }
+ index++;
+ if (buffer != null) {
+ buffer.unlock();
+ }
+ }
+ }
+ }
+};
+
+registerType("TriangleFanList", [TriangleFanList, TriangleFanList$, null]);
+
+
+// wwtlib.PointList
+
+export function PointList(device) {
+ this._points = [];
+ this._colors = [];
+ this._dates = [];
+ this._sizes = [];
+ this.timeSeries = false;
+ this.showFarSide = false;
+ this.sky = false;
+ this.depthBuffered = true;
+ this.decay = 0;
+ this.scale = 1;
+ this.autoTime = true;
+ this.jNow = 0;
+ this._dataToDraw = false;
+ this.items = [];
+ this._imageReady = false;
+ this._init = false;
+ this.minSize = 2;
+ this._pointBuffers = [];
+ this._pointBufferCounts = [];
+ this._device = device;
+}
+
+PointList.starTexture = null;
+
+var PointList$ = {
+ addPoint: function (v1, color, date, size) {
+ this._points.push(v1);
+ this._colors.push(color._clone());
+ this._dates.push(date);
+ this._sizes.push(size);
+ this._emptyPointBuffer();
+ },
+
+ clear: function () {
+ this._colors.length = 0;
+ this._points.length = 0;
+ this._dates.length = 0;
+ this._sizes.length = 0;
+ this._emptyPointBuffer();
+ },
+
+ _emptyPointBuffer: function () {
+ var $enum1 = ss.enumerate(this._pointBuffers);
+ while ($enum1.moveNext()) {
+ var pointBuffer = $enum1.current;
+ pointBuffer.dispose();
+ }
+ this._pointBuffers.length = 0;
+ this._init = false;
+ },
+
+ _initBuffer: function (renderContext) {
+ var $this = this;
+
+ if (!this._init) {
+ if (renderContext.gl == null) {
+ this._starProfile = document.createElement('img');
+ this._starProfile.addEventListener('load', function (e) {
+ $this._imageReady = true;
+ }, false);
+ this._starProfile.src = URLHelpers.singleton.engineAssetUrl('StarProfileAlpha.png');
+ this._worldList = new Array(this._points.length);
+ this._transformedList = new Array(this._points.length);
+ var index = 0;
+ var $enum1 = ss.enumerate(this._points);
+ while ($enum1.moveNext()) {
+ // todo filter by date
+ var pnt = $enum1.current;
+ var item = new DataItem();
+ item.location = pnt;
+ item.tranformed = new Vector3d();
+ item.size = this._sizes[index];
+ item.color = this._colors[index];
+ this._worldList[index] = item.location;
+ this._transformedList[index] = item.tranformed;
+ this.items.push(item);
+ index++;
+ }
+ } else {
+ if (!this._pointBuffers.length) {
+ if (PointList.starTexture == null) {
+ PointList.starTexture = Texture.fromUrl(URLHelpers.singleton.engineAssetUrl('StarProfileAlpha.png'));
+ }
+ var count = this._points.length;
+ var pointBuffer = null;
+ var pointList = null;
+ var countLeft = count;
+ var index = 0;
+ var counter = 0;
+ var $enum2 = ss.enumerate(this._points);
+ while ($enum2.moveNext()) {
+ var point = $enum2.current;
+ if (counter >= 100000 || pointList == null) {
+ if (pointBuffer != null) {
+ pointBuffer.unlock();
+ }
+ var thisCount = Math.min(100000, countLeft);
+ countLeft -= thisCount;
+ pointBuffer = new TimeSeriesPointVertexBuffer(thisCount);
+ pointList = pointBuffer.lock(); // Lock the buffer (which will return our structs)
+ this._pointBuffers.push(pointBuffer);
+ this._pointBufferCounts.push(thisCount);
+ counter = 0;
+ }
+ pointList[counter] = new TimeSeriesPointVertex();
+ pointList[counter].position = point;
+ pointList[counter].pointSize = this._sizes[index];
+ pointList[counter].tu = this._dates[index].startDate;
+ pointList[counter].tv = this._dates[index].endDate;
+ pointList[counter].set_color(this._colors[index]);
+ index++;
+ counter++;
+ }
+ if (pointBuffer != null) {
+ pointBuffer.unlock();
+ }
+ }
+ }
+ this._init = true;
+ }
+ },
+
+ draw: function (renderContext, opacity, cull) {
+ this._initBuffer(renderContext);
+ if (renderContext.gl == null) {
+ if (!this._imageReady) {
+ return;
+ }
+ renderContext.device.save();
+ renderContext.WVP.projectArrayToScreen(this._worldList, this._transformedList);
+ var ctx = renderContext.device;
+ ctx.globalAlpha = 0.4;
+ var width = renderContext.width;
+ var height = renderContext.height;
+ var viewPoint = Vector3d.makeCopy(renderContext.get_viewPoint());
+ var scaleFactor = renderContext.get_fovScale() / 100;
+ var $enum1 = ss.enumerate(this.items);
+ while ($enum1.moveNext()) {
+ // todo filter by date
+ var item = $enum1.current;
+ if (item.tranformed.z < 1) {
+ var x = item.tranformed.x;
+ var y = item.tranformed.y;
+ var size = 0.1 * item.size / scaleFactor;
+ var half = size / 2;
+ if (x > -half && x < width + half && y > -half && y < height + half) {
+ ctx.beginPath();
+ ctx.fillStyle = item.color.toFormat();
+ ctx.arc(x, y, size, 0, Math.PI * 2, true);
+ ctx.fill();
+ }
+ }
+ }
+ renderContext.device.restore();
+ } else {
+ var zero = new Vector3d();
+ var matInv = Matrix3d.multiplyMatrix(renderContext.get_world(), renderContext.get_view());
+ matInv.invert();
+ var cam = Vector3d._transformCoordinate(zero, matInv);
+ var $enum2 = ss.enumerate(this._pointBuffers);
+ while ($enum2.moveNext()) {
+ var pointBuffer = $enum2.current;
+ TimeSeriesPointSpriteShader.use(renderContext, pointBuffer.vertexBuffer, PointList.starTexture.texture2d, Color.fromArgb(255 * opacity, 255, 255, 255), this.depthBuffered, this.jNow, (this.timeSeries) ? this.decay : 0, cam, (this.scale * (renderContext.height / 960)), this.minSize, this.showFarSide, this.sky);
+ renderContext.gl.drawArrays(WEBGL.POINTS, 0, pointBuffer.count);
+ }
+ }
+ },
+
+ drawTextured: function (renderContext, texture, opacity) {
+ this._initBuffer(renderContext);
+ var zero = new Vector3d();
+ var matInv = Matrix3d.multiplyMatrix(renderContext.get_world(), renderContext.get_view());
+ matInv.invert();
+ var cam = Vector3d._transformCoordinate(zero, matInv);
+ var $enum1 = ss.enumerate(this._pointBuffers);
+ while ($enum1.moveNext()) {
+ var pointBuffer = $enum1.current;
+ TimeSeriesPointSpriteShader.use(renderContext, pointBuffer.vertexBuffer, texture, Color.fromArgb(255 * opacity, 255, 255, 255), this.depthBuffered, this.jNow, this.decay, cam, (this.scale * (renderContext.height / 960)), this.minSize, this.showFarSide, this.sky);
+ renderContext.gl.drawArrays(WEBGL.POINTS, 0, pointBuffer.count);
+ }
+ }
+};
+
+registerType("PointList", [PointList, PointList$, null]);
+
+
+// wwtlib.TimeSeriesLineVertex
+
+export function TimeSeriesLineVertex() {
+ this.position = new Vector3d();
+ this.normal = new Vector3d();
+ this.tu = 0;
+ this.tv = 0;
+}
+
+TimeSeriesLineVertex.create = function (position, normal, time, color) {
+ var temp = new TimeSeriesLineVertex();
+ temp.position = position;
+ temp.normal = normal;
+ temp.tu = time;
+ temp.tv = 0;
+ temp.color = color;
+ return temp;
+};
+
+var TimeSeriesLineVertex$ = {
+ get_color: function () {
+ return this.color;
+ },
+
+ set_color: function (value) {
+ this.color = value;
+ return value;
+ }
+};
+
+registerType("TimeSeriesLineVertex", [TimeSeriesLineVertex, TimeSeriesLineVertex$, null]);
+
+
+// wwtlib.TimeSeriesPointVertex
+
+export function TimeSeriesPointVertex() {
+ this.pointSize = 0;
+ this.tu = 0;
+ this.tv = 0;
+}
+
+TimeSeriesPointVertex.create = function (position, size, time, color) {
+ var tmp = new TimeSeriesPointVertex();
+ tmp.position = position;
+ tmp.pointSize = size;
+ tmp.tu = time;
+ tmp.tv = 0;
+ tmp.color = color;
+ return tmp;
+};
+
+var TimeSeriesPointVertex$ = {
+ get_color: function () {
+ return this.color;
+ },
+
+ set_color: function (value) {
+ this.color = value;
+ return value;
+ }
+};
+
+registerType("TimeSeriesPointVertex", [TimeSeriesPointVertex, TimeSeriesPointVertex$, null]);
diff --git a/engine/esm/graphics/shaders.js b/engine/esm/graphics/shaders.js
new file mode 100644
index 00000000..2e162a46
--- /dev/null
+++ b/engine/esm/graphics/shaders.js
@@ -0,0 +1,2181 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Core WebGL shaders for the WWT engine.
+
+import { registerType } from "../typesystem.js";
+import { Matrix3d, Vector3d } from "../double3d.js";
+import { Color } from "../color.js";
+import { set_tileUvMultiple, set_tileDemEnabled } from "../render_globals.js";
+import { WEBGL } from "./webgl_constants.js";
+import { Texture } from "./texture.js";
+
+
+// wwtlib.SimpleLineShader
+
+export function SimpleLineShader() { }
+
+SimpleLineShader.vertLoc = 0;
+SimpleLineShader.initialized = false;
+SimpleLineShader._prog = null;
+
+SimpleLineShader.init = function (renderContext) {
+ var gl = renderContext.gl;
+
+ const fragShaderText = `\
+ precision highp float;
+ uniform vec4 lineColor;
+
+ void main(void) {
+ gl_FragColor = lineColor;
+ }
+ `;
+
+ const vertexShaderText = `\
+ attribute vec3 aVertexPosition;
+
+ uniform mat4 uMVMatrix;
+ uniform mat4 uPMatrix;
+
+ void main(void) {
+ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
+ }
+ `;
+
+ SimpleLineShader._frag = gl.createShader(WEBGL.FRAGMENT_SHADER);
+ gl.shaderSource(SimpleLineShader._frag, fragShaderText);
+ gl.compileShader(SimpleLineShader._frag);
+ var stat = gl.getShaderParameter(SimpleLineShader._frag, WEBGL.COMPILE_STATUS);
+ SimpleLineShader._vert = gl.createShader(WEBGL.VERTEX_SHADER);
+ gl.shaderSource(SimpleLineShader._vert, vertexShaderText);
+ gl.compileShader(SimpleLineShader._vert);
+ var stat1 = gl.getShaderParameter(SimpleLineShader._vert, WEBGL.COMPILE_STATUS);
+ SimpleLineShader._prog = gl.createProgram();
+ gl.attachShader(SimpleLineShader._prog, SimpleLineShader._vert);
+ gl.attachShader(SimpleLineShader._prog, SimpleLineShader._frag);
+ gl.linkProgram(SimpleLineShader._prog);
+ var errcode = gl.getProgramParameter(SimpleLineShader._prog, WEBGL.LINK_STATUS);
+ gl.useProgram(SimpleLineShader._prog);
+ SimpleLineShader.vertLoc = gl.getAttribLocation(SimpleLineShader._prog, 'aVertexPosition');
+ SimpleLineShader.lineColorLoc = gl.getUniformLocation(SimpleLineShader._prog, 'lineColor');
+ SimpleLineShader.projMatLoc = gl.getUniformLocation(SimpleLineShader._prog, 'uPMatrix');
+ SimpleLineShader.mvMatLoc = gl.getUniformLocation(SimpleLineShader._prog, 'uMVMatrix');
+ gl.enable(WEBGL.BLEND);
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ SimpleLineShader.initialized = true;
+};
+
+SimpleLineShader.use = function (renderContext, vertex, lineColor, useDepth) {
+ var gl = renderContext.gl;
+ if (gl != null) {
+ if (!SimpleLineShader.initialized) {
+ SimpleLineShader.init(renderContext);
+ }
+ gl.useProgram(SimpleLineShader._prog);
+ var mvMat = Matrix3d.multiplyMatrix(renderContext.get_world(), renderContext.get_view());
+ gl.uniformMatrix4fv(SimpleLineShader.mvMatLoc, false, mvMat.floatArray());
+ gl.uniformMatrix4fv(SimpleLineShader.projMatLoc, false, renderContext.get_projection().floatArray());
+ gl.uniform4f(SimpleLineShader.lineColorLoc, lineColor.r / 255, lineColor.g / 255, lineColor.b / 255, 1);
+ if (renderContext.space || !useDepth) {
+ gl.disable(WEBGL.DEPTH_TEST);
+ } else {
+ gl.enable(WEBGL.DEPTH_TEST);
+ }
+ gl.disableVertexAttribArray(0);
+ gl.disableVertexAttribArray(1);
+ gl.disableVertexAttribArray(2);
+ gl.disableVertexAttribArray(3);
+ gl.enableVertexAttribArray(SimpleLineShader.vertLoc);
+ gl.bindBuffer(WEBGL.ARRAY_BUFFER, vertex);
+ gl.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, null);
+ gl.vertexAttribPointer(SimpleLineShader.vertLoc, 3, WEBGL.FLOAT, false, 0, 0);
+ gl.lineWidth(1);
+ gl.enable(WEBGL.BLEND);
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ }
+};
+
+var SimpleLineShader$ = {};
+
+registerType("SimpleLineShader", [SimpleLineShader, SimpleLineShader$, null]);
+
+
+// wwtlib.SimpleLineShader2D
+
+export function SimpleLineShader2D() { }
+
+SimpleLineShader2D.vertLoc = 0;
+SimpleLineShader2D.initialized = false;
+SimpleLineShader2D._prog = null;
+
+SimpleLineShader2D.init = function (renderContext) {
+ var gl = renderContext.gl;
+
+ const fragShaderText = `\
+ precision highp float;
+ uniform vec4 lineColor;
+
+ void main(void) {
+ gl_FragColor = lineColor;
+ }
+ `;
+
+ const vertexShaderText = `\
+ attribute vec3 aVertexPosition;
+
+ void main(void) {
+ gl_Position = vec4(aVertexPosition, 1.0);
+ }
+ `;
+
+ SimpleLineShader2D._frag = gl.createShader(WEBGL.FRAGMENT_SHADER);
+ gl.shaderSource(SimpleLineShader2D._frag, fragShaderText);
+ gl.compileShader(SimpleLineShader2D._frag);
+ var stat = gl.getShaderParameter(SimpleLineShader2D._frag, WEBGL.COMPILE_STATUS);
+ SimpleLineShader2D._vert = gl.createShader(WEBGL.VERTEX_SHADER);
+ gl.shaderSource(SimpleLineShader2D._vert, vertexShaderText);
+ gl.compileShader(SimpleLineShader2D._vert);
+ var stat1 = gl.getShaderParameter(SimpleLineShader2D._vert, WEBGL.COMPILE_STATUS);
+ SimpleLineShader2D._prog = gl.createProgram();
+ gl.attachShader(SimpleLineShader2D._prog, SimpleLineShader2D._vert);
+ gl.attachShader(SimpleLineShader2D._prog, SimpleLineShader2D._frag);
+ gl.linkProgram(SimpleLineShader2D._prog);
+ var errcode = gl.getProgramParameter(SimpleLineShader2D._prog, WEBGL.LINK_STATUS);
+ gl.useProgram(SimpleLineShader2D._prog);
+ SimpleLineShader2D.vertLoc = gl.getAttribLocation(SimpleLineShader2D._prog, 'aVertexPosition');
+ SimpleLineShader2D.lineColorLoc = gl.getUniformLocation(SimpleLineShader2D._prog, 'lineColor');
+ gl.enable(WEBGL.BLEND);
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ SimpleLineShader2D.initialized = true;
+};
+
+SimpleLineShader2D.use = function (renderContext, vertex, lineColor, useDepth) {
+ var gl = renderContext.gl;
+ if (gl != null) {
+ if (!SimpleLineShader2D.initialized) {
+ SimpleLineShader2D.init(renderContext);
+ }
+ gl.useProgram(SimpleLineShader2D._prog);
+ var mvMat = Matrix3d.multiplyMatrix(renderContext.get_world(), renderContext.get_view());
+ gl.uniform4f(SimpleLineShader2D.lineColorLoc, lineColor.r / 255, lineColor.g / 255, lineColor.b / 255, 1);
+ if (renderContext.space || !useDepth) {
+ gl.disable(WEBGL.DEPTH_TEST);
+ } else {
+ gl.enable(WEBGL.DEPTH_TEST);
+ }
+ gl.disableVertexAttribArray(0);
+ gl.disableVertexAttribArray(1);
+ gl.disableVertexAttribArray(2);
+ gl.disableVertexAttribArray(3);
+ gl.enableVertexAttribArray(SimpleLineShader2D.vertLoc);
+ gl.bindBuffer(WEBGL.ARRAY_BUFFER, vertex);
+ gl.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, null);
+ gl.vertexAttribPointer(SimpleLineShader2D.vertLoc, 3, WEBGL.FLOAT, false, 0, 0);
+ gl.lineWidth(1);
+ gl.enable(WEBGL.BLEND);
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ }
+};
+
+var SimpleLineShader2D$ = {};
+
+registerType("SimpleLineShader2D", [SimpleLineShader2D, SimpleLineShader2D$, null]);
+
+
+// wwtlib.OrbitLineShader
+
+export function OrbitLineShader() { }
+
+OrbitLineShader.vertLoc = 0;
+OrbitLineShader.colorLoc = 0;
+OrbitLineShader.initialized = false;
+OrbitLineShader._prog = null;
+
+OrbitLineShader.init = function (renderContext) {
+ var gl = renderContext.gl;
+
+ const fragShaderText = `\
+ precision highp float;
+ uniform vec4 lineColor;
+ varying lowp vec4 vColor;
+
+ void main(void) {
+ gl_FragColor = lineColor * vColor;
+ }
+ `;
+
+ const vertexShaderText = `\
+ attribute vec3 aVertexPosition;
+ attribute vec4 aVertexColor;
+
+ uniform mat4 uMVMatrix;
+ uniform mat4 uPMatrix;
+ varying lowp vec4 vColor;
+
+ void main(void) {
+ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
+ vColor = aVertexColor;
+ }
+ `;
+
+ OrbitLineShader._frag = gl.createShader(WEBGL.FRAGMENT_SHADER);
+ gl.shaderSource(OrbitLineShader._frag, fragShaderText);
+ gl.compileShader(OrbitLineShader._frag);
+ var stat = gl.getShaderParameter(OrbitLineShader._frag, WEBGL.COMPILE_STATUS);
+ OrbitLineShader._vert = gl.createShader(WEBGL.VERTEX_SHADER);
+ gl.shaderSource(OrbitLineShader._vert, vertexShaderText);
+ gl.compileShader(OrbitLineShader._vert);
+ var stat1 = gl.getShaderParameter(OrbitLineShader._vert, WEBGL.COMPILE_STATUS);
+ OrbitLineShader._prog = gl.createProgram();
+ gl.attachShader(OrbitLineShader._prog, OrbitLineShader._vert);
+ gl.attachShader(OrbitLineShader._prog, OrbitLineShader._frag);
+ gl.linkProgram(OrbitLineShader._prog);
+ var errcode = gl.getProgramParameter(OrbitLineShader._prog, WEBGL.LINK_STATUS);
+ gl.useProgram(OrbitLineShader._prog);
+ OrbitLineShader.vertLoc = gl.getAttribLocation(OrbitLineShader._prog, 'aVertexPosition');
+ OrbitLineShader.colorLoc = gl.getAttribLocation(OrbitLineShader._prog, 'aVertexColor');
+ OrbitLineShader.lineColorLoc = gl.getUniformLocation(OrbitLineShader._prog, 'lineColor');
+ OrbitLineShader.projMatLoc = gl.getUniformLocation(OrbitLineShader._prog, 'uPMatrix');
+ OrbitLineShader.mvMatLoc = gl.getUniformLocation(OrbitLineShader._prog, 'uMVMatrix');
+ gl.enable(WEBGL.BLEND);
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ OrbitLineShader.initialized = true;
+};
+
+OrbitLineShader.use = function (renderContext, vertex, lineColor) {
+ var gl = renderContext.gl;
+ if (gl != null) {
+ if (!OrbitLineShader.initialized) {
+ OrbitLineShader.init(renderContext);
+ }
+ gl.useProgram(OrbitLineShader._prog);
+ var mvMat = Matrix3d.multiplyMatrix(renderContext.get_world(), renderContext.get_view());
+ gl.uniformMatrix4fv(OrbitLineShader.mvMatLoc, false, mvMat.floatArray());
+ gl.uniformMatrix4fv(OrbitLineShader.projMatLoc, false, renderContext.get_projection().floatArray());
+ gl.uniform4f(OrbitLineShader.lineColorLoc, lineColor.r / 255, lineColor.g / 255, lineColor.b / 255, 1);
+ if (renderContext.space) {
+ gl.disable(WEBGL.DEPTH_TEST);
+ } else {
+ gl.enable(WEBGL.DEPTH_TEST);
+ }
+ gl.disableVertexAttribArray(0);
+ gl.disableVertexAttribArray(1);
+ gl.disableVertexAttribArray(2);
+ gl.disableVertexAttribArray(3);
+ gl.bindBuffer(WEBGL.ARRAY_BUFFER, vertex);
+ gl.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, null);
+ gl.enableVertexAttribArray(OrbitLineShader.vertLoc);
+ gl.enableVertexAttribArray(OrbitLineShader.colorLoc);
+ gl.vertexAttribPointer(OrbitLineShader.vertLoc, 3, WEBGL.FLOAT, false, 28, 0);
+ gl.vertexAttribPointer(OrbitLineShader.colorLoc, 4, WEBGL.FLOAT, false, 28, 12);
+ gl.lineWidth(1);
+ gl.enable(WEBGL.BLEND);
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ }
+};
+
+var OrbitLineShader$ = {};
+
+registerType("OrbitLineShader", [OrbitLineShader, OrbitLineShader$, null]);
+
+
+// wwtlib.LineShaderNormalDates
+
+export function LineShaderNormalDates() { }
+
+LineShaderNormalDates.vertLoc = 0;
+LineShaderNormalDates.colorLoc = 0;
+LineShaderNormalDates.timeLoc = 0;
+LineShaderNormalDates.initialized = false;
+LineShaderNormalDates._prog = null;
+
+LineShaderNormalDates.init = function (renderContext) {
+ var gl = renderContext.gl;
+
+ const fragShaderText = `\
+ precision highp float;
+ uniform vec4 lineColor;
+ varying lowp vec4 vColor;
+
+ void main(void)
+ {
+ gl_FragColor = lineColor * vColor;
+ }
+ `;
+
+ const vertexShaderText = `\
+ attribute vec3 aVertexPosition;
+ attribute vec4 aVertexColor;
+ attribute vec2 aTime;
+ uniform mat4 uMVMatrix;
+ uniform mat4 uPMatrix;
+ uniform float jNow;
+ uniform float decay;
+
+ varying lowp vec4 vColor;
+
+ void main(void)
+ {
+ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
+ float dAlpha = 1.0;
+
+ if (decay > 0.0)
+ {
+ dAlpha = 1.0 - ((jNow - aTime.y) / decay);
+ if (dAlpha > 1.0 )
+ {
+ dAlpha = 1.0;
+ }
+ }
+
+ if (jNow < aTime.x && decay > 0.0)
+ {
+ vColor = vec4(1, 1, 1, 1);
+ }
+ else
+ {
+ vColor = vec4(aVertexColor.r, aVertexColor.g, aVertexColor.b, dAlpha * aVertexColor.a);
+ }
+ }
+ `;
+
+ LineShaderNormalDates._frag = gl.createShader(WEBGL.FRAGMENT_SHADER);
+ gl.shaderSource(LineShaderNormalDates._frag, fragShaderText);
+ gl.compileShader(LineShaderNormalDates._frag);
+ var stat = gl.getShaderParameter(LineShaderNormalDates._frag, WEBGL.COMPILE_STATUS);
+ LineShaderNormalDates._vert = gl.createShader(WEBGL.VERTEX_SHADER);
+ gl.shaderSource(LineShaderNormalDates._vert, vertexShaderText);
+ gl.compileShader(LineShaderNormalDates._vert);
+ var stat1 = gl.getShaderParameter(LineShaderNormalDates._vert, WEBGL.COMPILE_STATUS);
+ LineShaderNormalDates._prog = gl.createProgram();
+ gl.attachShader(LineShaderNormalDates._prog, LineShaderNormalDates._vert);
+ gl.attachShader(LineShaderNormalDates._prog, LineShaderNormalDates._frag);
+ gl.linkProgram(LineShaderNormalDates._prog);
+ var errcode = gl.getProgramParameter(LineShaderNormalDates._prog, WEBGL.LINK_STATUS);
+ gl.useProgram(LineShaderNormalDates._prog);
+ LineShaderNormalDates.vertLoc = gl.getAttribLocation(LineShaderNormalDates._prog, 'aVertexPosition');
+ LineShaderNormalDates.colorLoc = gl.getAttribLocation(LineShaderNormalDates._prog, 'aVertexColor');
+ LineShaderNormalDates.timeLoc = gl.getAttribLocation(LineShaderNormalDates._prog, 'aTime');
+ LineShaderNormalDates.lineColorLoc = gl.getUniformLocation(LineShaderNormalDates._prog, 'lineColor');
+ LineShaderNormalDates.projMatLoc = gl.getUniformLocation(LineShaderNormalDates._prog, 'uPMatrix');
+ LineShaderNormalDates.mvMatLoc = gl.getUniformLocation(LineShaderNormalDates._prog, 'uMVMatrix');
+ LineShaderNormalDates.jNowLoc = gl.getUniformLocation(LineShaderNormalDates._prog, 'jNow');
+ LineShaderNormalDates.decayLoc = gl.getUniformLocation(LineShaderNormalDates._prog, 'decay');
+ gl.enable(WEBGL.BLEND);
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ LineShaderNormalDates.initialized = true;
+};
+
+LineShaderNormalDates.use = function (renderContext, vertex, lineColor, zBuffer, jNow, decay) {
+ var gl = renderContext.gl;
+ if (gl != null) {
+ if (!LineShaderNormalDates.initialized) {
+ LineShaderNormalDates.init(renderContext);
+ }
+ gl.useProgram(LineShaderNormalDates._prog);
+ var mvMat = Matrix3d.multiplyMatrix(renderContext.get_world(), renderContext.get_view());
+ gl.uniformMatrix4fv(LineShaderNormalDates.mvMatLoc, false, mvMat.floatArray());
+ gl.uniformMatrix4fv(LineShaderNormalDates.projMatLoc, false, renderContext.get_projection().floatArray());
+ gl.uniform4f(LineShaderNormalDates.lineColorLoc, lineColor.r / 255, lineColor.g / 255, lineColor.b / 255, 1);
+ gl.uniform1f(LineShaderNormalDates.jNowLoc, jNow);
+ gl.uniform1f(LineShaderNormalDates.decayLoc, decay);
+ if (zBuffer) {
+ gl.enable(WEBGL.DEPTH_TEST);
+ } else {
+ gl.disable(WEBGL.DEPTH_TEST);
+ }
+ gl.disableVertexAttribArray(0);
+ gl.disableVertexAttribArray(1);
+ gl.disableVertexAttribArray(2);
+ gl.disableVertexAttribArray(3);
+ gl.bindBuffer(WEBGL.ARRAY_BUFFER, vertex);
+ gl.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, null);
+ gl.enableVertexAttribArray(LineShaderNormalDates.vertLoc);
+ gl.enableVertexAttribArray(LineShaderNormalDates.colorLoc);
+ gl.vertexAttribPointer(LineShaderNormalDates.vertLoc, 3, WEBGL.FLOAT, false, 36, 0);
+ gl.vertexAttribPointer(LineShaderNormalDates.colorLoc, 4, WEBGL.FLOAT, false, 36, 12);
+ gl.vertexAttribPointer(LineShaderNormalDates.timeLoc, 2, WEBGL.FLOAT, false, 36, 28);
+ gl.lineWidth(1);
+ gl.enable(WEBGL.BLEND);
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ }
+};
+
+var LineShaderNormalDates$ = {};
+
+registerType("LineShaderNormalDates", [LineShaderNormalDates, LineShaderNormalDates$, null]);
+
+
+// wwtlib.TimeSeriesPointSpriteShader
+
+export function TimeSeriesPointSpriteShader() { }
+
+TimeSeriesPointSpriteShader.vertLoc = 0;
+TimeSeriesPointSpriteShader.colorLoc = 0;
+TimeSeriesPointSpriteShader.pointSizeLoc = 0;
+TimeSeriesPointSpriteShader.timeLoc = 0;
+TimeSeriesPointSpriteShader.initialized = false;
+TimeSeriesPointSpriteShader._prog = null;
+
+TimeSeriesPointSpriteShader.init = function (renderContext) {
+ var gl = renderContext.gl;
+
+ const fragShaderText = `\
+ precision mediump float;
+ uniform vec4 lineColor;
+ varying lowp vec4 vColor;
+ uniform sampler2D uSampler;
+
+ void main(void)
+ {
+ vec4 texColor;
+ texColor = texture2D(uSampler, gl_PointCoord);
+ gl_FragColor = lineColor * vColor * texColor;
+ }
+ `;
+
+ const vertexShaderText = `\
+ attribute vec3 aVertexPosition;
+ attribute vec4 aVertexColor;
+ attribute vec2 aTime;
+ attribute float aPointSize;
+ uniform mat4 uMVMatrix;
+ uniform mat4 uPMatrix;
+ uniform float jNow;
+ uniform vec3 cameraPosition;
+ uniform float decay;
+ uniform float scale;
+ uniform float minSize;
+ uniform float sky;
+ uniform float showFarSide;
+
+ varying lowp vec4 vColor;
+
+ void main(void)
+ {
+ float dotCam = dot( normalize(cameraPosition-aVertexPosition), normalize(aVertexPosition));
+ float dist = distance(aVertexPosition, cameraPosition);
+ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
+ float dAlpha = 1.0;
+
+ if ( decay > 0.0)
+ {
+ dAlpha = 1.0 - ((jNow - aTime.y) / decay);
+ if (dAlpha > 1.0 )
+ {
+ dAlpha = 1.0;
+ }
+ }
+
+ if ( showFarSide == 0.0 && (dotCam * sky) < 0.0 || (jNow < aTime.x && decay > 0.0))
+ {
+ vColor = vec4(0.0, 0.0, 0.0, 0.0);
+ }
+ else
+ {
+ vColor = vec4(aVertexColor.r, aVertexColor.g, aVertexColor.b, dAlpha);
+ }
+
+ float lSize = scale;
+
+ if (scale < 0.0)
+ {
+ lSize = -scale;
+ dist = 1.0;
+ }
+
+ gl_PointSize = max(minSize, (lSize * ( aPointSize ) / dist));
+ }
+ `;
+
+ TimeSeriesPointSpriteShader._frag = gl.createShader(WEBGL.FRAGMENT_SHADER);
+ gl.shaderSource(TimeSeriesPointSpriteShader._frag, fragShaderText);
+ gl.compileShader(TimeSeriesPointSpriteShader._frag);
+ var stat = gl.getShaderParameter(TimeSeriesPointSpriteShader._frag, WEBGL.COMPILE_STATUS);
+ TimeSeriesPointSpriteShader._vert = gl.createShader(WEBGL.VERTEX_SHADER);
+ gl.shaderSource(TimeSeriesPointSpriteShader._vert, vertexShaderText);
+ gl.compileShader(TimeSeriesPointSpriteShader._vert);
+ var stat1 = gl.getShaderParameter(TimeSeriesPointSpriteShader._vert, WEBGL.COMPILE_STATUS);
+ var compilationLog = gl.getShaderInfoLog(TimeSeriesPointSpriteShader._vert);
+ TimeSeriesPointSpriteShader._prog = gl.createProgram();
+ gl.attachShader(TimeSeriesPointSpriteShader._prog, TimeSeriesPointSpriteShader._vert);
+ gl.attachShader(TimeSeriesPointSpriteShader._prog, TimeSeriesPointSpriteShader._frag);
+ gl.linkProgram(TimeSeriesPointSpriteShader._prog);
+ var errcode = gl.getProgramParameter(TimeSeriesPointSpriteShader._prog, WEBGL.LINK_STATUS);
+ gl.useProgram(TimeSeriesPointSpriteShader._prog);
+ TimeSeriesPointSpriteShader.vertLoc = gl.getAttribLocation(TimeSeriesPointSpriteShader._prog, 'aVertexPosition');
+ TimeSeriesPointSpriteShader.colorLoc = gl.getAttribLocation(TimeSeriesPointSpriteShader._prog, 'aVertexColor');
+ TimeSeriesPointSpriteShader.pointSizeLoc = gl.getAttribLocation(TimeSeriesPointSpriteShader._prog, 'aPointSize');
+ TimeSeriesPointSpriteShader.timeLoc = gl.getAttribLocation(TimeSeriesPointSpriteShader._prog, 'aTime');
+ TimeSeriesPointSpriteShader.projMatLoc = gl.getUniformLocation(TimeSeriesPointSpriteShader._prog, 'uPMatrix');
+ TimeSeriesPointSpriteShader.mvMatLoc = gl.getUniformLocation(TimeSeriesPointSpriteShader._prog, 'uMVMatrix');
+ TimeSeriesPointSpriteShader.sampLoc = gl.getUniformLocation(TimeSeriesPointSpriteShader._prog, 'uSampler');
+ TimeSeriesPointSpriteShader.jNowLoc = gl.getUniformLocation(TimeSeriesPointSpriteShader._prog, 'jNow');
+ TimeSeriesPointSpriteShader.decayLoc = gl.getUniformLocation(TimeSeriesPointSpriteShader._prog, 'decay');
+ TimeSeriesPointSpriteShader.lineColorLoc = gl.getUniformLocation(TimeSeriesPointSpriteShader._prog, 'lineColor');
+ TimeSeriesPointSpriteShader.cameraPosLoc = gl.getUniformLocation(TimeSeriesPointSpriteShader._prog, 'cameraPosition');
+ TimeSeriesPointSpriteShader.scaleLoc = gl.getUniformLocation(TimeSeriesPointSpriteShader._prog, 'scale');
+ TimeSeriesPointSpriteShader.skyLoc = gl.getUniformLocation(TimeSeriesPointSpriteShader._prog, 'sky');
+ TimeSeriesPointSpriteShader.showFarSideLoc = gl.getUniformLocation(TimeSeriesPointSpriteShader._prog, 'showFarSide');
+ TimeSeriesPointSpriteShader.minSizeLoc = gl.getUniformLocation(TimeSeriesPointSpriteShader._prog, 'minSize');
+ gl.enable(WEBGL.BLEND);
+ TimeSeriesPointSpriteShader.initialized = true;
+};
+
+TimeSeriesPointSpriteShader.use = function (renderContext, vertex, texture, lineColor, zBuffer, jNow, decay, camera, scale, minSize, showFarSide, sky) {
+ if (texture == null) {
+ texture = Texture.getEmpty();
+ }
+ var gl = renderContext.gl;
+ if (gl != null) {
+ if (!TimeSeriesPointSpriteShader.initialized) {
+ TimeSeriesPointSpriteShader.init(renderContext);
+ }
+ gl.useProgram(TimeSeriesPointSpriteShader._prog);
+ var mvMat = Matrix3d.multiplyMatrix(renderContext.get_world(), renderContext.get_view());
+ gl.uniformMatrix4fv(TimeSeriesPointSpriteShader.mvMatLoc, false, mvMat.floatArray());
+ gl.uniformMatrix4fv(TimeSeriesPointSpriteShader.projMatLoc, false, renderContext.get_projection().floatArray());
+ gl.uniform1i(TimeSeriesPointSpriteShader.sampLoc, 0);
+ gl.uniform1f(TimeSeriesPointSpriteShader.jNowLoc, jNow);
+ gl.uniform1f(TimeSeriesPointSpriteShader.decayLoc, decay);
+ gl.uniform4f(TimeSeriesPointSpriteShader.lineColorLoc, lineColor.r / 255, lineColor.g / 255, lineColor.b / 255, lineColor.a / 255);
+ gl.uniform3f(TimeSeriesPointSpriteShader.cameraPosLoc, camera.x, camera.y, camera.z);
+ gl.uniform1f(TimeSeriesPointSpriteShader.scaleLoc, scale);
+ gl.uniform1f(TimeSeriesPointSpriteShader.minSizeLoc, minSize);
+ gl.uniform1f(TimeSeriesPointSpriteShader.showFarSideLoc, (showFarSide) ? 1 : 0);
+ gl.uniform1f(TimeSeriesPointSpriteShader.skyLoc, (sky) ? -1 : 1);
+ if (zBuffer) {
+ gl.enable(WEBGL.DEPTH_TEST);
+ } else {
+ gl.disable(WEBGL.DEPTH_TEST);
+ }
+ gl.disableVertexAttribArray(0);
+ gl.disableVertexAttribArray(1);
+ gl.disableVertexAttribArray(2);
+ gl.disableVertexAttribArray(3);
+ gl.bindBuffer(WEBGL.ARRAY_BUFFER, vertex);
+ gl.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, null);
+ gl.enableVertexAttribArray(TimeSeriesPointSpriteShader.vertLoc);
+ gl.enableVertexAttribArray(TimeSeriesPointSpriteShader.colorLoc);
+ gl.enableVertexAttribArray(TimeSeriesPointSpriteShader.pointSizeLoc);
+ gl.enableVertexAttribArray(TimeSeriesPointSpriteShader.timeLoc);
+ gl.vertexAttribPointer(TimeSeriesPointSpriteShader.vertLoc, 3, WEBGL.FLOAT, false, 40, 0);
+ gl.vertexAttribPointer(TimeSeriesPointSpriteShader.colorLoc, 4, WEBGL.FLOAT, false, 40, 12);
+ gl.vertexAttribPointer(TimeSeriesPointSpriteShader.pointSizeLoc, 1, WEBGL.FLOAT, false, 40, 36);
+ gl.vertexAttribPointer(TimeSeriesPointSpriteShader.timeLoc, 2, WEBGL.FLOAT, false, 40, 28);
+ gl.activeTexture(WEBGL.TEXTURE0);
+ gl.bindTexture(WEBGL.TEXTURE_2D, texture);
+ gl.lineWidth(1);
+ gl.enable(WEBGL.BLEND);
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE);
+ }
+};
+
+var TimeSeriesPointSpriteShader$ = {};
+
+registerType("TimeSeriesPointSpriteShader", [TimeSeriesPointSpriteShader, TimeSeriesPointSpriteShader$, null]);
+
+// wwtlib.KeplerPointSpriteShader
+
+export function KeplerPointSpriteShader() { }
+
+KeplerPointSpriteShader.abcLoc = 0;
+KeplerPointSpriteShader.abcLoc1 = 0;
+KeplerPointSpriteShader.pointSizeLoc = 0;
+KeplerPointSpriteShader.colorLoc = 0;
+KeplerPointSpriteShader.weLoc = 0;
+KeplerPointSpriteShader.nTLoc = 0;
+KeplerPointSpriteShader.azLoc = 0;
+KeplerPointSpriteShader.orbitLoc = 0;
+KeplerPointSpriteShader.initialized = false;
+KeplerPointSpriteShader._prog = null;
+
+KeplerPointSpriteShader.init = function (renderContext) {
+ var gl = renderContext.gl;
+
+ const fragShaderText = `\
+ precision mediump float;
+ uniform vec4 lineColor;
+ varying lowp vec4 vColor;
+ uniform sampler2D uSampler;
+
+ void main(void)
+ {
+ vec4 texColor;
+ texColor = texture2D(uSampler, gl_PointCoord);
+ gl_FragColor = lineColor * vColor * texColor;
+ }
+ `;
+
+ const vertexShaderText = `\
+ attribute vec3 ABC;
+ attribute vec3 abc;
+ attribute float PointSize;
+ attribute vec4 Color;
+ attribute vec2 we;
+ attribute vec2 nT;
+ attribute vec2 az;
+ attribute vec2 orbit;
+ uniform mat4 uMVMatrix;
+ uniform mat4 uPMatrix;
+ uniform float jNow;
+ uniform vec3 cameraPosition;
+ uniform float MM;
+ uniform float scaling;
+ uniform float minSize;
+ uniform float opacity;
+ varying lowp vec4 vColor;
+
+ void main(void)
+ {
+ float M = nT.x * (jNow - nT.y) * 0.01745329251994;
+ float e = we.y;
+ float a = az.x;
+ float PI = 3.1415926535897932384;
+ float w = we.x* 0.01745329251994;
+ float F = 1.0;
+
+ if (M < 0.0)
+ F = -1.0;
+
+ M = abs(M) / (2.0 * PI);
+ M = (M - float(int(M)))*2.0 *PI *F;
+
+ if (MM != 0.0)
+ {
+ M = MM + (1.0- orbit.x) *2.0 *PI;
+ if (M > (2.0*PI))
+ M = M - (2.0*PI);
+ }
+
+ if (M < 0.0)
+ M += 2.0 *PI;
+
+ F = 1.0;
+ if (M > PI)
+ F = -1.0;
+
+ if (M > PI)
+ M = 2.0 *PI - M;
+
+ float E = PI / 2.0;
+ float scale = PI / 4.0;
+
+ for (int i =0; i<23; i++)
+ {
+ float R = E - e *sin(E);
+ if (M > R)
+ E += scale;
+ else
+ E -= scale;
+ scale /= 2.0;
+ }
+
+ E = E * F;
+
+ float v = 2.0 * atan(sqrt((1.0 + e) / (1.0 -e )) * tan(E/2.0));
+ float r = a * (1.0-e * cos(E));
+
+ vec4 pnt;
+ pnt.x = r * abc.x * sin(ABC.x + w + v);
+ pnt.z = r * abc.y * sin(ABC.y + w + v);
+ pnt.y = r * abc.z * sin(ABC.z + w + v);
+ pnt.w = 1.0;
+
+ float dist = distance(pnt.xyz, cameraPosition.xyz);
+ gl_Position = uPMatrix * uMVMatrix * pnt;
+ vColor.a = opacity * (1.0-(orbit.x));
+ vColor.r = Color.r;
+ vColor.g = Color.g;
+ vColor.b = Color.b;
+ gl_PointSize = max(minSize, scaling * (PointSize / dist));
+ }
+ `;
+
+ KeplerPointSpriteShader._frag = gl.createShader(WEBGL.FRAGMENT_SHADER);
+ gl.shaderSource(KeplerPointSpriteShader._frag, fragShaderText);
+ gl.compileShader(KeplerPointSpriteShader._frag);
+ var stat = gl.getShaderParameter(KeplerPointSpriteShader._frag, WEBGL.COMPILE_STATUS);
+ KeplerPointSpriteShader._vert = gl.createShader(WEBGL.VERTEX_SHADER);
+ gl.shaderSource(KeplerPointSpriteShader._vert, vertexShaderText);
+ gl.compileShader(KeplerPointSpriteShader._vert);
+ var stat1 = gl.getShaderParameter(KeplerPointSpriteShader._vert, WEBGL.COMPILE_STATUS);
+ var compilationLog = gl.getShaderInfoLog(KeplerPointSpriteShader._vert);
+ KeplerPointSpriteShader._prog = gl.createProgram();
+ gl.attachShader(KeplerPointSpriteShader._prog, KeplerPointSpriteShader._vert);
+ gl.attachShader(KeplerPointSpriteShader._prog, KeplerPointSpriteShader._frag);
+ gl.linkProgram(KeplerPointSpriteShader._prog);
+ var errcode = gl.getProgramParameter(KeplerPointSpriteShader._prog, WEBGL.LINK_STATUS);
+ gl.useProgram(KeplerPointSpriteShader._prog);
+ KeplerPointSpriteShader.abcLoc1 = gl.getAttribLocation(KeplerPointSpriteShader._prog, 'abc');
+ KeplerPointSpriteShader.abcLoc = gl.getAttribLocation(KeplerPointSpriteShader._prog, 'ABC');
+ KeplerPointSpriteShader.pointSizeLoc = gl.getAttribLocation(KeplerPointSpriteShader._prog, 'PointSize');
+ KeplerPointSpriteShader.colorLoc = gl.getAttribLocation(KeplerPointSpriteShader._prog, 'Color');
+ KeplerPointSpriteShader.weLoc = gl.getAttribLocation(KeplerPointSpriteShader._prog, 'we');
+ KeplerPointSpriteShader.nTLoc = gl.getAttribLocation(KeplerPointSpriteShader._prog, 'nT');
+ KeplerPointSpriteShader.azLoc = gl.getAttribLocation(KeplerPointSpriteShader._prog, 'az');
+ KeplerPointSpriteShader.orbitLoc = gl.getAttribLocation(KeplerPointSpriteShader._prog, 'orbit');
+ KeplerPointSpriteShader.projMatLoc = gl.getUniformLocation(KeplerPointSpriteShader._prog, 'uPMatrix');
+ KeplerPointSpriteShader.mvMatLoc = gl.getUniformLocation(KeplerPointSpriteShader._prog, 'uMVMatrix');
+ KeplerPointSpriteShader.jNowLoc = gl.getUniformLocation(KeplerPointSpriteShader._prog, 'jNow');
+ KeplerPointSpriteShader.cameraPosLoc = gl.getUniformLocation(KeplerPointSpriteShader._prog, 'cameraPosition');
+ KeplerPointSpriteShader.mmLoc = gl.getUniformLocation(KeplerPointSpriteShader._prog, 'MM');
+ KeplerPointSpriteShader.scaleLoc = gl.getUniformLocation(KeplerPointSpriteShader._prog, 'scaling');
+ KeplerPointSpriteShader.minSizeLoc = gl.getUniformLocation(KeplerPointSpriteShader._prog, 'minSize');
+ KeplerPointSpriteShader.lineColorLoc = gl.getUniformLocation(KeplerPointSpriteShader._prog, 'lineColor');
+ KeplerPointSpriteShader.opacityLoc = gl.getUniformLocation(KeplerPointSpriteShader._prog, 'opacity');
+ KeplerPointSpriteShader.sampLoc = gl.getUniformLocation(KeplerPointSpriteShader._prog, 'uSampler');
+ gl.enable(WEBGL.BLEND);
+ KeplerPointSpriteShader.initialized = true;
+};
+
+KeplerPointSpriteShader.use = function (renderContext, worldView, vertex, texture, lineColor, opacity, zBuffer, jNow, MM, camera, scale, minSize) {
+ if (texture == null) {
+ texture = Texture.getEmpty();
+ }
+ var gl = renderContext.gl;
+ if (gl != null) {
+ if (!KeplerPointSpriteShader.initialized) {
+ KeplerPointSpriteShader.init(renderContext);
+ }
+ gl.useProgram(KeplerPointSpriteShader._prog);
+ gl.uniformMatrix4fv(KeplerPointSpriteShader.mvMatLoc, false, worldView.floatArray());
+ gl.uniformMatrix4fv(KeplerPointSpriteShader.projMatLoc, false, renderContext.get_projection().floatArray());
+ gl.uniform1i(KeplerPointSpriteShader.sampLoc, 0);
+ gl.uniform1f(KeplerPointSpriteShader.jNowLoc, jNow);
+ gl.uniform1f(KeplerPointSpriteShader.mmLoc, MM);
+ gl.uniform4f(KeplerPointSpriteShader.lineColorLoc, lineColor.r / 255, lineColor.g / 255, lineColor.b / 255, lineColor.a / 255);
+ gl.uniform1f(KeplerPointSpriteShader.opacityLoc, opacity);
+ gl.uniform3f(KeplerPointSpriteShader.cameraPosLoc, camera.x, camera.y, camera.z);
+ gl.uniform1f(KeplerPointSpriteShader.scaleLoc, scale);
+ gl.uniform1f(KeplerPointSpriteShader.minSizeLoc, minSize);
+ if (zBuffer) {
+ gl.enable(WEBGL.DEPTH_TEST);
+ } else {
+ gl.disable(WEBGL.DEPTH_TEST);
+ }
+ gl.disableVertexAttribArray(0);
+ gl.disableVertexAttribArray(1);
+ gl.disableVertexAttribArray(2);
+ gl.disableVertexAttribArray(3);
+ gl.bindBuffer(WEBGL.ARRAY_BUFFER, vertex);
+ gl.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, null);
+ gl.enableVertexAttribArray(KeplerPointSpriteShader.abcLoc);
+ gl.enableVertexAttribArray(KeplerPointSpriteShader.abcLoc1);
+ gl.enableVertexAttribArray(KeplerPointSpriteShader.colorLoc);
+ gl.enableVertexAttribArray(KeplerPointSpriteShader.pointSizeLoc);
+ gl.enableVertexAttribArray(KeplerPointSpriteShader.weLoc);
+ gl.enableVertexAttribArray(KeplerPointSpriteShader.nTLoc);
+ gl.enableVertexAttribArray(KeplerPointSpriteShader.azLoc);
+ gl.enableVertexAttribArray(KeplerPointSpriteShader.orbitLoc);
+ gl.enableVertexAttribArray(KeplerPointSpriteShader.weLoc);
+ gl.vertexAttribPointer(KeplerPointSpriteShader.abcLoc, 3, WEBGL.FLOAT, false, 76, 0);
+ gl.vertexAttribPointer(KeplerPointSpriteShader.abcLoc1, 3, WEBGL.FLOAT, false, 76, 12);
+ gl.vertexAttribPointer(KeplerPointSpriteShader.pointSizeLoc, 1, WEBGL.FLOAT, false, 76, 24);
+ gl.vertexAttribPointer(KeplerPointSpriteShader.colorLoc, 4, WEBGL.FLOAT, false, 76, 28);
+ gl.vertexAttribPointer(KeplerPointSpriteShader.weLoc, 2, WEBGL.FLOAT, false, 76, 44);
+ gl.vertexAttribPointer(KeplerPointSpriteShader.nTLoc, 2, WEBGL.FLOAT, false, 76, 52);
+ gl.vertexAttribPointer(KeplerPointSpriteShader.azLoc, 2, WEBGL.FLOAT, false, 76, 60);
+ gl.vertexAttribPointer(KeplerPointSpriteShader.orbitLoc, 2, WEBGL.FLOAT, false, 76, 68);
+ gl.activeTexture(WEBGL.TEXTURE0);
+ gl.bindTexture(WEBGL.TEXTURE_2D, texture);
+ gl.lineWidth(1);
+ gl.enable(WEBGL.BLEND);
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE);
+ }
+};
+
+var KeplerPointSpriteShader$ = {};
+
+registerType("KeplerPointSpriteShader", [KeplerPointSpriteShader, KeplerPointSpriteShader$, null]);
+
+
+// wwtlib.EllipseShader
+
+export function EllipseShader() { }
+
+EllipseShader.angleLoc = 0;
+EllipseShader.initialized = false;
+EllipseShader._prog = null;
+
+EllipseShader.init = function (renderContext) {
+ var gl = renderContext.gl;
+
+ const fragShaderText = `\
+ precision mediump float;
+ varying lowp vec4 vColor;
+
+ void main(void)
+ {
+ gl_FragColor = vColor;
+ }
+ `;
+
+ const vertexShaderText = `\
+ attribute vec3 Angle;
+ uniform mat4 matWVP;
+ uniform mat4 matPosition;
+ uniform vec3 positionNow;
+ uniform float semiMajorAxis;
+ uniform float eccentricity;
+ uniform vec4 color;
+ uniform float eccentricAnomaly;
+ varying lowp vec4 vColor;
+
+ void main(void)
+ {
+ float fade = (1.0 - Angle.x);
+ float PI = 3.1415927;
+ float E = eccentricAnomaly - Angle.x * 2.0 * PI;
+ vec2 semiAxes = vec2(1.0, sqrt(1.0 - eccentricity * eccentricity)) * semiMajorAxis;
+ vec2 planePos = semiAxes * vec2(cos(E) - eccentricity, sin(E));
+
+ if (Angle.x == 0.0)
+ gl_Position = matPosition * vec4(positionNow, 1.0);
+ else
+ gl_Position = matWVP * vec4(planePos.x, planePos.y, 0.0, 1.0);
+
+ vColor = vec4(color.rgb, fade * color.a);
+ }
+ `;
+
+ EllipseShader._frag = gl.createShader(WEBGL.FRAGMENT_SHADER);
+ gl.shaderSource(EllipseShader._frag, fragShaderText);
+ gl.compileShader(EllipseShader._frag);
+ var stat = gl.getShaderParameter(EllipseShader._frag, WEBGL.COMPILE_STATUS);
+ EllipseShader._vert = gl.createShader(WEBGL.VERTEX_SHADER);
+ gl.shaderSource(EllipseShader._vert, vertexShaderText);
+ gl.compileShader(EllipseShader._vert);
+ var stat1 = gl.getShaderParameter(EllipseShader._vert, WEBGL.COMPILE_STATUS);
+ var compilationLog = gl.getShaderInfoLog(EllipseShader._vert);
+ EllipseShader._prog = gl.createProgram();
+ gl.attachShader(EllipseShader._prog, EllipseShader._vert);
+ gl.attachShader(EllipseShader._prog, EllipseShader._frag);
+ gl.linkProgram(EllipseShader._prog);
+ var errcode = gl.getProgramParameter(EllipseShader._prog, WEBGL.LINK_STATUS);
+ gl.useProgram(EllipseShader._prog);
+ EllipseShader.angleLoc = gl.getAttribLocation(EllipseShader._prog, 'Angle');
+ EllipseShader.matWVPLoc = gl.getUniformLocation(EllipseShader._prog, 'matWVP');
+ EllipseShader.matPositionLoc = gl.getUniformLocation(EllipseShader._prog, 'matPosition');
+ EllipseShader.positionNowLoc = gl.getUniformLocation(EllipseShader._prog, 'positionNow');
+ EllipseShader.colorLoc = gl.getUniformLocation(EllipseShader._prog, 'color');
+ EllipseShader.semiMajorAxisLoc = gl.getUniformLocation(EllipseShader._prog, 'semiMajorAxis');
+ EllipseShader.eccentricityLoc = gl.getUniformLocation(EllipseShader._prog, 'eccentricity');
+ EllipseShader.eccentricAnomalyLoc = gl.getUniformLocation(EllipseShader._prog, 'eccentricAnomaly');
+ gl.enable(WEBGL.BLEND);
+ EllipseShader.initialized = true;
+};
+
+EllipseShader.use = function (renderContext, semiMajorAxis, eccentricity, eccentricAnomaly, lineColor, opacity, world, positionNow) {
+ var gl = renderContext.gl;
+ if (gl != null) {
+ if (!EllipseShader.initialized) {
+ EllipseShader.init(renderContext);
+ }
+ gl.useProgram(EllipseShader._prog);
+ var WVPPos = Matrix3d.multiplyMatrix(Matrix3d.multiplyMatrix(world, renderContext.get_view()), renderContext.get_projection());
+ var WVP = Matrix3d.multiplyMatrix(Matrix3d.multiplyMatrix(renderContext.get_world(), renderContext.get_view()), renderContext.get_projection());
+ gl.uniformMatrix4fv(EllipseShader.matWVPLoc, false, WVP.floatArray());
+ gl.uniformMatrix4fv(EllipseShader.matPositionLoc, false, WVPPos.floatArray());
+ gl.uniform3f(EllipseShader.positionNowLoc, positionNow.x, positionNow.y, positionNow.z);
+ gl.uniform4f(EllipseShader.colorLoc, lineColor.r / 255, lineColor.g / 255, lineColor.b / 255, lineColor.a / 255);
+ gl.uniform1f(EllipseShader.semiMajorAxisLoc, semiMajorAxis);
+ gl.uniform1f(EllipseShader.eccentricityLoc, eccentricity);
+ gl.uniform1f(EllipseShader.eccentricAnomalyLoc, eccentricAnomaly);
+ gl.disable(WEBGL.DEPTH_TEST);
+ gl.disableVertexAttribArray(0);
+ gl.disableVertexAttribArray(1);
+ gl.disableVertexAttribArray(2);
+ gl.disableVertexAttribArray(3);
+ gl.enableVertexAttribArray(EllipseShader.angleLoc);
+ gl.vertexAttribPointer(EllipseShader.angleLoc, 3, WEBGL.FLOAT, false, 0, 0);
+ gl.lineWidth(1);
+ gl.enable(WEBGL.BLEND);
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE);
+ }
+};
+
+var EllipseShader$ = {};
+
+registerType("EllipseShader", [EllipseShader, EllipseShader$, null]);
+
+
+// wwtlib.ModelShader
+
+export function ModelShader() { }
+
+ModelShader.vertLoc = 0;
+ModelShader.normalLoc = 0;
+ModelShader.textureLoc = 0;
+ModelShader.initialized = false;
+ModelShader._prog = null;
+ModelShader.sunPosition = Vector3d.create(-1, -1, -1);
+ModelShader.minLightingBrightness = 1;
+ModelShader.atmosphereColor = Color.fromArgb(0, 0, 0, 0);
+
+ModelShader.init = function (renderContext) {
+ var gl = renderContext.gl;
+
+ const fragShaderText = `\
+ precision mediump float;
+
+ varying vec2 vTextureCoord;
+ varying vec3 vNormal;
+ varying vec3 vCamVector;
+
+ uniform sampler2D uSampler;
+ uniform float opacity;
+ uniform vec3 uSunPosition;
+ uniform float uMinBrightness;
+ uniform vec3 uAtmosphereColor;
+
+ void main(void) {
+ vec3 normal = normalize(vNormal);
+ vec3 camVN = normalize(vCamVector);
+ vec3 cam = normalize(vec3(0.0,0.0,-1.0));
+ float dt = uMinBrightness + pow(max(0.0,- dot(normal,uSunPosition)),0.5);
+ float atm = max(0.0, 1.0 - 2.5 * dot(cam,camVN)) + 0.3 * dt;
+ atm = (dt > uMinBrightness) ? atm : 0.0;
+ if ( uMinBrightness == 1.0 ) { dt = 1.0; atm= 0.0; }
+ vec4 col = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
+ gl_FragColor = col * opacity;
+ gl_FragColor.rgb *= dt;
+ gl_FragColor.rgb += atm * uAtmosphereColor;
+ }
+ `;
+
+ const vertexShaderText = `\
+ attribute vec3 aVertexPosition;
+ attribute vec3 aNormal;
+ attribute vec2 aTextureCoord;
+
+ uniform mat4 uMVMatrix;
+ uniform mat4 uPMatrix;
+
+ varying vec2 vTextureCoord;
+ varying vec3 vNormal;
+ varying vec3 vCamVector;
+
+ void main(void) {
+ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
+ vCamVector = normalize((mat3(uMVMatrix) * aVertexPosition).xyz);
+ vec3 normalT = normalize(mat3(uMVMatrix) * aNormal);
+ vTextureCoord = aTextureCoord;
+ vNormal = normalT;
+ }
+ `;
+
+ ModelShader._frag = gl.createShader(WEBGL.FRAGMENT_SHADER);
+ gl.shaderSource(ModelShader._frag, fragShaderText);
+ gl.compileShader(ModelShader._frag);
+ var stat = gl.getShaderParameter(ModelShader._frag, WEBGL.COMPILE_STATUS);
+ if (!stat) {
+ var errorF = gl.getShaderInfoLog(ModelShader._frag);
+ }
+ ModelShader._vert = gl.createShader(WEBGL.VERTEX_SHADER);
+ gl.shaderSource(ModelShader._vert, vertexShaderText);
+ gl.compileShader(ModelShader._vert);
+ var stat1 = gl.getShaderParameter(ModelShader._vert, WEBGL.COMPILE_STATUS);
+ if (!stat1) {
+ var errorV = gl.getShaderInfoLog(ModelShader._vert);
+ }
+ ModelShader._prog = gl.createProgram();
+ gl.attachShader(ModelShader._prog, ModelShader._vert);
+ gl.attachShader(ModelShader._prog, ModelShader._frag);
+ gl.linkProgram(ModelShader._prog);
+ var errcode = gl.getProgramParameter(ModelShader._prog, WEBGL.LINK_STATUS);
+ gl.useProgram(ModelShader._prog);
+ ModelShader.vertLoc = gl.getAttribLocation(ModelShader._prog, 'aVertexPosition');
+ ModelShader.normalLoc = gl.getAttribLocation(ModelShader._prog, 'aNormal');
+ ModelShader.textureLoc = gl.getAttribLocation(ModelShader._prog, 'aTextureCoord');
+ ModelShader.projMatLoc = gl.getUniformLocation(ModelShader._prog, 'uPMatrix');
+ ModelShader.mvMatLoc = gl.getUniformLocation(ModelShader._prog, 'uMVMatrix');
+ ModelShader.sampLoc = gl.getUniformLocation(ModelShader._prog, 'uSampler');
+ ModelShader.sunLoc = gl.getUniformLocation(ModelShader._prog, 'uSunPosition');
+ ModelShader.minBrightnessLoc = gl.getUniformLocation(ModelShader._prog, 'uMinBrightness');
+ ModelShader.opacityLoc = gl.getUniformLocation(ModelShader._prog, 'opacity');
+ ModelShader.atmosphereColorLoc = gl.getUniformLocation(ModelShader._prog, 'uAtmosphereColor');
+ set_tileUvMultiple(1);
+ set_tileDemEnabled(true);
+ gl.enable(WEBGL.BLEND);
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ ModelShader.initialized = true;
+};
+
+ModelShader.use = function (renderContext, vertex, index, texture, opacity, noDepth, stride) {
+ if (texture == null) {
+ texture = Texture.getEmpty();
+ }
+ var gl = renderContext.gl;
+ if (gl != null) {
+ if (!ModelShader.initialized) {
+ ModelShader.init(renderContext);
+ }
+ gl.useProgram(ModelShader._prog);
+ var mvMat = Matrix3d.multiplyMatrix(renderContext.get_world(), renderContext.get_view());
+ gl.uniform1f(ModelShader.opacityLoc, opacity);
+ gl.uniform1f(ModelShader.minBrightnessLoc, (renderContext.lighting) ? ModelShader.minLightingBrightness : 1);
+ if (renderContext.lighting) {
+ gl.uniform3f(ModelShader.atmosphereColorLoc, ModelShader.atmosphereColor.r / 255, ModelShader.atmosphereColor.g / 255, ModelShader.atmosphereColor.b / 255);
+ } else {
+ gl.uniform3f(ModelShader.atmosphereColorLoc, 0, 0, 0);
+ }
+ gl.uniformMatrix4fv(ModelShader.mvMatLoc, false, mvMat.floatArray());
+ gl.uniformMatrix4fv(ModelShader.projMatLoc, false, renderContext.get_projection().floatArray());
+ ModelShader.sunPosition.normalize();
+ var mvInv = renderContext.get_view().clone();
+ mvInv.set_m41(0);
+ mvInv.set_m42(0);
+ mvInv.set_m43(0);
+ mvInv.set_m44(1);
+ var sp = Vector3d._transformCoordinate(ModelShader.sunPosition, mvInv);
+ sp.normalize();
+ gl.uniform3f(ModelShader.sunLoc, sp.x, sp.y, sp.z);
+ gl.uniform1i(ModelShader.sampLoc, 0);
+ if (renderContext.space || noDepth) {
+ gl.disable(WEBGL.DEPTH_TEST);
+ } else {
+ gl.enable(WEBGL.DEPTH_TEST);
+ }
+ gl.disableVertexAttribArray(0);
+ gl.disableVertexAttribArray(1);
+ gl.disableVertexAttribArray(2);
+ gl.disableVertexAttribArray(3);
+ gl.bindBuffer(WEBGL.ARRAY_BUFFER, vertex);
+ gl.enableVertexAttribArray(ModelShader.vertLoc);
+ gl.enableVertexAttribArray(ModelShader.normalLoc);
+ gl.enableVertexAttribArray(ModelShader.textureLoc);
+ gl.vertexAttribPointer(ModelShader.vertLoc, 3, WEBGL.FLOAT, false, stride, 0);
+ gl.vertexAttribPointer(ModelShader.normalLoc, 3, WEBGL.FLOAT, false, stride, 12);
+ gl.vertexAttribPointer(ModelShader.textureLoc, 2, WEBGL.FLOAT, false, stride, stride - 8);
+ gl.activeTexture(WEBGL.TEXTURE0);
+ gl.bindTexture(WEBGL.TEXTURE_2D, texture);
+ gl.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, index);
+ gl.enable(WEBGL.BLEND);
+ if (noDepth) {
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE);
+ } else {
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ }
+ }
+};
+
+var ModelShader$ = {};
+
+registerType("ModelShader", [ModelShader, ModelShader$, null]);
+
+
+// wwtlib.ModelShaderTan
+
+export function ModelShaderTan() { }
+
+ModelShaderTan.vertLoc = 0;
+ModelShaderTan.normalLoc = 0;
+ModelShaderTan.textureLoc = 0;
+ModelShaderTan.initialized = false;
+ModelShaderTan._prog = null;
+ModelShaderTan.sunPosition = Vector3d.create(-1, -1, -1);
+ModelShaderTan.minLightingBrightness = 1;
+ModelShaderTan.atmosphereColor = Color.fromArgb(0, 0, 0, 0);
+
+ModelShaderTan.init = function (renderContext) {
+ var gl = renderContext.gl;
+
+ const fragShaderText = `\
+ precision mediump float;
+
+ varying vec2 vTextureCoord;
+ varying vec3 vNormal;
+ varying vec3 vCamVector;
+
+ uniform sampler2D uSampler;
+ uniform float opacity;
+ uniform vec3 uSunPosition;
+ uniform float uMinBrightness;
+ uniform vec3 uAtmosphereColor;
+
+ void main(void) {
+ vec3 normal = normalize(vNormal);
+ vec3 camVN = normalize(vCamVector);
+ vec3 cam = normalize(vec3(0.0,0.0,-1.0));
+ float dt = uMinBrightness + pow(max(0.0,- dot(normal,uSunPosition)),0.5);
+ float atm = max(0.0, 1.0 - 2.5 * dot(cam,camVN)) + 0.3 * dt;
+ atm = (dt > uMinBrightness) ? atm : 0.0;
+ if ( uMinBrightness == 1.0 ) { dt = 1.0; atm= 0.0; }
+ vec4 col = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
+ gl_FragColor = col * opacity;
+ gl_FragColor.rgb *= dt;
+ gl_FragColor.rgb += atm * uAtmosphereColor;
+ }
+ `;
+
+ const vertexShaderText = `\
+ attribute vec3 aVertexPosition;
+ attribute vec3 aNormal;
+ attribute vec2 aTextureCoord;
+
+ uniform mat4 uMVMatrix;
+ uniform mat4 uPMatrix;
+
+ varying vec2 vTextureCoord;
+ varying vec3 vNormal;
+ varying vec3 vCamVector;
+
+ void main(void) {
+ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
+ vCamVector = normalize((mat3(uMVMatrix) * aVertexPosition).xyz);
+ vec3 normalT = normalize(mat3(uMVMatrix) * aNormal);
+ vTextureCoord = aTextureCoord;
+ vNormal = normalT;
+ }
+ `;
+
+ ModelShaderTan._frag = gl.createShader(WEBGL.FRAGMENT_SHADER);
+ gl.shaderSource(ModelShaderTan._frag, fragShaderText);
+ gl.compileShader(ModelShaderTan._frag);
+ var stat = gl.getShaderParameter(ModelShaderTan._frag, WEBGL.COMPILE_STATUS);
+ if (!stat) {
+ var errorF = gl.getShaderInfoLog(ModelShaderTan._frag);
+ }
+ ModelShaderTan._vert = gl.createShader(WEBGL.VERTEX_SHADER);
+ gl.shaderSource(ModelShaderTan._vert, vertexShaderText);
+ gl.compileShader(ModelShaderTan._vert);
+ var stat1 = gl.getShaderParameter(ModelShaderTan._vert, WEBGL.COMPILE_STATUS);
+ if (!stat1) {
+ var errorV = gl.getShaderInfoLog(ModelShaderTan._vert);
+ }
+ ModelShaderTan._prog = gl.createProgram();
+ gl.attachShader(ModelShaderTan._prog, ModelShaderTan._vert);
+ gl.attachShader(ModelShaderTan._prog, ModelShaderTan._frag);
+ gl.linkProgram(ModelShaderTan._prog);
+ var errcode = gl.getProgramParameter(ModelShaderTan._prog, WEBGL.LINK_STATUS);
+ gl.useProgram(ModelShaderTan._prog);
+ ModelShaderTan.vertLoc = gl.getAttribLocation(ModelShaderTan._prog, 'aVertexPosition');
+ ModelShaderTan.normalLoc = gl.getAttribLocation(ModelShaderTan._prog, 'aNormal');
+ ModelShaderTan.textureLoc = gl.getAttribLocation(ModelShaderTan._prog, 'aTextureCoord');
+ ModelShaderTan.projMatLoc = gl.getUniformLocation(ModelShaderTan._prog, 'uPMatrix');
+ ModelShaderTan.mvMatLoc = gl.getUniformLocation(ModelShaderTan._prog, 'uMVMatrix');
+ ModelShaderTan.sampLoc = gl.getUniformLocation(ModelShaderTan._prog, 'uSampler');
+ ModelShaderTan.sunLoc = gl.getUniformLocation(ModelShaderTan._prog, 'uSunPosition');
+ ModelShaderTan.minBrightnessLoc = gl.getUniformLocation(ModelShaderTan._prog, 'uMinBrightness');
+ ModelShaderTan.opacityLoc = gl.getUniformLocation(ModelShaderTan._prog, 'opacity');
+ ModelShaderTan.atmosphereColorLoc = gl.getUniformLocation(ModelShaderTan._prog, 'uAtmosphereColor');
+ set_tileUvMultiple(1);
+ set_tileDemEnabled(true);
+ gl.enable(WEBGL.BLEND);
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ ModelShaderTan.initialized = true;
+};
+
+ModelShaderTan.use = function (renderContext, vertex, index, texture, opacity, noDepth, stride) {
+ if (texture == null) {
+ texture = Texture.getEmpty();
+ }
+ var gl = renderContext.gl;
+ if (gl != null) {
+ if (!ModelShaderTan.initialized) {
+ ModelShaderTan.init(renderContext);
+ }
+ gl.useProgram(ModelShaderTan._prog);
+ var mvMat = Matrix3d.multiplyMatrix(renderContext.get_world(), renderContext.get_view());
+ gl.uniform1f(ModelShaderTan.opacityLoc, opacity);
+ gl.uniform1f(ModelShaderTan.minBrightnessLoc, (renderContext.lighting) ? ModelShaderTan.minLightingBrightness : 1);
+ if (renderContext.lighting) {
+ gl.uniform3f(ModelShaderTan.atmosphereColorLoc, ModelShaderTan.atmosphereColor.r / 255, ModelShaderTan.atmosphereColor.g / 255, ModelShaderTan.atmosphereColor.b / 255);
+ } else {
+ gl.uniform3f(ModelShaderTan.atmosphereColorLoc, 0, 0, 0);
+ }
+ gl.uniformMatrix4fv(ModelShaderTan.mvMatLoc, false, mvMat.floatArray());
+ gl.uniformMatrix4fv(ModelShaderTan.projMatLoc, false, renderContext.get_projection().floatArray());
+ ModelShaderTan.sunPosition.normalize();
+ var mvInv = renderContext.get_view().clone();
+ mvInv.set_m41(0);
+ mvInv.set_m42(0);
+ mvInv.set_m43(0);
+ mvInv.set_m44(1);
+ var sp = Vector3d._transformCoordinate(ModelShaderTan.sunPosition, mvInv);
+ sp.normalize();
+ gl.uniform3f(ModelShaderTan.sunLoc, -sp.x, -sp.y, -sp.z);
+ gl.uniform1i(ModelShaderTan.sampLoc, 0);
+ if (renderContext.space || noDepth) {
+ gl.disable(WEBGL.DEPTH_TEST);
+ } else {
+ gl.enable(WEBGL.DEPTH_TEST);
+ }
+ gl.disableVertexAttribArray(0);
+ gl.disableVertexAttribArray(1);
+ gl.disableVertexAttribArray(2);
+ gl.disableVertexAttribArray(3);
+ gl.bindBuffer(WEBGL.ARRAY_BUFFER, vertex);
+ gl.enableVertexAttribArray(ModelShaderTan.vertLoc);
+ gl.enableVertexAttribArray(ModelShaderTan.normalLoc);
+ gl.enableVertexAttribArray(ModelShaderTan.textureLoc);
+ gl.vertexAttribPointer(ModelShaderTan.vertLoc, 3, WEBGL.FLOAT, false, stride, 0);
+ gl.vertexAttribPointer(ModelShaderTan.normalLoc, 3, WEBGL.FLOAT, false, stride, 12);
+ gl.vertexAttribPointer(ModelShaderTan.textureLoc, 2, WEBGL.FLOAT, false, stride, stride - 8);
+ gl.activeTexture(WEBGL.TEXTURE0);
+ gl.bindTexture(WEBGL.TEXTURE_2D, texture);
+ gl.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, index);
+ gl.enable(WEBGL.BLEND);
+ if (noDepth) {
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE);
+ } else {
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ }
+ }
+};
+
+var ModelShaderTan$ = {};
+
+registerType("ModelShaderTan", [ModelShaderTan, ModelShaderTan$, null]);
+
+
+// wwtlib.TileShader
+
+export function TileShader() { }
+
+TileShader.vertLoc = 0;
+TileShader.textureLoc = 0;
+TileShader.initialized = false;
+TileShader._prog = null;
+TileShader.sunPosition = Vector3d.create(-1, -1, -1);
+TileShader.minLightingBrightness = 1;
+TileShader.atmosphereColor = Color.fromArgb(0, 0, 0, 0);
+
+TileShader.init = function (renderContext) {
+ var gl = renderContext.gl;
+
+ const fragShaderText = `\
+ precision mediump float;
+
+ varying vec2 vTextureCoord;
+ varying vec3 vNormal;
+ varying vec3 vCamVector;
+
+ uniform sampler2D uSampler;
+ uniform float opacity;
+ uniform vec3 uSunPosition;
+ uniform float uMinBrightness;
+ uniform vec3 uAtmosphereColor;
+
+ void main(void) {
+ vec3 normal = normalize(vNormal);
+ vec3 camVN = normalize(vCamVector);
+ vec3 cam = normalize(vec3(0.0,0.0,-1.0));
+ float dt = uMinBrightness + pow(max(0.0,- dot(normal,uSunPosition)),0.5);
+ float atm = max(0.0, 1.0 - 2.5 * dot(cam,camVN)) + 0.3 * dt;
+ atm = (dt > uMinBrightness) ? atm : 0.0;
+ if ( uMinBrightness == 1.0 ) { dt = 1.0; atm = 0.0; }
+ vec4 col = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
+ gl_FragColor = col * opacity;
+ gl_FragColor.rgb *= dt;
+ gl_FragColor.rgb += atm * uAtmosphereColor;
+ }
+ `;
+
+ const vertexShaderText = `\
+ attribute vec3 aVertexPosition;
+ attribute vec2 aTextureCoord;
+
+ uniform mat4 uMVMatrix;
+ uniform mat4 uPMatrix;
+ uniform vec3 uCenterScreen;
+ uniform vec3 uCenterWorld;
+
+ varying vec2 vTextureCoord;
+ varying vec3 vNormal;
+ varying vec3 vCamVector;
+
+ void main(void) {
+ vec3 normal;
+
+ if (length(uCenterWorld) > 0.00001) {
+ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 0.0) + vec4(uCenterScreen, 1.0);
+ vCamVector = normalize((mat3(uMVMatrix) * (aVertexPosition + uCenterWorld)).xyz);
+ normal = normalize(aVertexPosition + uCenterWorld);
+ } else {
+ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
+ vCamVector = normalize((mat3(uMVMatrix) * aVertexPosition).xyz);
+ normal = normalize(aVertexPosition);
+ }
+
+ vec3 normalT = normalize(mat3(uMVMatrix) * normal);
+ vTextureCoord = aTextureCoord;
+ vNormal = normalT;
+ }
+ `;
+
+ TileShader._frag = gl.createShader(WEBGL.FRAGMENT_SHADER);
+ gl.shaderSource(TileShader._frag, fragShaderText);
+ gl.compileShader(TileShader._frag);
+ var stat = gl.getShaderParameter(TileShader._frag, WEBGL.COMPILE_STATUS);
+ if (!stat) {
+ var errorF = gl.getShaderInfoLog(TileShader._frag);
+ }
+ TileShader._vert = gl.createShader(WEBGL.VERTEX_SHADER);
+ gl.shaderSource(TileShader._vert, vertexShaderText);
+ gl.compileShader(TileShader._vert);
+ var stat1 = gl.getShaderParameter(TileShader._vert, WEBGL.COMPILE_STATUS);
+ if (!stat1) {
+ var errorV = gl.getShaderInfoLog(TileShader._vert);
+ }
+ TileShader._prog = gl.createProgram();
+ gl.attachShader(TileShader._prog, TileShader._vert);
+ gl.attachShader(TileShader._prog, TileShader._frag);
+ gl.linkProgram(TileShader._prog);
+ var errcode = gl.getProgramParameter(TileShader._prog, WEBGL.LINK_STATUS);
+ gl.useProgram(TileShader._prog);
+ TileShader.vertLoc = gl.getAttribLocation(TileShader._prog, 'aVertexPosition');
+ TileShader.textureLoc = gl.getAttribLocation(TileShader._prog, 'aTextureCoord');
+ TileShader.projMatLoc = gl.getUniformLocation(TileShader._prog, 'uPMatrix');
+ TileShader.mvMatLoc = gl.getUniformLocation(TileShader._prog, 'uMVMatrix');
+ TileShader.sampLoc = gl.getUniformLocation(TileShader._prog, 'uSampler');
+ TileShader.centerScreenLoc = gl.getUniformLocation(TileShader._prog, 'uCenterScreen');
+ TileShader.centerWorldLoc = gl.getUniformLocation(TileShader._prog, 'uCenterWorld');
+ TileShader.sunLoc = gl.getUniformLocation(TileShader._prog, 'uSunPosition');
+ TileShader.minBrightnessLoc = gl.getUniformLocation(TileShader._prog, 'uMinBrightness');
+ TileShader.opacityLoc = gl.getUniformLocation(TileShader._prog, 'opacity');
+ TileShader.atmosphereColorLoc = gl.getUniformLocation(TileShader._prog, 'uAtmosphereColor');
+ set_tileUvMultiple(1);
+ set_tileDemEnabled(true);
+ gl.enable(WEBGL.BLEND);
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ TileShader.initialized = true;
+};
+
+TileShader.use = function (renderContext, vertex, index, texture, opacity, noDepth, centerWorld) {
+ if (texture == null) {
+ texture = Texture.getEmpty();
+ }
+ var gl = renderContext.gl;
+ if (gl != null) {
+ if (!TileShader.initialized) {
+ TileShader.init(renderContext);
+ }
+ gl.useProgram(TileShader._prog);
+ var mvMat = Matrix3d.multiplyMatrix(renderContext.get_world(), renderContext.get_view());
+ gl.uniform1f(TileShader.opacityLoc, opacity);
+ gl.uniform1f(TileShader.minBrightnessLoc, (renderContext.lighting) ? TileShader.minLightingBrightness : 1);
+ if (renderContext.lighting) {
+ gl.uniform3f(TileShader.atmosphereColorLoc, TileShader.atmosphereColor.r / 255, TileShader.atmosphereColor.g / 255, TileShader.atmosphereColor.b / 255);
+ } else {
+ gl.uniform3f(TileShader.atmosphereColorLoc, 0, 0, 0);
+ }
+ gl.uniform3f(TileShader.centerWorldLoc, centerWorld.x, centerWorld.y, centerWorld.z);
+
+ // "This would be clearer by making the 'centerWorld' parameter optional. Unfortunately, that's not allowed in C# 2.0"
+ if (centerWorld.lengthSq() > 0.001) {
+ var wvp = Matrix3d.multiplyMatrix(mvMat, renderContext.get_projection());
+ var centerScreen = wvp.transform(centerWorld);
+ gl.uniform3f(TileShader.centerScreenLoc, centerScreen.x, centerScreen.y, centerScreen.z);
+ } else {
+ gl.uniform3f(TileShader.centerScreenLoc, 0, 0, 0);
+ }
+ gl.uniformMatrix4fv(TileShader.mvMatLoc, false, mvMat.floatArray());
+ gl.uniformMatrix4fv(TileShader.projMatLoc, false, renderContext.get_projection().floatArray());
+ TileShader.sunPosition.normalize();
+ var mvInv = renderContext.get_view().clone();
+ mvInv.set_m41(0);
+ mvInv.set_m42(0);
+ mvInv.set_m43(0);
+ mvInv.set_m44(1);
+ var sp = Vector3d._transformCoordinate(TileShader.sunPosition, mvInv);
+ sp.normalize();
+ gl.uniform3f(TileShader.sunLoc, -sp.x, -sp.y, -sp.z);
+ gl.uniform1i(TileShader.sampLoc, 0);
+ if (renderContext.space || noDepth) {
+ gl.disable(WEBGL.DEPTH_TEST);
+ } else {
+ gl.enable(WEBGL.DEPTH_TEST);
+ }
+ gl.disableVertexAttribArray(0);
+ gl.disableVertexAttribArray(1);
+ gl.disableVertexAttribArray(2);
+ gl.disableVertexAttribArray(3);
+ gl.bindBuffer(WEBGL.ARRAY_BUFFER, vertex);
+ gl.enableVertexAttribArray(TileShader.vertLoc);
+ gl.enableVertexAttribArray(TileShader.textureLoc);
+ gl.vertexAttribPointer(TileShader.vertLoc, 3, WEBGL.FLOAT, false, 20, 0);
+ gl.vertexAttribPointer(TileShader.textureLoc, 2, WEBGL.FLOAT, false, 20, 12);
+ gl.activeTexture(WEBGL.TEXTURE0);
+ gl.bindTexture(WEBGL.TEXTURE_2D, texture);
+ gl.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, index);
+ gl.enable(WEBGL.BLEND);
+ if (noDepth) {
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE);
+ } else {
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ }
+ }
+};
+
+var TileShader$ = {};
+
+registerType("TileShader", [TileShader, TileShader$, null]);
+
+
+// wwtlib.FitsShader
+
+export function FitsShader() { }
+
+FitsShader.vertLoc = 0;
+FitsShader.textureLoc = 0;
+FitsShader.initialized = false;
+FitsShader._prog = null;
+FitsShader.blankValue = 0;
+FitsShader.bScale = 1;
+FitsShader.bZero = 0;
+FitsShader.min = 0;
+FitsShader.max = 0;
+FitsShader.transparentBlack = false;
+FitsShader.containsBlanks = false;
+FitsShader.scaleType = 0;
+
+FitsShader.init = function (renderContext) {
+ var gl = renderContext.gl;
+
+ const fragShaderText = `\
+ #version 300 es
+
+ precision mediump float;
+ in vec2 vTextureCoord;
+ in vec3 vNormal;
+ in vec3 vCamVector;
+ out vec4 fragmentColor;
+
+ uniform sampler2D uSampler;
+ uniform sampler2D colorSampler;
+ uniform float blank;
+ uniform float bzero;
+ uniform float bscale;
+ uniform float min;
+ uniform float max;
+ uniform bool containsBlanks;
+ uniform bool transparentBlack;
+ uniform int scaleType;
+ uniform float opacity;
+
+ bool isNaN(float value) {
+ // See https://stackoverflow.com/questions/9446888/best-way-to-detect-nans-in-opengl-shaders
+ // PKGW also finds that we need "value != value" on his Dell laptop running
+ // Chrome on Linux.
+ return (value != value) || !(value < 0.0 || 0.0 < value || value == 0.0);
+ }
+
+ void main(void) {
+ //FITS images are flipped on the y axis
+ vec4 color = texture(uSampler, vec2(vTextureCoord.x, 1.0 - vTextureCoord.y));
+
+ if(isNaN(color.r) || (containsBlanks && abs(blank - color.r) < 0.00000001)){
+ fragmentColor = vec4(0.0, 0.0, 0.0, 0.0);
+ } else {
+ float physicalValue = (bzero + bscale * color.r - min) / (max - min);
+ if(transparentBlack && physicalValue <= 0.0){
+ fragmentColor = vec4(0.0, 0.0, 0.0, 0.0);
+ return;
+ }
+
+ physicalValue = clamp(physicalValue, 0.0, 1.0);
+
+ switch(scaleType){
+ case 1:
+ physicalValue = log(physicalValue * 255.0 + 1.0 ) / log(256.0);
+ break;
+ case 2:
+ physicalValue = physicalValue * physicalValue;
+ break;
+ case 3:
+ physicalValue = sqrt(physicalValue);
+ break;
+ }
+ vec4 colorFromColorMapper = texture(colorSampler, vec2(physicalValue, 0.5));
+ fragmentColor = vec4(colorFromColorMapper.rgb, opacity);
+ }
+ }
+ `;
+
+ const vertexShaderText = `\
+ #version 300 es
+
+ in vec3 aVertexPosition;
+ in vec2 aTextureCoord;
+
+ uniform mat4 uMVMatrix;
+ uniform mat4 uPMatrix;
+ uniform vec3 uCenterScreen;
+
+ out vec2 vTextureCoord;
+
+ void main(void) {
+ if(length(uCenterScreen) > 0.0000001) {
+ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 0.0) + vec4(uCenterScreen, 1.0);
+ } else {
+ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
+ }
+
+ vTextureCoord = aTextureCoord;
+ }
+ `;
+
+ FitsShader._frag = gl.createShader(WEBGL.FRAGMENT_SHADER);
+ gl.shaderSource(FitsShader._frag, fragShaderText);
+ gl.compileShader(FitsShader._frag);
+ var stat = gl.getShaderParameter(FitsShader._frag, WEBGL.COMPILE_STATUS);
+ if (!stat) {
+ var errorF = gl.getShaderInfoLog(FitsShader._frag);
+ console.log(errorF);
+ }
+ FitsShader._vert = gl.createShader(WEBGL.VERTEX_SHADER);
+ gl.shaderSource(FitsShader._vert, vertexShaderText);
+ gl.compileShader(FitsShader._vert);
+ var stat1 = gl.getShaderParameter(FitsShader._vert, WEBGL.COMPILE_STATUS);
+ if (!stat1) {
+ var errorV = gl.getShaderInfoLog(FitsShader._vert);
+ console.log(errorV);
+ }
+ FitsShader._prog = gl.createProgram();
+ gl.attachShader(FitsShader._prog, FitsShader._vert);
+ gl.attachShader(FitsShader._prog, FitsShader._frag);
+ gl.linkProgram(FitsShader._prog);
+ var errcode = gl.getProgramParameter(FitsShader._prog, WEBGL.LINK_STATUS);
+ gl.useProgram(FitsShader._prog);
+ FitsShader.vertLoc = gl.getAttribLocation(FitsShader._prog, 'aVertexPosition');
+ FitsShader.textureLoc = gl.getAttribLocation(FitsShader._prog, 'aTextureCoord');
+ FitsShader.projMatLoc = gl.getUniformLocation(FitsShader._prog, 'uPMatrix');
+ FitsShader.mvMatLoc = gl.getUniformLocation(FitsShader._prog, 'uMVMatrix');
+ FitsShader.sampLoc = gl.getUniformLocation(FitsShader._prog, 'uSampler');
+ FitsShader.colorLoc = gl.getUniformLocation(FitsShader._prog, 'colorSampler');
+ FitsShader.centerScreenLoc = gl.getUniformLocation(FitsShader._prog, 'uCenterScreen');
+ FitsShader.blank = gl.getUniformLocation(FitsShader._prog, 'blank');
+ FitsShader.bzero = gl.getUniformLocation(FitsShader._prog, 'bzero');
+ FitsShader.bscale = gl.getUniformLocation(FitsShader._prog, 'bscale');
+ FitsShader.minLoc = gl.getUniformLocation(FitsShader._prog, 'min');
+ FitsShader.maxLoc = gl.getUniformLocation(FitsShader._prog, 'max');
+ FitsShader.transparentBlackLoc = gl.getUniformLocation(FitsShader._prog, 'transparentBlack');
+ FitsShader.containsBlanksLoc = gl.getUniformLocation(FitsShader._prog, 'containsBlanks');
+ FitsShader.scalingLocation = gl.getUniformLocation(FitsShader._prog, 'scaleType');
+ FitsShader.opacityLoc = gl.getUniformLocation(FitsShader._prog, 'opacity');
+ set_tileUvMultiple(1);
+ set_tileDemEnabled(true);
+ gl.enable(WEBGL.BLEND);
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ FitsShader.initialized = true;
+};
+
+FitsShader.use = function (renderContext, vertex, index, texture, opacity, noDepth, centerWorld) {
+ if (texture == null) {
+ texture = Texture.getEmpty();
+ }
+ var gl = renderContext.gl;
+ if (gl != null) {
+ if (!FitsShader.initialized) {
+ FitsShader.init(renderContext);
+ }
+ gl.useProgram(FitsShader._prog);
+ var mvMat = Matrix3d.multiplyMatrix(renderContext.get_world(), renderContext.get_view());
+ gl.uniform1f(FitsShader.opacityLoc, opacity);
+ gl.uniformMatrix4fv(FitsShader.mvMatLoc, false, mvMat.floatArray());
+ gl.uniformMatrix4fv(FitsShader.projMatLoc, false, renderContext.get_projection().floatArray());
+
+ // "This would be clearer by making the 'centerWorld' parameter optional. Unfortunately, that's not allowed in C# 2.0"
+ if (centerWorld.lengthSq() > 0.001) {
+ var wvp = Matrix3d.multiplyMatrix(mvMat, renderContext.get_projection());
+ var centerScreen = wvp.transform(centerWorld);
+ gl.uniform3f(FitsShader.centerScreenLoc, centerScreen.x, centerScreen.y, centerScreen.z);
+ } else {
+ gl.uniform3f(FitsShader.centerScreenLoc, 0, 0, 0);
+ }
+
+ gl.uniform1i(FitsShader.sampLoc, 0);
+ gl.uniform1i(FitsShader.colorLoc, 1);
+ gl.uniform1f(FitsShader.blank, FitsShader.blankValue);
+ gl.uniform1f(FitsShader.bzero, FitsShader.bZero);
+ gl.uniform1f(FitsShader.bscale, FitsShader.bScale);
+ gl.uniform1f(FitsShader.minLoc, FitsShader.min);
+ gl.uniform1f(FitsShader.maxLoc, FitsShader.max);
+ gl.uniform1i(FitsShader.transparentBlackLoc, FitsShader.transparentBlack);
+ gl.uniform1i(FitsShader.containsBlanksLoc, FitsShader.containsBlanks);
+ gl.uniform1i(FitsShader.scalingLocation, FitsShader.scaleType);
+ if (renderContext.space || noDepth) {
+ gl.disable(WEBGL.DEPTH_TEST);
+ } else {
+ gl.enable(WEBGL.DEPTH_TEST);
+ }
+ gl.disableVertexAttribArray(0);
+ gl.disableVertexAttribArray(1);
+ gl.disableVertexAttribArray(2);
+ gl.disableVertexAttribArray(3);
+ gl.bindBuffer(WEBGL.ARRAY_BUFFER, vertex);
+ gl.enableVertexAttribArray(FitsShader.vertLoc);
+ gl.enableVertexAttribArray(FitsShader.textureLoc);
+ gl.vertexAttribPointer(FitsShader.vertLoc, 3, WEBGL.FLOAT, false, 20, 0);
+ gl.vertexAttribPointer(FitsShader.textureLoc, 2, WEBGL.FLOAT, false, 20, 12);
+ gl.activeTexture(WEBGL.TEXTURE0);
+ gl.bindTexture(WEBGL.TEXTURE_2D, texture);
+ gl.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, index);
+ gl.enable(WEBGL.BLEND);
+ if (noDepth) {
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE);
+ } else {
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ }
+ }
+};
+
+var FitsShader$ = {};
+
+registerType("FitsShader", [FitsShader, FitsShader$, null]);
+
+
+// wwtlib.ImageShader
+
+export function ImageShader() { }
+
+ImageShader.vertLoc = 0;
+ImageShader.textureLoc = 0;
+ImageShader.initialized = false;
+ImageShader._prog = null;
+
+ImageShader.init = function (renderContext) {
+ var gl = renderContext.gl;
+
+ const fragShaderText = `\
+ precision mediump float;
+
+ varying vec2 vTextureCoord;
+
+ uniform sampler2D uSampler;
+ uniform float opacity;
+
+ void main(void) {
+ vec4 col = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
+ gl_FragColor = col * opacity;
+ }
+ `;
+
+ const vertexShaderText = `\
+ attribute vec3 aVertexPosition;
+ attribute vec2 aTextureCoord;
+
+ uniform mat4 uMVMatrix;
+ uniform mat4 uPMatrix;
+
+ varying vec2 vTextureCoord;
+ varying vec3 vNormal;
+ varying vec3 vCamVector;
+
+ void main(void) {
+ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
+ vTextureCoord = aTextureCoord;
+ }
+ `;
+
+ ImageShader._frag = gl.createShader(WEBGL.FRAGMENT_SHADER);
+ gl.shaderSource(ImageShader._frag, fragShaderText);
+ gl.compileShader(ImageShader._frag);
+ var stat = gl.getShaderParameter(ImageShader._frag, WEBGL.COMPILE_STATUS);
+ if (!stat) {
+ var errorF = gl.getShaderInfoLog(ImageShader._frag);
+ }
+ ImageShader._vert = gl.createShader(WEBGL.VERTEX_SHADER);
+ gl.shaderSource(ImageShader._vert, vertexShaderText);
+ gl.compileShader(ImageShader._vert);
+ var stat1 = gl.getShaderParameter(ImageShader._vert, WEBGL.COMPILE_STATUS);
+ if (!stat1) {
+ var errorV = gl.getShaderInfoLog(ImageShader._vert);
+ }
+ ImageShader._prog = gl.createProgram();
+ gl.attachShader(ImageShader._prog, ImageShader._vert);
+ gl.attachShader(ImageShader._prog, ImageShader._frag);
+ gl.linkProgram(ImageShader._prog);
+ var errcode = gl.getProgramParameter(ImageShader._prog, WEBGL.LINK_STATUS);
+ gl.useProgram(ImageShader._prog);
+ ImageShader.vertLoc = gl.getAttribLocation(ImageShader._prog, 'aVertexPosition');
+ ImageShader.textureLoc = gl.getAttribLocation(ImageShader._prog, 'aTextureCoord');
+ ImageShader.projMatLoc = gl.getUniformLocation(ImageShader._prog, 'uPMatrix');
+ ImageShader.mvMatLoc = gl.getUniformLocation(ImageShader._prog, 'uMVMatrix');
+ ImageShader.sampLoc = gl.getUniformLocation(ImageShader._prog, 'uSampler');
+ ImageShader.opacityLoc = gl.getUniformLocation(ImageShader._prog, 'opacity');
+ set_tileUvMultiple(1);
+ set_tileDemEnabled(true);
+ gl.enable(WEBGL.BLEND);
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ ImageShader.initialized = true;
+};
+
+ImageShader.use = function (renderContext, vertex, index, texture, opacity, noDepth) {
+ if (texture == null) {
+ texture = Texture.getEmpty();
+ }
+ var gl = renderContext.gl;
+ if (gl != null) {
+ if (!ImageShader.initialized) {
+ ImageShader.init(renderContext);
+ }
+ gl.useProgram(ImageShader._prog);
+ var mvMat = Matrix3d.multiplyMatrix(renderContext.get_world(), renderContext.get_view());
+ gl.uniform1f(ImageShader.opacityLoc, opacity);
+ gl.uniformMatrix4fv(ImageShader.mvMatLoc, false, mvMat.floatArray());
+ gl.uniformMatrix4fv(ImageShader.projMatLoc, false, renderContext.get_projection().floatArray());
+ gl.uniform1i(ImageShader.sampLoc, 0);
+ if (renderContext.space || noDepth) {
+ gl.disable(WEBGL.DEPTH_TEST);
+ } else {
+ gl.enable(WEBGL.DEPTH_TEST);
+ }
+ gl.disableVertexAttribArray(0);
+ gl.disableVertexAttribArray(1);
+ gl.disableVertexAttribArray(2);
+ gl.disableVertexAttribArray(3);
+ gl.bindBuffer(WEBGL.ARRAY_BUFFER, vertex);
+ gl.enableVertexAttribArray(ImageShader.vertLoc);
+ gl.enableVertexAttribArray(ImageShader.textureLoc);
+ gl.vertexAttribPointer(ImageShader.vertLoc, 3, WEBGL.FLOAT, false, 20, 0);
+ gl.vertexAttribPointer(ImageShader.textureLoc, 2, WEBGL.FLOAT, false, 20, 12);
+ gl.activeTexture(WEBGL.TEXTURE0);
+ gl.bindTexture(WEBGL.TEXTURE_2D, texture);
+ gl.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, index);
+ gl.enable(WEBGL.BLEND);
+ if (noDepth) {
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE);
+ } else {
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ }
+ }
+};
+
+var ImageShader$ = {};
+
+registerType("ImageShader", [ImageShader, ImageShader$, null]);
+
+
+// wwtlib.ImageShader2
+
+export function ImageShader2() { }
+
+ImageShader2.vertLoc = 0;
+ImageShader2.textureLoc = 0;
+ImageShader2.initialized = false;
+ImageShader2._prog = null;
+
+ImageShader2.init = function (renderContext) {
+ var gl = renderContext.gl;
+
+ const fragShaderText = `\
+ precision mediump float;
+
+ varying vec2 vTextureCoord;
+
+ uniform sampler2D uSampler;
+ uniform float opacity;
+
+ void main(void) {
+ vec4 col = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
+ gl_FragColor = col * opacity;
+ }
+ `;
+
+ const vertexShaderText = `\
+ attribute vec3 aVertexPosition;
+ attribute vec2 aTextureCoord;
+
+ uniform mat4 uMVMatrix;
+ uniform mat4 uPMatrix;
+
+ varying vec2 vTextureCoord;
+ varying vec3 vNormal;
+ varying vec3 vCamVector;
+
+ void main(void) {
+ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
+ vTextureCoord = aTextureCoord;
+ }
+ `;
+
+ ImageShader2._frag = gl.createShader(WEBGL.FRAGMENT_SHADER);
+ gl.shaderSource(ImageShader2._frag, fragShaderText);
+ gl.compileShader(ImageShader2._frag);
+ var stat = gl.getShaderParameter(ImageShader2._frag, WEBGL.COMPILE_STATUS);
+ if (!stat) {
+ var errorF = gl.getShaderInfoLog(ImageShader2._frag);
+ }
+ ImageShader2._vert = gl.createShader(WEBGL.VERTEX_SHADER);
+ gl.shaderSource(ImageShader2._vert, vertexShaderText);
+ gl.compileShader(ImageShader2._vert);
+ var stat1 = gl.getShaderParameter(ImageShader2._vert, WEBGL.COMPILE_STATUS);
+ if (!stat1) {
+ var errorV = gl.getShaderInfoLog(ImageShader2._vert);
+ }
+ ImageShader2._prog = gl.createProgram();
+ gl.attachShader(ImageShader2._prog, ImageShader2._vert);
+ gl.attachShader(ImageShader2._prog, ImageShader2._frag);
+ gl.linkProgram(ImageShader2._prog);
+ var errcode = gl.getProgramParameter(ImageShader2._prog, WEBGL.LINK_STATUS);
+ gl.useProgram(ImageShader2._prog);
+ ImageShader2.vertLoc = gl.getAttribLocation(ImageShader2._prog, 'aVertexPosition');
+ ImageShader2.textureLoc = gl.getAttribLocation(ImageShader2._prog, 'aTextureCoord');
+ ImageShader2.projMatLoc = gl.getUniformLocation(ImageShader2._prog, 'uPMatrix');
+ ImageShader2.mvMatLoc = gl.getUniformLocation(ImageShader2._prog, 'uMVMatrix');
+ ImageShader2.sampLoc = gl.getUniformLocation(ImageShader2._prog, 'uSampler');
+ ImageShader2.opacityLoc = gl.getUniformLocation(ImageShader2._prog, 'opacity');
+ set_tileUvMultiple(1);
+ set_tileDemEnabled(true);
+ gl.enable(WEBGL.BLEND);
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ ImageShader2.initialized = true;
+};
+
+ImageShader2.use = function (renderContext, vertex, index, texture, opacity, noDepth) {
+ if (texture == null) {
+ texture = Texture.getEmpty();
+ }
+ var gl = renderContext.gl;
+ if (gl != null) {
+ if (!ImageShader2.initialized) {
+ ImageShader2.init(renderContext);
+ }
+ gl.useProgram(ImageShader2._prog);
+ var mvMat = Matrix3d.multiplyMatrix(renderContext.get_world(), renderContext.get_view());
+ gl.uniform1f(ImageShader2.opacityLoc, opacity);
+ gl.uniformMatrix4fv(ImageShader2.mvMatLoc, false, mvMat.floatArray());
+ gl.uniformMatrix4fv(ImageShader2.projMatLoc, false, renderContext.get_projection().floatArray());
+ gl.uniform1i(ImageShader2.sampLoc, 0);
+ if (renderContext.space || noDepth) {
+ gl.disable(WEBGL.DEPTH_TEST);
+ } else {
+ gl.enable(WEBGL.DEPTH_TEST);
+ }
+ gl.disableVertexAttribArray(0);
+ gl.disableVertexAttribArray(1);
+ gl.disableVertexAttribArray(2);
+ gl.disableVertexAttribArray(3);
+ gl.bindBuffer(WEBGL.ARRAY_BUFFER, vertex);
+ gl.enableVertexAttribArray(ImageShader2.vertLoc);
+ gl.enableVertexAttribArray(ImageShader2.textureLoc);
+ gl.vertexAttribPointer(ImageShader2.vertLoc, 3, WEBGL.FLOAT, false, 32, 0);
+ gl.vertexAttribPointer(ImageShader2.textureLoc, 2, WEBGL.FLOAT, false, 32, 24);
+ gl.activeTexture(WEBGL.TEXTURE0);
+ gl.bindTexture(WEBGL.TEXTURE_2D, texture);
+ gl.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, index);
+ gl.enable(WEBGL.BLEND);
+ if (noDepth) {
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE);
+ } else {
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ }
+ }
+};
+
+var ImageShader2$ = {};
+
+registerType("ImageShader2", [ImageShader2, ImageShader2$, null]);
+
+
+// wwtlib.SpriteShader
+
+export function SpriteShader() { }
+
+SpriteShader.vertLoc = 0;
+SpriteShader.textureLoc = 0;
+SpriteShader.colorLoc = 0;
+SpriteShader.initialized = false;
+SpriteShader._prog = null;
+
+SpriteShader.init = function (renderContext) {
+ var gl = renderContext.gl;
+
+ const fragShaderText = `\
+ precision mediump float;
+
+ varying vec2 vTextureCoord;
+ varying lowp vec4 vColor;
+ uniform sampler2D uSampler;
+
+ void main(void) {
+ gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t)) * vColor;
+ }
+ `;
+
+ const vertexShaderText = `\
+ attribute vec3 aVertexPosition;
+ attribute vec2 aTextureCoord;
+ attribute lowp vec4 aColor;
+
+ uniform mat4 uMVMatrix;
+ uniform mat4 uPMatrix;
+
+ varying vec2 vTextureCoord;
+ varying vec4 vColor;
+
+ void main(void) {
+ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
+ vTextureCoord = aTextureCoord;
+ vColor = aColor;
+ }
+ `;
+
+ SpriteShader._frag = gl.createShader(WEBGL.FRAGMENT_SHADER);
+ gl.shaderSource(SpriteShader._frag, fragShaderText);
+ gl.compileShader(SpriteShader._frag);
+ var stat = gl.getShaderParameter(SpriteShader._frag, WEBGL.COMPILE_STATUS);
+ SpriteShader._vert = gl.createShader(WEBGL.VERTEX_SHADER);
+ gl.shaderSource(SpriteShader._vert, vertexShaderText);
+ gl.compileShader(SpriteShader._vert);
+ var stat1 = gl.getShaderParameter(SpriteShader._vert, WEBGL.COMPILE_STATUS);
+ SpriteShader._prog = gl.createProgram();
+ gl.attachShader(SpriteShader._prog, SpriteShader._vert);
+ gl.attachShader(SpriteShader._prog, SpriteShader._frag);
+ gl.linkProgram(SpriteShader._prog);
+ var errcode = gl.getProgramParameter(SpriteShader._prog, WEBGL.LINK_STATUS);
+ gl.useProgram(SpriteShader._prog);
+ SpriteShader.vertLoc = gl.getAttribLocation(SpriteShader._prog, 'aVertexPosition');
+ SpriteShader.textureLoc = gl.getAttribLocation(SpriteShader._prog, 'aTextureCoord');
+ SpriteShader.colorLoc = gl.getAttribLocation(SpriteShader._prog, 'aColor');
+ SpriteShader.projMatLoc = gl.getUniformLocation(SpriteShader._prog, 'uPMatrix');
+ SpriteShader.mvMatLoc = gl.getUniformLocation(SpriteShader._prog, 'uMVMatrix');
+ SpriteShader.sampLoc = gl.getUniformLocation(SpriteShader._prog, 'uSampler');
+ set_tileUvMultiple(1);
+ set_tileDemEnabled(true);
+ gl.enable(WEBGL.BLEND);
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ SpriteShader.initialized = true;
+};
+
+SpriteShader.use = function (renderContext, vertex, texture) {
+ if (texture == null) {
+ texture = Texture.getEmpty();
+ }
+ var gl = renderContext.gl;
+ if (gl != null) {
+ if (!SpriteShader.initialized) {
+ SpriteShader.init(renderContext);
+ }
+ gl.useProgram(SpriteShader._prog);
+ var mvMat = Matrix3d.multiplyMatrix(renderContext.get_world(), renderContext.get_view());
+ gl.uniformMatrix4fv(SpriteShader.mvMatLoc, false, mvMat.floatArray());
+ gl.uniformMatrix4fv(SpriteShader.projMatLoc, false, renderContext.get_projection().floatArray());
+ gl.uniform1i(SpriteShader.sampLoc, 0);
+ gl.disable(WEBGL.DEPTH_TEST);
+ gl.disableVertexAttribArray(0);
+ gl.disableVertexAttribArray(1);
+ gl.disableVertexAttribArray(2);
+ gl.disableVertexAttribArray(3);
+ gl.bindBuffer(WEBGL.ARRAY_BUFFER, vertex);
+ gl.enableVertexAttribArray(SpriteShader.vertLoc);
+ gl.enableVertexAttribArray(SpriteShader.textureLoc);
+ gl.enableVertexAttribArray(SpriteShader.colorLoc);
+ gl.vertexAttribPointer(SpriteShader.vertLoc, 3, WEBGL.FLOAT, false, 36, 0);
+ gl.vertexAttribPointer(SpriteShader.colorLoc, 4, WEBGL.FLOAT, false, 36, 12);
+ gl.vertexAttribPointer(SpriteShader.textureLoc, 2, WEBGL.FLOAT, false, 36, 28);
+ gl.activeTexture(WEBGL.TEXTURE0);
+ gl.bindTexture(WEBGL.TEXTURE_2D, texture);
+ gl.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, null);
+ gl.enable(WEBGL.BLEND);
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ }
+};
+
+var SpriteShader$ = {};
+
+registerType("SpriteShader", [SpriteShader, SpriteShader$, null]);
+
+
+// wwtlib.ShapeSpriteShader
+
+export function ShapeSpriteShader() { }
+
+ShapeSpriteShader.vertLoc = 0;
+ShapeSpriteShader.textureLoc = 0;
+ShapeSpriteShader.colorLoc = 0;
+ShapeSpriteShader.initialized = false;
+ShapeSpriteShader._prog = null;
+
+ShapeSpriteShader.init = function (renderContext) {
+ var gl = renderContext.gl;
+
+ const fragShaderText = `\
+ precision mediump float;
+
+ varying lowp vec4 vColor;
+
+ void main(void) {
+ gl_FragColor = vColor;
+ }
+ `;
+
+ const vertexShaderText = `\
+ attribute vec3 aVertexPosition;
+ attribute lowp vec4 aColor;
+
+ uniform mat4 uMVMatrix;
+ uniform mat4 uPMatrix;
+
+ varying vec2 vTextureCoord;
+ varying vec4 vColor;
+
+ void main(void) {
+ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
+ vColor = aColor;
+ }
+ `;
+
+ ShapeSpriteShader._frag = gl.createShader(WEBGL.FRAGMENT_SHADER);
+ gl.shaderSource(ShapeSpriteShader._frag, fragShaderText);
+ gl.compileShader(ShapeSpriteShader._frag);
+ var stat = gl.getShaderParameter(ShapeSpriteShader._frag, WEBGL.COMPILE_STATUS);
+ ShapeSpriteShader._vert = gl.createShader(WEBGL.VERTEX_SHADER);
+ gl.shaderSource(ShapeSpriteShader._vert, vertexShaderText);
+ gl.compileShader(ShapeSpriteShader._vert);
+ var stat1 = gl.getShaderParameter(ShapeSpriteShader._vert, WEBGL.COMPILE_STATUS);
+ ShapeSpriteShader._prog = gl.createProgram();
+ gl.attachShader(ShapeSpriteShader._prog, ShapeSpriteShader._vert);
+ gl.attachShader(ShapeSpriteShader._prog, ShapeSpriteShader._frag);
+ gl.linkProgram(ShapeSpriteShader._prog);
+ var errcode = gl.getProgramParameter(ShapeSpriteShader._prog, WEBGL.LINK_STATUS);
+ gl.useProgram(ShapeSpriteShader._prog);
+ ShapeSpriteShader.vertLoc = gl.getAttribLocation(ShapeSpriteShader._prog, 'aVertexPosition');
+ ShapeSpriteShader.colorLoc = gl.getAttribLocation(ShapeSpriteShader._prog, 'aColor');
+ ShapeSpriteShader.projMatLoc = gl.getUniformLocation(ShapeSpriteShader._prog, 'uPMatrix');
+ ShapeSpriteShader.mvMatLoc = gl.getUniformLocation(ShapeSpriteShader._prog, 'uMVMatrix');
+ gl.disable(WEBGL.DEPTH_TEST);
+ gl.enable(WEBGL.BLEND);
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ ShapeSpriteShader.initialized = true;
+};
+
+ShapeSpriteShader.use = function (renderContext, vertex) {
+ var gl = renderContext.gl;
+ if (gl != null) {
+ if (!ShapeSpriteShader.initialized) {
+ ShapeSpriteShader.init(renderContext);
+ }
+ gl.useProgram(ShapeSpriteShader._prog);
+ var mvMat = Matrix3d.multiplyMatrix(renderContext.get_world(), renderContext.get_view());
+ gl.uniformMatrix4fv(ShapeSpriteShader.mvMatLoc, false, mvMat.floatArray());
+ gl.uniformMatrix4fv(ShapeSpriteShader.projMatLoc, false, renderContext.get_projection().floatArray());
+ gl.uniform1i(ShapeSpriteShader.sampLoc, 0);
+ gl.disable(WEBGL.DEPTH_TEST);
+ gl.disableVertexAttribArray(0);
+ gl.disableVertexAttribArray(1);
+ gl.disableVertexAttribArray(2);
+ gl.disableVertexAttribArray(3);
+ gl.bindBuffer(WEBGL.ARRAY_BUFFER, vertex);
+ gl.enableVertexAttribArray(ShapeSpriteShader.vertLoc);
+ gl.enableVertexAttribArray(ShapeSpriteShader.textureLoc);
+ gl.enableVertexAttribArray(ShapeSpriteShader.colorLoc);
+ gl.vertexAttribPointer(ShapeSpriteShader.vertLoc, 3, WEBGL.FLOAT, false, 36, 0);
+ gl.vertexAttribPointer(ShapeSpriteShader.colorLoc, 4, WEBGL.FLOAT, false, 36, 12);
+ gl.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, null);
+ gl.enable(WEBGL.BLEND);
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ }
+};
+
+var ShapeSpriteShader$ = {};
+
+registerType("ShapeSpriteShader", [ShapeSpriteShader, ShapeSpriteShader$, null]);
+
+
+// wwtlib.TextShader
+
+export function TextShader() { }
+
+TextShader.vertLoc = 0;
+TextShader.textureLoc = 0;
+TextShader.initialized = false;
+TextShader._prog = null;
+
+TextShader.init = function (renderContext) {
+ var gl = renderContext.gl;
+
+ const fragShaderText = `\
+ precision mediump float;
+
+ varying vec2 vTextureCoord;
+
+ uniform sampler2D uSampler;
+
+ void main(void) {
+ gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
+ }
+ `;
+
+ const vertexShaderText = `\
+ attribute vec3 aVertexPosition;
+ attribute vec2 aTextureCoord;
+
+ uniform mat4 uMVMatrix;
+ uniform mat4 uPMatrix;
+
+ varying vec2 vTextureCoord;
+
+ void main(void) {
+ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
+ vTextureCoord = aTextureCoord;
+ }
+ `;
+
+ TextShader._frag = gl.createShader(WEBGL.FRAGMENT_SHADER);
+ gl.shaderSource(TextShader._frag, fragShaderText);
+ gl.compileShader(TextShader._frag);
+ var stat = gl.getShaderParameter(TextShader._frag, WEBGL.COMPILE_STATUS);
+ TextShader._vert = gl.createShader(WEBGL.VERTEX_SHADER);
+ gl.shaderSource(TextShader._vert, vertexShaderText);
+ gl.compileShader(TextShader._vert);
+ var stat1 = gl.getShaderParameter(TextShader._vert, WEBGL.COMPILE_STATUS);
+ TextShader._prog = gl.createProgram();
+ gl.attachShader(TextShader._prog, TextShader._vert);
+ gl.attachShader(TextShader._prog, TextShader._frag);
+ gl.linkProgram(TextShader._prog);
+ var errcode = gl.getProgramParameter(TextShader._prog, WEBGL.LINK_STATUS);
+ gl.useProgram(TextShader._prog);
+ TextShader.vertLoc = gl.getAttribLocation(TextShader._prog, 'aVertexPosition');
+ TextShader.textureLoc = gl.getAttribLocation(TextShader._prog, 'aTextureCoord');
+ TextShader.projMatLoc = gl.getUniformLocation(TextShader._prog, 'uPMatrix');
+ TextShader.mvMatLoc = gl.getUniformLocation(TextShader._prog, 'uMVMatrix');
+ TextShader.sampLoc = gl.getUniformLocation(TextShader._prog, 'uSampler');
+ set_tileUvMultiple(1);
+ set_tileDemEnabled(true);
+ gl.enable(WEBGL.BLEND);
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ TextShader.initialized = true;
+};
+
+TextShader.use = function (renderContext, vertex, texture) {
+ if (texture == null) {
+ texture = Texture.getEmpty();
+ }
+ var gl = renderContext.gl;
+ if (gl != null) {
+ if (!TextShader.initialized) {
+ TextShader.init(renderContext);
+ }
+ gl.useProgram(TextShader._prog);
+ var mvMat = Matrix3d.multiplyMatrix(renderContext.get_world(), renderContext.get_view());
+ gl.uniformMatrix4fv(TextShader.mvMatLoc, false, mvMat.floatArray());
+ gl.uniformMatrix4fv(TextShader.projMatLoc, false, renderContext.get_projection().floatArray());
+ gl.uniform1i(TextShader.sampLoc, 0);
+ if (renderContext.space) {
+ gl.disable(WEBGL.DEPTH_TEST);
+ } else {
+ gl.enable(WEBGL.DEPTH_TEST);
+ }
+ gl.disableVertexAttribArray(0);
+ gl.disableVertexAttribArray(1);
+ gl.disableVertexAttribArray(2);
+ gl.disableVertexAttribArray(3);
+ gl.bindBuffer(WEBGL.ARRAY_BUFFER, vertex);
+ gl.enableVertexAttribArray(TextShader.vertLoc);
+ gl.enableVertexAttribArray(TextShader.textureLoc);
+ gl.vertexAttribPointer(TextShader.vertLoc, 3, WEBGL.FLOAT, false, 20, 0);
+ gl.vertexAttribPointer(TextShader.textureLoc, 2, WEBGL.FLOAT, false, 20, 12);
+ gl.activeTexture(WEBGL.TEXTURE0);
+ gl.bindTexture(WEBGL.TEXTURE_2D, texture);
+ gl.enable(WEBGL.BLEND);
+ gl.blendFunc(WEBGL.SRC_ALPHA, WEBGL.ONE_MINUS_SRC_ALPHA);
+ }
+};
+
+var TextShader$ = {};
+
+registerType("TextShader", [TextShader, TextShader$, null]);
diff --git a/engine/esm/graphics/sprite2d.js b/engine/esm/graphics/sprite2d.js
new file mode 100644
index 00000000..51310457
--- /dev/null
+++ b/engine/esm/graphics/sprite2d.js
@@ -0,0 +1,84 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Sprites.
+
+import { registerType } from "../typesystem.js";
+import { ss } from "../ss.js";
+import { tilePrepDevice } from "../render_globals.js";
+import { SpriteShader, ShapeSpriteShader } from "./shaders.js";
+import { WEBGL } from "./webgl_constants.js";
+
+
+// wwtlib.Sprite2d
+
+export function Sprite2d() {
+ this.vertCount = 0;
+}
+
+var Sprite2d$ = {
+ draw: function (renderContext, points, count, texture, triangleStrips, opacity) {
+ if (this.vertexBuffer == null) {
+ this.create(points);
+ } else {
+ this.update(points);
+ }
+ if (texture == null) {
+ ShapeSpriteShader.use(renderContext, this.vertexBuffer);
+ renderContext.gl.drawArrays(triangleStrips ? WEBGL.TRIANGLE_STRIP : WEBGL.TRIANGLES, 0, points.length);
+ } else {
+ SpriteShader.use(renderContext, this.vertexBuffer, (texture != null) ? texture.texture2d : null);
+ renderContext.gl.drawArrays(triangleStrips ? WEBGL.TRIANGLE_STRIP : WEBGL.TRIANGLES, 0, points.length);
+ }
+ },
+
+ create: function (verts) {
+ this.vertexBuffer = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ARRAY_BUFFER, this.vertexBuffer);
+ var f32array = new Float32Array(verts.length * 9);
+ var buffer = f32array;
+ var index = 0;
+ var $enum1 = ss.enumerate(verts);
+ while ($enum1.moveNext()) {
+ var pt = $enum1.current;
+ buffer[index++] = pt.position.x;
+ buffer[index++] = pt.position.y;
+ buffer[index++] = pt.position.z;
+ buffer[index++] = pt.color.r / 255;
+ buffer[index++] = pt.color.g / 255;
+ buffer[index++] = pt.color.b / 255;
+ buffer[index++] = pt.color.a / 255;
+ buffer[index++] = pt.tu;
+ buffer[index++] = pt.tv;
+ }
+ tilePrepDevice.bufferData(WEBGL.ARRAY_BUFFER, f32array, WEBGL.DYNAMIC_DRAW);
+ },
+
+ update: function (verts) {
+ if (this.vertCount < verts.length) {
+ tilePrepDevice.deleteBuffer(this.vertexBuffer);
+ this.create(verts);
+ return;
+ }
+ tilePrepDevice.bindBuffer(WEBGL.ARRAY_BUFFER, this.vertexBuffer);
+ var f32array = new Float32Array(verts.length * 9);
+ var buffer = f32array;
+ var index = 0;
+ var $enum1 = ss.enumerate(verts);
+ while ($enum1.moveNext()) {
+ var pt = $enum1.current;
+ buffer[index++] = pt.position.x;
+ buffer[index++] = pt.position.y;
+ buffer[index++] = pt.position.z;
+ buffer[index++] = pt.color.r / 255;
+ buffer[index++] = pt.color.g / 255;
+ buffer[index++] = pt.color.b / 255;
+ buffer[index++] = pt.color.a / 255;
+ buffer[index++] = pt.tu;
+ buffer[index++] = pt.tv;
+ }
+ tilePrepDevice.bufferSubData(WEBGL.ARRAY_BUFFER, 0, f32array);
+ }
+};
+
+registerType("Sprite2d", [Sprite2d, Sprite2d$, null]);
diff --git a/engine/esm/graphics/tessellator.js b/engine/esm/graphics/tessellator.js
new file mode 100644
index 00000000..4402f016
--- /dev/null
+++ b/engine/esm/graphics/tessellator.js
@@ -0,0 +1,124 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A tessellator algorithm.
+
+import { registerType } from "../typesystem.js";
+import { Vector3d } from "../double3d.js";
+
+
+// wwtlib.Tessellator
+
+export function Tessellator() { }
+
+Tessellator.tesselateSimplePoly = function (inputList) {
+ var results = [];
+ var tess = new Tessellator();
+ tess.process(inputList, results);
+ return results;
+};
+
+var Tessellator$ = {
+ _isLeftOfHalfSpace: function (pntA, pntB, pntTest) {
+ pntA.normalize();
+ pntB.normalize();
+ var cross = Vector3d.cross(pntA, pntB);
+ var dot = Vector3d.dot(cross, pntTest);
+ return dot > 0;
+ },
+
+ _insideTriangle: function (pntA, pntB, pntC, pntTest) {
+ if (!this._isLeftOfHalfSpace(pntA, pntB, pntTest)) {
+ return false;
+ }
+ if (!this._isLeftOfHalfSpace(pntB, pntC, pntTest)) {
+ return false;
+ }
+ if (!this._isLeftOfHalfSpace(pntC, pntA, pntTest)) {
+ return false;
+ }
+ return true;
+ },
+
+ _canClipEar: function (poly, u, v, w, n, verts) {
+ var p;
+ var a = poly[verts[u]].copy();
+ var b = poly[verts[v]].copy();
+ var c = poly[verts[w]].copy();
+ var P;
+ var d = Vector3d.subtractVectors(b, a);
+ d.normalize();
+ var e = Vector3d.subtractVectors(b, c);
+ e.normalize();
+ var g = Vector3d.cross(d, e);
+ var bn = b.copy();
+ bn.normalize();
+
+ // Determine if convex edge
+ if (Vector3d.dot(g, bn) > 0) {
+ return false;
+ }
+
+ // Check for any intersecting vertices that would invalidate this ear
+ for (p = 0; p < n; p++) {
+ if ((p === u) || (p === v) || (p === w)) {
+ continue;
+ }
+ P = poly[verts[p]].copy();
+
+ // don't clip earth if other intersecting vertex
+ if (this._insideTriangle(a, b, c, P)) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ process: function (poly, result) {
+ var n = poly.length;
+ if (poly.length < 3) {
+ return false;
+ }
+ var verts = new Array(poly.length);
+ for (var i = 0; i < n; i++) {
+ verts[i] = i;
+ }
+ var nv = n;
+ var count = 2 * nv;
+ for (var m = 0, v = nv - 1; nv > 2;) {
+ if (0 >= (count--)) {
+ // not enough ears to clip. Non-Simple Polygon
+ return false;
+ }
+ var u = v;
+ if (nv <= u) {
+ u = 0;
+ }
+ v = u + 1;
+ if (nv <= v) {
+ v = 0;
+ }
+ var w = v + 1;
+ if (nv <= w) {
+ w = 0;
+ }
+ if (this._canClipEar(poly, u, v, w, nv, verts)) {
+ var s, t;
+ result.push(verts[u]);
+ result.push(verts[v]);
+ result.push(verts[w]);
+ m++;
+
+ // remove clipped ear
+ for (s = v, t = v + 1; t < nv; s++, t++) {
+ verts[s] = verts[t];
+ }
+ nv--;
+ count = 2 * nv;
+ }
+ }
+ return true;
+ }
+};
+
+registerType("Tessellator", [Tessellator, Tessellator$, null]);
diff --git a/engine/esm/graphics/texture.js b/engine/esm/graphics/texture.js
new file mode 100644
index 00000000..0cbb0381
--- /dev/null
+++ b/engine/esm/graphics/texture.js
@@ -0,0 +1,128 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// The basic GL texture type.
+
+import { registerType } from "../typesystem.js";
+import { ss } from "../ss.js";
+import { tilePrepDevice } from "../render_globals.js";
+import { URLHelpers } from "../url_helpers.js";
+import { WEBGL } from "./webgl_constants.js";
+
+
+// wwtlib.Texture
+
+export function Texture() {
+ this.imageElement = null;
+ this.texture2d = null;
+ this._downloading = false;
+ this._ready = false;
+ this._errored = false;
+ this.URL = '';
+}
+
+Texture.empty = null;
+
+Texture.getEmpty = function () {
+ if (Texture.empty == null) {
+ Texture.empty = tilePrepDevice.createTexture();
+ tilePrepDevice.bindTexture(WEBGL.TEXTURE_2D, Texture.empty);
+ tilePrepDevice.texImage2D(WEBGL.TEXTURE_2D, 0, WEBGL.RGBA, 1, 1, 0, WEBGL.RGBA, WEBGL.UNSIGNED_BYTE, new Uint8Array([0, 0, 0, 0]));
+ tilePrepDevice.bindTexture(WEBGL.TEXTURE_2D, null);
+ }
+ return Texture.empty;
+};
+
+Texture.fromUrl = function (url) {
+ var tex = new Texture();
+ tex.load(url);
+ return tex;
+};
+
+Texture.isPowerOfTwo = function (val) {
+ return !(val & (val - 1));
+};
+
+Texture.fitPowerOfTwo = function (val) {
+ val--;
+ for (var i = 1; i < 32; i <<= 1) {
+ val = val | val >> i;
+ }
+ return val + 1;
+};
+
+var Texture$ = {
+ cleanUp: function () {
+ this.imageElement = null;
+ tilePrepDevice.deleteTexture(this.texture2d);
+ },
+
+ dispose: function () {
+ this.cleanUp();
+ },
+
+ load: function (url) {
+ var $this = this;
+
+ this.URL = url;
+ if (typeof document === "undefined") { return; }
+ if (!this._downloading) {
+ this._downloading = true;
+ this.imageElement = document.createElement('img');
+ var xdomimg = this.imageElement;
+ this.imageElement.addEventListener('load', function (e) {
+ $this._ready = true;
+ $this._downloading = false;
+ $this._errored = false;
+ $this.makeTexture();
+ }, false);
+ this.imageElement.addEventListener('error', function (e) {
+ if (!$this.imageElement.hasAttribute('proxyattempt')) {
+ $this.imageElement.setAttribute('proxyattempt', true);
+ var new_url = URLHelpers.singleton.activateProxy($this.URL);
+ if (new_url != null) { // null => don't bother: we know that the proxy won't help
+ $this.imageElement.src = new_url;
+ return;
+ }
+ }
+ $this._downloading = false;
+ $this._ready = false;
+ $this._errored = true;
+ }, false);
+ xdomimg.crossOrigin = 'anonymous';
+ this.imageElement.src = this.URL;
+ }
+ },
+
+ makeTexture: function () {
+ if (tilePrepDevice != null) {
+ try {
+ this.texture2d = tilePrepDevice.createTexture();
+ tilePrepDevice.bindTexture(WEBGL.TEXTURE_2D, this.texture2d);
+ var image = this.imageElement;
+
+ // Before we bind resize to a power of two if nessesary so we can MIPMAP
+ if ((!Texture.isPowerOfTwo(this.imageElement.height) | !Texture.isPowerOfTwo(this.imageElement.width)) === 1) {
+ var temp = document.createElement('canvas');
+ temp.height = Texture.fitPowerOfTwo(image.height);
+ temp.width = Texture.fitPowerOfTwo(image.width);
+ var ctx = temp.getContext('2d');
+ ctx.drawImage(image, 0, 0, temp.width, temp.height);
+ //Substitute the resized image
+ image = temp;
+ }
+
+ tilePrepDevice.texParameteri(WEBGL.TEXTURE_2D, WEBGL.TEXTURE_WRAP_S, WEBGL.CLAMP_TO_EDGE);
+ tilePrepDevice.texParameteri(WEBGL.TEXTURE_2D, WEBGL.TEXTURE_WRAP_T, WEBGL.CLAMP_TO_EDGE);
+ tilePrepDevice.texImage2D(WEBGL.TEXTURE_2D, 0, WEBGL.RGBA, WEBGL.RGBA, WEBGL.UNSIGNED_BYTE, image);
+ tilePrepDevice.texParameteri(WEBGL.TEXTURE_2D, WEBGL.TEXTURE_MIN_FILTER, WEBGL.LINEAR_MIPMAP_NEAREST);
+ tilePrepDevice.generateMipmap(WEBGL.TEXTURE_2D);
+ tilePrepDevice.bindTexture(WEBGL.TEXTURE_2D, null);
+ } catch ($e1) {
+ this._errored = true;
+ }
+ }
+ }
+};
+
+registerType("Texture", [Texture, Texture$, null, ss.IDisposable]);
diff --git a/engine/esm/graphics/webgl_constants.js b/engine/esm/graphics/webgl_constants.js
new file mode 100644
index 00000000..8f59df68
--- /dev/null
+++ b/engine/esm/graphics/webgl_constants.js
@@ -0,0 +1,314 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Magic constants defined by WebGL.
+
+export const WEBGL = {
+ ACTIVE_ATTRIBUTE_MAX_LENGTH: 35722,
+ ACTIVE_ATTRIBUTES: 35721,
+ ACTIVE_TEXTURE: 34016,
+ ACTIVE_UNIFORM_MAX_LENGTH: 35719,
+ ACTIVE_UNIFORMS: 35718,
+ ALIASED_LINE_WIDTH_RANGE: 33902,
+ ALIASED_POINT_SIZE_RANGE: 33901,
+ ALPHA: 6406,
+ ALPHA_BITS: 3413,
+ ALWAYS: 519,
+ ARRAY_BUFFER: 34962,
+ ARRAY_BUFFER_BINDING: 34964,
+ ATTACHED_SHADERS: 35717,
+ BACK: 1029,
+ BLEND: 3042,
+ BLEND_COLOR: 32773,
+ BLEND_DST_ALPHA: 32970,
+ BLEND_DST_RGB: 32968,
+ BLEND_EQUATION: 32777,
+ BLEND_EQUATION_ALPHA: 34877,
+ BLEND_EQUATION_RGB: 32777,
+ BLEND_SRC_ALPHA: 32971,
+ BLEND_SRC_RGB: 32969,
+ BLUE_BITS: 3412,
+ BOOL: 35670,
+ BOOL_VEC2: 35671,
+ BOOL_VEC3: 35672,
+ BOOL_VEC4: 35673,
+ BUFFER_SIZE: 34660,
+ BUFFER_USAGE: 34661,
+ BYTE: 5120,
+ CCW: 2305,
+ CLAMP_TO_EDGE: 33071,
+ COLOR_ATTACHMENT0: 36064,
+ COLOR_BUFFER_BIT: 16384,
+ COLOR_CLEAR_VALUE: 3106,
+ COLOR_WRITEMASK: 3107,
+ COMPILE_STATUS: 35713,
+ COMPRESSED_TEXTURE_FORMATS: 34467,
+ CONSTANT_ALPHA: 32771,
+ CONSTANT_COLOR: 32769,
+ CULL_FACE: 2884,
+ CULL_FACE_MODE: 2885,
+ CURRENT_PROGRAM: 35725,
+ CURRENT_VERTEX_ATTRIB: 34342,
+ CW: 2304,
+ DECR: 7683,
+ DECR_WRAP: 34056,
+ DELETE_STATUS: 35712,
+ DEPTH_ATTACHMENT: 36096,
+ DEPTH_BITS: 3414,
+ DEPTH_BUFFER_BIT: 256,
+ DEPTH_CLEAR_VALUE: 2931,
+ DEPTH_COMPONENT: 6402,
+ DEPTH_COMPONENT16: 33189,
+ DEPTH_FUNC: 2932,
+ DEPTH_RANGE: 2928,
+ DEPTH_STENCIL: 34041,
+ DEPTH_STENCIL_ATTACHMENT: 33306,
+ DEPTH_TEST: 2929,
+ DEPTH_WRITEMASK: 2930,
+ DITHER: 3024,
+ DONT_CARE: 4352,
+ DST_ALPHA: 772,
+ DST_COLOR: 774,
+ DYNAMIC_DRAW: 35048,
+ ELEMENT_ARRAY_BUFFER: 34963,
+ ELEMENT_ARRAY_BUFFER_BINDING: 34965,
+ EQUAL: 514,
+ EXTENSIONS: 7939,
+ FASTEST: 4353,
+ FLOAT: 5126,
+ FLOAT_MAT2: 35674,
+ FLOAT_MAT3: 35675,
+ FLOAT_MAT4: 35676,
+ FLOAT_VEC2: 35664,
+ FLOAT_VEC3: 35665,
+ FLOAT_VEC4: 35666,
+ FRAGMENT_SHADER: 35632,
+ FRAMEBUFFER: 36160,
+ FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: 36049,
+ FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: 36048,
+ FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: 36051,
+ FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: 36050,
+ FRAMEBUFFER_BINDING: 36006,
+ FRAMEBUFFER_COMPLETE: 36053,
+ FRAMEBUFFER_INCOMPLETE_ATTACHMENT: 36054,
+ FRAMEBUFFER_INCOMPLETE_DIMENSIONS: 36057,
+ FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: 36055,
+ FRAMEBUFFER_UNSUPPORTED: 36061,
+ FRONT: 1028,
+ FRONT_AND_BACK: 1032,
+ FRONT_FACE: 2886,
+ FUNC_ADD: 32774,
+ FUNC_REVERSE_SUBTRACT: 32779,
+ FUNC_SUBTRACT: 32778,
+ GENERATE_MIPMAP_HINT: 33170,
+ GEQUAL: 518,
+ GREATER: 516,
+ GREEN_BITS: 3411,
+ HIGH_FLOAT: 36338,
+ HIGH_INT: 36341,
+ IMPLEMENTATION_COLOR_READ_FORMAT: 35739,
+ IMPLEMENTATION_COLOR_READ_TYPE: 35738,
+ INCR: 7682,
+ INCR_WRAP: 34055,
+ INFO_LOG_LENGTH: 35716,
+ INT: 5124,
+ INT_VEC2: 35667,
+ INT_VEC3: 35668,
+ INT_VEC4: 35669,
+ INVALID_ENUM: 1280,
+ INVALID_FRAMEBUFFER_OPERATION: 1286,
+ INVALID_OPERATION: 1282,
+ INVALID_VALUE: 1281,
+ INVERT: 5386,
+ KEEP: 7680,
+ LEQUAL: 515,
+ LESS: 513,
+ LINE_LOOP: 2,
+ LINE_STRIP: 3,
+ LINE_WIDTH: 2849,
+ LINEAR: 9729,
+ LINEAR_MIPMAP_LINEAR: 9987,
+ LINEAR_MIPMAP_NEAREST: 9985,
+ LINES: 1,
+ LINK_STATUS: 35714,
+ LOW_FLOAT: 36336,
+ LOW_INT: 36339,
+ LUMINANCE: 6409,
+ LUMINANCE_ALPHA: 6410,
+ MAX_COMBINED_TEXTURE_IMAGE_UNITS: 35661,
+ MAX_CUBE_MAP_TEXTURE_SIZE: 34076,
+ MAX_FRAGMENT_UNIFORM_VECTORS: 36349,
+ MAX_RENDERBUFFER_SIZE: 34024,
+ MAX_TEXTURE_IMAGE_UNITS: 34930,
+ MAX_TEXTURE_SIZE: 3379,
+ MAX_VARYING_VECTORS: 36348,
+ MAX_VERTEX_ATTRIBS: 34921,
+ MAX_VERTEX_TEXTURE_IMAGE_UNITS: 35660,
+ MAX_VERTEX_UNIFORM_VECTORS: 36347,
+ MAX_VIEWPORT_DIMS: 3386,
+ MEDIUM_FLOAT: 36337,
+ MEDIUM_INT: 36340,
+ MIRRORED_REPEAT: 33648,
+ NEAREST: 9728,
+ NEAREST_MIPMAP_LINEAR: 9986,
+ NEAREST_MIPMAP_NEAREST: 9984,
+ NEVER: 512,
+ NICEST: 4354,
+ NO_ERROR: 0,
+ NONE: 0,
+ NOTEQUAL: 517,
+ NUM_COMPRESSED_TEXTURE_FORMATS: 34466,
+ ONE: 1,
+ ONE_MINUS_CONSTANT_ALPHA: 32772,
+ ONE_MINUS_CONSTANT_COLOR: 32770,
+ ONE_MINUS_DST_ALPHA: 773,
+ ONE_MINUS_DST_COLOR: 775,
+ ONE_MINUS_SRC_ALPHA: 771,
+ ONE_MINUS_SRC_COLOR: 769,
+ OUT_OF_MEMORY: 1285,
+ PACK_ALIGNMENT: 3333,
+ POINTS: 0,
+ POLYGON_OFFSET_FACTOR: 32824,
+ POLYGON_OFFSET_FILL: 32823,
+ POLYGON_OFFSET_UNITS: 10752,
+ RED_BITS: 3410,
+ RENDERBUFFER: 36161,
+ RENDERBUFFER_ALPHA_SIZE: 36179,
+ RENDERBUFFER_BINDING: 36007,
+ RENDERBUFFER_BLUE_SIZE: 36178,
+ RENDERBUFFER_DEPTH_SIZE: 36180,
+ RENDERBUFFER_GREEN_SIZE: 36177,
+ RENDERBUFFER_HEIGHT: 36163,
+ RENDERBUFFER_INTERNAL_FORMAT: 36164,
+ RENDERBUFFER_RED_SIZE: 36176,
+ RENDERBUFFER_STENCIL_SIZE: 36181,
+ RENDERBUFFER_WIDTH: 36162,
+ RENDERER: 7937,
+ REPEAT: 10497,
+ REPLACE: 7681,
+ RGB: 6407,
+ RGB8: 32849,
+ RGB5_A1: 32855,
+ RGB565: 36194,
+ RGBA: 6408,
+ RGBA8: 32856,
+ RGBA16I: 36232,
+ RED_INTEGER: 36244,
+ RED: 6403,
+ R32F: 33326,
+ R16I: 33331,
+ RGBA4: 32854,
+ SAMPLE_ALPHA_TO_COVERAGE: 32926,
+ SAMPLE_BUFFERS: 32936,
+ SAMPLE_COVERAGE: 32928,
+ SAMPLE_COVERAGE_INVERT: 32939,
+ SAMPLE_COVERAGE_VALUE: 32938,
+ SAMPLER_2D: 35678,
+ SAMPLER_CUBE: 35680,
+ SAMPLES: 32937,
+ SCISSOR_BOX: 3088,
+ SCISSOR_TEST: 3089,
+ SHADER_COMPILER: 36346,
+ SHADER_SOURCE_LENGTH: 35720,
+ SHADER_TYPE: 35663,
+ SHADING_LANGUAGE_VERSION: 35724,
+ SHORT: 5122,
+ SRC_ALPHA: 770,
+ SRC_ALPHA_SATURATE: 776,
+ SRC_COLOR: 768,
+ STATIC_DRAW: 35044,
+ STENCIL_ATTACHMENT: 36128,
+ STENCIL_BACK_FAIL: 34817,
+ STENCIL_BACK_FUNC: 34816,
+ STENCIL_BACK_PASS_DEPTH_FAIL: 34818,
+ STENCIL_BACK_PASS_DEPTH_PASS: 34819,
+ STENCIL_BACK_REF: 36003,
+ STENCIL_BACK_VALUE_MASK: 36004,
+ STENCIL_BACK_WRITEMASK: 36005,
+ STENCIL_BITS: 3415,
+ STENCIL_BUFFER_BIT: 1024,
+ STENCIL_CLEAR_VALUE: 2961,
+ STENCIL_FAIL: 2964,
+ STENCIL_FUNC: 2962,
+ STENCIL_INDEX: 6401,
+ STENCIL_INDEX8: 36168,
+ STENCIL_PASS_DEPTH_FAIL: 2965,
+ STENCIL_PASS_DEPTH_PASS: 2966,
+ STENCIL_REF: 2967,
+ STENCIL_TEST: 2960,
+ STENCIL_VALUE_MASK: 2963,
+ STENCIL_WRITEMASK: 2968,
+ STREAM_DRAW: 35040,
+ SUBPIXEL_BITS: 3408,
+ TEXTURE: 5890,
+ TEXTURE_2D: 3553,
+ TEXTURE_BINDING_2D: 32873,
+ TEXTURE_BINDING_CUBE_MAP: 34068,
+ TEXTURE_CUBE_MAP: 34067,
+ TEXTURE_CUBE_MAP_NEGATIVE_X: 34070,
+ TEXTURE_CUBE_MAP_NEGATIVE_Y: 34072,
+ TEXTURE_CUBE_MAP_NEGATIVE_Z: 34074,
+ TEXTURE_CUBE_MAP_POSITIVE_X: 34069,
+ TEXTURE_CUBE_MAP_POSITIVE_Y: 34071,
+ TEXTURE_CUBE_MAP_POSITIVE_Z: 34073,
+ UNPACK_FLIP_Y_WEBGL: 37440,
+ TEXTURE_MAG_FILTER: 10240,
+ TEXTURE_MIN_FILTER: 10241,
+ TEXTURE_WRAP_S: 10242,
+ TEXTURE_WRAP_T: 10243,
+ TEXTURE0: 33984,
+ TEXTURE1: 33985,
+ TEXTURE10: 33994,
+ TEXTURE11: 33995,
+ TEXTURE12: 33996,
+ TEXTURE13: 33997,
+ TEXTURE14: 33998,
+ TEXTURE15: 33999,
+ TEXTURE16: 34000,
+ TEXTURE17: 34001,
+ TEXTURE18: 34002,
+ TEXTURE19: 34003,
+ TEXTURE2: 33986,
+ TEXTURE20: 34004,
+ TEXTURE21: 34005,
+ TEXTURE22: 34006,
+ TEXTURE23: 34007,
+ TEXTURE24: 34008,
+ TEXTURE25: 34009,
+ TEXTURE26: 34010,
+ TEXTURE27: 34011,
+ TEXTURE28: 34012,
+ TEXTURE29: 34013,
+ TEXTURE3: 33987,
+ TEXTURE30: 34014,
+ TEXTURE31: 34015,
+ TEXTURE4: 33988,
+ TEXTURE5: 33989,
+ TEXTURE6: 33990,
+ TEXTURE7: 33991,
+ TEXTURE8: 33992,
+ TEXTURE9: 33993,
+ TRIANGLE_FAN: 6,
+ TRIANGLE_STRIP: 5,
+ TRIANGLES: 4,
+ UNPACK_ALIGNMENT: 3317,
+ UNSIGNED_BYTE: 5121,
+ UNSIGNED_INT: 5125,
+ UNSIGNED_SHORT: 5123,
+ UNSIGNED_SHORT_4_4_4_4: 32819,
+ UNSIGNED_SHORT_5_5_5_1: 32820,
+ UNSIGNED_SHORT_5_6_5: 33635,
+ VALIDATE_STATUS: 35715,
+ VENDOR: 7936,
+ VERSION: 7938,
+ VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: 34975,
+ VERTEX_ATTRIB_ARRAY_ENABLED: 34338,
+ VERTEX_ATTRIB_ARRAY_NORMALIZED: 34922,
+ VERTEX_ATTRIB_ARRAY_POINTER: 34373,
+ VERTEX_ATTRIB_ARRAY_SIZE: 34339,
+ VERTEX_ATTRIB_ARRAY_STRIDE: 34340,
+ VERTEX_ATTRIB_ARRAY_TYPE: 34341,
+ VERTEX_SHADER: 35633,
+ VIEWPORT: 2978,
+ ZERO: 0,
+};
diff --git a/engine/esm/grids.js b/engine/esm/grids.js
new file mode 100644
index 00000000..6521fc64
--- /dev/null
+++ b/engine/esm/grids.js
@@ -0,0 +1,974 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Various grids that can overlay the sky view.
+
+import { ss } from "./ss.js";
+import { registerType } from "./typesystem.js";
+import { URLHelpers } from "./url_helpers.js";
+import { Vector3d, Matrix3d, PositionTexture } from "./double3d.js";
+import { DT } from "./astrocalc/date.js";
+import { CT } from "./astrocalc/coordinate_transformation.js";
+import { WEBGL } from "./graphics/webgl_constants.js";
+import { PointList, SimpleLineList, Dates } from "./graphics/primitives3d.js";
+import { PositionTextureVertexBuffer } from "./graphics/gl_buffers.js";
+import { Texture } from "./graphics/texture.js";
+import { ImageShader } from "./graphics/shaders.js";
+import { Colors } from "./color.js";
+import { freestandingMode } from "./data_globals.js";
+import { globalRenderContext, tilePrepDevice } from "./render_globals.js";
+import { BinaryReader } from "./utilities/binary_reader.js";
+import { Coordinates } from "./coordinates.js";
+import { Text3d, Text3dBatch } from "./sky_text.js";
+import { Planets } from "./planets.js";
+import { SpaceTimeController } from "./space_time_controller.js";
+import { Star, Galaxy } from "./star.js";
+import { WebFile } from "./web_file.js";
+
+
+// wwtlib.Grids
+
+export function Grids() { }
+
+Grids._galaxyImageIndexBuffer = null;
+Grids._galaxyImageTriangleCount = 0;
+Grids._milkyWayImage = null;
+Grids._starSprites = null;
+Grids._starCount = 0;
+Grids._starsDownloading = false;
+Grids._stars = null;
+Grids._hipparcosIndex = {};
+Grids._limitingMagnitude = 16;
+Grids._galaxyTextures = null;
+Grids._galaxyVertexCounts = null;
+Grids._largeSet = true;
+Grids._cosmosReady = false;
+Grids._cosmos = null;
+Grids._downloadingGalaxy = false;
+Grids._eclipticCount = 0;
+Grids._eclipticYear = 0;
+Grids._monthDays = [31, 28.2421, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
+Grids._monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
+Grids._eclipticTextYear = 0;
+
+Grids._createGalaxyImage = function (renderContext) {
+ if (Grids._milkyWayImage == null) {
+ Grids._milkyWayImage = Texture.fromUrl(URLHelpers.singleton.engineAssetUrl('milkywaybar.jpg'));
+ }
+ var subdivs = 50;
+ var lat, lng;
+ var index = 0;
+ var latMin = 64;
+ var latMax = -64;
+ var lngMin = -64;
+ var lngMax = 64;
+ Grids._galaxyImageVertexBuffer = new PositionTextureVertexBuffer((subdivs + 1) * (subdivs + 1));
+ var verts = Grids._galaxyImageVertexBuffer.lock();
+ var x1, y1;
+ var latDegrees = latMax - latMin;
+ var lngDegrees = lngMax - lngMin;
+ var scaleFactor = 60800000;
+ var ecliptic = Coordinates.meanObliquityOfEcliptic(SpaceTimeController.get_jNow()) / 180 * Math.PI;
+ var point;
+ var textureStepX = 1 / subdivs;
+ var textureStepY = 1 / subdivs;
+ for (y1 = 0; y1 <= subdivs; y1++) {
+ if (y1 !== subdivs) {
+ lat = latMax - (textureStepY * latDegrees * y1);
+ } else {
+ lat = latMin;
+ }
+ for (x1 = 0; x1 <= subdivs; x1++) {
+ if (x1 !== subdivs) {
+ lng = lngMin + (textureStepX * lngDegrees * x1);
+ }
+ else {
+ lng = lngMax;
+ }
+ index = y1 * (subdivs + 1) + x1;
+ point = Vector3d.create(lng * scaleFactor, 0, (lat - 28) * scaleFactor);
+ point.rotateY(213 / 180 * Math.PI);
+ point.rotateZ((-62.87175) / 180 * Math.PI);
+ point.rotateY((-192.8595083) / 180 * Math.PI);
+ point.rotateX(ecliptic);
+ verts[index] = PositionTexture.createPosRaw(point, (1 - x1 * textureStepX), (y1 * textureStepY));
+ }
+ }
+ Grids._galaxyImageVertexBuffer.unlock();
+ Grids._galaxyImageTriangleCount = subdivs * subdivs * 2;
+ var ui16array = new Uint16Array(subdivs * subdivs * 6);
+ var indexArray = ui16array;
+ for (y1 = 0; y1 < subdivs; y1++) {
+ for (x1 = 0; x1 < subdivs; x1++) {
+ index = (y1 * subdivs * 6) + 6 * x1;
+
+ // First triangle in quad
+ indexArray[index] = (y1 * (subdivs + 1) + x1);
+ indexArray[index + 2] = ((y1 + 1) * (subdivs + 1) + x1);
+ indexArray[index + 1] = (y1 * (subdivs + 1) + (x1 + 1));
+
+ // Second triangle in quad
+ indexArray[index + 3] = (y1 * (subdivs + 1) + (x1 + 1));
+ indexArray[index + 5] = ((y1 + 1) * (subdivs + 1) + x1);
+ indexArray[index + 4] = ((y1 + 1) * (subdivs + 1) + (x1 + 1));
+ }
+ }
+ Grids._galaxyImageIndexBuffer = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, Grids._galaxyImageIndexBuffer);
+ tilePrepDevice.bufferData(WEBGL.ELEMENT_ARRAY_BUFFER, ui16array, WEBGL.STATIC_DRAW);
+};
+
+Grids.drawGalaxyImage = function (renderContext, opacity) {
+ if (Grids._galaxyImageIndexBuffer == null) {
+ Grids._createGalaxyImage(renderContext);
+ }
+ var zoom = renderContext.viewCamera.zoom;
+ var log = Math.log(Math.max(1, zoom)) / Math.log(4);
+ var distAlpha = (log - 14) * 128;
+ var alpha = (Math.min(255, Math.max(0, distAlpha)) * opacity);
+ ImageShader.use(renderContext, Grids._galaxyImageVertexBuffer.vertexBuffer, Grids._galaxyImageIndexBuffer, Grids._milkyWayImage.texture2d, opacity, true);
+ renderContext.gl.drawElements(WEBGL.TRIANGLES, Grids._galaxyImageTriangleCount * 3, WEBGL.UNSIGNED_SHORT, 0);
+};
+
+Grids.drawStars3D = function (renderContext, opacity) {
+ var zoom = renderContext.viewCamera.zoom;
+ var distAlpha = Math.max(Math.min(255, (Math.log(zoom) - 15.5) * 40.8), 0);
+ var alpha = Math.min(255, Math.max(0, ss.truncate(distAlpha)));
+ if (alpha > 254) {
+ return;
+ }
+ alpha = ((255 - alpha) * opacity);
+ if (Grids._starSprites == null) {
+ Grids.initStarVertexBuffer(renderContext);
+ }
+ if (Grids._starSprites != null) {
+ Grids._starSprites.draw(renderContext, alpha / 255, false);
+ }
+};
+
+Grids.initStarVertexBuffer = function (renderContext) {
+ if (!Grids._starsDownloading && !freestandingMode) {
+ Grids.getStarFile(URLHelpers.singleton.coreStaticUrl('wwtweb/catalog.aspx?Q=hipparcos'));
+ Grids._starsDownloading = true;
+ }
+ if (Grids._starSprites == null && Grids._starCount > 0) {
+ var ecliptic = Coordinates.meanObliquityOfEcliptic(SpaceTimeController.get_jNow()) / 180 * Math.PI;
+ var count = Grids._stars.length;
+ Grids._starCount = count;
+ Grids._starSprites = new PointList(renderContext);
+ Grids._starSprites.depthBuffered = false;
+ Grids._starSprites.showFarSide = true;
+ var $enum1 = ss.enumerate(Grids._stars);
+ while ($enum1.moveNext()) {
+ var star = $enum1.current;
+ var pos = Coordinates.raDecTo3dAu(star.RA, star.dec, star.distance);
+ pos.rotateX(ecliptic);
+ star.position = pos;
+ var radDec = (1200000) / Math.pow(1.6, star.absoluteMagnitude);
+ Grids._starSprites.addPoint(pos, star.col, new Dates(0, 1), radDec * 100);
+ }
+ }
+};
+
+Grids.initializeStarDB = function (text) {
+ if (Grids._stars == null) {
+ if (Grids._stars == null) {
+ Grids._stars = [];
+ var rows = text.split('\r\n');
+ var star;
+ var $enum1 = ss.enumerate(rows);
+ while ($enum1.moveNext()) {
+ var row = $enum1.current;
+ var line = row;
+ star = new Star(line);
+ if (star.magnitude < Grids._limitingMagnitude && star.par > 0.001) {
+ Grids._stars.push(star);
+ Grids._hipparcosIndex[star.id] = star;
+ }
+ }
+ Grids._starCount = Grids._stars.length;
+ }
+ }
+};
+
+Grids.getStarFile = function (url) {
+ Grids._webFileStar = new WebFile(url);
+ Grids._webFileStar.onStateChange = Grids.starFileStateChange;
+ Grids._webFileStar.send();
+};
+
+Grids.starFileStateChange = function () {
+ if (Grids._webFileStar.get_state() === 2) {
+ alert(Grids._webFileStar.get_message());
+ }
+ else if (Grids._webFileStar.get_state() === 1) {
+ Grids.initializeStarDB(Grids._webFileStar.getText());
+ }
+};
+
+Grids.getGalaxyFile = function (url) {
+ Grids._webFileGalaxy = new WebFile(url);
+ Grids._webFileGalaxy.responseType = 'blob';
+ Grids._webFileGalaxy.onStateChange = Grids.galaxyFileStateChange;
+ Grids._webFileGalaxy.send();
+};
+
+Grids.galaxyFileStateChange = function () {
+ if (Grids._webFileGalaxy.get_state() === 2) {
+ alert(Grids._webFileGalaxy.get_message());
+ }
+ else if (Grids._webFileGalaxy.get_state() === 1) {
+ var mainBlob = Grids._webFileGalaxy.getBlob();
+ var chunck = new FileReader();
+ chunck.onloadend = function (e) {
+ var br = new BinaryReader(new Uint8Array(chunck.result));
+ Grids.initializeCosmos(br);
+ };
+ chunck.readAsArrayBuffer(mainBlob);
+ }
+};
+
+Grids.drawCosmos3D = function (renderContext, opacity) {
+ var device = renderContext.gl;
+ var zoom = renderContext.viewCamera.zoom;
+ var distAlpha = ((Math.log(Math.max(1, zoom)) / Math.log(4)) - 15.5) * 90;
+ var alpha = Math.min(255, Math.max(0, ss.truncate(distAlpha)));
+ if (alpha < 3) {
+ return;
+ }
+ Grids.initCosmosVertexBuffer();
+ if (Grids._galaxyTextures == null) {
+ if (Grids._largeSet) {
+ Grids._galaxyTextures = new Array(256);
+ for (var i = 0; i < 256; i++) {
+ var num = i.toString();
+ while (num.length < 4) {
+ num = '0' + num;
+ }
+ var name = ss.format(URLHelpers.singleton.engineAssetUrl('galimg/gal_{0}.jpg'), num);
+ Grids._galaxyTextures[i] = Texture.fromUrl(name);
+ }
+ }
+ }
+ if (Grids._cosmosReady) {
+ var count = 256;
+ for (var i = 0; i < count; i++) {
+ Grids._cosmosSprites[i].drawTextured(renderContext, Grids._galaxyTextures[i].texture2d, (alpha * opacity) / 255);
+ }
+ }
+};
+
+Grids.initCosmosVertexBuffer = function () {
+ if (Grids._cosmosSprites == null) {
+ Grids._downloadCosmosFile();
+ }
+};
+
+Grids._createCosmosVertexBuffer = function (renderContext) {
+ var device = tilePrepDevice;
+ var bucketCount = 256;
+ if (Grids._cosmosSprites != null) {
+ for (var ij = 0; ij < bucketCount; ij++) {
+ if (Grids._cosmosSprites[ij] != null) {
+ Grids._cosmosSprites[ij] = null;
+ }
+ }
+ }
+ Grids._cosmosSprites = null;
+ var ecliptic = Coordinates.meanObliquityOfEcliptic(SpaceTimeController.get_jNow()) / 180 * Math.PI;
+ Grids._cosmosSprites = new Array(bucketCount);
+ var indexList = new Array(bucketCount);
+ for (var i = 0; i < bucketCount; i++) {
+ var count = Grids._galaxyVertexCounts[i];
+ Grids._cosmosSprites[i] = new PointList(renderContext);
+ Grids._cosmosSprites[i].depthBuffered = false;
+ Grids._cosmosSprites[i].showFarSide = true;
+ indexList[i] = 0;
+ }
+ var $enum1 = ss.enumerate(Grids._cosmos);
+ while ($enum1.moveNext()) {
+ var galaxy = $enum1.current;
+ var bucket = galaxy.eTypeBucket;
+ var index = indexList[bucket];
+ var pos = Coordinates.raDecTo3dAu(galaxy.RA, galaxy.dec, (galaxy.distance * 206264.806 * 1000000) / 0.73);
+ pos.rotateX(ecliptic);
+ galaxy.position = pos;
+ Grids._cosmosSprites[bucket].addPoint(pos, Colors.get_white(), new Dates(0, 1), (1E+09 * galaxy.size * 100));
+ indexList[bucket]++;
+ }
+ Grids._cosmosReady = true;
+};
+
+Grids.initializeCosmos = function (br) {
+ var max = Math.pow(100, 2.849485002);
+ if (Grids._cosmos == null) {
+ Grids._galaxyVertexCounts = new Array((Grids._largeSet) ? 256 : 20);
+ if (Grids._cosmos == null) {
+ Grids._cosmos = [];
+ var galaxy;
+ try {
+ var count = 0;
+ while (br.get_position() < br.get_length()) {
+ galaxy = new Galaxy(br);
+ Grids._cosmos.push(galaxy);
+ Grids._galaxyVertexCounts[galaxy.eTypeBucket]++;
+ count++;
+ }
+ }
+ catch ($e1) {
+ }
+ br.close();
+ }
+ Grids._createCosmosVertexBuffer(globalRenderContext);
+ }
+};
+
+Grids._downloadCosmosFile = function () {
+ if (!Grids._downloadingGalaxy && !freestandingMode) {
+ Grids.getGalaxyFile(URLHelpers.singleton.coreStaticUrl('wwtweb/catalog.aspx?Q=cosmosnewbin'));
+ Grids._downloadingGalaxy = true;
+ }
+ return false;
+};
+
+Grids.drawEquitorialGrid = function (renderContext, opacity, drawColor) {
+ if (Grids._equLineList == null) {
+ Grids._equLineList = new SimpleLineList();
+ Grids._equLineList.set_depthBuffered(false);
+ for (var hour = 0; hour < 24; hour++) {
+ for (var dec = -80; dec < 80; dec += 2) {
+ Grids._equLineList.addLine(Coordinates.raDecTo3dAu(hour, dec, 1), Coordinates.raDecTo3dAu(hour, dec + 2, 1));
+ }
+ }
+ for (var dec = -80; dec <= 80; dec += 10) {
+ for (var hour = 0; hour < 23.8; hour += 0.2) {
+ Grids._equLineList.addLine(Coordinates.raDecTo3dAu(hour, dec, 1), Coordinates.raDecTo3dAu(hour + 0.2, dec, 1));
+ //todo fix for color bright
+ }
+ }
+ var counter = 0;
+ for (var ra = 0; ra < 24; ra += 0.25) {
+ var dec = 0.5;
+ switch (counter % 4) {
+ case 0:
+ counter++;
+ continue;
+ case 3:
+ case 1:
+ dec = 0.25;
+ break;
+ }
+ counter++;
+ Grids._equLineList.addLine(Coordinates.raDecTo3dAu(ra, dec, 1), Coordinates.raDecTo3dAu(ra, -dec, 1));
+ }
+ counter = 0;
+ for (var ra = 0; ra < 24; ra += 3) {
+ counter = 0;
+ for (var dec = -80; dec <= 80; dec += 1) {
+ var width = 0.5 / 30;
+ switch (counter % 10) {
+ case 0:
+ counter++;
+ continue;
+ case 5:
+ width = 0.5 / 15;
+ break;
+ }
+ counter++;
+ Grids._equLineList.addLine(Coordinates.raDecTo3dAu(ra + width, dec, 1), Coordinates.raDecTo3dAu(ra - width, dec, 1));
+ }
+ }
+ }
+ Grids._equLineList.drawLines(renderContext, opacity, drawColor);
+ return true;
+};
+
+Grids.drawEquitorialGridText = function (renderContext, opacity, drawColor) {
+ Grids._makeEquitorialGridText();
+ Grids._equTextBatch.draw(renderContext, opacity, drawColor);
+ return true;
+};
+
+Grids._makeEquitorialGridText = function () {
+ if (Grids._equTextBatch == null) {
+ Grids._equTextBatch = new Text3dBatch(30);
+ var index = 0;
+ for (var ra = 0; ra < 24; ra++) {
+ var text = ra.toString() + ' hr';
+ if (ra < 10) {
+ text = ' ' + ra.toString() + ' hr';
+ }
+ Grids._equTextBatch.add(new Text3d(Coordinates.raDecTo3dAu(ra + 0.005, 0.4, 1), Coordinates.raDecTo3dAu(ra + 0.005, 0.5, 1), text, 45, 0.00018));
+ }
+ index = 0;
+ for (var ra = 0; ra < 24; ra += 3) {
+ for (var dec = -80; dec <= 80; dec += 10) {
+ if (!dec) {
+ continue;
+ }
+ var text = dec.toString();
+ if (dec > 0) {
+ text = ' +' + dec.toString();
+ Grids._equTextBatch.add(new Text3d(Coordinates.raDecTo3dAu(ra, dec - 0.4, 1), Coordinates.raDecTo3dAu(ra, dec - 0.3, 1), text, 45, 0.00018));
+ }
+ else {
+ text = ' - ' + text.substr(1);
+ Grids._equTextBatch.add(new Text3d(Coordinates.raDecTo3dAu(ra, dec + 0.4, 1), Coordinates.raDecTo3dAu(ra, dec + 0.5, 1), text, 45, 0.00018));
+ }
+ index++;
+ }
+ }
+ }
+};
+
+Grids.drawEcliptic = function (renderContext, opacity, drawColor) {
+ var col = drawColor;
+ var year = SpaceTimeController.get_now().getUTCFullYear();
+ if (Grids._eclipticOverviewLineList == null || year !== Grids._eclipticYear) {
+ if (Grids._eclipticOverviewLineList != null) {
+ Grids._eclipticOverviewLineList.clear();
+ Grids._eclipticOverviewLineList = null;
+ }
+ Grids._eclipticYear = year;
+ var obliquity = Coordinates.meanObliquityOfEcliptic(SpaceTimeController.get_jNow());
+ var mat = Matrix3d._rotationX((-obliquity / 360 * (Math.PI * 2)));
+ var daysPerYear = 365.25;
+ if (DT.isLeap(year, true)) {
+ Grids._monthDays[1] = 29;
+ daysPerYear = 366;
+ } else {
+ Grids._monthDays[1] = 28;
+ daysPerYear = 365;
+ }
+ var count = 2 * ss.truncate(daysPerYear);
+ Grids._eclipticCount = ss.truncate(daysPerYear);
+ var jYear = SpaceTimeController.utcToJulian(new Date(year, 0, 1, 12, 0, 0));
+ var index = 0;
+ var d = 0;
+ Grids._eclipticOverviewLineList = new SimpleLineList();
+ Grids._eclipticOverviewLineList.set_depthBuffered(false);
+ for (var m = 0; m < 12; m++) {
+ var daysThisMonth = ss.truncate(Grids._monthDays[m]);
+ for (var i = 0; i < daysThisMonth; i++) {
+ var sunRaDec = Planets.getPlanetLocationJD('Sun', jYear);
+ var sunEcliptic = CT.eq2Ec(sunRaDec.RA, sunRaDec.dec, obliquity);
+ d = sunEcliptic.x;
+ var width = 0.005;
+ if (!i) {
+ width = 0.01;
+ }
+ var dd = d;
+ Grids._eclipticOverviewLineList.addLine(Vector3d._transformCoordinate(Vector3d.create(Math.cos((dd * Math.PI * 2) / 360), width, Math.sin((dd * Math.PI * 2) / 360)), mat), Vector3d._transformCoordinate(Vector3d.create(Math.cos((dd * Math.PI * 2) / 360), -width, Math.sin((dd * Math.PI * 2) / 360)), mat));
+ index++;
+ jYear += 1;
+ }
+ d += Grids._monthDays[m];
+ }
+ }
+ Grids._eclipticOverviewLineList.drawLines(renderContext, opacity, drawColor);
+ return true;
+};
+
+Grids.drawEclipticText = function (renderContext, opacity, drawColor) {
+ Grids._makeEclipticText();
+ Grids._eclipOvTextBatch.draw(renderContext, opacity, drawColor);
+ return true;
+};
+
+Grids._makeEclipticText = function () {
+ var year = SpaceTimeController.get_now().getUTCFullYear();
+ if (Grids._eclipOvTextBatch == null) {
+ Grids._eclipOvTextBatch = new Text3dBatch(80);
+ Grids._eclipticTextYear = year;
+ var obliquity = Coordinates.meanObliquityOfEcliptic(SpaceTimeController.get_jNow());
+ var mat = Matrix3d._rotationX((-obliquity / 360 * (Math.PI * 2)));
+ var daysPerYear = 365.25;
+ if (DT.isLeap(year, true)) {
+ Grids._monthDays[1] = 29;
+ daysPerYear = 366;
+ } else {
+ Grids._monthDays[1] = 28;
+ daysPerYear = 365;
+ }
+ var count = 2 * ss.truncate(daysPerYear);
+ Grids._eclipticCount = ss.truncate(daysPerYear);
+ var jYear = SpaceTimeController.utcToJulian(new Date(year, 0, 1, 12, 0, 0));
+ var index = 0;
+ var d = 0;
+ for (var m = 0; m < 12; m++) {
+ var daysThisMonth = ss.truncate(Grids._monthDays[m]);
+ for (var i = 0; i < daysThisMonth; i++) {
+ var sunRaDec = Planets.getPlanetLocationJD('Sun', jYear);
+ var sunEcliptic = CT.eq2Ec(sunRaDec.RA, sunRaDec.dec, obliquity);
+ d = sunEcliptic.x;
+ var dd = d;
+ if (i === Math.floor(daysThisMonth / 2)) {
+ var center = Vector3d._transformCoordinate(Vector3d.create(Math.cos((dd * Math.PI * 2) / 360), 0.025, Math.sin((dd * Math.PI * 2) / 360)), mat);
+ var up = Vector3d._transformCoordinate(Vector3d.create(Math.cos((dd * Math.PI * 2) / 360), 0.045, Math.sin((dd * Math.PI * 2) / 360)), mat);
+ up.subtract(center);
+ up.normalize();
+ Grids._eclipOvTextBatch.add(new Text3d(center, up, Grids._monthNames[m], 80, 0.000159375));
+ }
+ index++;
+ index++;
+ jYear += 1;
+ }
+ d += Grids._monthDays[m];
+ }
+ }
+};
+
+Grids.drawPrecessionChart = function (renderContext, opacity, drawColor) {
+ Grids._makePrecessionChart();
+ Grids._precTextBatch.draw(renderContext, opacity, drawColor);
+ Grids._precLineList.drawLines(renderContext, opacity, drawColor);
+ return true;
+};
+
+Grids._makePrecessionChart = function () {
+ var obliquity = Coordinates.meanObliquityOfEcliptic(SpaceTimeController.get_jNow());
+ var mat = Matrix3d._rotationX((obliquity / 360 * (Math.PI * 2)));
+ var col = Colors.get_white();
+ if (Grids._precLineList == null) {
+ Grids._precLineList = new SimpleLineList();
+ Grids._precLineList.set_depthBuffered(false);
+ for (var l = 0; l < 360; l++) {
+ var b = 90 - obliquity;
+ Grids._precLineList.addLine(Vector3d._transformCoordinate(Coordinates.raDecTo3dAu(l / 15, b, 1), mat), Vector3d._transformCoordinate(Coordinates.raDecTo3dAu((l + 1) / 15, b, 1), mat));
+ }
+ for (var l = -12000; l < 13000; l += 2000) {
+ var b = 90 - obliquity;
+ var p = -((l - 2000) / 25772 * 24) - 6;
+ Grids._precLineList.addLine(Vector3d._transformCoordinate(Coordinates.raDecTo3dAu(p, b - 0.5, 1), mat), Vector3d._transformCoordinate(Coordinates.raDecTo3dAu(p, b + 0.5, 1), mat));
+ }
+ }
+ if (Grids._precTextBatch == null) {
+ Grids._precTextBatch = new Text3dBatch(50);
+ for (var l = -12000; l < 13000; l += 2000) {
+ var b = 90 - obliquity + 3;
+ var p = -((l - 2000) / 25772 * 24) - 6;
+ var text = l.toString();
+ if (!l) {
+ b = 90 - obliquity + 2;
+ text = '1 CE';
+ }
+ else if (l < 0) {
+ text = ' ' + Math.abs(l).toString() + ' BCE';
+ }
+ else {
+ text = Math.abs(l).toString() + ' CE';
+ }
+ if (text.length === 9) {
+ text = ' ' + text;
+ }
+ Grids._precTextBatch.add(new Text3d(Vector3d._transformCoordinate(Coordinates.raDecTo3dAu(p, b, 1), mat), Vector3d._transformCoordinate(Coordinates.raDecTo3dAu(p + 0.01, b, 1), mat), text, 75, 0.00015));
+ }
+ }
+ return;
+};
+
+Grids.drawAltAzGrid = function (renderContext, opacity, drawColor) {
+ var zenithAltAz = new Coordinates(0, 0);
+ var zenith = Coordinates.horizonToEquitorial(zenithAltAz, SpaceTimeController.get_location(), SpaceTimeController.get_now());
+ var raPart = -((zenith.get_RA() + 6) / 24 * (Math.PI * 2));
+ var decPart = -(zenith.get_dec() / 360 * (Math.PI * 2));
+ var raText = Coordinates.formatDMS(zenith.get_RA());
+ var mat = Matrix3d._rotationY(-raPart);
+ mat._multiply(Matrix3d._rotationX(decPart));
+ mat.invert();
+ if (Grids._altAzLineList == null) {
+ Grids._altAzLineList = new SimpleLineList();
+ Grids._altAzLineList.set_depthBuffered(false);
+ for (var l = 0; l < 360; l += 10) {
+ for (var b = -80; b < 80; b += 2) {
+ Grids._altAzLineList.addLine(Coordinates.raDecTo3dAu(l / 15, b, 1), Coordinates.raDecTo3dAu(l / 15, b + 2, 1));
+ }
+ }
+ for (var b = -80; b <= 80; b += 10) {
+ for (var l = 0; l < 360; l += 5) {
+ Grids._altAzLineList.addLine(Coordinates.raDecTo3dAu(l / 15, b, 1), Coordinates.raDecTo3dAu((l + 5) / 15, b, 1));
+ }
+ }
+ var counter = 0;
+ for (var l = 0; l < 360; l += 1) {
+ var b = 0.25;
+ switch (counter % 10) {
+ case 0:
+ counter++;
+ continue;
+ case 5:
+ b = 0.5;
+ break;
+ }
+ counter++;
+ Grids._altAzLineList.addLine(Coordinates.raDecTo3dAu(l / 15, b, 1), Coordinates.raDecTo3dAu(l / 15, -b, 1));
+ }
+ counter = 0;
+ for (var l = 0; l < 360; l += 90) {
+ counter = 0;
+ for (var b = -80; b <= 80; b += 1) {
+ var width = 0.5 / 2;
+ switch (counter % 10) {
+ case 0:
+ counter++;
+ continue;
+ case 5:
+ width = 0.5;
+ break;
+ }
+ counter++;
+ Grids._altAzLineList.addLine(Coordinates.raDecTo3dAu((l + width) / 15, b, 1), Coordinates.raDecTo3dAu((l - width) / 15, b, 1));
+ }
+ }
+ }
+ var matOldWorld = renderContext.get_world().clone();
+ var matOldWorldBase = renderContext.get_worldBase().clone();
+ renderContext.set_worldBase(Matrix3d.multiplyMatrix(mat, renderContext.get_world()));
+ renderContext.set_world(renderContext.get_worldBase().clone());
+ renderContext.makeFrustum();
+ Grids._altAzLineList.viewTransform = Matrix3d.invertMatrix(mat);
+ Grids._altAzLineList.drawLines(renderContext, opacity, drawColor);
+ renderContext.set_worldBase(matOldWorldBase);
+ renderContext.set_world(matOldWorld);
+ renderContext.makeFrustum();
+ return true;
+};
+
+Grids.drawAltAzGridText = function (renderContext, opacity, drawColor) {
+ var zenithAltAz = new Coordinates(0, 0);
+ var zenith = Coordinates.horizonToEquitorial(zenithAltAz, SpaceTimeController.get_location(), SpaceTimeController.get_now());
+ var raPart = -((zenith.get_RA() - 6) / 24 * (Math.PI * 2));
+ var decPart = -(zenith.get_dec() / 360 * (Math.PI * 2));
+ var raText = Coordinates.formatDMS(zenith.get_RA());
+ var mat = Matrix3d._rotationY(-raPart - Math.PI);
+ mat._multiply(Matrix3d._rotationX(decPart));
+ mat.invert();
+ Grids._makeAltAzGridText();
+ var matOldWorld = renderContext.get_world().clone();
+ var matOldWorldBase = renderContext.get_worldBase().clone();
+ renderContext.set_worldBase(Matrix3d.multiplyMatrix(mat, renderContext.get_world()));
+ renderContext.set_world(renderContext.get_worldBase().clone());
+ renderContext.makeFrustum();
+ Grids._altAzTextBatch.viewTransform = Matrix3d.invertMatrix(mat);
+ Grids._altAzTextBatch.draw(renderContext, opacity, drawColor);
+ renderContext.set_worldBase(matOldWorldBase);
+ renderContext.set_world(matOldWorld);
+ renderContext.makeFrustum();
+ return true;
+};
+
+Grids._makeAltAzGridText = function () {
+ var drawColor = Colors.get_white();
+ var index = 0;
+ if (Grids._altAzTextBatch == null) {
+ Grids._altAzTextBatch = new Text3dBatch(30);
+ for (var l = 0; l < 360; l += 10) {
+ var text = ' ' + l.toString();
+ if (l < 10) {
+ text = ' ' + l.toString();
+ }
+ else if (l < 100) {
+ text = ' ' + l.toString();
+ }
+ var lc = 360 - l;
+ Grids._altAzTextBatch.add(new Text3d(Coordinates.raDecTo3dAu(lc / 15 - 6, 0.4, 1), Coordinates.raDecTo3dAu(lc / 15 - 6, 0.5, 1), text, 75, 0.00018));
+ }
+ index = 0;
+ for (var l = 0; l < 360; l += 90) {
+ for (var b = -80; b <= 80; b += 10) {
+ if (!b) {
+ continue;
+ }
+ var text = b.toString();
+ if (b > 0) {
+ text = ' +' + b.toString();
+ Grids._altAzTextBatch.add(new Text3d(Coordinates.raDecTo3dAu(l / 15, b - 0.4, 1), Coordinates.raDecTo3dAu(l / 15, b - 0.3, 1), text, 75, 0.00018));
+ }
+ else {
+ text = ' - ' + text.substr(1);
+ Grids._altAzTextBatch.add(new Text3d(Coordinates.raDecTo3dAu(l / 15, b + 0.4, 1), Coordinates.raDecTo3dAu(l / 15, b + 0.5, 1), text, 75, 0.00018));
+ }
+ index++;
+ }
+ }
+ }
+ return;
+};
+
+Grids.drawEclipticGrid = function (renderContext, opacity, drawColor) {
+ if (Grids._eclipticLineList == null) {
+ Grids._eclipticLineList = new SimpleLineList();
+ Grids._eclipticLineList.set_depthBuffered(false);
+ var obliquity = Coordinates.meanObliquityOfEcliptic(2451545);
+ var mat = Matrix3d._rotationX((-obliquity / 360 * (Math.PI * 2)));
+ for (var l = 0; l < 360; l += 10) {
+ for (var b = -80; b < 80; b += 2) {
+ Grids._eclipticLineList.addLine(Vector3d._transformCoordinate(Coordinates.raDecTo3dAu(l / 15, b, 1), mat), Vector3d._transformCoordinate(Coordinates.raDecTo3dAu(l / 15, b + 2, 1), mat));
+ }
+ }
+ for (var b = -80; b <= 80; b += 10) {
+ for (var l = 0; l < 360; l += 5) {
+ Grids._eclipticLineList.addLine(Vector3d._transformCoordinate(Coordinates.raDecTo3dAu(l / 15, b, 1), mat), Vector3d._transformCoordinate(Coordinates.raDecTo3dAu((l + 5) / 15, b, 1), mat));
+ }
+ }
+ var counter = 0;
+ for (var l = 0; l < 360; l += 1) {
+ var b = 0.25;
+ switch (counter % 10) {
+ case 0:
+ counter++;
+ continue;
+ case 5:
+ b = 0.5;
+ break;
+ }
+ counter++;
+ Grids._eclipticLineList.addLine(Vector3d._transformCoordinate(Coordinates.raDecTo3dAu(l / 15, b, 1), mat), Vector3d._transformCoordinate(Coordinates.raDecTo3dAu(l / 15, -b, 1), mat));
+ }
+ counter = 0;
+ for (var l = 0; l < 360; l += 90) {
+ counter = 0;
+ for (var b = -80; b <= 80; b += 1) {
+ var width = 0.5 / 2;
+ switch (counter % 10) {
+ case 0:
+ counter++;
+ continue;
+ case 5:
+ width = 0.5;
+ break;
+ }
+ counter++;
+ Grids._eclipticLineList.addLine(Vector3d._transformCoordinate(Coordinates.raDecTo3dAu((l + width) / 15, b, 1), mat), Vector3d._transformCoordinate(Coordinates.raDecTo3dAu((l - width) / 15, b, 1), mat));
+ }
+ }
+ }
+ Grids._eclipticLineList.drawLines(renderContext, opacity, drawColor);
+ return true;
+};
+
+Grids.drawEclipticGridText = function (renderContext, opacity, drawColor) {
+ Grids._makeEclipticGridText();
+ Grids._eclipticTextBatch.draw(renderContext, opacity, drawColor);
+ return true;
+};
+
+Grids._makeEclipticGridText = function () {
+ var drawColor = Colors.get_white();
+ var obliquity = Coordinates.meanObliquityOfEcliptic(SpaceTimeController.get_jNow());
+ var mat = Matrix3d._rotationX((-obliquity / 360 * (Math.PI * 2)));
+ if (Grids._eclipticTextBatch == null) {
+ Grids._eclipticTextBatch = new Text3dBatch(30);
+ for (var l = 0; l < 360; l += 10) {
+ var text = ' ' + l.toString();
+ if (l < 10) {
+ text = ' ' + l.toString();
+ }
+ else if (l < 100) {
+ text = ' ' + l.toString();
+ }
+ Grids._eclipticTextBatch.add(new Text3d(Vector3d._transformCoordinate(Coordinates.raDecTo3dAu(l / 15, 0.4, 1), mat), Vector3d._transformCoordinate(Coordinates.raDecTo3dAu(l / 15, 0.5, 1), mat), text, 75, 0.00018));
+ }
+ for (var l = 0; l < 360; l += 90) {
+ for (var b = -80; b <= 80; b += 10) {
+ if (!b) {
+ continue;
+ }
+ var text = b.toString();
+ if (b > 0) {
+ text = ' +' + b.toString();
+ Grids._eclipticTextBatch.add(new Text3d(Vector3d._transformCoordinate(Coordinates.raDecTo3dAu(l / 15, b - 0.4, 1), mat), Vector3d._transformCoordinate(Coordinates.raDecTo3dAu(l / 15, b - 0.3, 1), mat), text, 75, 0.00018));
+ }
+ else {
+ text = ' - ' + text.substr(1);
+ Grids._eclipticTextBatch.add(new Text3d(Vector3d._transformCoordinate(Coordinates.raDecTo3dAu(l / 15, b + 0.4, 1), mat), Vector3d._transformCoordinate(Coordinates.raDecTo3dAu(l / 15, b + 0.5, 1), mat), text, 75, 0.00018));
+ }
+ }
+ }
+ }
+ return;
+};
+
+Grids.drawGalacticGrid = function (renderContext, opacity, drawColor) {
+ if (Grids._galLineList == null) {
+ Grids._galLineList = new SimpleLineList();
+ Grids._galLineList.set_depthBuffered(false);
+ for (var l = 0; l < 360; l += 10) {
+ for (var b = -80; b < 80; b += 2) {
+ Grids._galLineList.addLine(Coordinates.galacticTo3dDouble(l, b), Coordinates.galacticTo3dDouble(l, b + 2));
+ }
+ }
+ for (var b = -80; b <= 80; b += 10) {
+ for (var l = 0; l < 360; l += 5) {
+ Grids._galLineList.addLine(Coordinates.galacticTo3dDouble(l, b), Coordinates.galacticTo3dDouble(l + 5, b));
+ }
+ }
+ var counter = 0;
+ for (var l = 0; l < 360; l += 1) {
+ var b = 0.25;
+ switch (counter % 10) {
+ case 0:
+ counter++;
+ continue;
+ case 5:
+ b = 0.5;
+ break;
+ }
+ counter++;
+ Grids._galLineList.addLine(Coordinates.galacticTo3dDouble(l, b), Coordinates.galacticTo3dDouble(l, -b));
+ }
+ counter = 0;
+ for (var l = 0; l < 360; l += 90) {
+ counter = 0;
+ for (var b = -80; b <= 80; b += 1) {
+ var width = 0.5 / 2;
+ switch (counter % 10) {
+ case 0:
+ counter++;
+ continue;
+ case 5:
+ width = 0.5;
+ break;
+ }
+ counter++;
+ Grids._galLineList.addLine(Coordinates.galacticTo3dDouble(l + width, b), Coordinates.galacticTo3dDouble(l - width, b));
+ }
+ }
+ }
+ Grids._galLineList.drawLines(renderContext, opacity, drawColor);
+ return true;
+};
+
+Grids.drawGalacticGridText = function (renderContext, opacity, drawColor) {
+ Grids._makeGalacticGridText();
+ Grids._galTextBatch.draw(renderContext, opacity, drawColor);
+ return true;
+};
+
+Grids._makeGalacticGridText = function () {
+ if (Grids._galTextBatch == null) {
+ Grids._galTextBatch = new Text3dBatch(30);
+ for (var l = 0; l < 360; l += 10) {
+ var text = ' ' + l.toString();
+ if (l < 10) {
+ text = ' ' + l.toString();
+ }
+ else if (l < 100) {
+ text = ' ' + l.toString();
+ }
+ Grids._galTextBatch.add(new Text3d(Coordinates.galacticTo3dDouble(l, 0.4), Coordinates.galacticTo3dDouble(l, 0.5), text, 75, 0.00018));
+ }
+ for (var l = 0; l < 360; l += 90) {
+ for (var b = -80; b <= 80; b += 10) {
+ if (!b) {
+ continue;
+ }
+ var text = b.toString();
+ if (b > 0) {
+ text = ' +' + b.toString();
+ Grids._galTextBatch.add(new Text3d(Coordinates.galacticTo3dDouble(l, b - 0.4), Coordinates.galacticTo3dDouble(l, b - 0.3), text, 75, 0.00018));
+ }
+ else {
+ text = ' - ' + text.substr(1);
+ Grids._galTextBatch.add(new Text3d(Coordinates.galacticTo3dDouble(l, b + 0.4), Coordinates.galacticTo3dDouble(l, b + 0.5), text, 75, 0.00018));
+ }
+ }
+ }
+ }
+};
+
+Grids.drawPlanetGrid = function (renderContext, opacity, drawColor) {
+ if (Grids._planetLineList == null) {
+ Grids._planetLineList = new SimpleLineList();
+ Grids._planetLineList.set_depthBuffered(true);
+ var col = drawColor;
+ for (var lng = 0; lng < 360; lng += 10) {
+ for (var lat = -80; lat < 80; lat += 2) {
+ Grids._planetLineList.addLine(Coordinates.geoTo3dDouble(lat, lng), Coordinates.geoTo3dDouble(lat + 2, lng));
+ }
+ }
+ for (var lat = -80; lat <= 80; lat += 10) {
+ for (var l = 0; l < 360; l += 5) {
+ Grids._planetLineList.addLine(Coordinates.geoTo3dDouble(lat, l), Coordinates.geoTo3dDouble(lat, l + 5));
+ }
+ }
+ var counter = 0;
+ for (var lng = 0; lng < 360; lng += 1) {
+ var lat = 0.25;
+ switch (counter % 10) {
+ case 0:
+ counter++;
+ continue;
+ case 5:
+ lat = 0.5;
+ break;
+ }
+ counter++;
+ Grids._planetLineList.addLine(Coordinates.geoTo3dDouble(lat, lng), Coordinates.geoTo3dDouble(-lat, lng));
+ }
+ counter = 0;
+ for (var lng = 0; lng < 360; lng += 90) {
+ counter = 0;
+ for (var b = -80; b <= 80; b += 1) {
+ var width = 0.5 / 2;
+ switch (counter % 10) {
+ case 0:
+ counter++;
+ continue;
+ case 5:
+ width = 0.5;
+ break;
+ }
+ counter++;
+ Grids._planetLineList.addLine(Coordinates.geoTo3dDouble(b, lng + width), Coordinates.geoTo3dDouble(b, lng - width));
+ }
+ }
+ }
+ Grids._planetLineList.aaFix = false;
+ Grids._planetLineList.set_depthBuffered(true);
+ Grids._planetLineList.sky = false;
+ Grids._planetLineList.drawLines(renderContext, opacity, drawColor);
+ return true;
+};
+
+Grids.drawPlanetGridText = function (renderContext, opacity, drawColor) {
+ Grids._makePlanetGridText();
+ Grids._planetTextBatch.draw(renderContext, opacity, drawColor);
+ return true;
+};
+
+Grids._makePlanetGridText = function () {
+ if (Grids._planetTextBatch == null) {
+ Grids._planetTextBatch = new Text3dBatch(80);
+ for (var lng = -180; lng < 180; lng += 10) {
+ var text = ' ' + lng.toString();
+ if (lng < 10) {
+ text = ' ' + lng.toString();
+ }
+ else if (lng < 100) {
+ text = ' ' + lng.toString();
+ }
+ Grids._planetTextBatch.add(new Text3d(Coordinates.geoTo3dDouble(0.4, lng), Coordinates.geoTo3dDouble(0.5, lng), text, -80, 6E-05));
+ }
+ for (var lng = 0; lng < 360; lng += 90) {
+ for (var lat = -80; lat <= 80; lat += 10) {
+ if (!lat) {
+ continue;
+ }
+ var text = lat.toString();
+ if (lat > 0) {
+ text = ' +' + lat.toString();
+ Grids._planetTextBatch.add(new Text3d(Coordinates.geoTo3dDouble(lat - 0.4, lng), Coordinates.geoTo3dDouble(lat - 0.3, lng), text, -80, 6E-05));
+ }
+ else {
+ text = ' - ' + text.substring(1);
+ Grids._planetTextBatch.add(new Text3d(Coordinates.geoTo3dDouble(lat + 0.4, lng), Coordinates.geoTo3dDouble(lat + 0.5, lng), text, -80, 6E-05));
+ }
+ }
+ }
+ }
+};
+
+var Grids$ = {};
+
+registerType("Grids", [Grids, Grids$, null]);
diff --git a/engine/esm/healpix_tables.js b/engine/esm/healpix_tables.js
new file mode 100644
index 00000000..e3447cbf
--- /dev/null
+++ b/engine/esm/healpix_tables.js
@@ -0,0 +1,24 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Data tables relating to HEALPix.
+
+import { registerType } from "./typesystem.js";
+
+
+// wwtlib.HealpixTables
+
+export function HealpixTables() { }
+
+HealpixTables.ctab = [0, 1, 256, 257, 2, 3, 258, 259, 512, 513, 768, 769, 514, 515, 770, 771, 4, 5, 260, 261, 6, 7, 262, 263, 516, 517, 772, 773, 518, 519, 774, 775, 1024, 1025, 1280, 1281, 1026, 1027, 1282, 1283, 1536, 1537, 1792, 1793, 1538, 1539, 1794, 1795, 1028, 1029, 1284, 1285, 1030, 1031, 1286, 1287, 1540, 1541, 1796, 1797, 1542, 1543, 1798, 1799, 8, 9, 264, 265, 10, 11, 266, 267, 520, 521, 776, 777, 522, 523, 778, 779, 12, 13, 268, 269, 14, 15, 270, 271, 524, 525, 780, 781, 526, 527, 782, 783, 1032, 1033, 1288, 1289, 1034, 1035, 1290, 1291, 1544, 1545, 1800, 1801, 1546, 1547, 1802, 1803, 1036, 1037, 1292, 1293, 1038, 1039, 1294, 1295, 1548, 1549, 1804, 1805, 1550, 1551, 1806, 1807, 2048, 2049, 2304, 2305, 2050, 2051, 2306, 2307, 2560, 2561, 2816, 2817, 2562, 2563, 2818, 2819, 2052, 2053, 2308, 2309, 2054, 2055, 2310, 2311, 2564, 2565, 2820, 2821, 2566, 2567, 2822, 2823, 3072, 3073, 3328, 3329, 3074, 3075, 3330, 3331, 3584, 3585, 3840, 3841, 3586, 3587, 3842, 3843, 3076, 3077, 3332, 3333, 3078, 3079, 3334, 3335, 3588, 3589, 3844, 3845, 3590, 3591, 3846, 3847, 2056, 2057, 2312, 2313, 2058, 2059, 2314, 2315, 2568, 2569, 2824, 2825, 2570, 2571, 2826, 2827, 2060, 2061, 2316, 2317, 2062, 2063, 2318, 2319, 2572, 2573, 2828, 2829, 2574, 2575, 2830, 2831, 3080, 3081, 3336, 3337, 3082, 3083, 3338, 3339, 3592, 3593, 3848, 3849, 3594, 3595, 3850, 3851, 3084, 3085, 3340, 3341, 3086, 3087, 3342, 3343, 3596, 3597, 3852, 3853, 3598, 3599, 3854, 3855];
+HealpixTables.utab = [0, 1, 4, 5, 16, 17, 20, 21, 64, 65, 68, 69, 80, 81, 84, 85, 256, 257, 260, 261, 272, 273, 276, 277, 320, 321, 324, 325, 336, 337, 340, 341, 1024, 1025, 1028, 1029, 1040, 1041, 1044, 1045, 1088, 1089, 1092, 1093, 1104, 1105, 1108, 1109, 1280, 1281, 1284, 1285, 1296, 1297, 1300, 1301, 1344, 1345, 1348, 1349, 1360, 1361, 1364, 1365, 4096, 4097, 4100, 4101, 4112, 4113, 4116, 4117, 4160, 4161, 4164, 4165, 4176, 4177, 4180, 4181, 4352, 4353, 4356, 4357, 4368, 4369, 4372, 4373, 4416, 4417, 4420, 4421, 4432, 4433, 4436, 4437, 5120, 5121, 5124, 5125, 5136, 5137, 5140, 5141, 5184, 5185, 5188, 5189, 5200, 5201, 5204, 5205, 5376, 5377, 5380, 5381, 5392, 5393, 5396, 5397, 5440, 5441, 5444, 5445, 5456, 5457, 5460, 5461, 16384, 16385, 16388, 16389, 16400, 16401, 16404, 16405, 16448, 16449, 16452, 16453, 16464, 16465, 16468, 16469, 16640, 16641, 16644, 16645, 16656, 16657, 16660, 16661, 16704, 16705, 16708, 16709, 16720, 16721, 16724, 16725, 17408, 17409, 17412, 17413, 17424, 17425, 17428, 17429, 17472, 17473, 17476, 17477, 17488, 17489, 17492, 17493, 17664, 17665, 17668, 17669, 17680, 17681, 17684, 17685, 17728, 17729, 17732, 17733, 17744, 17745, 17748, 17749, 20480, 20481, 20484, 20485, 20496, 20497, 20500, 20501, 20544, 20545, 20548, 20549, 20560, 20561, 20564, 20565, 20736, 20737, 20740, 20741, 20752, 20753, 20756, 20757, 20800, 20801, 20804, 20805, 20816, 20817, 20820, 20821, 21504, 21505, 21508, 21509, 21520, 21521, 21524, 21525, 21568, 21569, 21572, 21573, 21584, 21585, 21588, 21589, 21760, 21761, 21764, 21765, 21776, 21777, 21780, 21781, 21824, 21825, 21828, 21829, 21840, 21841, 21844, 21845];
+
+// coordinate of the lowest corner of each face
+HealpixTables.jrll = [2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4];
+HealpixTables.jpll = [1, 3, 5, 7, 0, 2, 4, 6, 1, 3, 5, 7];
+HealpixTables.xoffset = [-1, -1, 0, 1, 1, 1, 0, -1];
+HealpixTables.yoffset = [0, 1, 1, 1, 0, -1, -1, -1];
+
+var HealpixTables$ = {};
+
+registerType("HealpixTables", [HealpixTables, HealpixTables$, null]);
diff --git a/engine/esm/healpix_tile.js b/engine/esm/healpix_tile.js
new file mode 100644
index 00000000..9cfc56e7
--- /dev/null
+++ b/engine/esm/healpix_tile.js
@@ -0,0 +1,654 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A tile in a pyramid that uses a HEALPix projection.
+
+import { ss } from "./ss.js";
+import { registerType } from "./typesystem.js";
+import {
+ tileCacheAddTileToQueue,
+ tileCacheGetTile,
+ tileCacheRemoveFromQueue,
+ tilePrepDevice,
+ set_tileDemEnabled,
+} from "./render_globals.js";
+import { Vector3d, Matrix3d, ConvexHull, PositionTexture } from "./double3d.js";
+import { DistanceCalc } from "./util.js";
+import { WEBGL } from "./graphics/webgl_constants.js";
+import { Coordinates } from "./coordinates.js";
+import { Fxyf } from "./fxyf.js";
+import { WebFile } from "./web_file.js";
+import { UiTools } from "./ui_tools.js";
+import { Tile } from "./tile.js";
+
+
+// wwtlib.Xyf
+
+export function Xyf() {
+ this.ix = 0;
+ this.iy = 0;
+ this.face = 0;
+}
+
+Xyf.create = function (x, y, f) {
+ var temp = new Xyf();
+ temp.ix = x;
+ temp.iy = y;
+ temp.face = f;
+ return temp;
+};
+
+var Xyf$ = {};
+
+registerType("Xyf", [Xyf, Xyf$, null]);
+
+
+// wwtlib.HealpixTile
+
+export function HealpixTile(level, x, y, dataset, parent) {
+ this.ipix = 0;
+ this.indexBuffer = new Array(4);
+ this._vertexList$1 = null;
+ this._nside$1 = 0;
+ this._tileIndex$1 = 0;
+ this._face$1 = 0;
+ this._faceX$1 = 0;
+ this._faceY$1 = 0;
+ this._step$1 = 0;
+ this._subDivided$1 = false;
+ this._catalogRows$1 = [];
+ Tile.call(this);
+ this.level = level;
+ this.tileX = x;
+ this.tileY = y;
+ this.dataset = dataset;
+ set_tileDemEnabled(false);
+
+ if (!level) {
+ this._nside$1 = 4;
+ } else {
+ this._nside$1 = Math.pow(2, level + 1);
+ }
+
+ if (parent == null) {
+ this._face$1 = x * 4 + y;
+ this.ipix = this._face$1;
+ } else {
+ this.parent = parent;
+ var parentTile = parent;
+ this._face$1 = parentTile._face$1;
+ this._tileIndex$1 = parentTile._tileIndex$1 * 4 + y * 2 + x;
+ this.ipix = this._face$1 * this._nside$1 * this._nside$1 / 4 + this._tileIndex$1;
+ this._faceX$1 = parentTile._faceX$1 * 2 + x;
+ this._faceY$1 = parentTile._faceY$1 * 2 + y;
+ }
+ this.isCatalogTile = ss.keyExists(dataset.get_hipsProperties().get_properties(), 'dataproduct_type') && dataset.get_hipsProperties().get_properties()['dataproduct_type'].toLowerCase() === 'catalog';
+ this._computeBoundingSphere$1();
+}
+
+HealpixTile._galacticMatrix$1 = Matrix3d.create(-0.0548755604024359, -0.483835015526738, -0.873437090247923, 0, -0.867666148981161, 0.455983776232537, -0.198076373464674, 0, 0.494109427943568, 0.746982244476371, -0.444829629919504, 0, 0, 0, 0, 1);
+
+var HealpixTile$ = {
+ get_URL: function () {
+ if (this._url$1 == null) {
+ this._url$1 = this._getUrl$1(this.dataset, this.level, this.tileX, this.tileY);
+ return this._url$1;
+ } else {
+ return this._url$1;
+ }
+ },
+
+ _computeBoundingSphere$1: function () {
+ this._setStep$1();
+ this.createGeometry(null);
+ var pointList = new Array(this._vertexList$1.length);
+ for (var i = 0; i < this._vertexList$1.length; i++) {
+ pointList[i] = this._vertexList$1[i].position;
+ }
+ this._calcSphere$1(pointList);
+ this._setCorners$1();
+ },
+
+ createGeometry: function (renderContext) {
+ if (this._vertexList$1 != null) {
+ return true;
+ }
+ this._vertexList$1 = [];
+ this._populateVertexList$1(this._vertexList$1, this._step$1);
+ if (ss.keyExists(this.dataset.get_hipsProperties().get_properties(), 'hips_frame') && this.dataset.get_hipsProperties().get_properties()['hips_frame'] === 'galactic') {
+ for (var i = 0; i < this._vertexList$1.length; i++) {
+ var vert = this._vertexList$1[i];
+ HealpixTile._galacticMatrix$1.multiplyVector(vert.position);
+ }
+ }
+ this.triangleCount = this._step$1 * this._step$1 / 2;
+ var ui16array = new Uint16Array(3 * this.triangleCount);
+ var indexArray = ui16array;
+ if (!this._subDivided$1) {
+ try {
+ this._vertexBuffer = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ARRAY_BUFFER, this._vertexBuffer);
+ var f32array = new Float32Array(this._vertexList$1.length * 5);
+ var buffer = f32array;
+ var index = 0;
+ var $enum1 = ss.enumerate(this._vertexList$1);
+ while ($enum1.moveNext()) {
+ var vert = $enum1.current;
+ index = this.addVertex(buffer, index, vert);
+ }
+ tilePrepDevice.bufferData(WEBGL.ARRAY_BUFFER, f32array, WEBGL.STATIC_DRAW);
+ index = 0;
+ var offset = this._vertexList$1.length / (4 * this._step$1);
+
+ //0 0 = left
+ //1 0 = top
+ //1 1 = right
+ this._setIndexBufferForQuadrant$1(indexArray, 0, 1);
+ if (this._step$1 > 1) {
+ this._setIndexBufferForQuadrant$1(indexArray, 0, 0);
+ this._setIndexBufferForQuadrant$1(indexArray, 1, 1);
+ this._setIndexBufferForQuadrant$1(indexArray, 1, 0);
+ }
+ }
+ catch (exception) {
+ }
+ }
+ return true;
+ },
+
+ _setIndexBufferForQuadrant$1: function (indexArray, x, y) {
+ var index = 0;
+ for (var i = x * this._step$1 / 2; i < (this._step$1 / 2) * (x + 1); i++) {
+ for (var j = y * this._step$1 / 2; j < (this._step$1 / 2) * (y + 1); j++) {
+ indexArray[index++] = (i * (this._step$1 + 1) + j);
+ indexArray[index++] = (1 + i * (this._step$1 + 1) + j);
+ indexArray[index++] = (this._step$1 + 1 + i * (this._step$1 + 1) + j);
+ indexArray[index++] = (1 + i * (this._step$1 + 1) + j);
+ indexArray[index++] = (this._step$1 + 1 + i * (this._step$1 + 1) + j);
+ indexArray[index++] = (this._step$1 + 2 + i * (this._step$1 + 1) + j);
+ }
+ }
+ this._processIndexBuffer$1(indexArray, x * 2 + y);
+ },
+
+ _getUrl$1: function (dataset, level, x, y) {
+ var extension = this._getHipsFileExtension$1();
+ var tileTextureIndex = -1;
+ if (!level) {
+ tileTextureIndex = this._face$1;
+ } else {
+ tileTextureIndex = this._face$1 * this._nside$1 * this._nside$1 / 4 + this._tileIndex$1;
+ }
+ var sb = new ss.StringBuilder();
+ var subDirIndex = Math.floor(tileTextureIndex / 10000) * 10000;
+ return ss.format(dataset.get_url(), level.toString(), subDirIndex.toString(), tileTextureIndex.toString() + extension);
+ },
+
+ _getHipsFileExtension$1: function () {
+ // The extension will contain either a space-separated list of types
+ // or a single type. We currently match preferred filetypes
+ // greedily. The extension must be exactly ".fits" in order to
+ // render correctly -- not only because of the greedy matching here,
+ // but because there are other parts of the code that check for an
+ // exact match.
+
+ //prioritize transparent Png over other image formats
+ if (this.dataset.get_extension().toLowerCase().indexOf('png') > -1) {
+ return '.png';
+ }
+ if (this.dataset.get_extension().toLowerCase().indexOf('jpeg') > -1 || this.dataset.get_extension().toLowerCase().indexOf('jpg') > -1) {
+ return '.jpg';
+ }
+ if (this.dataset.get_extension().toLowerCase().indexOf('tsv') > -1) {
+ return '.tsv';
+ }
+ if (this.dataset.get_extension().toLowerCase().indexOf('fits') > -1) {
+ return '.fits';
+ }
+
+ //default to most common
+ return '.jpg';
+ },
+
+ isTileBigEnough: function (renderContext) {
+ if (this.dataset.get_dataSetType() === 1) {
+ var arcPixels = (180 / (Math.pow(2, this.level) * 4));
+ return (renderContext.get_fovScale() < arcPixels);
+ } else {
+ var arcPixels = (3600 / (Math.pow(2, this.level) * 4));
+ return (renderContext.get_fovScale() < arcPixels);
+ }
+ },
+
+ _boundaries$1: function (x, y, step) {
+ var nside = step * Math.pow(2, this.level);
+ var points = new Array(4);
+ var xyf = Xyf.create(x + this._faceX$1 * step, y + this._faceY$1 * step, this._face$1);
+ var dc = 0.5 / nside;
+ var xc = (xyf.ix + 0.5) / nside;
+ var yc = (xyf.iy + 0.5) / nside;
+ points[0] = Fxyf.create(xc + dc, yc + dc, xyf.face).toVec3();
+ points[1] = Fxyf.create(xc - dc, yc + dc, xyf.face).toVec3();
+ points[2] = Fxyf.create(xc - dc, yc - dc, xyf.face).toVec3();
+ points[3] = Fxyf.create(xc + dc, yc - dc, xyf.face).toVec3();
+ return points;
+ },
+
+ _setCorners$1: function () {
+ var xyf = Xyf.create(this.tileX, this.tileY, this._face$1);
+ var dc = 0.5 / this._nside$1;
+ var xc = (xyf.ix + 0.5) / this._nside$1;
+ var yc = (xyf.iy + 0.5) / this._nside$1;
+ this.topLeft = Fxyf.create(xc + dc, yc + dc, xyf.face).toVec3();
+ this.bottomLeft = Fxyf.create(xc - dc, yc + dc, xyf.face).toVec3();
+ this.bottomRight = Fxyf.create(xc - dc, yc - dc, xyf.face).toVec3();
+ this.topRight = Fxyf.create(xc + dc, yc - dc, xyf.face).toVec3();
+ },
+
+ draw3D: function (renderContext, opacity) {
+ if (this.isCatalogTile) {
+ this.drawCatalogTile(renderContext, opacity);
+ return true;
+ }
+ this.renderedGeneration = Tile.currentRenderGeneration;
+ Tile.tilesTouched++;
+ this.inViewFrustum = true;
+ var onlyDrawChildren = false;
+ if (!this.readyToRender) {
+ if (!this.errored) {
+ tileCacheAddTileToQueue(this);
+ return false;
+ }
+ if (this.errored && this.level < 3) {
+ //Level 0-2 sometimes deleted in favor of allsky.jpg/tsv
+ onlyDrawChildren = true;
+ }
+ else {
+ return false;
+ }
+ }
+ var partCount = this.triangleCount;
+ Tile.trianglesRendered += partCount;
+ var anythingToRender = false;
+ var childRendered = false;
+ var childIndex = 0;
+ for (var y1 = 0; y1 < 2; y1++) {
+ for (var x1 = 0; x1 < 2; x1++) {
+ if (this.level < this.dataset.get_levels()) {
+ if (this.children[childIndex] == null) {
+ this.children[childIndex] = tileCacheGetTile(this.level + 1, x1, y1, this.dataset, this);
+ }
+ if (this.children[childIndex].isTileInFrustum(renderContext.get_frustum())) {
+ this.inViewFrustum = true;
+ if (this.children[childIndex].isTileBigEnough(renderContext) || onlyDrawChildren) {
+ this.renderChildPart[childIndex].set_targetState(!this.children[childIndex].draw3D(renderContext, opacity));
+ if (this.renderChildPart[childIndex].get_targetState()) {
+ childRendered = true;
+ }
+ }
+ else {
+ this.renderChildPart[childIndex].set_targetState(true);
+ }
+ }
+ else {
+ this.renderChildPart[childIndex].set_targetState(this.renderChildPart[childIndex].set_state(false));
+ }
+ }
+ else {
+ this.renderChildPart[childIndex].set_state(true);
+ }
+ if (!!this.renderChildPart[childIndex].get_state()) {
+ anythingToRender = true;
+ }
+ childIndex++;
+ }
+ }
+ if (childRendered || anythingToRender) {
+ this.renderedAtOrBelowGeneration = Tile.currentRenderGeneration;
+ if (this.parent != null) {
+ this.parent.renderedAtOrBelowGeneration = this.renderedAtOrBelowGeneration;
+ }
+ }
+ if (!anythingToRender) {
+ return true;
+ }
+ if (!this.createGeometry(renderContext)) {
+ return false;
+ }
+ if (onlyDrawChildren) {
+ return true;
+ }
+ Tile.tilesInView++;
+ for (var i = 0; i < 4; i++) {
+ if (this.renderChildPart[i].get_targetState()) {
+ this.renderPart(renderContext, i, opacity / 100, false);
+ }
+ }
+ return true;
+ },
+
+ drawCatalogTile: function (renderContext, opacity) {
+ this.renderedGeneration = Tile.currentRenderGeneration;
+ Tile.tilesTouched++;
+ this.inViewFrustum = true;
+ var onlyDrawChildren = false;
+ if (!this.readyToRender) {
+ if (!this.errored) {
+ tileCacheAddTileToQueue(this);
+ return;
+ }
+ if (this.errored && this.level < 3) {
+ //Level 0-2 sometimes deleted in favor of allsky.jpg/tsv
+ onlyDrawChildren = true;
+ }
+ else {
+ return;
+ }
+ }
+ var anyChildInFrustum = false;
+ var childIndex = 0;
+ for (var y1 = 0; y1 < 2; y1++) {
+ for (var x1 = 0; x1 < 2; x1++) {
+ if (this.level < this.dataset.get_levels()) {
+ if (this.children[childIndex] == null) {
+ this.children[childIndex] = tileCacheGetTile(this.level + 1, x1, y1, this.dataset, this);
+ }
+ if (this.children[childIndex].isTileInFrustum(renderContext.get_frustum())) {
+ this.inViewFrustum = true;
+ anyChildInFrustum = true;
+ if (this.children[childIndex].isTileBigEnough(renderContext) || onlyDrawChildren) {
+ (this.children[childIndex]).drawCatalogTile(renderContext, opacity);
+ }
+ else {
+ (this.children[childIndex]).removeCatalogTile();
+ }
+ }
+ else {
+ (this.children[childIndex]).removeCatalogTile();
+ }
+ }
+ childIndex++;
+ }
+ }
+ if (!this.level && !anyChildInFrustum && !onlyDrawChildren) {
+ this.removeCatalogTile();
+ } else if (anyChildInFrustum) {
+ Tile.tilesInView++;
+ this._addCatalogTile$1();
+ }
+ },
+
+ removeCatalogTile: function () {
+ this.dataset.get_hipsProperties().get_catalogSpreadSheetLayer().removeTileRows(this.get_key(), this._catalogRows$1);
+ },
+
+ _addCatalogTile$1: function () {
+ this.dataset.get_hipsProperties().get_catalogSpreadSheetLayer().addTileRows(this.get_key(), this._catalogRows$1);
+ },
+
+ _extractCatalogTileRows$1: function () {
+ var headerRemoved = false;
+ var $enum1 = ss.enumerate(this._catalogData$1.getText().split('\n'));
+ while ($enum1.moveNext()) {
+ var line = $enum1.current;
+ if (!ss.startsWith(line, '#') && !headerRemoved) {
+ headerRemoved = true;
+ continue;
+ }
+ if (!ss.startsWith(line, '#')) {
+ var rowData = UiTools.splitString(line, this.dataset.get_hipsProperties().get_catalogSpreadSheetLayer().get__table().delimiter);
+ this._catalogRows$1.push(rowData);
+ }
+ }
+ },
+
+ getDataInView: function (renderContext, limit, catalogSpreadSheetLayer) {
+ if (!this.readyToRender) {
+ if (!this.errored) {
+ this.requestImage();
+ if (limit) {
+ return false;
+ }
+ }
+ else if (this.level >= 3) {
+ //Level 0-2 sometimes deleted in favor of allsky.jpg/tsv
+ return true;
+ }
+ }
+ var allChildrenReady = true;
+ var anyChildInFrustum = false;
+ var childIndex = 0;
+ for (var y1 = 0; y1 < 2; y1++) {
+ for (var x1 = 0; x1 < 2; x1++) {
+ if (this.level < this.dataset.get_levels()) {
+ if (this.children[childIndex] == null) {
+ this.children[childIndex] = tileCacheGetTile(this.level + 1, x1, y1, this.dataset, this);
+ }
+ if (this.children[childIndex].isTileInFrustum(renderContext.get_frustum())) {
+ anyChildInFrustum = true;
+ allChildrenReady = allChildrenReady && (this.children[childIndex]).getDataInView(renderContext, limit, catalogSpreadSheetLayer);
+ }
+ }
+ childIndex++;
+ }
+ }
+ if (anyChildInFrustum) {
+ catalogSpreadSheetLayer.addTileRows(this.get_key(), this._catalogRows$1);
+ }
+ return allChildrenReady && !this.downloading;
+ },
+
+ _setStep$1: function () {
+ if (this.isCatalogTile) {
+ this._step$1 = 2;
+ } else {
+ switch (this.level) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ this._step$1 = 16;
+ break;
+ case 5:
+ this._step$1 = 8;
+ break;
+ case 6:
+ this._step$1 = 4;
+ break;
+ default:
+ this._step$1 = 2;
+ break;
+ }
+ }
+ },
+
+ requestImage: function () {
+ if (this.isCatalogTile) {
+ if (!this.downloading && !this.readyToRender) {
+ this.downloading = true;
+ this._catalogData$1 = new WebFile(this.get_URL());
+ this._catalogData$1.onStateChange = ss.bind('_loadCatalogData$1', this);
+ this._catalogData$1.send();
+ }
+ } else {
+ Tile.prototype.requestImage.call(this);
+ }
+ },
+
+ _loadCatalogData$1: function () {
+ if (this._catalogData$1.get_state() === 2) {
+ this.requestPending = false;
+ this.downloading = false;
+ this.errored = true;
+ tileCacheRemoveFromQueue(this.get_key(), true);
+ } else if (this._catalogData$1.get_state() === 1) {
+ this._extractCatalogTileRows$1();
+ this.texReady = true;
+ this.downloading = false;
+ this.errored = false;
+ this.readyToRender = true;
+ this.requestPending = false;
+ tileCacheRemoveFromQueue(this.get_key(), true);
+ }
+ },
+
+ getIndexBuffer: function (index, accomidation) {
+ return this.indexBuffer[index];
+ },
+
+ _calcSphere$1: function (list) {
+ var result = ConvexHull.findEnclosingSphere(list);
+ this.sphereCenter = result.center;
+ this.sphereRadius = result.radius;
+ },
+
+ isPointInTile: function (lat, lng) {
+ if (!this.level) {
+ return true;
+ }
+ if (this.level === 1) {
+ if ((lng >= 0 && lng <= 90) && (!this.tileX && this.tileY === 1)) {
+ return true;
+ }
+ if ((lng > 90 && lng <= 180) && (this.tileX === 1 && this.tileY === 1)) {
+ return true;
+ }
+ if ((lng < 0 && lng >= -90) && (!this.tileX && !this.tileY)) {
+ return true;
+ }
+ if ((lng < -90 && lng >= -180) && (this.tileX === 1 && !this.tileY)) {
+ return true;
+ }
+ }
+ var testPoint = Coordinates.geoTo3dDouble(lat, lng);
+ var top = this._isLeftOfHalfSpace$1(this.topLeft, this.topRight, testPoint);
+ var right = this._isLeftOfHalfSpace$1(this.topRight, this.bottomRight, testPoint);
+ var bottom = this._isLeftOfHalfSpace$1(this.bottomRight, this.bottomLeft, testPoint);
+ var left = this._isLeftOfHalfSpace$1(this.bottomLeft, this.topLeft, testPoint);
+ if (top && right && bottom && left) {
+ return true;
+ }
+ return false;
+ },
+
+ _isLeftOfHalfSpace$1: function (pntA, pntB, pntTest) {
+ pntA.normalize();
+ pntB.normalize();
+ var cross = Vector3d.cross(pntA, pntB);
+ var dot = Vector3d.dot(cross, pntTest);
+ return dot > 0;
+ },
+
+ getSurfacePointAltitude: function (lat, lng, meters) {
+ if (this.level < Tile.lastDeepestLevel) {
+ var $enum1 = ss.enumerate(this.children);
+ while ($enum1.moveNext()) {
+ var child = $enum1.current;
+ if (child != null) {
+ if (child.isPointInTile(lat, lng)) {
+ var retVal = child.getSurfacePointAltitude(lat, lng, meters);
+ if (!!retVal) {
+ return retVal;
+ }
+ else {
+ break;
+ }
+ }
+ }
+ }
+ }
+ return this._getAltitudeFromLatLng$1(lat, lng, meters);
+ },
+
+ _getAltitudeFromLatLng$1: function (lat, lng, meters) {
+ var testPoint = Coordinates.geoTo3dDouble(lat, lng);
+ var uv = DistanceCalc.getUVFromInnerPoint(this.topLeft, this.topRight, this.bottomLeft, this.bottomRight, testPoint);
+
+ // Get 4 samples and interpolate
+ var uud = Math.max(0, Math.min(16, (uv.x * 16)));
+ var vvd = Math.max(0, Math.min(16, (uv.y * 16)));
+ var uu = Math.max(0, Math.min(15, ss.truncate((uv.x * 16))));
+ var vv = Math.max(0, Math.min(15, ss.truncate((uv.y * 16))));
+ var ha = uud - uu;
+ var va = vvd - vv;
+ if (this.demArray != null) {
+ // 4 nearest neighbors
+ var ul = this.demArray[uu + 17 * vv];
+ var ur = this.demArray[(uu + 1) + 17 * vv];
+ var ll = this.demArray[uu + 17 * (vv + 1)];
+ var lr = this.demArray[(uu + 1) + 17 * (vv + 1)];
+ var top = ul * (1 - ha) + ha * ur;
+ var bottom = ll * (1 - ha) + ha * lr;
+ var val = top * (1 - va) + va * bottom;
+ return val / ((meters) ? 1 : this.get__demScaleFactor());
+ }
+ return this.demAverage / ((meters) ? 1 : this.get__demScaleFactor());
+ },
+
+ _processIndexBuffer$1: function (indexArray, part) {
+ this.indexBuffer[part] = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, this.indexBuffer[part]);
+ tilePrepDevice.bufferData(WEBGL.ELEMENT_ARRAY_BUFFER, indexArray, WEBGL.STATIC_DRAW);
+ },
+
+ cleanUp: function (removeFromParent) {
+ Tile.prototype.cleanUp.call(this, removeFromParent);
+ this._returnBuffers$1();
+ this._subDivided$1 = false;
+ },
+
+ _returnBuffers$1: function () {
+ if (this._vertexList$1 != null) {
+ this._vertexList$1 = null;
+ }
+ },
+
+ // Vertices distributed in a grid pattern like the example below
+ // Example for pattern with step set to 4
+ // 24
+ // 19 23
+ // 14 18 22
+ // 9 13 17 21
+ // 4 8 12 16 20
+ // 3 7 11 15
+ // 2 6 10
+ // 1 5
+ // 0
+ _populateVertexList$1: function (vertexList, step) {
+ for (var i = 0; i < step; i += 2) {
+ for (var j = 0; j < step; j += 2) {
+ var points = this._boundaries$1(j, i, step);
+ vertexList[i * (step + 1) + j] = PositionTexture.createPos(points[2], (1 / step) * i, (1 / step) * j);
+ vertexList[i * (step + 1) + j + 1] = PositionTexture.createPos(points[3], (1 / step) * i, (1 / step) + (1 / step) * j);
+ vertexList[(i + 1) * (step + 1) + j] = PositionTexture.createPos(points[1], (1 / step) + (1 / step) * i, (1 / step) * j);
+ vertexList[(i + 1) * (step + 1) + j + 1] = PositionTexture.createPos(points[0], (1 / step) + (1 / step) * i, (1 / step) + (1 / step) * j);
+ if (j + 2 >= step && step > 1) {
+ j = step - 1;
+ points = this._boundaries$1(j, i, step);
+ vertexList[i * (step + 1) + step] = PositionTexture.createPos(points[3], (1 / step) * i, (1 / step) + (1 / step) * j);
+ vertexList[(i + 1) * (step + 1) + step] = PositionTexture.createPos(points[0], (1 / step) + (1 / step) * i, (1 / step) + (1 / step) * j);
+ }
+ }
+ }
+ if (step > 1) {
+ this._vertexOfLastRow$1(vertexList, step);
+ }
+ },
+
+ _vertexOfLastRow$1: function (vertexList, step) {
+ var i = step - 1;
+ for (var j = 0; j < step; j += 2) {
+ var points = this._boundaries$1(j, i, step);
+ vertexList[(i + 1) * (step + 1) + j] = PositionTexture.createPos(points[1], (1 / step) + (1 / step) * i, (1 / step) * j);
+ vertexList[(i + 1) * (step + 1) + j + 1] = PositionTexture.createPos(points[0], (1 / step) + (1 / step) * i, (1 / step) + (1 / step) * j);
+ if (j + 2 >= step) {
+ j = step - 1;
+ points = this._boundaries$1(j, i, step);
+ vertexList[(i + 1) * (step + 1) + step] = PositionTexture.createPos(points[0], (1 / step) + (1 / step) * i, (1 / step) + (1 / step) * j);
+ }
+ }
+ }
+};
+
+registerType("HealpixTile", [HealpixTile, HealpixTile$, Tile]);
diff --git a/engine/esm/healpix_utils.js b/engine/esm/healpix_utils.js
new file mode 100644
index 00000000..ef62bab8
--- /dev/null
+++ b/engine/esm/healpix_utils.js
@@ -0,0 +1,51 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Utilities relating to HEALPix.
+
+import { registerType } from "./typesystem.js";
+import { FastMath } from "./fast_math.js";
+
+
+// wwtlib.HealpixUtils
+
+export function HealpixUtils() { }
+
+HealpixUtils.check = function (cond, errtxt) {
+ if (!cond) {
+ throw new Error(errtxt);
+ }
+};
+
+// Integer square root.
+HealpixUtils.isqrt = function (arg) {
+ var res = Math.sqrt((arg) + 0.5);
+ if (arg < (1 << 50)) {
+ return res;
+ }
+ if (res * res > arg) {
+ --res;
+ }
+ else if ((res + 1) * (res + 1) <= arg) {
+ ++res;
+ }
+ return res;
+};
+
+// Computes the cosine of the angular distance between two z, phi positions on
+// the unit sphere
+HealpixUtils.cosdist_zphi = function (z1, phi1, z2, phi2) {
+ return z1 * z2 + FastMath.cos(phi1 - phi2) * Math.sqrt((1 - z1 * z1) * (1 - z2 * z2));
+};
+
+HealpixUtils.fmodulo = function (v1, v2) {
+ if (v1 >= 0) {
+ return (v1 < v2) ? v1 : v1 % v2;
+ }
+ var tmp = v1 % v2 + v2;
+ return (tmp === v2) ? 0 : tmp;
+};
+
+var HealpixUtils$ = {};
+
+registerType("HealpixUtils", [HealpixUtils, HealpixUtils$, null]);
diff --git a/engine/esm/hips_properties.js b/engine/esm/hips_properties.js
new file mode 100644
index 00000000..d5d8d03e
--- /dev/null
+++ b/engine/esm/hips_properties.js
@@ -0,0 +1,136 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Summary properties about HiPS datasets.
+
+import { ss } from "./ss.js";
+import { registerType } from "./typesystem.js";
+import { set_makeNewHipsProperties } from "./data_globals.js";
+import { WebFile } from "./web_file.js";
+import { Guid } from "./util.js";
+import { CatalogSpreadSheetLayer } from "./layers/spreadsheet_layer.js";
+import { VoTable } from "./layers/vo_table.js";
+import { LayerManager } from "./layers/layer_manager.js";
+
+
+// wwtlib.HipsProperties
+
+export function HipsProperties(dataset) {
+ this._properties = {};
+ this._catalogColumnInfo = null;
+ this._catalogSpreadSheetLayer = new CatalogSpreadSheetLayer();
+ this._downloadComplete = false;
+ this.dataset = dataset;
+ this._datasetName = dataset.get_name();
+ this._url = dataset.get_url();
+ if (this._url.toLowerCase().indexOf('norder') > -1) {
+ this._url = this._url.substring(0, this._url.toLowerCase().indexOf('norder'));
+ }
+ this._url += 'properties';
+ this._download();
+}
+
+var HipsProperties$ = {
+ get_properties: function () {
+ return this._properties;
+ },
+
+ get_catalogSpreadSheetLayer: function () {
+ return this._catalogSpreadSheetLayer;
+ },
+
+ set_catalogSpreadSheetLayer: function (value) {
+ this._catalogSpreadSheetLayer = value;
+ return value;
+ },
+
+ get_catalogColumnInfo: function () {
+ return this._catalogColumnInfo;
+ },
+
+ set_catalogColumnInfo: function (value) {
+ this._catalogColumnInfo = value;
+ return value;
+ },
+
+ get_downloadComplete: function () {
+ return this._downloadComplete;
+ },
+
+ _download: function () {
+ this._webFile = new WebFile(this._url);
+ this._webFile.onStateChange = ss.bind('_onPropertiesDownloadComplete', this);
+ this._webFile.send();
+ },
+
+ _onPropertiesDownloadComplete: function () {
+ if (this._webFile.get_state() === 1) {
+ this._parseProperties(this._webFile.getText());
+ if (ss.keyExists(this.get_properties(), 'dataproduct_type') && this.get_properties()['dataproduct_type'].toLowerCase() === 'catalog') {
+ this._catalogColumnInfo = VoTable.loadFromUrl(ss.replaceString(this._url, '/properties', '/metadata.xml'), ss.bind('_onCatalogMetadataDownloadComplete', this));
+ }
+ else {
+ if (ss.keyExists(this.get_properties(), 'hips_data_range')) {
+ var hips_data_range = this.get_properties()['hips_data_range'];
+ this.dataset.get_fitsProperties().minVal = parseFloat(hips_data_range.split(' ')[0]);
+ this.dataset.get_fitsProperties().maxVal = parseFloat(hips_data_range.split(' ')[1]);
+ this.dataset.get_fitsProperties().lowerCut = this.dataset.get_fitsProperties().minVal;
+ this.dataset.get_fitsProperties().upperCut = this.dataset.get_fitsProperties().maxVal;
+ }
+ if (ss.keyExists(this.get_properties(), 'hips_pixel_cut')) {
+ var hips_pixel_cut = this.get_properties()['hips_pixel_cut'];
+ this.dataset.get_fitsProperties().lowerCut = parseFloat(hips_pixel_cut.split(' ')[0]);
+ this.dataset.get_fitsProperties().upperCut = parseFloat(hips_pixel_cut.split(' ')[1]);
+ if (!ss.keyExists(this.get_properties(), 'hips_data_range')) {
+ this.dataset.get_fitsProperties().minVal = this.dataset.get_fitsProperties().lowerCut;
+ this.dataset.get_fitsProperties().maxVal = this.dataset.get_fitsProperties().upperCut;
+ }
+ }
+ this._downloadComplete = true;
+ if (this._onDownloadComplete != null) {
+ this._onDownloadComplete();
+ }
+ }
+ }
+ },
+
+ _onCatalogMetadataDownloadComplete: function () {
+ this._catalogSpreadSheetLayer.useHeadersFromVoTable(this._catalogColumnInfo);
+ this._catalogSpreadSheetLayer.set_name(this._datasetName);
+ this._catalogSpreadSheetLayer.id = Guid.createFrom(this._datasetName);
+ LayerManager.addSpreadsheetLayer(this.get_catalogSpreadSheetLayer(), 'Sky');
+ this._downloadComplete = true;
+ if (this._onDownloadComplete != null) {
+ this._onDownloadComplete();
+ }
+ },
+
+ setDownloadCompleteListener: function (listener) {
+ this._onDownloadComplete = listener;
+ },
+
+ _parseProperties: function (data) {
+ var lines = data.split('\n');
+ var $enum1 = ss.enumerate(lines);
+ while ($enum1.moveNext()) {
+ var line = $enum1.current;
+ if (!ss.whitespace(line) && !ss.startsWith(line, '#')) {
+ var parts = line.split('=');
+ if (parts.length === 2) {
+ var key = ss.trim(parts[0]);
+ var val = ss.trim(parts[1]);
+ if (!ss.whitespace(key) && !ss.whitespace(val)) {
+ this.get_properties()[key] = val;
+ }
+ }
+ }
+ }
+ }
+};
+
+registerType("HipsProperties", [HipsProperties, HipsProperties$, null]);
+
+set_makeNewHipsProperties(function (imageset) {
+ return new HipsProperties(imageset);
+});
+
diff --git a/engine/esm/hploc.js b/engine/esm/hploc.js
new file mode 100644
index 00000000..fef4cb65
--- /dev/null
+++ b/engine/esm/hploc.js
@@ -0,0 +1,46 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A HEALPix location type.
+
+import { registerType } from "./typesystem.js";
+import { Vector3d } from "./double3d.js";
+import { FastMath } from "./fast_math.js";
+
+
+// wwtlib.Hploc
+
+export function Hploc() {
+ this.z = 0;
+ this.phi = 0;
+ this.sth = 0;
+ this.have_sth = false;
+}
+
+Hploc.create = function (v) {
+ var temp = new Hploc();
+ var xl = 1 / v.length();
+ temp.z = v.z * xl;
+ temp.phi = FastMath.atan2(v.y, v.x);
+ if (Math.abs(temp.z) > 0.99) {
+ temp.sth = Math.sqrt(v.x * v.x + v.y * v.y) * xl;
+ temp.have_sth = true;
+ }
+ return temp;
+};
+
+var Hploc$ = {
+ toVec3: function () {
+ var st;
+ if (this.have_sth) {
+ st = this.sth;
+ } else {
+ st = Math.sqrt((1 - this.z) * (1 + this.z));
+ }
+ var x = st * FastMath.cos(this.phi);
+ var y = st * FastMath.sin(this.phi);
+ return Vector3d.create(x, this.z, y);
+ }
+};
+
+registerType("Hploc", [Hploc, Hploc$, null]);
diff --git a/engine/esm/imageset.js b/engine/esm/imageset.js
new file mode 100644
index 00000000..6dfa22d8
--- /dev/null
+++ b/engine/esm/imageset.js
@@ -0,0 +1,910 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// An image tile pyramid.
+
+import { ss } from "./ss.js";
+import { registerType, registerEnum, Enums } from "./typesystem.js";
+import { freestandingMode, makeNewHipsProperties } from "./data_globals.js";
+import { Matrix3d } from "./double3d.js";
+import { Util } from "./baseutil.js";
+import { IThumbnail } from "./interfaces.js";
+import { URLHelpers } from "./url_helpers.js";
+import { Coordinates } from "./coordinates.js";
+import { FitsProperties } from "./fits_properties.js";
+import { FitsImage } from "./layers/fits_image.js";
+import { EquirectangularTile } from "./equirectangular_tile.js";
+import { HealpixTile } from "./healpix_tile.js";
+import { MercatorTile } from "./mercator_tile.js";
+import { PlotTile } from "./plot_tile.js";
+import { TangentTile } from "./tangent_tile.js";
+import { SkyImageTile } from "./sky_image_tile.js";
+import { ToastTile } from "./toast_tile.js";
+
+
+// wwtlib.ProjectionType
+//
+// This was originally defined in `IImageset.cs`, not `Imageset.cs`, but we've
+// folded it into this file.
+
+export var ProjectionType = {
+ mercator: 0,
+ equirectangular: 1,
+ tangent: 2,
+ tan: 2,
+ toast: 3,
+ spherical: 4,
+ skyImage: 5,
+ plotted: 6,
+ healpix: 7
+};
+
+registerType("ProjectionType", ProjectionType);
+registerEnum("ProjectionType", ProjectionType);
+
+
+// wwtlib.ImageSetType
+//
+// This was originally defined in `IImageset.cs`, not `Imageset.cs`, but we've
+// folded it into this file.
+
+export var ImageSetType = {
+ earth: 0,
+ planet: 1,
+ sky: 2,
+ panorama: 3,
+ solarSystem: 4,
+ sandbox: 5
+};
+
+registerType("ImageSetType", ImageSetType);
+registerEnum("ImageSetType", ImageSetType);
+
+
+// wwtlib.BandPass
+//
+// This was originally defined in `IImageset.cs`, not `Imageset.cs`, but we've
+// folded it into this file.
+
+export var BandPass = {
+ gamma: 0,
+ xRay: 1,
+ ultraviolet: 2,
+ visible: 3,
+ hydrogenAlpha: 4,
+ IR: 4,
+ microwave: 5,
+ radio: 6,
+ visibleNight: 6
+};
+
+registerType("BandPass", BandPass);
+registerEnum("BandPass", BandPass);
+
+
+// wwtlib.Imageset
+
+export function Imageset() {
+ this._projection = 0;
+ this._imageSetID = 0;
+ this._baseTileDegrees = 0;
+ this._widthFactor = 1;
+ this.demUrl = '';
+ this._levels = 0;
+ this._mercator = false;
+ this._bottomsUp = false;
+ this._baseLevel = 1;
+ this._quadTreeTileMap = '0123';
+ this._centerX = 0;
+ this._centerY = 0;
+ this._rotation = 0;
+ this._meanRadius = 0;
+ this._dataSetType = 0;
+ this._bandPass = 3;
+ this._altUrl = '';
+ this._singleImage = false;
+ this._fitsProperties = new FitsProperties();
+ this._matrixComputed = false;
+ this._name = '';
+ this._sparse = false;
+ this._thumbnailUrl = '';
+ this._generic = false;
+ this._defaultSet = false;
+ this._elevationModel = false;
+ this._offsetX = 0;
+ this._offsetY = 0;
+}
+
+Imageset.getNewTile = function (imageset, level, x, y, parent) {
+ // Note: "spherical" projection type not handled in the WebGL engine.
+ switch (imageset.get_projection()) {
+ case ProjectionType.mercator:
+ var newTile = MercatorTile.create(level, x, y, imageset, parent);
+ return newTile;
+ case ProjectionType.equirectangular:
+ return EquirectangularTile.create(level, x, y, imageset, parent);
+ case ProjectionType.toast:
+ default:
+ return ToastTile.create(level, x, y, imageset, parent);
+ case ProjectionType.skyImage:
+ return new SkyImageTile(level, x, y, imageset, parent);
+ case ProjectionType.plotted:
+ return PlotTile.create(level, x, y, imageset, parent);
+ case ProjectionType.healpix:
+ if (imageset.get_hipsProperties() == null) {
+ imageset.set_hipsProperties(makeNewHipsProperties(imageset));
+ }
+ if (imageset.get_hipsProperties().get_downloadComplete()) {
+ return new HealpixTile(level, x, y, imageset, parent);
+ }
+ else {
+ return null;
+ }
+ case ProjectionType.tangent:
+ var newTile = new TangentTile(level, x, y, imageset, parent);
+ return newTile;
+ }
+};
+
+Imageset.fromXMLNode = function (node) {
+ try {
+ var type = 2;
+ var projection = 2;
+ if (node.attributes.getNamedItem('DataSetType') != null) {
+ type = Enums.parse('ImageSetType', node.attributes.getNamedItem('DataSetType').nodeValue);
+ }
+ var bandPass = 3;
+ bandPass = Enums.parse('BandPass', node.attributes.getNamedItem('BandPass').nodeValue);
+ var wf = 1;
+ if (node.attributes.getNamedItem('WidthFactor') != null) {
+ wf = parseInt(node.attributes.getNamedItem('WidthFactor').nodeValue);
+ }
+ if (node.attributes.getNamedItem('Generic') == null || !ss.boolean(node.attributes.getNamedItem('Generic').nodeValue)) {
+ projection = Enums.parse('ProjectionType', node.attributes.getNamedItem('Projection').nodeValue);
+ var fileType = node.attributes.getNamedItem('FileType').nodeValue;
+ if (!ss.startsWith(fileType, '.')) {
+ fileType = '.' + fileType;
+ }
+ var thumbnailUrl = '';
+ var thumbUrl = Util.selectSingleNode(node, 'ThumbnailUrl');
+ if (thumbUrl != null) {
+ if (ss.emptyString(thumbUrl.text)) {
+ var cn = thumbUrl;
+ thumbnailUrl = cn.textContent;
+ }
+ else {
+ thumbnailUrl = thumbUrl.text;
+ }
+ }
+ var stockSet = false;
+ var elevationModel = false;
+ if (node.attributes.getNamedItem('StockSet') != null) {
+ stockSet = ss.boolean(node.attributes.getNamedItem('StockSet').nodeValue);
+ }
+ if (node.attributes.getNamedItem('ElevationModel') != null) {
+ elevationModel = ss.boolean(node.attributes.getNamedItem('ElevationModel').nodeValue);
+ }
+ var demUrl = '';
+ if (node.attributes.getNamedItem('DemUrl') != null) {
+ demUrl = node.attributes.getNamedItem('DemUrl').nodeValue;
+ }
+ var alturl = '';
+ if (node.attributes.getNamedItem('AltUrl') != null) {
+ alturl = node.attributes.getNamedItem('AltUrl').nodeValue;
+ }
+ var offsetX = 0;
+ if (node.attributes.getNamedItem('OffsetX') != null) {
+ offsetX = parseFloat(node.attributes.getNamedItem('OffsetX').nodeValue);
+ }
+ var offsetY = 0;
+ if (node.attributes.getNamedItem('OffsetY') != null) {
+ offsetY = parseFloat(node.attributes.getNamedItem('OffsetY').nodeValue);
+ }
+ var creditText = '';
+ var credits = Util.selectSingleNode(node, 'Credits');
+ if (credits != null) {
+ creditText = Util.getInnerText(credits);
+ }
+ var creditsUrl = '';
+ credits = Util.selectSingleNode(node, 'CreditsUrl');
+ if (credits != null) {
+ creditsUrl = Util.getInnerText(credits);
+ }
+ var meanRadius = 0;
+ if (node.attributes.getNamedItem('MeanRadius') != null) {
+ meanRadius = parseFloat(node.attributes.getNamedItem('MeanRadius').nodeValue);
+ }
+ var referenceFrame = null;
+ if (node.attributes.getNamedItem('ReferenceFrame') != null) {
+ referenceFrame = node.attributes.getNamedItem('ReferenceFrame').nodeValue;
+ }
+ var name = '';
+ if (node.attributes.getNamedItem('Name') != null) {
+ name = node.attributes.getNamedItem('Name').nodeValue;
+ }
+ var url = '';
+ if (node.attributes.getNamedItem('Url') != null) {
+ url = node.attributes.getNamedItem('Url').nodeValue;
+ }
+ var baseTileLevel = 0;
+ if (node.attributes.getNamedItem('BaseTileLevel') != null) {
+ baseTileLevel = parseInt(node.attributes.getNamedItem('BaseTileLevel').nodeValue);
+ }
+ var tileLevels = 0;
+ if (node.attributes.getNamedItem('TileLevels') != null) {
+ tileLevels = parseInt(node.attributes.getNamedItem('TileLevels').nodeValue);
+ }
+ var baseDegreesPerTile = 0;
+ if (node.attributes.getNamedItem('BaseDegreesPerTile') != null) {
+ baseDegreesPerTile = parseFloat(node.attributes.getNamedItem('BaseDegreesPerTile').nodeValue);
+ }
+ var bottomsUp = false;
+ if (node.attributes.getNamedItem('BottomsUp') != null) {
+ bottomsUp = ss.boolean(node.attributes.getNamedItem('BottomsUp').nodeValue);
+ }
+ var quadTreeMap = '';
+ if (node.attributes.getNamedItem('QuadTreeMap') != null) {
+ quadTreeMap = node.attributes.getNamedItem('QuadTreeMap').nodeValue;
+ }
+ var centerX = 0;
+ if (node.attributes.getNamedItem('CenterX') != null) {
+ centerX = parseFloat(node.attributes.getNamedItem('CenterX').nodeValue);
+ }
+ var centerY = 0;
+ if (node.attributes.getNamedItem('CenterY') != null) {
+ centerY = parseFloat(node.attributes.getNamedItem('CenterY').nodeValue);
+ }
+ var rotation = 0;
+ if (node.attributes.getNamedItem('Rotation') != null) {
+ rotation = parseFloat(node.attributes.getNamedItem('Rotation').nodeValue);
+ }
+ var sparse = false;
+ if (node.attributes.getNamedItem('Sparse') != null) {
+ sparse = ss.boolean(node.attributes.getNamedItem('Sparse').nodeValue);
+ }
+ return Imageset.create(name, url, type, bandPass, projection, Math.abs(Util.getHashCode(url)), baseTileLevel, tileLevels, 256, baseDegreesPerTile, fileType, bottomsUp, quadTreeMap, centerX, centerY, rotation, sparse, thumbnailUrl, stockSet, elevationModel, wf, offsetX, offsetY, creditText, creditsUrl, demUrl, alturl, meanRadius, referenceFrame);
+ } else {
+ return Imageset.createGeneric(type, bandPass);
+ }
+ }
+ catch ($e1) {
+ return null;
+ }
+};
+
+Imageset.saveToXml = function (xmlWriter, imageset, alternateUrl) {
+ xmlWriter._writeStartElement('ImageSet');
+ xmlWriter._writeAttributeString('Generic', imageset.get_generic().toString());
+ xmlWriter._writeAttributeString('DataSetType', Enums.toXml('ImageSetType', imageset.get_dataSetType()));
+ xmlWriter._writeAttributeString('BandPass', Enums.toXml('BandPass', imageset.get_bandPass()));
+ if (!imageset.get_generic()) {
+ xmlWriter._writeAttributeString('Name', imageset.get_name());
+ if (ss.emptyString(alternateUrl)) {
+ xmlWriter._writeAttributeString('Url', imageset.get_url());
+ } else {
+ xmlWriter._writeAttributeString('Url', alternateUrl);
+ }
+ xmlWriter._writeAttributeString('DemUrl', imageset.get_demUrl());
+ xmlWriter._writeAttributeString('BaseTileLevel', imageset.get_baseLevel().toString());
+ xmlWriter._writeAttributeString('TileLevels', imageset.get_levels().toString());
+ xmlWriter._writeAttributeString('BaseDegreesPerTile', imageset.get_baseTileDegrees().toString());
+ xmlWriter._writeAttributeString('FileType', imageset.get_extension());
+ xmlWriter._writeAttributeString('BottomsUp', imageset.get_bottomsUp().toString());
+ xmlWriter._writeAttributeString('Projection', Enums.toXml('ProjectionType', imageset.get_projection()));
+ xmlWriter._writeAttributeString('QuadTreeMap', imageset.get_quadTreeTileMap());
+ xmlWriter._writeAttributeString('CenterX', imageset.get_centerX().toString());
+ xmlWriter._writeAttributeString('CenterY', imageset.get_centerY().toString());
+ xmlWriter._writeAttributeString('OffsetX', imageset.get_offsetX().toString());
+ xmlWriter._writeAttributeString('OffsetY', imageset.get_offsetY().toString());
+ xmlWriter._writeAttributeString('Rotation', imageset.get_rotation().toString());
+ xmlWriter._writeAttributeString('Sparse', imageset.get_sparse().toString());
+ xmlWriter._writeAttributeString('ElevationModel', imageset.get_elevationModel().toString());
+ xmlWriter._writeAttributeString('StockSet', imageset.get_defaultSet().toString());
+ xmlWriter._writeAttributeString('WidthFactor', imageset.get_widthFactor().toString());
+ xmlWriter._writeAttributeString('MeanRadius', imageset.get_meanRadius().toString());
+ xmlWriter._writeAttributeString('ReferenceFrame', imageset.get_referenceFrame());
+ if (ss.emptyString(alternateUrl)) {
+ xmlWriter._writeElementString('ThumbnailUrl', imageset.get_thumbnailUrl());
+ } else {
+ xmlWriter._writeElementString('ThumbnailUrl', imageset.get_url());
+ }
+ }
+ xmlWriter._writeEndElement();
+};
+
+Imageset.createGeneric = function (dataSetType, bandPass) {
+ var temp = new Imageset();
+ temp._generic = true;
+ temp._name = 'Generic';
+ temp._sparse = false;
+ temp._dataSetType = dataSetType;
+ temp._bandPass = bandPass;
+ temp._quadTreeTileMap = '';
+ temp.url = '';
+ temp._levels = 0;
+ temp._baseTileDegrees = 0;
+ temp._imageSetID = 0;
+ temp._extension = '';
+ temp._projection = 1;
+ temp._bottomsUp = false;
+ temp._baseLevel = 0;
+ temp._mercator = (!temp._projection);
+ temp._centerX = 0;
+ temp._centerY = 0;
+ temp._rotation = 0;
+ temp._thumbnailUrl = '';
+ temp._matrix = Matrix3d.get_identity();
+ temp._matrix._multiply(Matrix3d._rotationX((temp.get_rotation() / 180 * Math.PI)));
+ temp._matrix._multiply(Matrix3d._rotationZ((temp.get_centerY() / 180 * Math.PI)));
+ temp._matrix._multiply(Matrix3d._rotationY((((360 - temp.get_centerX()) + 180) / 180 * Math.PI)));
+ return temp;
+};
+
+Imageset.create = function (name, url, dataSetType, bandPass, projection, imageSetID, baseLevel, levels, tileSize, baseTileDegrees, extension, bottomsUp, quadTreeMap, centerX, centerY, rotation, sparse, thumbnailUrl, defaultSet, elevationModel, wf, offsetX, offsetY, credits, creditsUrl, demUrlIn, alturl, meanRadius, referenceFrame) {
+ var temp = new Imageset();
+ temp.setInitialParameters(name, url, dataSetType, bandPass, projection, imageSetID, baseLevel, levels, baseTileDegrees, extension, bottomsUp, quadTreeMap, centerX, centerY, rotation, sparse, thumbnailUrl, defaultSet, elevationModel, wf, offsetX, offsetY, credits, creditsUrl, demUrlIn, alturl, meanRadius, referenceFrame);
+ return temp;
+};
+
+var Imageset$ = {
+ get_wcsImage: function () {
+ return this._wcsImage;
+ },
+
+ set_wcsImage: function (value) {
+ this._wcsImage = value;
+ return value;
+ },
+
+ get_projection: function () {
+ return this._projection;
+ },
+
+ set_projection: function (value) {
+ this._projection = value;
+ return value;
+ },
+
+ get_referenceFrame: function () {
+ return this._referenceFrame;
+ },
+
+ set_referenceFrame: function (value) {
+ this._referenceFrame = value;
+ return value;
+ },
+
+ get_imageSetID: function () {
+ return this._imageSetID;
+ },
+
+ set_imageSetID: function (value) {
+ this._imageSetID = value;
+ return value;
+ },
+
+ get_baseTileDegrees: function () {
+ return this._baseTileDegrees;
+ },
+
+ set_baseTileDegrees: function (value) {
+ this._baseTileDegrees = value;
+ return value;
+ },
+
+ get_widthFactor: function () {
+ return this._widthFactor;
+ },
+
+ set_widthFactor: function (value) {
+ this._widthFactor = value;
+ return value;
+ },
+
+ getHashCode: function () {
+ return Util.getHashCode(this.get_url());
+ },
+
+ get_url: function () {
+ return this.url;
+ },
+
+ set_url: function (value) {
+ this.url = value;
+ return value;
+ },
+
+ get_demUrl: function () {
+ if (ss.emptyString(this.demUrl) && !this._projection && !freestandingMode) {
+ return URLHelpers.singleton.coreStaticUrl('wwtweb/BingDemTile.aspx?Q={0},{1},{2}');
+ }
+ return this.demUrl;
+ },
+
+ set_demUrl: function (value) {
+ this.demUrl = value;
+ return value;
+ },
+
+ get_extension: function () {
+ return this._extension;
+ },
+
+ set_extension: function (value) {
+ this._extension = value;
+ return value;
+ },
+
+ get_levels: function () {
+ return this._levels;
+ },
+
+ set_levels: function (value) {
+ this._levels = value;
+ return value;
+ },
+
+ get_bottomsUp: function () {
+ return this._bottomsUp;
+ },
+
+ set_bottomsUp: function (value) {
+ this._bottomsUp = value;
+ return value;
+ },
+
+ get_mercator: function () {
+ return this._mercator;
+ },
+
+ set_mercator: function (value) {
+ this._mercator = value;
+ return value;
+ },
+
+ get_baseLevel: function () {
+ return this._baseLevel;
+ },
+
+ set_baseLevel: function (value) {
+ this._baseLevel = value;
+ return value;
+ },
+
+ get_quadTreeTileMap: function () {
+ return this._quadTreeTileMap;
+ },
+
+ set_quadTreeTileMap: function (value) {
+ this._quadTreeTileMap = value;
+ return value;
+ },
+
+ get_centerX: function () {
+ return this._centerX;
+ },
+
+ set_centerX: function (value) {
+ if (this._centerX !== value) {
+ this._centerX = value;
+ this._computeMatrix();
+ }
+ return value;
+ },
+
+ get_centerY: function () {
+ return this._centerY;
+ },
+
+ set_centerY: function (value) {
+ if (this._centerY !== value) {
+ this._centerY = value;
+ this._computeMatrix();
+ }
+ return value;
+ },
+
+ get_rotation: function () {
+ return this._rotation;
+ },
+
+ set_rotation: function (value) {
+ if (this._rotation !== value) {
+ this._rotation = value;
+ this._computeMatrix();
+ }
+ return value;
+ },
+
+ get_meanRadius: function () {
+ return this._meanRadius;
+ },
+
+ set_meanRadius: function (value) {
+ this._meanRadius = value;
+ return value;
+ },
+
+ get_bandPass: function () {
+ return this._bandPass;
+ },
+
+ set_bandPass: function (value) {
+ this._bandPass = value;
+ return value;
+ },
+
+ get_dataSetType: function () {
+ return this._dataSetType;
+ },
+
+ set_dataSetType: function (value) {
+ this._dataSetType = value;
+ return value;
+ },
+
+ get_altUrl: function () {
+ return this._altUrl;
+ },
+
+ set_altUrl: function (value) {
+ this._altUrl = value;
+ return value;
+ },
+
+ get_singleImage: function () {
+ return this._singleImage;
+ },
+
+ set_singleImage: function (value) {
+ this._singleImage = value;
+ return value;
+ },
+
+ get_hipsProperties: function () {
+ return this._hipsProperties;
+ },
+
+ set_hipsProperties: function (value) {
+ this._hipsProperties = value;
+ return value;
+ },
+
+ get_fitsProperties: function () {
+ return this._fitsProperties;
+ },
+
+ set_fitsProperties: function (value) {
+ this._fitsProperties = value;
+ return value;
+ },
+
+ toString: function () {
+ if (this.get_defaultSet()) {
+ return this._name + ' *';
+ } else {
+ return this._name;
+ }
+ },
+
+ get_stockImageSet: function () {
+ if (this._generic || !this._defaultSet) {
+ return this;
+ } else {
+ return Imageset.createGeneric(this.get_dataSetType(), this.get_bandPass());
+ }
+ },
+
+ equals: function (obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (!(ss.canCast(obj, Imageset))) {
+ return false;
+ }
+ var b = obj;
+ return (Util.getHashCode(b.get_url()) === Util.getHashCode(this.get_url()) && b.get_dataSetType() === this.get_dataSetType() && b.get_bandPass() === this.get_bandPass() && b.get_generic() === this.get_generic());
+ },
+
+ get_matrix: function () {
+ if (!this._matrixComputed) {
+ this._computeMatrix();
+ }
+ return this._matrix;
+ },
+
+ set_matrix: function (value) {
+ this._matrix = value;
+ return value;
+ },
+
+ _computeMatrix: function () {
+ this._matrixComputed = true;
+ this._matrix = Matrix3d.get_identity();
+ this._matrix._multiply(Matrix3d._rotationX((this.get_rotation() / 180 * Math.PI)));
+ this._matrix._multiply(Matrix3d._rotationZ((this.get_centerY() / 180 * Math.PI)));
+ this._matrix._multiply(Matrix3d._rotationY(((360 - this.get_centerX()) / 180 * Math.PI)));
+ },
+
+ get_name: function () {
+ return this._name;
+ },
+
+ set_name: function (value) {
+ this._name = value;
+ return value;
+ },
+
+ get_sparse: function () {
+ return this._sparse;
+ },
+
+ set_sparse: function (value) {
+ this._sparse = value;
+ return value;
+ },
+
+ get_thumbnailUrl: function () {
+ return this._thumbnailUrl;
+ },
+
+ set_thumbnailUrl: function (value) {
+ this._thumbnailUrl = value;
+ return value;
+ },
+
+ get_generic: function () {
+ return this._generic;
+ },
+
+ set_generic: function (value) {
+ this._generic = value;
+ return value;
+ },
+
+ get_elevationModel: function () {
+ return this._elevationModel;
+ },
+
+ set_elevationModel: function (value) {
+ this._elevationModel = value;
+ return value;
+ },
+
+ get_defaultSet: function () {
+ return this._defaultSet;
+ },
+
+ set_defaultSet: function (value) {
+ this._defaultSet = value;
+ return value;
+ },
+
+ get_offsetX: function () {
+ return this._offsetX;
+ },
+
+ set_offsetX: function (value) {
+ this._offsetX = value;
+ return value;
+ },
+
+ get_offsetY: function () {
+ return this._offsetY;
+ },
+
+ set_offsetY: function (value) {
+ this._offsetY = value;
+ return value;
+ },
+
+ get_creditsText: function () {
+ return this._creditsText;
+ },
+
+ set_creditsText: function (value) {
+ this._creditsText = value;
+ return value;
+ },
+
+ get_creditsUrl: function () {
+ return this._creditsUrl;
+ },
+
+ set_creditsUrl: function (value) {
+ this._creditsUrl = value;
+ return value;
+ },
+
+ get_isMandelbrot: function () {
+ return false;
+ },
+
+ // Calculate either the X or Y coordinate of the estimated image center.
+ //
+ // This estimate has some important limitations. First, because images
+ // might contain transparent regions, the "center" of the image that a
+ // user will perceive might have nothing to do with the center of the
+ // image bitmap. For instance, imagine that the bitmap is 100x100 but
+ // that everything is transparent except for 10x10 pixels in the
+ // top-left corner. We don't know anything about the "barycenter" of the
+ // image here, so we can't account for that.
+ //
+ // Second, for untiled SkyImage imagesets, to properly compute the
+ // bitmap center we need its dimensions, which simply aren't available
+ // here. All we can do is guess a "reasonable" image size.
+ //
+ // For these reasons, this method should be avoided when possible. The
+ // preferred way to "know" the location of an image's center is to wrap
+ // the image in a Place object, which can just specify the exact
+ // coordinates and zoom level too.
+ //
+ // Even disregarding the above, it's non-trivial to locate the image
+ // center because of the OffsetX/Y parameters and potential rotation of
+ // the image's coordinate system relative to the sky.
+ _calcViewCenterCoordinate: function (isX) {
+ var rot = Coordinates.degreesToRadians(this._rotation);
+ var crot = Math.cos(rot);
+ var srot = Math.sin(rot);
+ var dx = 0, dy = 0;
+ if (this.get_levels() > 0) {
+ dx = -this._offsetX;
+ dy = this._offsetY;
+ } else {
+ // This is the part where we need the image's dimensions to
+ // be able to compute the center coordinate correctly. Since
+ // we don't have that information, we just guess :-(
+ var effWidth = 800;
+ var effHeight = 800;
+ dx = (this._offsetX - effWidth / 2) * this._baseTileDegrees;
+ dy = (effHeight / 2 - this._offsetY) * this._baseTileDegrees;
+ }
+ if (this._bottomsUp) {
+ dx = -dx;
+ }
+ if (isX) {
+ return this._centerX + dx * crot + dy * srot;
+ } else {
+ return this._centerY - dx * srot + dy * crot;
+ }
+ },
+
+ get_viewCenterX: function () {
+ if (this.get_wcsImage() != null) {
+ return (this.get_wcsImage()).get_viewCenterX();
+ } else {
+ return this._calcViewCenterCoordinate(true);
+ }
+ },
+
+ get_viewCenterY: function () {
+ if (this.get_wcsImage() != null) {
+ return (this.get_wcsImage()).get_viewCenterY();
+ } else {
+ return this._calcViewCenterCoordinate(false);
+ }
+ },
+
+ setInitialParameters: function (name, url, dataSetType, bandPass, projection, imageSetID, baseLevel, levels, baseTileDegrees, extension, bottomsUp, quadTreeMap, centerX, centerY, rotation, sparse, thumbnailUrl, defaultSet, elevationModel, wf, offsetX, offsetY, credits, creditsUrl, demUrlIn, alturl, meanRadius, referenceFrame) {
+ this.set_referenceFrame(referenceFrame);
+ this.set_meanRadius(meanRadius);
+ this._altUrl = alturl;
+ this.demUrl = demUrlIn;
+ this._creditsText = credits;
+ this._creditsUrl = creditsUrl;
+ this._offsetY = offsetY;
+ this._offsetX = offsetX;
+ this._widthFactor = wf;
+ this._elevationModel = elevationModel;
+ this._defaultSet = defaultSet;
+ this._name = name;
+ this._sparse = sparse;
+ this._dataSetType = dataSetType;
+ this._bandPass = bandPass;
+ this._quadTreeTileMap = quadTreeMap;
+ this.url = url;
+ this._levels = levels;
+ this._baseTileDegrees = baseTileDegrees;
+ this._imageSetID = imageSetID;
+ this._extension = extension;
+ this._projection = projection;
+ this._bottomsUp = bottomsUp;
+ this._baseLevel = baseLevel;
+ this._mercator = (!projection);
+ this._centerX = centerX;
+ this._centerY = centerY;
+ this._rotation = rotation;
+ this._thumbnailUrl = thumbnailUrl;
+ this._computeMatrix();
+ },
+
+ // Ideally, imagesets will be associated with Places that specify
+ // exactly how the view should be set up when "going to" them, but
+ // sometimes (especially research datasets) we're interested in deriving
+ // a reasonable zoom setting without that extra information. The returned value
+ // isn't going to be perfect but it should hopefully be OK.
+ _guessZoomSetting: function (currentZoom) {
+ const FOV_FACTOR = 1.7;
+ var zoom = currentZoom;
+ var aswcs = ss.safeCast(this._wcsImage, FitsImage);
+ if (this.get_projection() === ProjectionType.skyImage) {
+ // Untiled SkyImage: basetiledegrees is degrees per pixel
+ if (aswcs != null) {
+ zoom = this.get_baseTileDegrees() * aswcs.get_sizeY() * 6 * FOV_FACTOR;
+ }
+ } else if (aswcs != null) {
+ zoom = aswcs.get_scaleY() * aswcs.get_sizeY() * 6 * FOV_FACTOR;
+ } else {
+ // Tiled. basetiledegrees is angular height of whole image after
+ // power-of-2 padding.
+ zoom = this.get_baseTileDegrees() * 6 * FOV_FACTOR;
+ }
+
+ // Only zoom in, not out. Usability-wise this tends to make the most
+ // sense.
+ if (zoom > currentZoom) {
+ zoom = currentZoom;
+ }
+ return zoom;
+ },
+
+ // URL parameters
+ //{0} ImageSetID
+ //{1} level
+ //{2} x tile id
+ //{3} y tile id
+ //{4} quadtree address (VE style)
+ //{5} quadtree address (Google maps style)
+ //{6} top left corner RA
+ //{7} top left corner Dec
+ //{8} bottom right corner RA
+ //{9} bottom right corner dec
+ //{10} bottom left corner RA
+ //{11} bottom left corner dec
+ //{12} top right corner RA
+ //{13} top right corner dec
+
+ get_thumbnail: function () {
+ return this._thumbnail;
+ },
+
+ set_thumbnail: function (value) {
+ this._thumbnail = value;
+ return value;
+ },
+
+ get_bounds: function () {
+ return this._bounds;
+ },
+
+ set_bounds: function (value) {
+ this._bounds = value;
+ return value;
+ },
+
+ get_isImage: function () {
+ return true;
+ },
+
+ get_isTour: function () {
+ return false;
+ },
+
+ get_isFolder: function () {
+ return false;
+ },
+
+ get_isCloudCommunityItem: function () {
+ return false;
+ },
+
+ get_readOnly: function () {
+ return false;
+ },
+
+ get_children: function () {
+ return [];
+ }
+};
+
+registerType("Imageset", [Imageset, Imageset$, null, IThumbnail]);
diff --git a/engine/esm/index.js b/engine/esm/index.js
new file mode 100644
index 00000000..8c6127d1
--- /dev/null
+++ b/engine/esm/index.js
@@ -0,0 +1,408 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// The toplevel WorldWide Telescope WebGL engine API module.
+//
+// To maintain compatibility with a *lot* of legacy code, we export way more
+// types and interfaces than we would if we were starting from scratch, often
+// with confusing or misspelled names. So it goes.
+//
+// The import/exports here are in rough dependency order throughout the
+// codebase, although there are numerous places where circular references sneak
+// in.
+
+export { ss } from "./ss.js";
+
+export { Util } from "./baseutil.js";
+
+export { CalD, DAY_OF_WEEK, DT } from "./astrocalc/date.js";
+export { COR, C3D, CT } from "./astrocalc/coordinate_transformation.js";
+export { ASEP } from "./astrocalc/angular_separation.js";
+export { CAAEarth, VSC, } from "./astrocalc/earth.js";
+export { CAAFK5 } from "./astrocalc/fk5.js";
+export { NUC, CAANutation } from "./astrocalc/nutation.js";
+export { CAASun } from "./astrocalc/sun.js";
+export { CAAMercury } from "./astrocalc/mercury.js";
+export { CAAVenus } from "./astrocalc/venus.js";
+export { CAAMars } from "./astrocalc/mars.js";
+export { CAAJupiter } from "./astrocalc/jupiter.js";
+export { CAASaturn } from "./astrocalc/saturn.js";
+export { CAAUranus } from "./astrocalc/uranus.js";
+export { CAANeptune } from "./astrocalc/neptune.js";
+export { CAAPluto, PlutoCoefficient1, PlutoCoefficient2 } from "./astrocalc/pluto.js";
+export { CAAKepler } from "./astrocalc/kepler.js";
+export { ABR, ACFT } from "./astrocalc/aberration.js";
+export { DYT } from "./astrocalc/dynamical_time.js";
+export { CAAEclipticalElementDetails, CAAEclipticalElements } from "./astrocalc/ecliptical_elements.js";
+export { EPO } from "./astrocalc/elements_planetary_orbit.js";
+export { EOE, EPD, EOD, EO, ELL } from "./astrocalc/elliptical.js";
+export { EOT } from "./astrocalc/equation_of_time.js";
+export { GMD, GMDS, GM } from "./astrocalc/galilean_moons.js";
+export { CAAGlobe } from "./astrocalc/globe.js";
+export { IFR } from "./astrocalc/illuminated_fraction.js";
+export { INTP } from "./astrocalc/interpolate.js";
+export { CAAMoon, MoonCoefficient1, MoonCoefficient2 } from "./astrocalc/moon.js";
+export { MIFR } from "./astrocalc/moon_illuminated_fraction.js";
+export { CAAMoonNodes } from "./astrocalc/moon_nodes.js";
+export { CAAMoonPerigeeApogee, MPAC } from "./astrocalc/moon_perigee_apogee.js";
+export { CAAMoonPhases } from "./astrocalc/moon_phases.js";
+export { CAAParallax, CAATopocentricEclipticDetails } from "./astrocalc/parallax.js";
+export { CAASidereal } from "./astrocalc/sidereal.js";
+export { CAAPhysicalJupiterDetails, CAAPhysicalJupiter } from "./astrocalc/physical_jupiter.js";
+export { CAAPhysicalMarsDetails, CAAPhysicalMars } from "./astrocalc/physical_mars.js";
+export { CAAPhysicalSunDetails, CAAPhysicalSun } from "./astrocalc/physical_sun.js";
+export { CAAPrecession } from "./astrocalc/precession.js";
+export { CAARiseTransitSetDetails, CAARiseTransitSet } from "./astrocalc/rise_transit_set.js";
+export { CAASaturnRingDetails, CAASaturnRings } from "./astrocalc/saturn_rings.js";
+export { CAAStellarMagnitudes } from "./astrocalc/stellar_magnitudes.js";
+
+export { BlendState } from "./blend_state.js";
+export { Color, Colors } from "./color.js";
+export { URLHelpers, URLRewriteMode } from "./url_helpers.js";
+
+export {
+ LocationHint,
+ PositionTexture,
+ PositionColoredTextured,
+ PositionColored,
+ PositionNormalTexturedTangent,
+ Vector3d,
+ Vector2d,
+ Matrix3d,
+ Matrix2d,
+ DoubleUtilities,
+ PlaneD,
+ Vector4d,
+ PositionNormalTexturedX2,
+ PositionNormalTextured,
+ SphereHull,
+ ConvexHull
+} from "./double3d.js";
+
+export {
+ Rectangle,
+ Guid,
+ Mouse,
+ Language,
+ Cursor,
+ Cursors,
+ Keys,
+ SelectLink,
+ PopupVolume,
+ PopupColorPicker,
+ OverlayProperties,
+ DialogResult,
+} from "./util.js";
+
+export { AstroRaDec, RiseSetDetails, AstroCalc } from "./astrocalc.js";
+
+export {
+ ShortIndexBuffer,
+ IndexBuffer,
+ VertexBufferBase,
+ PositionVertexBuffer,
+ PositionNormalTexturedVertexBuffer,
+ PositionNormalTexturedTangentVertexBuffer,
+} from "./graphics/gl_buffers.js"
+
+export { Texture } from "./graphics/texture.js";
+export { Tessellator } from "./graphics/tessellator.js";
+
+export {
+ SimpleLineShader,
+ SimpleLineShader2D,
+ OrbitLineShader,
+ LineShaderNormalDates,
+ TimeSeriesPointSpriteShader,
+ KeplerPointSpriteShader,
+ EllipseShader,
+ ModelShader,
+ ModelShaderTan,
+ TileShader,
+ FitsShader,
+ ImageShader,
+ ImageShader2,
+ SpriteShader,
+ ShapeSpriteShader,
+ TextShader,
+} from "./graphics/shaders.js";
+
+export {
+ CullMode,
+ PointScaleTypes,
+ DataItem,
+ Dates,
+ SimpleLineList,
+ OrbitLineList,
+ LineList,
+ TriangleList,
+ TriangleFanList,
+ PointList,
+ TimeSeriesLineVertex,
+ TimeSeriesPointVertex,
+} from "./graphics/primitives3d.js";
+
+// These are new, post-C# APIs that we wouldn't normally expose, but they
+// support the test suite.
+export {
+ set_tilePrepDevice,
+ set_useGlVersion2
+} from "./render_globals.js";
+
+export { Bitmap } from "./utilities/bitmap.js";
+
+export {
+ ContextMenuStrip,
+ ToolStripMenuItem,
+ ToolStripSeparator,
+ TagMe,
+} from "./utilities/context_menu_strip.js";
+
+export { BinaryReader } from "./utilities/binary_reader.js";
+export { SimpleInput } from "./utilities/simple_input.js";
+export { XmlTextWriter, Formatting } from "./utilities/xml_text_writer.js";
+
+export { Coordinates } from "./coordinates.js";
+export { FastMath } from "./fast_math.js";
+export { HealpixTables } from "./healpix_tables.js";
+export { HealpixUtils } from "./healpix_utils.js";
+export { Hploc } from "./hploc.js";
+export { Fxyf } from "./fxyf.js";
+export {
+ IThumbnail,
+ IPlace,
+ IUiController,
+ IViewMover,
+ IUIServicesCallbacks,
+ ISettings,
+ IUndoStep,
+} from "./interfaces.js";
+export { Annotation, Circle, Poly, PolyLine } from "./annotation.js";
+export { SolarSystemObjects, InterpolationType, CameraParameters } from "./camera_parameters.js";
+export { ConstellationFilter } from "./constellation_filter.js";
+export { FitsProperties, ScaleTypes } from "./fits_properties.js";
+export { Star, Galaxy } from "./star.js";
+export { UiTools } from "./ui_tools.js";
+export { StateType, WebFile } from "./web_file.js";
+
+export { ColorMapContainer } from "./layers/color_map_container.js";
+export { WcsImage } from "./layers/wcs_image.js";
+export { FitsImage } from "./layers/fits_image.js";
+export {
+ DataTypes,
+ ScaleMap,
+ ScaleLinear,
+ ScaleLog,
+ ScalePow,
+ ScaleSqrt,
+ HistogramEqualization,
+ FitsImageJs,
+} from "./layers/fits_image_js.js";
+export { FitsImageTile } from "./layers/fits_image_tile.js";
+
+export { Tile } from "./tile.js";
+export { RenderTriangle } from "./render_triangle.js";
+export { EquirectangularTile } from "./equirectangular_tile.js";
+export { HealpixTile, Xyf } from "./healpix_tile.js";
+export { MercatorTile } from "./mercator_tile.js";
+export { PlotTile } from "./plot_tile.js";
+export { LatLngEdges, TangentTile } from "./tangent_tile.js";
+export { SkyImageTile } from "./sky_image_tile.js";
+export { ToastTile } from "./toast_tile.js";
+export { ProjectionType, ImageSetType, BandPass, Imageset } from "./imageset.js";
+export { Settings, SettingParameter, StockSkyOverlayTypes } from "./settings.js";
+export { TextBorderStyle, TextObject } from "./tours/text_object.js";
+export { Alignment, Text3dBatch, Text3d, GlyphItem, GlyphCache } from "./sky_text.js";
+export { PointType, Lineset, Linepoint, Constellations } from "./constellations.js";
+export { SpaceTimeController } from "./space_time_controller.js";
+export { KeplerianElements, BodyAngles, Planets } from "./planets.js";
+export { Place, Classification } from "./place.js";
+export { FolderUp } from "./folder_up.js";
+export { Grids } from "./grids.js";
+export { KeplerVertex } from "./kepler_vertex.js";
+export { Pointing } from "./pointing.js";
+export { Tour } from "./tour.js";
+export { VideoOutputType } from "./video_output_type.js";
+export { ViewMoverKenBurnsStyle } from "./view_mover.js";
+export { VizLayer } from "./viz_layer.js";
+export { ColorPicker } from "./utilities/color_picker.js";
+export { Dialog } from "./utilities/dialog.js";
+export { Histogram } from "./utilities/histogram.js";
+
+export { Layer, DomainValue, AltUnits, FadeType } from "./layers/layer.js";
+export {
+ LayerUI,
+ LayerUIMenuItem,
+ LayerUITreeNode,
+} from "./layers/layer_ui.js";
+
+// To keep API compatibility, we can't fix this typo.
+export { GreatCirlceRouteLayer } from "./layers/great_circle_route_layer.js";
+
+export { GridLayer } from "./layers/grid_layer.js";
+export { ImageSetLayer } from "./layers/imageset_layer.js";
+export {
+ Group,
+ Material,
+ Mesh,
+ Object3d,
+ ObjectNode,
+ Object3dLayer,
+ Object3dLayerUI,
+} from "./layers/object3d.js";
+export { Orbit, EllipseRenderer } from "./layers/orbit.js";
+export { ReferenceFrame, ReferenceFrameTypes } from "./layers/reference_frame.js";
+export { OrbitLayer, OrbitLayerUI } from "./layers/orbit_layer.js";
+export { Table } from "./layers/table.js";
+export { Primitives, VoTable, VoRow, VoColumn } from "./layers/vo_table.js";
+
+export { FileEntry, FileCabinet } from "./tours/file_cabinet.js";
+export {
+ OverlayAnchor,
+ AudioType,
+ ShapeType,
+ LoopTypes,
+ Overlay,
+ AudioOverlay,
+ BitmapOverlay,
+ FlipbookOverlay,
+ ShapeOverlay,
+ TextOverlay,
+} from "./tours/overlay.js";
+export { Selection, SelectionAnchor } from "./tours/selection.js";
+export {
+ TransitionType,
+ TourStop,
+ LayerInfo,
+ UndoTourStopChange,
+} from "./tours/tour_stop.js";
+export {
+ Undo,
+ UndoStep,
+ UndoTourSlidelistChange,
+ UndoTourPropertiesChange,
+} from "./tours/undo.js";
+export {
+ TourEditor,
+ OverlayList,
+ TourEdit,
+ SoundEditor,
+ TourStopList,
+ TimeLine,
+} from "./tours/tour_editor.js";
+export { TourPlayer, MasterTime } from "./tours/tour_player.js";
+
+export { ISSLayer } from "./layers/iss_layer.js";
+export {
+ CoordinatesTypes,
+ AltTypes,
+ MarkerMixes,
+ ColorMaps,
+ PlotTypes,
+ MarkerScales,
+ RAUnits,
+ TimeSeriesLayer,
+} from "./layers/time_series_layer.js";
+export {
+ KmlCoordinate,
+ KmlLineList,
+ PushPin,
+ SpreadSheetLayer,
+ CatalogSpreadSheetLayer,
+} from "./layers/spreadsheet_layer.js";
+export { VoTableLayer } from "./layers/vo_table_layer.js";
+export {
+ ReferenceFrames,
+ LayerManager,
+ LayerMap,
+ SkyOverlays,
+ GroundOverlayLayer,
+ FrameTarget,
+} from "./layers/layer_manager.js";
+
+// When we import this module, we install the `Layer.fromXml()` function, which
+// depends on the specific layer types established above. I am probably being
+// too conservative about circular module dependencies but there are worse ways
+// to be.
+import { layerFromXml as _ } from "./layers/from_xml.js";
+
+// And when we import *this* module, we also attach some instances to the
+// LayerManager class. I'm not sure if they're even used in the webclient, which
+// would be the only place that reasonably would.
+export {
+ FrameWizard,
+ ReferenceFrameProps,
+ GreatCircleDialog,
+ DataVizWizard,
+} from "./layers/manager_dialogs.js";
+
+export { UserLevel, TourDocument } from "./tours/tour_document.js";
+export { TourEditTab } from "./tours/tour_edit.js";
+
+export {
+ FolderGroup,
+ FolderRefreshType,
+ FolderType,
+ Folder,
+} from "./folder.js";
+export { FolderBrowser, ThumbnailSize } from "./folder_browser.js";
+export { HipsProperties } from "./hips_properties.js";
+export { InViewReturnMessage, RenderContext } from "./render_context.js";
+export {
+ SlideChangedEventArgs,
+ ArrivedEventArgs,
+ AnnotationClickEventArgs,
+ CollectionLoadedEventArgs,
+ ScriptInterface,
+} from "./script_interface.js";
+
+export {
+ WWTControl,
+ WWTControlBuilder,
+ WWTElementEvent,
+} from "./wwt_control.js";
+
+export {
+ FolderDownloadAction,
+ Wtml,
+} from "./wtml.js";
+
+
+// GFX
+//
+// This was a global holder for constants used in the AstroCalc component. We've
+// moved those constants into their specific modules, but still expose the name
+// just in case someone actually referenced it. Since we've removed all of the
+// constants that it contains, though, if someone was reckless enough to try to
+// use this variable their usage would almost surely be broken by now.
+
+import { registerType } from "./typesystem.js";
+
+export function GFX() { }
+
+registerType("GFX", [GFX, null, null]);
+
+
+// Nontrivial initializations.
+
+import { ss } from "./ss.js";
+import { set_globalRenderContext } from "./render_globals.js";
+import { set_globalWWTControl } from "./data_globals.js";
+import { KeplerVertex } from "./kepler_vertex.js";
+import { SpaceTimeController } from "./space_time_controller.js";
+import { Folder } from "./folder.js";
+import { RenderContext } from "./render_context.js";
+import { WWTControl } from "./wwt_control.js";
+
+WWTControl.exploreRoot = new Folder();
+WWTControl.singleton = new WWTControl();
+WWTControl.singleton.renderContext = new RenderContext();
+set_globalWWTControl(WWTControl.singleton);
+set_globalRenderContext(WWTControl.singleton.renderContext);
+
+SpaceTimeController._metaNow = ss.now();
+SpaceTimeController._now = ss.now();
+SpaceTimeController.last = SpaceTimeController.get_metaNow();
+SpaceTimeController.updateClock();
+
+KeplerVertex.baseDate = ss.truncate(SpaceTimeController.utcToJulian(ss.now()));
diff --git a/engine/esm/interfaces.js b/engine/esm/interfaces.js
new file mode 100644
index 00000000..d20de1f4
--- /dev/null
+++ b/engine/esm/interfaces.js
@@ -0,0 +1,74 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// "Classes" corresponding to C# interfaces
+//
+// In our current JS translation, these classes don't declare anything
+// themselves. They can in principle be used in `canCast()` calls for dynamic
+// type checking, but it appears that we don't use this functionality in the
+// current codebase.
+//
+// If/when we translate to TypeScript, these could become TypeScript interfaces
+// that are more useful.
+//
+// Files in this module used to be in
+// `I{Folder,IThumbnail,Place,UIController,ViewMover,Tours/ISettings}.cs`. Note
+// that the source file was indeed (incorrectly) named `IIThumbnail.cs`.
+
+import { registerType } from "./typesystem.js";
+
+
+// wwtlib.IFolder
+
+export function IFolder() { }
+
+registerType("IFolder", [IFolder]);
+
+
+// wwtlib.IThumbnail
+
+export function IThumbnail() { }
+
+registerType("IThumbnail", [IThumbnail]);
+
+
+// wwtlib.IPlace
+
+export function IPlace() { }
+
+registerType("IPlace", [IPlace]);
+
+
+// wwtlib.IUiController
+
+export function IUiController() { }
+
+registerType("IUiController", [IUiController]);
+
+
+// wwtlib.IViewMover
+
+export function IViewMover() { }
+
+registerType("IViewMover", [IViewMover]);
+
+
+// wwtlib.IUIServicesCallbacks
+
+export function IUIServicesCallbacks() { }
+
+registerType("IUIServicesCallbacks", [IUIServicesCallbacks]);
+
+
+// wwtlib.ISettings
+
+export function ISettings() { }
+
+registerType("ISettings", [ISettings]);
+
+
+// wwtlib.IUndoStep
+
+export function IUndoStep() { }
+
+registerType("IUndoStep", [IUndoStep]);
diff --git a/engine/esm/kepler_vertex.js b/engine/esm/kepler_vertex.js
new file mode 100644
index 00000000..95e69f69
--- /dev/null
+++ b/engine/esm/kepler_vertex.js
@@ -0,0 +1,85 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Kepler Vertex.
+
+import { registerType } from "./typesystem.js";
+import { Vector3d } from "./double3d.js";
+import { Colors } from "./color.js";
+
+
+// wwtlib.KeplerVertex
+
+export function KeplerVertex() {
+ this.ABC = new Vector3d();
+ this.abc1 = new Vector3d();
+ this.pointSize = 0;
+ this.w = 0;
+ this.e = 0;
+ this.n = 0;
+ this.t = 0;
+ this.a = 0;
+ this.z = 0;
+ this.orbitPos = 0;
+ this.orbits = 0;
+}
+
+KeplerVertex._sine = 0;
+KeplerVertex._cose = 1;
+KeplerVertex._degrad = Math.PI / 180;
+
+var KeplerVertex$ = {
+ fill: function (ee) {
+ var F = Math.cos(ee.omega * KeplerVertex._degrad);
+ var sinOmega = Math.sin(ee.omega * KeplerVertex._degrad);
+ var cosi = Math.cos(ee.i * KeplerVertex._degrad);
+ var sini = Math.sin(ee.i * KeplerVertex._degrad);
+ var G = sinOmega * KeplerVertex._cose;
+ var H = sinOmega * KeplerVertex._sine;
+ var P = -sinOmega * cosi;
+ var Q = (F * cosi * KeplerVertex._cose) - (sini * KeplerVertex._sine);
+ var R = (F * cosi * KeplerVertex._sine) + (sini * KeplerVertex._cose);
+ var checkA = (F * F) + (G * G) + (H * H); // Should be 1.0
+ var checkB = (P * P) + (Q * Q) + (R * R); // Should be 1.0 as well
+ this.ABC.x = Math.atan2(F, P);
+ this.ABC.y = Math.atan2(G, Q);
+ this.ABC.z = Math.atan2(H, R);
+ this.abc1.x = Math.sqrt((F * F) + (P * P));
+ this.abc1.y = Math.sqrt((G * G) + (Q * Q));
+ this.abc1.z = Math.sqrt((H * H) + (R * R));
+ this.pointSize = 0.1;
+ if (ee.a < 2.5) {
+ this.color = Colors.get_white();
+ } else if (ee.a < 2.83) {
+ this.color = Colors.get_red();
+ } else if (ee.a < 2.96) {
+ this.color = Colors.get_green();
+ } else if (ee.a < 3.3) {
+ this.color = Colors.get_magenta();
+ } else if (ee.a < 5) {
+ this.color = Colors.get_cyan();
+ } else if (ee.a < 10) {
+ this.color = Colors.get_yellow();
+ this.pointSize = 0.9;
+ } else {
+ this.color = Colors.get_white();
+ this.pointSize = 8;
+ }
+ this.w = ee.w;
+ this.e = ee.e;
+ if (!ee.n) {
+ this.n = (0.9856076686 / (ee.a * Math.sqrt(ee.a)));
+ } else {
+ this.n = ee.n;
+ }
+ this.t = (ee.t - KeplerVertex.baseDate);
+ this.a = ee.a;
+ this.z = 0;
+ this.orbitPos = 0;
+ this.orbits = 0;
+ }
+};
+
+registerType("KeplerVertex", [KeplerVertex, KeplerVertex$, null]);
+
+// KeplerVertex.baseDate is initialized at the bottom of the main module.
diff --git a/engine/esm/layers/color_map_container.js b/engine/esm/layers/color_map_container.js
new file mode 100644
index 00000000..77b82bf5
--- /dev/null
+++ b/engine/esm/layers/color_map_container.js
@@ -0,0 +1,638 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A collection of named colormaps.
+
+import { ss } from "../ss.js";
+import { registerType } from "../typesystem.js";
+import { Color } from "../color.js";
+import { WEBGL } from "../graphics/webgl_constants.js";
+
+
+// wwtlib.ColorMapContainer
+//
+// This class is intended to be used to store colormaps. It does not handle any
+// interpolation and when using FindClosestColor it will simply check which
+// color is closest to the requested value. Therefore, continuous colormaps should
+// be created by providing a sufficient number of colors (ideally 256 or more).
+
+export function ColorMapContainer() {
+ this.colors = [];
+}
+
+ColorMapContainer.colorTextures = {};
+
+// Class method to create a new colormap from a list of [a, r, g, b] lists.
+ColorMapContainer.fromArgbList = function (color_list) {
+ var temp = new ColorMapContainer();
+ var $enum1 = ss.enumerate(color_list);
+ while ($enum1.moveNext()) {
+ var color = $enum1.current;
+ temp.colors.push(Color.fromArgb(color[0], color[1], color[2], color[3]));
+ }
+ return temp;
+};
+
+// Class method to create a new colormap from a list of strings.
+ColorMapContainer.fromStringList = function (color_list) {
+ var temp = new ColorMapContainer();
+ var $enum1 = ss.enumerate(color_list);
+ while ($enum1.moveNext()) {
+ var color = $enum1.current;
+ temp.colors.push(Color.load(color));
+ }
+ return temp;
+};
+
+// Names are chosen to match matplotlib (which explains why some are
+// less-than-ideal).
+ColorMapContainer.fromNamedColormap = function (name) {
+ if (name == null) {
+ return null;
+ }
+ switch (name.toLowerCase()) {
+ case 'viridis':
+ return ColorMapContainer.viridis;
+ case 'plasma':
+ return ColorMapContainer.plasma;
+ case 'inferno':
+ return ColorMapContainer.inferno;
+ case 'magma':
+ return ColorMapContainer.magma;
+ case 'cividis':
+ return ColorMapContainer.cividis;
+ case 'greys': // this is 0=>white, 1=>black
+ return ColorMapContainer.greys;
+ case 'gray': // this is 0=>black, 1=>white
+ return ColorMapContainer.gray;
+ case 'purples':
+ return ColorMapContainer.purples;
+ case 'blues':
+ return ColorMapContainer.blues;
+ case 'greens':
+ return ColorMapContainer.greens;
+ case 'oranges':
+ return ColorMapContainer.oranges;
+ case 'reds':
+ return ColorMapContainer.reds;
+ case 'rdylbu':
+ return ColorMapContainer.rdYlBu;
+ }
+ return null;
+};
+
+ColorMapContainer._getTextureFromName = function (gl, name) {
+ var texture = ColorMapContainer.colorTextures[name];
+ if (texture == null) {
+ var colorMapContainer = ColorMapContainer.fromNamedColormap(name);
+ if (colorMapContainer != null) {
+ texture = ColorMapContainer._initColorTexture(gl, colorMapContainer);
+ ColorMapContainer.colorTextures[name.toLowerCase()] = texture;
+ }
+ }
+ return texture;
+};
+
+ColorMapContainer.bindColorMapTexture = function (gl, colorMapName) {
+ var texture = ColorMapContainer._getTextureFromName(gl, colorMapName);
+ if (texture == null) {
+ texture = ColorMapContainer._getTextureFromName(gl, 'gray');
+ }
+ gl.activeTexture(WEBGL.TEXTURE1);
+ gl.bindTexture(WEBGL.TEXTURE_2D, texture);
+};
+
+ColorMapContainer._initColorTexture = function (gl, colorMapContainer) {
+ var colorTexture = gl.createTexture();
+ gl.activeTexture(WEBGL.TEXTURE1);
+ gl.bindTexture(WEBGL.TEXTURE_2D, colorTexture);
+ gl.texParameteri(WEBGL.TEXTURE_2D, WEBGL.TEXTURE_WRAP_S, WEBGL.CLAMP_TO_EDGE);
+ gl.texParameteri(WEBGL.TEXTURE_2D, WEBGL.TEXTURE_WRAP_T, WEBGL.CLAMP_TO_EDGE);
+ var colorBuffer = ColorMapContainer._extractColorArray(colorMapContainer.colors);
+ gl.texImage2D(WEBGL.TEXTURE_2D, 0, WEBGL.RGB8, colorBuffer.length / 3, 1, 0, WEBGL.RGB, WEBGL.UNSIGNED_BYTE, colorBuffer);
+ gl.texParameteri(WEBGL.TEXTURE_2D, WEBGL.TEXTURE_MIN_FILTER, WEBGL.NEAREST);
+ gl.texParameteri(WEBGL.TEXTURE_2D, WEBGL.TEXTURE_MAG_FILTER, WEBGL.NEAREST);
+ return colorTexture;
+};
+
+ColorMapContainer._extractColorArray = function (colors) {
+ var index = 0;
+ var colorBuffer = new Uint8Array(colors.length * 3);
+ var $enum1 = ss.enumerate(colors);
+ while ($enum1.moveNext()) {
+ var color = $enum1.current;
+ colorBuffer[index++] = color.r;
+ colorBuffer[index++] = color.g;
+ colorBuffer[index++] = color.b;
+ }
+ return colorBuffer;
+};
+
+var ColorMapContainer$ = {
+ // Given a floating-point value in the range 0 to 1, find the color that is
+ // the closest to it.
+ findClosestColor: function (value) {
+ var index;
+ if (value <= 0) {
+ return this.colors[0];
+ } else if (value >= 1) {
+ return this.colors[this.colors.length - 1];
+ } else {
+ index = ss.truncate((value * this.colors.length));
+ return this.colors[index];
+ }
+ }
+};
+
+registerType("ColorMapContainer", [ColorMapContainer, ColorMapContainer$, null]);
+
+// The colormaps below were produced using the following Python code:
+//
+// import numpy as np
+// from matplotlib import cm
+// from matplotlib.colors import to_hex
+// from textwrap import wrap, indent
+//
+// TEMPLATE = """
+// public static ColorMapContainer {name} = ColorMapContainer.FromStringList(new List(
+// {colors}
+// ));
+// """
+//
+// TEMPLATE_CASE = """
+// case "{name_lower}":
+// return {name};"""
+// COLORMAPS = ["viridis", "plasma", "inferno", "magma", "cividis",
+// "Greys", "gray", "Purples", "Blues", "Greens", "Oranges", "Reds", "RdYlBu"]
+//
+// named_code = ""
+// case_code = ""
+//
+// for name in COLORMAPS:
+// cmap = cm.get_cmap(name)
+// x = np.linspace(0.5 / 256, 255.5/256, 256)
+// colors = ", ".join(['"{0}"'.format(to_hex(c)) for c in cmap(x)])
+// pretty_name = name[0].upper() + name[1:]
+// named_code += TEMPLATE.format(name=pretty_name, colors=indent('\n'.join(wrap(colors, 90)), " " * 10))
+// case_code += TEMPLATE_CASE.format(name=pretty_name, name_lower=name.lower())
+//
+// named_code = indent(named_code, " " * 8)
+//
+// print(named_code)
+// print('-' * 72)
+// print(case_code)
+
+ColorMapContainer.viridis = ColorMapContainer.fromStringList([
+ '#440154', '#440256', '#450457', '#450559', '#46075a', '#46085c', '#460a5d', '#460b5e',
+ '#470d60', '#470e61', '#471063', '#471164', '#471365', '#481467', '#481668', '#481769',
+ '#48186a', '#481a6c', '#481b6d', '#481c6e', '#481d6f', '#481f70', '#482071', '#482173',
+ '#482374', '#482475', '#482576', '#482677', '#482878', '#482979', '#472a7a', '#472c7a',
+ '#472d7b', '#472e7c', '#472f7d', '#46307e', '#46327e', '#46337f', '#463480', '#453581',
+ '#453781', '#453882', '#443983', '#443a83', '#443b84', '#433d84', '#433e85', '#423f85',
+ '#424086', '#424186', '#414287', '#414487', '#404588', '#404688', '#3f4788', '#3f4889',
+ '#3e4989', '#3e4a89', '#3e4c8a', '#3d4d8a', '#3d4e8a', '#3c4f8a', '#3c508b', '#3b518b',
+ '#3b528b', '#3a538b', '#3a548c', '#39558c', '#39568c', '#38588c', '#38598c', '#375a8c',
+ '#375b8d', '#365c8d', '#365d8d', '#355e8d', '#355f8d', '#34608d', '#34618d', '#33628d',
+ '#33638d', '#32648e', '#32658e', '#31668e', '#31678e', '#31688e', '#30698e', '#306a8e',
+ '#2f6b8e', '#2f6c8e', '#2e6d8e', '#2e6e8e', '#2e6f8e', '#2d708e', '#2d718e', '#2c718e',
+ '#2c728e', '#2c738e', '#2b748e', '#2b758e', '#2a768e', '#2a778e', '#2a788e', '#29798e',
+ '#297a8e', '#297b8e', '#287c8e', '#287d8e', '#277e8e', '#277f8e', '#27808e', '#26818e',
+ '#26828e', '#26828e', '#25838e', '#25848e', '#25858e', '#24868e', '#24878e', '#23888e',
+ '#23898e', '#238a8d', '#228b8d', '#228c8d', '#228d8d', '#218e8d', '#218f8d', '#21908d',
+ '#21918c', '#20928c', '#20928c', '#20938c', '#1f948c', '#1f958b', '#1f968b', '#1f978b',
+ '#1f988b', '#1f998a', '#1f9a8a', '#1e9b8a', '#1e9c89', '#1e9d89', '#1f9e89', '#1f9f88',
+ '#1fa088', '#1fa188', '#1fa187', '#1fa287', '#20a386', '#20a486', '#21a585', '#21a685',
+ '#22a785', '#22a884', '#23a983', '#24aa83', '#25ab82', '#25ac82', '#26ad81', '#27ad81',
+ '#28ae80', '#29af7f', '#2ab07f', '#2cb17e', '#2db27d', '#2eb37c', '#2fb47c', '#31b57b',
+ '#32b67a', '#34b679', '#35b779', '#37b878', '#38b977', '#3aba76', '#3bbb75', '#3dbc74',
+ '#3fbc73', '#40bd72', '#42be71', '#44bf70', '#46c06f', '#48c16e', '#4ac16d', '#4cc26c',
+ '#4ec36b', '#50c46a', '#52c569', '#54c568', '#56c667', '#58c765', '#5ac864', '#5cc863',
+ '#5ec962', '#60ca60', '#63cb5f', '#65cb5e', '#67cc5c', '#69cd5b', '#6ccd5a', '#6ece58',
+ '#70cf57', '#73d056', '#75d054', '#77d153', '#7ad151', '#7cd250', '#7fd34e', '#81d34d',
+ '#84d44b', '#86d549', '#89d548', '#8bd646', '#8ed645', '#90d743', '#93d741', '#95d840',
+ '#98d83e', '#9bd93c', '#9dd93b', '#a0da39', '#a2da37', '#a5db36', '#a8db34', '#aadc32',
+ '#addc30', '#b0dd2f', '#b2dd2d', '#b5de2b', '#b8de29', '#bade28', '#bddf26', '#c0df25',
+ '#c2df23', '#c5e021', '#c8e020', '#cae11f', '#cde11d', '#d0e11c', '#d2e21b', '#d5e21a',
+ '#d8e219', '#dae319', '#dde318', '#dfe318', '#e2e418', '#e5e419', '#e7e419', '#eae51a',
+ '#ece51b', '#efe51c', '#f1e51d', '#f4e61e', '#f6e620', '#f8e621', '#fbe723', '#fde725'
+]);
+
+ColorMapContainer.plasma = ColorMapContainer.fromStringList([
+ '#0d0887', '#100788', '#130789', '#16078a', '#19068c', '#1b068d', '#1d068e', '#20068f',
+ '#220690', '#240691', '#260591', '#280592', '#2a0593', '#2c0594', '#2e0595', '#2f0596',
+ '#310597', '#330597', '#350498', '#370499', '#38049a', '#3a049a', '#3c049b', '#3e049c',
+ '#3f049c', '#41049d', '#43039e', '#44039e', '#46039f', '#48039f', '#4903a0', '#4b03a1',
+ '#4c02a1', '#4e02a2', '#5002a2', '#5102a3', '#5302a3', '#5502a4', '#5601a4', '#5801a4',
+ '#5901a5', '#5b01a5', '#5c01a6', '#5e01a6', '#6001a6', '#6100a7', '#6300a7', '#6400a7',
+ '#6600a7', '#6700a8', '#6900a8', '#6a00a8', '#6c00a8', '#6e00a8', '#6f00a8', '#7100a8',
+ '#7201a8', '#7401a8', '#7501a8', '#7701a8', '#7801a8', '#7a02a8', '#7b02a8', '#7d03a8',
+ '#7e03a8', '#8004a8', '#8104a7', '#8305a7', '#8405a7', '#8606a6', '#8707a6', '#8808a6',
+ '#8a09a5', '#8b0aa5', '#8d0ba5', '#8e0ca4', '#8f0da4', '#910ea3', '#920fa3', '#9410a2',
+ '#9511a1', '#9613a1', '#9814a0', '#99159f', '#9a169f', '#9c179e', '#9d189d', '#9e199d',
+ '#a01a9c', '#a11b9b', '#a21d9a', '#a31e9a', '#a51f99', '#a62098', '#a72197', '#a82296',
+ '#aa2395', '#ab2494', '#ac2694', '#ad2793', '#ae2892', '#b02991', '#b12a90', '#b22b8f',
+ '#b32c8e', '#b42e8d', '#b52f8c', '#b6308b', '#b7318a', '#b83289', '#ba3388', '#bb3488',
+ '#bc3587', '#bd3786', '#be3885', '#bf3984', '#c03a83', '#c13b82', '#c23c81', '#c33d80',
+ '#c43e7f', '#c5407e', '#c6417d', '#c7427c', '#c8437b', '#c9447a', '#ca457a', '#cb4679',
+ '#cc4778', '#cc4977', '#cd4a76', '#ce4b75', '#cf4c74', '#d04d73', '#d14e72', '#d24f71',
+ '#d35171', '#d45270', '#d5536f', '#d5546e', '#d6556d', '#d7566c', '#d8576b', '#d9586a',
+ '#da5a6a', '#da5b69', '#db5c68', '#dc5d67', '#dd5e66', '#de5f65', '#de6164', '#df6263',
+ '#e06363', '#e16462', '#e26561', '#e26660', '#e3685f', '#e4695e', '#e56a5d', '#e56b5d',
+ '#e66c5c', '#e76e5b', '#e76f5a', '#e87059', '#e97158', '#e97257', '#ea7457', '#eb7556',
+ '#eb7655', '#ec7754', '#ed7953', '#ed7a52', '#ee7b51', '#ef7c51', '#ef7e50', '#f07f4f',
+ '#f0804e', '#f1814d', '#f1834c', '#f2844b', '#f3854b', '#f3874a', '#f48849', '#f48948',
+ '#f58b47', '#f58c46', '#f68d45', '#f68f44', '#f79044', '#f79143', '#f79342', '#f89441',
+ '#f89540', '#f9973f', '#f9983e', '#f99a3e', '#fa9b3d', '#fa9c3c', '#fa9e3b', '#fb9f3a',
+ '#fba139', '#fba238', '#fca338', '#fca537', '#fca636', '#fca835', '#fca934', '#fdab33',
+ '#fdac33', '#fdae32', '#fdaf31', '#fdb130', '#fdb22f', '#fdb42f', '#fdb52e', '#feb72d',
+ '#feb82c', '#feba2c', '#febb2b', '#febd2a', '#febe2a', '#fec029', '#fdc229', '#fdc328',
+ '#fdc527', '#fdc627', '#fdc827', '#fdca26', '#fdcb26', '#fccd25', '#fcce25', '#fcd025',
+ '#fcd225', '#fbd324', '#fbd524', '#fbd724', '#fad824', '#fada24', '#f9dc24', '#f9dd25',
+ '#f8df25', '#f8e125', '#f7e225', '#f7e425', '#f6e626', '#f6e826', '#f5e926', '#f5eb27',
+ '#f4ed27', '#f3ee27', '#f3f027', '#f2f227', '#f1f426', '#f1f525', '#f0f724', '#f0f921'
+]);
+
+ColorMapContainer.inferno = ColorMapContainer.fromStringList([
+ '#000004', '#010005', '#010106', '#010108', '#02010a', '#02020c', '#02020e', '#030210',
+ '#040312', '#040314', '#050417', '#060419', '#07051b', '#08051d', '#09061f', '#0a0722',
+ '#0b0724', '#0c0826', '#0d0829', '#0e092b', '#10092d', '#110a30', '#120a32', '#140b34',
+ '#150b37', '#160b39', '#180c3c', '#190c3e', '#1b0c41', '#1c0c43', '#1e0c45', '#1f0c48',
+ '#210c4a', '#230c4c', '#240c4f', '#260c51', '#280b53', '#290b55', '#2b0b57', '#2d0b59',
+ '#2f0a5b', '#310a5c', '#320a5e', '#340a5f', '#360961', '#380962', '#390963', '#3b0964',
+ '#3d0965', '#3e0966', '#400a67', '#420a68', '#440a68', '#450a69', '#470b6a', '#490b6a',
+ '#4a0c6b', '#4c0c6b', '#4d0d6c', '#4f0d6c', '#510e6c', '#520e6d', '#540f6d', '#550f6d',
+ '#57106e', '#59106e', '#5a116e', '#5c126e', '#5d126e', '#5f136e', '#61136e', '#62146e',
+ '#64156e', '#65156e', '#67166e', '#69166e', '#6a176e', '#6c186e', '#6d186e', '#6f196e',
+ '#71196e', '#721a6e', '#741a6e', '#751b6e', '#771c6d', '#781c6d', '#7a1d6d', '#7c1d6d',
+ '#7d1e6d', '#7f1e6c', '#801f6c', '#82206c', '#84206b', '#85216b', '#87216b', '#88226a',
+ '#8a226a', '#8c2369', '#8d2369', '#8f2469', '#902568', '#922568', '#932667', '#952667',
+ '#972766', '#982766', '#9a2865', '#9b2964', '#9d2964', '#9f2a63', '#a02a63', '#a22b62',
+ '#a32c61', '#a52c60', '#a62d60', '#a82e5f', '#a92e5e', '#ab2f5e', '#ad305d', '#ae305c',
+ '#b0315b', '#b1325a', '#b3325a', '#b43359', '#b63458', '#b73557', '#b93556', '#ba3655',
+ '#bc3754', '#bd3853', '#bf3952', '#c03a51', '#c13a50', '#c33b4f', '#c43c4e', '#c63d4d',
+ '#c73e4c', '#c83f4b', '#ca404a', '#cb4149', '#cc4248', '#ce4347', '#cf4446', '#d04545',
+ '#d24644', '#d34743', '#d44842', '#d54a41', '#d74b3f', '#d84c3e', '#d94d3d', '#da4e3c',
+ '#db503b', '#dd513a', '#de5238', '#df5337', '#e05536', '#e15635', '#e25734', '#e35933',
+ '#e45a31', '#e55c30', '#e65d2f', '#e75e2e', '#e8602d', '#e9612b', '#ea632a', '#eb6429',
+ '#eb6628', '#ec6726', '#ed6925', '#ee6a24', '#ef6c23', '#ef6e21', '#f06f20', '#f1711f',
+ '#f1731d', '#f2741c', '#f3761b', '#f37819', '#f47918', '#f57b17', '#f57d15', '#f67e14',
+ '#f68013', '#f78212', '#f78410', '#f8850f', '#f8870e', '#f8890c', '#f98b0b', '#f98c0a',
+ '#f98e09', '#fa9008', '#fa9207', '#fa9407', '#fb9606', '#fb9706', '#fb9906', '#fb9b06',
+ '#fb9d07', '#fc9f07', '#fca108', '#fca309', '#fca50a', '#fca60c', '#fca80d', '#fcaa0f',
+ '#fcac11', '#fcae12', '#fcb014', '#fcb216', '#fcb418', '#fbb61a', '#fbb81d', '#fbba1f',
+ '#fbbc21', '#fbbe23', '#fac026', '#fac228', '#fac42a', '#fac62d', '#f9c72f', '#f9c932',
+ '#f9cb35', '#f8cd37', '#f8cf3a', '#f7d13d', '#f7d340', '#f6d543', '#f6d746', '#f5d949',
+ '#f5db4c', '#f4dd4f', '#f4df53', '#f4e156', '#f3e35a', '#f3e55d', '#f2e661', '#f2e865',
+ '#f2ea69', '#f1ec6d', '#f1ed71', '#f1ef75', '#f1f179', '#f2f27d', '#f2f482', '#f3f586',
+ '#f3f68a', '#f4f88e', '#f5f992', '#f6fa96', '#f8fb9a', '#f9fc9d', '#fafda1', '#fcffa4'
+]);
+
+ColorMapContainer.magma = ColorMapContainer.fromStringList([
+ '#000004', '#010005', '#010106', '#010108', '#020109', '#02020b', '#02020d', '#03030f',
+ '#030312', '#040414', '#050416', '#060518', '#06051a', '#07061c', '#08071e', '#090720',
+ '#0a0822', '#0b0924', '#0c0926', '#0d0a29', '#0e0b2b', '#100b2d', '#110c2f', '#120d31',
+ '#130d34', '#140e36', '#150e38', '#160f3b', '#180f3d', '#19103f', '#1a1042', '#1c1044',
+ '#1d1147', '#1e1149', '#20114b', '#21114e', '#221150', '#241253', '#251255', '#271258',
+ '#29115a', '#2a115c', '#2c115f', '#2d1161', '#2f1163', '#311165', '#331067', '#341069',
+ '#36106b', '#38106c', '#390f6e', '#3b0f70', '#3d0f71', '#3f0f72', '#400f74', '#420f75',
+ '#440f76', '#451077', '#471078', '#491078', '#4a1079', '#4c117a', '#4e117b', '#4f127b',
+ '#51127c', '#52137c', '#54137d', '#56147d', '#57157e', '#59157e', '#5a167e', '#5c167f',
+ '#5d177f', '#5f187f', '#601880', '#621980', '#641a80', '#651a80', '#671b80', '#681c81',
+ '#6a1c81', '#6b1d81', '#6d1d81', '#6e1e81', '#701f81', '#721f81', '#732081', '#752181',
+ '#762181', '#782281', '#792282', '#7b2382', '#7c2382', '#7e2482', '#802582', '#812581',
+ '#832681', '#842681', '#862781', '#882781', '#892881', '#8b2981', '#8c2981', '#8e2a81',
+ '#902a81', '#912b81', '#932b80', '#942c80', '#962c80', '#982d80', '#992d80', '#9b2e7f',
+ '#9c2e7f', '#9e2f7f', '#a02f7f', '#a1307e', '#a3307e', '#a5317e', '#a6317d', '#a8327d',
+ '#aa337d', '#ab337c', '#ad347c', '#ae347b', '#b0357b', '#b2357b', '#b3367a', '#b5367a',
+ '#b73779', '#b83779', '#ba3878', '#bc3978', '#bd3977', '#bf3a77', '#c03a76', '#c23b75',
+ '#c43c75', '#c53c74', '#c73d73', '#c83e73', '#ca3e72', '#cc3f71', '#cd4071', '#cf4070',
+ '#d0416f', '#d2426f', '#d3436e', '#d5446d', '#d6456c', '#d8456c', '#d9466b', '#db476a',
+ '#dc4869', '#de4968', '#df4a68', '#e04c67', '#e24d66', '#e34e65', '#e44f64', '#e55064',
+ '#e75263', '#e85362', '#e95462', '#ea5661', '#eb5760', '#ec5860', '#ed5a5f', '#ee5b5e',
+ '#ef5d5e', '#f05f5e', '#f1605d', '#f2625d', '#f2645c', '#f3655c', '#f4675c', '#f4695c',
+ '#f56b5c', '#f66c5c', '#f66e5c', '#f7705c', '#f7725c', '#f8745c', '#f8765c', '#f9785d',
+ '#f9795d', '#f97b5d', '#fa7d5e', '#fa7f5e', '#fa815f', '#fb835f', '#fb8560', '#fb8761',
+ '#fc8961', '#fc8a62', '#fc8c63', '#fc8e64', '#fc9065', '#fd9266', '#fd9467', '#fd9668',
+ '#fd9869', '#fd9a6a', '#fd9b6b', '#fe9d6c', '#fe9f6d', '#fea16e', '#fea36f', '#fea571',
+ '#fea772', '#fea973', '#feaa74', '#feac76', '#feae77', '#feb078', '#feb27a', '#feb47b',
+ '#feb67c', '#feb77e', '#feb97f', '#febb81', '#febd82', '#febf84', '#fec185', '#fec287',
+ '#fec488', '#fec68a', '#fec88c', '#feca8d', '#fecc8f', '#fecd90', '#fecf92', '#fed194',
+ '#fed395', '#fed597', '#fed799', '#fed89a', '#fdda9c', '#fddc9e', '#fddea0', '#fde0a1',
+ '#fde2a3', '#fde3a5', '#fde5a7', '#fde7a9', '#fde9aa', '#fdebac', '#fcecae', '#fceeb0',
+ '#fcf0b2', '#fcf2b4', '#fcf4b6', '#fcf6b8', '#fcf7b9', '#fcf9bb', '#fcfbbd', '#fcfdbf'
+]);
+
+ColorMapContainer.cividis = ColorMapContainer.fromStringList([
+ '#00224e', '#00234f', '#002451', '#002553', '#002554', '#002656', '#002758', '#002859',
+ '#00285b', '#00295d', '#002a5f', '#002a61', '#002b62', '#002c64', '#002c66', '#002d68',
+ '#002e6a', '#002e6c', '#002f6d', '#00306f', '#003070', '#003170', '#003171', '#013271',
+ '#053371', '#083370', '#0c3470', '#0f3570', '#123570', '#143670', '#163770', '#18376f',
+ '#1a386f', '#1c396f', '#1e3a6f', '#203a6f', '#213b6e', '#233c6e', '#243c6e', '#263d6e',
+ '#273e6e', '#293f6e', '#2a3f6d', '#2b406d', '#2d416d', '#2e416d', '#2f426d', '#31436d',
+ '#32436d', '#33446d', '#34456c', '#35456c', '#36466c', '#38476c', '#39486c', '#3a486c',
+ '#3b496c', '#3c4a6c', '#3d4a6c', '#3e4b6c', '#3f4c6c', '#404c6c', '#414d6c', '#424e6c',
+ '#434e6c', '#444f6c', '#45506c', '#46516c', '#47516c', '#48526c', '#49536c', '#4a536c',
+ '#4b546c', '#4c556c', '#4d556c', '#4e566c', '#4f576c', '#50576c', '#51586d', '#52596d',
+ '#535a6d', '#545a6d', '#555b6d', '#555c6d', '#565c6d', '#575d6d', '#585e6d', '#595e6e',
+ '#5a5f6e', '#5b606e', '#5c616e', '#5d616e', '#5e626e', '#5e636f', '#5f636f', '#60646f',
+ '#61656f', '#62656f', '#636670', '#646770', '#656870', '#656870', '#666970', '#676a71',
+ '#686a71', '#696b71', '#6a6c71', '#6b6d72', '#6c6d72', '#6c6e72', '#6d6f72', '#6e6f73',
+ '#6f7073', '#707173', '#717274', '#727274', '#727374', '#737475', '#747475', '#757575',
+ '#767676', '#777776', '#777777', '#787877', '#797977', '#7a7a78', '#7b7a78', '#7c7b78',
+ '#7d7c78', '#7e7c78', '#7e7d78', '#7f7e78', '#807f78', '#817f78', '#828079', '#838179',
+ '#848279', '#858279', '#868379', '#878478', '#888578', '#898578', '#8a8678', '#8b8778',
+ '#8c8878', '#8d8878', '#8e8978', '#8f8a78', '#908b78', '#918b78', '#928c78', '#928d78',
+ '#938e78', '#948e77', '#958f77', '#969077', '#979177', '#989277', '#999277', '#9a9376',
+ '#9b9476', '#9c9576', '#9d9576', '#9e9676', '#9f9775', '#a09875', '#a19975', '#a29975',
+ '#a39a74', '#a49b74', '#a59c74', '#a69c74', '#a79d73', '#a89e73', '#a99f73', '#aaa073',
+ '#aba072', '#aca172', '#ada272', '#aea371', '#afa471', '#b0a571', '#b1a570', '#b3a670',
+ '#b4a76f', '#b5a86f', '#b6a96f', '#b7a96e', '#b8aa6e', '#b9ab6d', '#baac6d', '#bbad6d',
+ '#bcae6c', '#bdae6c', '#beaf6b', '#bfb06b', '#c0b16a', '#c1b26a', '#c2b369', '#c3b369',
+ '#c4b468', '#c5b568', '#c6b667', '#c7b767', '#c8b866', '#c9b965', '#cbb965', '#ccba64',
+ '#cdbb63', '#cebc63', '#cfbd62', '#d0be62', '#d1bf61', '#d2c060', '#d3c05f', '#d4c15f',
+ '#d5c25e', '#d6c35d', '#d7c45c', '#d9c55c', '#dac65b', '#dbc75a', '#dcc859', '#ddc858',
+ '#dec958', '#dfca57', '#e0cb56', '#e1cc55', '#e2cd54', '#e4ce53', '#e5cf52', '#e6d051',
+ '#e7d150', '#e8d24f', '#e9d34e', '#ead34c', '#ebd44b', '#edd54a', '#eed649', '#efd748',
+ '#f0d846', '#f1d945', '#f2da44', '#f3db42', '#f5dc41', '#f6dd3f', '#f7de3e', '#f8df3c',
+ '#f9e03a', '#fbe138', '#fce236', '#fde334', '#fee434', '#fee535', '#fee636', '#fee838'
+]);
+
+ColorMapContainer.greys = ColorMapContainer.fromStringList([
+ '#ffffff', '#ffffff', '#fefefe', '#fefefe', '#fdfdfd', '#fdfdfd', '#fcfcfc', '#fcfcfc',
+ '#fbfbfb', '#fbfbfb', '#fafafa', '#fafafa', '#f9f9f9', '#f9f9f9', '#f8f8f8', '#f8f8f8',
+ '#f7f7f7', '#f7f7f7', '#f7f7f7', '#f6f6f6', '#f6f6f6', '#f5f5f5', '#f5f5f5', '#f4f4f4',
+ '#f4f4f4', '#f3f3f3', '#f3f3f3', '#f2f2f2', '#f2f2f2', '#f1f1f1', '#f1f1f1', '#f0f0f0',
+ '#f0f0f0', '#efefef', '#eeeeee', '#eeeeee', '#ededed', '#ececec', '#ececec', '#ebebeb',
+ '#eaeaea', '#e9e9e9', '#e9e9e9', '#e8e8e8', '#e7e7e7', '#e7e7e7', '#e6e6e6', '#e5e5e5',
+ '#e4e4e4', '#e4e4e4', '#e3e3e3', '#e2e2e2', '#e1e1e1', '#e1e1e1', '#e0e0e0', '#dfdfdf',
+ '#dfdfdf', '#dedede', '#dddddd', '#dcdcdc', '#dcdcdc', '#dbdbdb', '#dadada', '#dadada',
+ '#d9d9d9', '#d8d8d8', '#d7d7d7', '#d6d6d6', '#d5d5d5', '#d4d4d4', '#d4d4d4', '#d3d3d3',
+ '#d2d2d2', '#d1d1d1', '#d0d0d0', '#cfcfcf', '#cecece', '#cdcdcd', '#cccccc', '#cccccc',
+ '#cbcbcb', '#cacaca', '#c9c9c9', '#c8c8c8', '#c7c7c7', '#c6c6c6', '#c5c5c5', '#c5c5c5',
+ '#c4c4c4', '#c3c3c3', '#c2c2c2', '#c1c1c1', '#c0c0c0', '#bfbfbf', '#bebebe', '#bebebe',
+ '#bdbdbd', '#bbbbbb', '#bababa', '#b9b9b9', '#b8b8b8', '#b6b6b6', '#b5b5b5', '#b4b4b4',
+ '#b3b3b3', '#b2b2b2', '#b0b0b0', '#afafaf', '#aeaeae', '#adadad', '#ababab', '#aaaaaa',
+ '#a9a9a9', '#a8a8a8', '#a7a7a7', '#a5a5a5', '#a4a4a4', '#a3a3a3', '#a2a2a2', '#a0a0a0',
+ '#9f9f9f', '#9e9e9e', '#9d9d9d', '#9c9c9c', '#9a9a9a', '#999999', '#989898', '#979797',
+ '#959595', '#949494', '#939393', '#929292', '#919191', '#909090', '#8f8f8f', '#8e8e8e',
+ '#8d8d8d', '#8c8c8c', '#8a8a8a', '#898989', '#888888', '#878787', '#868686', '#858585',
+ '#848484', '#838383', '#828282', '#818181', '#7f7f7f', '#7e7e7e', '#7d7d7d', '#7c7c7c',
+ '#7b7b7b', '#7a7a7a', '#797979', '#787878', '#777777', '#767676', '#757575', '#737373',
+ '#727272', '#717171', '#707070', '#6f6f6f', '#6e6e6e', '#6d6d6d', '#6c6c6c', '#6b6b6b',
+ '#6a6a6a', '#696969', '#686868', '#676767', '#666666', '#656565', '#646464', '#636363',
+ '#626262', '#616161', '#606060', '#5f5f5f', '#5e5e5e', '#5d5d5d', '#5c5c5c', '#5b5b5b',
+ '#5a5a5a', '#585858', '#575757', '#565656', '#555555', '#545454', '#535353', '#525252',
+ '#515151', '#505050', '#4e4e4e', '#4d4d4d', '#4b4b4b', '#4a4a4a', '#484848', '#474747',
+ '#464646', '#444444', '#434343', '#414141', '#404040', '#3f3f3f', '#3d3d3d', '#3c3c3c',
+ '#3a3a3a', '#393939', '#383838', '#363636', '#353535', '#333333', '#323232', '#303030',
+ '#2f2f2f', '#2e2e2e', '#2c2c2c', '#2b2b2b', '#292929', '#282828', '#272727', '#252525',
+ '#242424', '#232323', '#222222', '#212121', '#1f1f1f', '#1e1e1e', '#1d1d1d', '#1c1c1c',
+ '#1b1b1b', '#1a1a1a', '#181818', '#171717', '#161616', '#151515', '#141414', '#131313',
+ '#111111', '#101010', '#0f0f0f', '#0e0e0e', '#0d0d0d', '#0c0c0c', '#0a0a0a', '#090909',
+ '#080808', '#070707', '#060606', '#050505', '#030303', '#020202', '#010101', '#000000'
+]);
+
+ColorMapContainer.gray = ColorMapContainer.fromStringList([
+ '#000000', '#010101', '#020202', '#030303', '#040404', '#050505', '#060606', '#070707',
+ '#080808', '#090909', '#0a0a0a', '#0b0b0b', '#0c0c0c', '#0d0d0d', '#0e0e0e', '#0f0f0f',
+ '#101010', '#111111', '#121212', '#131313', '#141414', '#151515', '#161616', '#171717',
+ '#181818', '#191919', '#1a1a1a', '#1b1b1b', '#1c1c1c', '#1d1d1d', '#1e1e1e', '#1f1f1f',
+ '#202020', '#212121', '#222222', '#232323', '#242424', '#252525', '#262626', '#272727',
+ '#282828', '#292929', '#2a2a2a', '#2b2b2b', '#2c2c2c', '#2d2d2d', '#2e2e2e', '#2f2f2f',
+ '#303030', '#313131', '#323232', '#333333', '#343434', '#353535', '#363636', '#373737',
+ '#383838', '#393939', '#3a3a3a', '#3b3b3b', '#3c3c3c', '#3d3d3d', '#3e3e3e', '#3f3f3f',
+ '#404040', '#414141', '#424242', '#434343', '#444444', '#454545', '#464646', '#474747',
+ '#484848', '#494949', '#4a4a4a', '#4b4b4b', '#4c4c4c', '#4d4d4d', '#4e4e4e', '#4f4f4f',
+ '#505050', '#515151', '#525252', '#535353', '#545454', '#555555', '#565656', '#575757',
+ '#585858', '#595959', '#5a5a5a', '#5b5b5b', '#5c5c5c', '#5d5d5d', '#5e5e5e', '#5f5f5f',
+ '#606060', '#616161', '#626262', '#636363', '#646464', '#656565', '#666666', '#676767',
+ '#686868', '#696969', '#6a6a6a', '#6b6b6b', '#6c6c6c', '#6d6d6d', '#6e6e6e', '#6f6f6f',
+ '#707070', '#717171', '#727272', '#737373', '#747474', '#757575', '#767676', '#777777',
+ '#787878', '#797979', '#7a7a7a', '#7b7b7b', '#7c7c7c', '#7d7d7d', '#7e7e7e', '#7f7f7f',
+ '#808080', '#818181', '#828282', '#838383', '#848484', '#858585', '#868686', '#878787',
+ '#888888', '#898989', '#8a8a8a', '#8b8b8b', '#8c8c8c', '#8d8d8d', '#8e8e8e', '#8f8f8f',
+ '#909090', '#919191', '#929292', '#939393', '#949494', '#959595', '#969696', '#979797',
+ '#989898', '#999999', '#9a9a9a', '#9b9b9b', '#9c9c9c', '#9d9d9d', '#9e9e9e', '#9f9f9f',
+ '#a0a0a0', '#a1a1a1', '#a2a2a2', '#a3a3a3', '#a4a4a4', '#a5a5a5', '#a6a6a6', '#a7a7a7',
+ '#a8a8a8', '#a9a9a9', '#aaaaaa', '#ababab', '#acacac', '#adadad', '#aeaeae', '#afafaf',
+ '#b0b0b0', '#b1b1b1', '#b2b2b2', '#b3b3b3', '#b4b4b4', '#b5b5b5', '#b6b6b6', '#b7b7b7',
+ '#b8b8b8', '#b9b9b9', '#bababa', '#bbbbbb', '#bcbcbc', '#bdbdbd', '#bebebe', '#bfbfbf',
+ '#c0c0c0', '#c1c1c1', '#c2c2c2', '#c3c3c3', '#c4c4c4', '#c5c5c5', '#c6c6c6', '#c7c7c7',
+ '#c8c8c8', '#c9c9c9', '#cacaca', '#cbcbcb', '#cccccc', '#cdcdcd', '#cecece', '#cfcfcf',
+ '#d0d0d0', '#d1d1d1', '#d2d2d2', '#d3d3d3', '#d4d4d4', '#d5d5d5', '#d6d6d6', '#d7d7d7',
+ '#d8d8d8', '#d9d9d9', '#dadada', '#dbdbdb', '#dcdcdc', '#dddddd', '#dedede', '#dfdfdf',
+ '#e0e0e0', '#e1e1e1', '#e2e2e2', '#e3e3e3', '#e4e4e4', '#e5e5e5', '#e6e6e6', '#e7e7e7',
+ '#e8e8e8', '#e9e9e9', '#eaeaea', '#ebebeb', '#ececec', '#ededed', '#eeeeee', '#efefef',
+ '#f0f0f0', '#f1f1f1', '#f2f2f2', '#f3f3f3', '#f4f4f4', '#f5f5f5', '#f6f6f6', '#f7f7f7',
+ '#f8f8f8', '#f9f9f9', '#fafafa', '#fbfbfb', '#fcfcfc', '#fdfdfd', '#fefefe', '#ffffff'
+]);
+
+ColorMapContainer.purples = ColorMapContainer.fromStringList([
+ '#fcfbfd', '#fcfbfd', '#fbfafc', '#fbfafc', '#faf9fc', '#faf9fc', '#faf8fb', '#f9f8fb',
+ '#f9f7fb', '#f8f7fb', '#f8f7fa', '#f8f6fa', '#f7f6fa', '#f7f5fa', '#f6f5f9', '#f6f4f9',
+ '#f5f4f9', '#f5f4f9', '#f5f3f8', '#f4f3f8', '#f4f2f8', '#f3f2f8', '#f3f1f7', '#f3f1f7',
+ '#f2f0f7', '#f2f0f7', '#f1f0f6', '#f1eff6', '#f1eff6', '#f0eef6', '#f0eef5', '#efedf5',
+ '#efedf5', '#eeecf5', '#eeecf4', '#edebf4', '#ecebf4', '#eceaf3', '#ebe9f3', '#eae9f3',
+ '#eae8f2', '#e9e8f2', '#e8e7f2', '#e8e6f2', '#e7e6f1', '#e6e5f1', '#e6e5f1', '#e5e4f0',
+ '#e4e3f0', '#e4e3f0', '#e3e2ef', '#e2e2ef', '#e2e1ef', '#e1e0ee', '#e0e0ee', '#e0dfee',
+ '#dfdfed', '#dedeed', '#dedded', '#ddddec', '#dcdcec', '#dcdcec', '#dbdbec', '#dadaeb',
+ '#dadaeb', '#d9d9ea', '#d8d8ea', '#d7d7e9', '#d6d6e9', '#d5d5e9', '#d4d4e8', '#d3d3e8',
+ '#d2d2e7', '#d1d2e7', '#d0d1e6', '#cfd0e6', '#cecfe5', '#cecee5', '#cdcde4', '#cccce4',
+ '#cbcbe3', '#cacae3', '#c9c9e2', '#c8c8e2', '#c7c8e1', '#c6c7e1', '#c5c6e1', '#c4c5e0',
+ '#c3c4e0', '#c2c3df', '#c1c2df', '#c0c1de', '#bfc0de', '#bebfdd', '#bebedd', '#bdbedc',
+ '#bcbddc', '#bbbbdb', '#babadb', '#b9b9da', '#b8b8d9', '#b7b7d9', '#b6b6d8', '#b5b5d7',
+ '#b4b4d7', '#b3b3d6', '#b2b2d5', '#b1b1d5', '#b0afd4', '#afaed4', '#aeadd3', '#aeacd2',
+ '#adabd2', '#acaad1', '#aba9d0', '#aaa8d0', '#a9a7cf', '#a8a6cf', '#a7a4ce', '#a6a3cd',
+ '#a5a2cd', '#a4a1cc', '#a3a0cb', '#a29fcb', '#a19eca', '#a09dca', '#9f9cc9', '#9e9bc8',
+ '#9e9ac8', '#9d99c7', '#9c98c7', '#9b97c6', '#9a96c6', '#9995c6', '#9894c5', '#9793c5',
+ '#9692c4', '#9591c4', '#9490c3', '#9390c3', '#928fc3', '#918ec2', '#908dc2', '#8f8cc1',
+ '#8e8bc1', '#8e8ac0', '#8d89c0', '#8c88bf', '#8b87bf', '#8a86bf', '#8986be', '#8885be',
+ '#8784bd', '#8683bd', '#8582bc', '#8481bc', '#8380bb', '#827fbb', '#817ebb', '#807dba',
+ '#807cba', '#7f7bb9', '#7e79b8', '#7d78b7', '#7d77b7', '#7c75b6', '#7b74b5', '#7b72b4',
+ '#7a71b4', '#7970b3', '#796eb2', '#786db2', '#776cb1', '#776ab0', '#7669af', '#7567af',
+ '#7566ae', '#7465ad', '#7363ad', '#7262ac', '#7261ab', '#715faa', '#705eaa', '#705ca9',
+ '#6f5ba8', '#6e5aa8', '#6e58a7', '#6d57a6', '#6c55a5', '#6c54a5', '#6b53a4', '#6a51a3',
+ '#6950a3', '#694fa2', '#684da1', '#674ca1', '#674ba0', '#66499f', '#65489f', '#65479e',
+ '#64459e', '#63449d', '#63439c', '#62429c', '#61409b', '#613f9a', '#603e9a', '#5f3c99',
+ '#5e3b98', '#5e3a98', '#5d3897', '#5c3797', '#5c3696', '#5b3495', '#5a3395', '#5a3294',
+ '#593093', '#582f93', '#582e92', '#572c92', '#562b91', '#552a90', '#552890', '#54278f',
+ '#53268f', '#53258e', '#52238d', '#51228d', '#51218c', '#50208c', '#4f1f8b', '#4f1d8b',
+ '#4e1c8a', '#4d1b89', '#4d1a89', '#4c1888', '#4c1788', '#4b1687', '#4a1587', '#4a1486',
+ '#491285', '#481185', '#481084', '#470f84', '#460d83', '#460c83', '#450b82', '#440a82',
+ '#440981', '#430780', '#420680', '#42057f', '#41047f', '#40027e', '#40017e', '#3f007d'
+]);
+
+ColorMapContainer.blues = ColorMapContainer.fromStringList([
+ '#f7fbff', '#f6faff', '#f5fafe', '#f5f9fe', '#f4f9fe', '#f3f8fe', '#f2f8fd', '#f2f7fd',
+ '#f1f7fd', '#f0f6fd', '#eff6fc', '#eef5fc', '#eef5fc', '#edf4fc', '#ecf4fb', '#ebf3fb',
+ '#eaf3fb', '#eaf2fb', '#e9f2fa', '#e8f1fa', '#e7f1fa', '#e7f0fa', '#e6f0f9', '#e5eff9',
+ '#e4eff9', '#e3eef9', '#e3eef8', '#e2edf8', '#e1edf8', '#e0ecf8', '#dfecf7', '#dfebf7',
+ '#deebf7', '#ddeaf7', '#dceaf6', '#dce9f6', '#dbe9f6', '#dae8f6', '#d9e8f5', '#d9e7f5',
+ '#d8e7f5', '#d7e6f5', '#d6e6f4', '#d6e5f4', '#d5e5f4', '#d4e4f4', '#d3e4f3', '#d3e3f3',
+ '#d2e3f3', '#d1e2f3', '#d0e2f2', '#d0e1f2', '#cfe1f2', '#cee0f2', '#cde0f1', '#cddff1',
+ '#ccdff1', '#cbdef1', '#cadef0', '#caddf0', '#c9ddf0', '#c8dcf0', '#c7dcef', '#c7dbef',
+ '#c6dbef', '#c4daee', '#c3daee', '#c2d9ee', '#c1d9ed', '#bfd8ed', '#bed8ec', '#bdd7ec',
+ '#bcd7eb', '#bad6eb', '#b9d6ea', '#b8d5ea', '#b7d4ea', '#b5d4e9', '#b4d3e9', '#b3d3e8',
+ '#b2d2e8', '#b0d2e7', '#afd1e7', '#aed1e7', '#add0e6', '#abd0e6', '#aacfe5', '#a9cfe5',
+ '#a8cee4', '#a6cee4', '#a5cde3', '#a4cce3', '#a3cce3', '#a1cbe2', '#a0cbe2', '#9fcae1',
+ '#9dcae1', '#9cc9e1', '#9ac8e0', '#99c7e0', '#97c6df', '#95c5df', '#94c4df', '#92c4de',
+ '#91c3de', '#8fc2de', '#8dc1dd', '#8cc0dd', '#8abfdd', '#89bedc', '#87bddc', '#85bcdc',
+ '#84bcdb', '#82bbdb', '#81badb', '#7fb9da', '#7db8da', '#7cb7da', '#7ab6d9', '#79b5d9',
+ '#77b5d9', '#75b4d8', '#74b3d8', '#72b2d8', '#71b1d7', '#6fb0d7', '#6dafd7', '#6caed6',
+ '#6aaed6', '#69add5', '#68acd5', '#66abd4', '#65aad4', '#64a9d3', '#63a8d3', '#61a7d2',
+ '#60a7d2', '#5fa6d1', '#5da5d1', '#5ca4d0', '#5ba3d0', '#5aa2cf', '#58a1cf', '#57a0ce',
+ '#56a0ce', '#549fcd', '#539ecd', '#529dcc', '#519ccc', '#4f9bcb', '#4e9acb', '#4d99ca',
+ '#4b98ca', '#4a98c9', '#4997c9', '#4896c8', '#4695c8', '#4594c7', '#4493c7', '#4292c6',
+ '#4191c6', '#4090c5', '#3f8fc5', '#3e8ec4', '#3d8dc4', '#3c8cc3', '#3b8bc2', '#3a8ac2',
+ '#3989c1', '#3888c1', '#3787c0', '#3686c0', '#3585bf', '#3484bf', '#3383be', '#3282be',
+ '#3181bd', '#3080bd', '#2f7fbc', '#2e7ebc', '#2d7dbb', '#2c7cba', '#2b7bba', '#2a7ab9',
+ '#2979b9', '#2777b8', '#2676b8', '#2575b7', '#2474b7', '#2373b6', '#2272b6', '#2171b5',
+ '#2070b4', '#206fb4', '#1f6eb3', '#1e6db2', '#1d6cb1', '#1c6bb0', '#1c6ab0', '#1b69af',
+ '#1a68ae', '#1967ad', '#1966ad', '#1865ac', '#1764ab', '#1663aa', '#1562a9', '#1561a9',
+ '#1460a8', '#135fa7', '#125ea6', '#125da6', '#115ca5', '#105ba4', '#0f5aa3', '#0e59a2',
+ '#0e58a2', '#0d57a1', '#0c56a0', '#0b559f', '#0a549e', '#0a539e', '#09529d', '#08519c',
+ '#08509b', '#084f99', '#084e98', '#084d96', '#084c95', '#084b93', '#084a91', '#084990',
+ '#08488e', '#08478d', '#08468b', '#08458a', '#084488', '#084387', '#084285', '#084184',
+ '#084082', '#083e81', '#083d7f', '#083c7d', '#083b7c', '#083a7a', '#083979', '#083877',
+ '#083776', '#083674', '#083573', '#083471', '#083370', '#08326e', '#08316d', '#08306b'
+]);
+
+ColorMapContainer.greens = ColorMapContainer.fromStringList([
+ '#f7fcf5', '#f6fcf4', '#f6fcf4', '#f5fbf3', '#f5fbf2', '#f4fbf2', '#f4fbf1', '#f3faf0',
+ '#f2faf0', '#f2faef', '#f1faee', '#f1faee', '#f0f9ed', '#f0f9ec', '#eff9ec', '#eff9eb',
+ '#eef8ea', '#edf8ea', '#edf8e9', '#ecf8e8', '#ecf8e8', '#ebf7e7', '#ebf7e7', '#eaf7e6',
+ '#e9f7e5', '#e9f7e5', '#e8f6e4', '#e8f6e3', '#e7f6e3', '#e7f6e2', '#e6f5e1', '#e5f5e1',
+ '#e5f5e0', '#e4f5df', '#e3f4de', '#e2f4dd', '#e1f3dc', '#e0f3db', '#dff3da', '#def2d9',
+ '#ddf2d8', '#dcf2d7', '#dbf1d6', '#dbf1d5', '#daf0d4', '#d9f0d3', '#d8f0d2', '#d7efd1',
+ '#d6efd0', '#d5efcf', '#d4eece', '#d3eecd', '#d2edcc', '#d1edcb', '#d0edca', '#cfecc9',
+ '#ceecc8', '#cdecc7', '#ccebc6', '#cbebc5', '#cbeac4', '#caeac3', '#c9eac2', '#c8e9c1',
+ '#c7e9c0', '#c6e8bf', '#c4e8bd', '#c3e7bc', '#c2e7bb', '#c1e6ba', '#c0e6b9', '#bee5b8',
+ '#bde5b6', '#bce4b5', '#bbe4b4', '#bae3b3', '#b8e3b2', '#b7e2b1', '#b6e2af', '#b5e1ae',
+ '#b4e1ad', '#b2e0ac', '#b1e0ab', '#b0dfaa', '#afdfa8', '#aedea7', '#acdea6', '#abdda5',
+ '#aadda4', '#a9dca3', '#a8dca2', '#a7dba0', '#a5db9f', '#a4da9e', '#a3da9d', '#a2d99c',
+ '#a0d99b', '#9fd899', '#9ed798', '#9cd797', '#9bd696', '#99d595', '#98d594', '#97d492',
+ '#95d391', '#94d390', '#92d28f', '#91d28e', '#90d18d', '#8ed08b', '#8dd08a', '#8bcf89',
+ '#8ace88', '#88ce87', '#87cd86', '#86cc85', '#84cc83', '#83cb82', '#81ca81', '#80ca80',
+ '#7fc97f', '#7dc87e', '#7cc87c', '#7ac77b', '#79c67a', '#78c679', '#76c578', '#75c477',
+ '#73c476', '#72c375', '#70c274', '#6ec173', '#6dc072', '#6bc072', '#6abf71', '#68be70',
+ '#66bd6f', '#65bd6f', '#63bc6e', '#62bb6d', '#60ba6c', '#5eb96b', '#5db96b', '#5bb86a',
+ '#5ab769', '#58b668', '#56b567', '#55b567', '#53b466', '#52b365', '#50b264', '#4eb264',
+ '#4db163', '#4bb062', '#4aaf61', '#48ae60', '#46ae60', '#45ad5f', '#43ac5e', '#42ab5d',
+ '#40aa5d', '#3fa95c', '#3fa85b', '#3ea75a', '#3da65a', '#3ca559', '#3ba458', '#3aa357',
+ '#39a257', '#38a156', '#37a055', '#369f54', '#359e53', '#349d53', '#339c52', '#329b51',
+ '#319a50', '#309950', '#2f984f', '#2f974e', '#2e964d', '#2d954d', '#2c944c', '#2b934b',
+ '#2a924a', '#29914a', '#289049', '#278f48', '#268e47', '#258d47', '#248c46', '#238b45',
+ '#228a44', '#218944', '#208843', '#1f8742', '#1e8741', '#1d8640', '#1c8540', '#1a843f',
+ '#19833e', '#18823d', '#17813d', '#16803c', '#157f3b', '#147e3a', '#137d39', '#127c39',
+ '#117b38', '#107a37', '#0e7936', '#0d7836', '#0c7735', '#0b7734', '#0a7633', '#097532',
+ '#087432', '#077331', '#067230', '#05712f', '#03702e', '#026f2e', '#016e2d', '#006d2c',
+ '#006c2c', '#006b2b', '#00692a', '#00682a', '#006729', '#006529', '#006428', '#006328',
+ '#006227', '#006027', '#005f26', '#005e26', '#005c25', '#005b25', '#005a24', '#005924',
+ '#005723', '#005622', '#005522', '#005321', '#005221', '#005120', '#005020', '#004e1f',
+ '#004d1f', '#004c1e', '#004a1e', '#00491d', '#00481d', '#00471c', '#00451c', '#00441b'
+]);
+
+ColorMapContainer.oranges = ColorMapContainer.fromStringList([
+ '#fff5eb', '#fff5ea', '#fff4e9', '#fff4e8', '#fff3e7', '#fff3e6', '#fff2e6', '#fff2e5',
+ '#fff1e4', '#fff1e3', '#fff0e2', '#fff0e1', '#ffefe0', '#ffefdf', '#ffeede', '#ffeedd',
+ '#feeddc', '#feeddc', '#feeddb', '#feecda', '#feecd9', '#feebd8', '#feebd7', '#feead6',
+ '#feead5', '#fee9d4', '#fee9d3', '#fee8d2', '#fee8d2', '#fee7d1', '#fee7d0', '#fee6cf',
+ '#fee6ce', '#fee5cc', '#fee5cb', '#fee4ca', '#fee3c8', '#fee2c7', '#fee2c6', '#fee1c4',
+ '#fee0c3', '#fee0c1', '#fedfc0', '#fedebf', '#fedebd', '#feddbc', '#fedcbb', '#fedcb9',
+ '#fddbb8', '#fddab6', '#fdd9b5', '#fdd9b4', '#fdd8b2', '#fdd7b1', '#fdd7af', '#fdd6ae',
+ '#fdd5ad', '#fdd5ab', '#fdd4aa', '#fdd3a9', '#fdd3a7', '#fdd2a6', '#fdd1a4', '#fdd1a3',
+ '#fdd0a2', '#fdcfa0', '#fdce9e', '#fdcd9c', '#fdcb9b', '#fdca99', '#fdc997', '#fdc895',
+ '#fdc794', '#fdc692', '#fdc590', '#fdc48f', '#fdc38d', '#fdc28b', '#fdc189', '#fdc088',
+ '#fdbf86', '#fdbe84', '#fdbd83', '#fdbb81', '#fdba7f', '#fdb97d', '#fdb87c', '#fdb77a',
+ '#fdb678', '#fdb576', '#fdb475', '#fdb373', '#fdb271', '#fdb170', '#fdb06e', '#fdaf6c',
+ '#fdae6a', '#fdad69', '#fdac67', '#fdab66', '#fda965', '#fda863', '#fda762', '#fda660',
+ '#fda55f', '#fda45d', '#fda35c', '#fda25a', '#fda159', '#fda057', '#fd9f56', '#fd9e54',
+ '#fd9d53', '#fd9c51', '#fd9b50', '#fd9a4e', '#fd994d', '#fd984b', '#fd974a', '#fd9649',
+ '#fd9547', '#fd9446', '#fd9344', '#fd9243', '#fd9141', '#fd9040', '#fd8f3e', '#fd8e3d',
+ '#fd8c3b', '#fc8b3a', '#fc8a39', '#fc8937', '#fb8836', '#fb8735', '#fb8634', '#fa8532',
+ '#fa8331', '#f98230', '#f9812e', '#f9802d', '#f87f2c', '#f87e2b', '#f87d29', '#f77b28',
+ '#f77a27', '#f67925', '#f67824', '#f67723', '#f57622', '#f57520', '#f5741f', '#f4721e',
+ '#f4711c', '#f3701b', '#f36f1a', '#f36e19', '#f26d17', '#f26c16', '#f26b15', '#f16913',
+ '#f16813', '#f06712', '#ef6612', '#ee6511', '#ee6410', '#ed6310', '#ec620f', '#eb610f',
+ '#eb600e', '#ea5f0e', '#e95e0d', '#e85d0c', '#e75c0c', '#e75b0b', '#e65a0b', '#e5590a',
+ '#e4580a', '#e45709', '#e35608', '#e25508', '#e15407', '#e15307', '#e05206', '#df5106',
+ '#de5005', '#de4e05', '#dd4d04', '#dc4c03', '#db4b03', '#db4a02', '#da4902', '#d94801',
+ '#d84801', '#d64701', '#d54601', '#d34601', '#d14501', '#d04501', '#ce4401', '#cd4401',
+ '#cb4302', '#c94202', '#c84202', '#c64102', '#c54102', '#c34002', '#c14002', '#c03f02',
+ '#be3f02', '#bd3e02', '#bb3d02', '#b93d02', '#b83c02', '#b63c02', '#b53b02', '#b33b02',
+ '#b13a03', '#b03903', '#ae3903', '#ad3803', '#ab3803', '#a93703', '#a83703', '#a63603',
+ '#a53603', '#a43503', '#a23503', '#a13403', '#a03403', '#9f3303', '#9e3303', '#9c3203',
+ '#9b3203', '#9a3103', '#993103', '#973003', '#963003', '#952f03', '#942f03', '#932f03',
+ '#912e04', '#902e04', '#8f2d04', '#8e2d04', '#8c2c04', '#8b2c04', '#8a2b04', '#892b04',
+ '#882a04', '#862a04', '#852904', '#842904', '#832804', '#812804', '#802704', '#7f2704'
+]);
+
+ColorMapContainer.reds = ColorMapContainer.fromStringList([
+ '#fff5f0', '#fff4ef', '#fff4ee', '#fff3ed', '#fff2ec', '#fff2eb', '#fff1ea', '#fff0e9',
+ '#fff0e8', '#ffefe8', '#ffeee7', '#ffeee6', '#ffede5', '#ffece4', '#ffece3', '#ffebe2',
+ '#feeae1', '#feeae0', '#fee9df', '#fee8de', '#fee8dd', '#fee7dc', '#fee7db', '#fee6da',
+ '#fee5d9', '#fee5d8', '#fee4d8', '#fee3d7', '#fee3d6', '#fee2d5', '#fee1d4', '#fee1d3',
+ '#fee0d2', '#fedfd0', '#fedecf', '#fedccd', '#fedbcc', '#fedaca', '#fed9c9', '#fed8c7',
+ '#fdd7c6', '#fdd5c4', '#fdd4c2', '#fdd3c1', '#fdd2bf', '#fdd1be', '#fdd0bc', '#fdcebb',
+ '#fdcdb9', '#fdccb8', '#fdcbb6', '#fdcab5', '#fdc9b3', '#fdc7b2', '#fdc6b0', '#fdc5ae',
+ '#fcc4ad', '#fcc3ab', '#fcc2aa', '#fcc1a8', '#fcbfa7', '#fcbea5', '#fcbda4', '#fcbca2',
+ '#fcbba1', '#fcb99f', '#fcb89e', '#fcb79c', '#fcb69b', '#fcb499', '#fcb398', '#fcb296',
+ '#fcb095', '#fcaf93', '#fcae92', '#fcad90', '#fcab8f', '#fcaa8d', '#fca98c', '#fca78b',
+ '#fca689', '#fca588', '#fca486', '#fca285', '#fca183', '#fca082', '#fc9e80', '#fc9d7f',
+ '#fc9c7d', '#fc9b7c', '#fc997a', '#fc9879', '#fc9777', '#fc9576', '#fc9474', '#fc9373',
+ '#fc9272', '#fc9070', '#fc8f6f', '#fc8e6e', '#fc8d6d', '#fc8b6b', '#fc8a6a', '#fc8969',
+ '#fc8767', '#fc8666', '#fc8565', '#fc8464', '#fc8262', '#fc8161', '#fc8060', '#fc7f5f',
+ '#fb7d5d', '#fb7c5c', '#fb7b5b', '#fb7a5a', '#fb7858', '#fb7757', '#fb7656', '#fb7555',
+ '#fb7353', '#fb7252', '#fb7151', '#fb7050', '#fb6e4e', '#fb6d4d', '#fb6c4c', '#fb6b4b',
+ '#fb694a', '#fa6849', '#fa6648', '#fa6547', '#f96346', '#f96245', '#f96044', '#f85f43',
+ '#f85d42', '#f75c41', '#f75b40', '#f7593f', '#f6583e', '#f6563d', '#f6553c', '#f5533b',
+ '#f5523a', '#f4503a', '#f44f39', '#f44d38', '#f34c37', '#f34a36', '#f34935', '#f24734',
+ '#f24633', '#f14432', '#f14331', '#f14130', '#f0402f', '#f03f2e', '#f03d2d', '#ef3c2c',
+ '#ee3a2c', '#ed392b', '#ec382b', '#eb372a', '#ea362a', '#e93529', '#e83429', '#e63328',
+ '#e53228', '#e43027', '#e32f27', '#e22e27', '#e12d26', '#e02c26', '#de2b25', '#dd2a25',
+ '#dc2924', '#db2824', '#da2723', '#d92523', '#d82422', '#d72322', '#d52221', '#d42121',
+ '#d32020', '#d21f20', '#d11e1f', '#d01d1f', '#cf1c1f', '#ce1a1e', '#cc191e', '#cb181d',
+ '#ca181d', '#c9181d', '#c8171c', '#c7171c', '#c5171c', '#c4161c', '#c3161b', '#c2161b',
+ '#c1161b', '#bf151b', '#be151a', '#bd151a', '#bc141a', '#bb141a', '#b91419', '#b81419',
+ '#b71319', '#b61319', '#b51318', '#b31218', '#b21218', '#b11218', '#b01217', '#af1117',
+ '#ad1117', '#ac1117', '#ab1016', '#aa1016', '#a91016', '#a81016', '#a60f15', '#a50f15',
+ '#a30f15', '#a10e15', '#9f0e14', '#9d0d14', '#9c0d14', '#9a0c14', '#980c13', '#960b13',
+ '#940b13', '#920a13', '#900a12', '#8e0912', '#8c0912', '#8a0812', '#880811', '#860811',
+ '#840711', '#820711', '#800610', '#7e0610', '#7c0510', '#7a0510', '#79040f', '#77040f',
+ '#75030f', '#73030f', '#71020e', '#6f020e', '#6d010e', '#6b010e', '#69000d', '#67000d'
+]);
+
+ColorMapContainer.rdYlBu = ColorMapContainer.fromStringList([
+ '#a50026', '#a70226', '#a90426', '#ab0626', '#ad0826', '#af0926', '#b10b26', '#b30d26',
+ '#b50f26', '#b71126', '#b91326', '#bb1526', '#bd1726', '#be1827', '#c01a27', '#c21c27',
+ '#c41e27', '#c62027', '#c82227', '#ca2427', '#cc2627', '#ce2827', '#d02927', '#d22b27',
+ '#d42d27', '#d62f27', '#d83128', '#d93429', '#da362a', '#db382b', '#dc3b2c', '#dd3d2d',
+ '#de402e', '#e0422f', '#e14430', '#e24731', '#e34933', '#e44c34', '#e54e35', '#e65036',
+ '#e75337', '#e95538', '#ea5739', '#eb5a3a', '#ec5c3b', '#ed5f3c', '#ee613e', '#ef633f',
+ '#f16640', '#f26841', '#f36b42', '#f46d43', '#f47044', '#f57245', '#f57547', '#f57748',
+ '#f67a49', '#f67c4a', '#f67f4b', '#f7814c', '#f7844e', '#f8864f', '#f88950', '#f88c51',
+ '#f98e52', '#f99153', '#f99355', '#fa9656', '#fa9857', '#fa9b58', '#fb9d59', '#fba05b',
+ '#fba35c', '#fca55d', '#fca85e', '#fcaa5f', '#fdad60', '#fdaf62', '#fdb164', '#fdb366',
+ '#fdb567', '#fdb769', '#fdb96b', '#fdbb6d', '#fdbd6f', '#fdbf71', '#fdc173', '#fdc374',
+ '#fdc576', '#fdc778', '#fec87a', '#feca7c', '#fecc7e', '#fece7f', '#fed081', '#fed283',
+ '#fed485', '#fed687', '#fed889', '#feda8a', '#fedc8c', '#fede8e', '#fee090', '#fee192',
+ '#fee294', '#fee496', '#fee597', '#fee699', '#fee79b', '#fee99d', '#feea9f', '#feeba1',
+ '#feeca2', '#feeda4', '#feefa6', '#fff0a8', '#fff1aa', '#fff2ac', '#fff3ad', '#fff5af',
+ '#fff6b1', '#fff7b3', '#fff8b5', '#fffab7', '#fffbb9', '#fffcba', '#fffdbc', '#fffebe',
+ '#feffc0', '#fdfec2', '#fcfec5', '#fbfdc7', '#fafdc9', '#f8fccb', '#f7fcce', '#f6fbd0',
+ '#f5fbd2', '#f3fbd4', '#f2fad6', '#f1fad9', '#f0f9db', '#eff9dd', '#edf8df', '#ecf8e2',
+ '#ebf7e4', '#eaf7e6', '#e9f6e8', '#e7f6eb', '#e6f5ed', '#e5f5ef', '#e4f4f1', '#e2f4f4',
+ '#e1f3f6', '#e0f3f8', '#def2f7', '#dcf1f7', '#daf0f6', '#d8eff6', '#d6eef5', '#d4edf4',
+ '#d1ecf4', '#cfebf3', '#cdeaf3', '#cbe9f2', '#c9e8f2', '#c7e7f1', '#c5e6f0', '#c3e5f0',
+ '#c1e4ef', '#bfe3ef', '#bde2ee', '#bbe1ed', '#b9e0ed', '#b6dfec', '#b4deec', '#b2ddeb',
+ '#b0dcea', '#aedbea', '#acdae9', '#aad8e9', '#a8d6e8', '#a6d5e7', '#a3d3e6', '#a1d1e5',
+ '#9fd0e4', '#9dcee3', '#9bcce2', '#99cae1', '#97c9e0', '#94c7df', '#92c5de', '#90c3dd',
+ '#8ec2dc', '#8cc0db', '#8abeda', '#87bdd9', '#85bbd9', '#83b9d8', '#81b7d7', '#7fb6d6',
+ '#7db4d5', '#7ab2d4', '#78b0d3', '#76afd2', '#74add1', '#72abd0', '#70a9cf', '#6ea6ce',
+ '#6da4cc', '#6ba2cb', '#69a0ca', '#679ec9', '#659bc8', '#6399c7', '#6297c6', '#6095c4',
+ '#5e93c3', '#5c90c2', '#5a8ec1', '#588cc0', '#578abf', '#5588be', '#5385bd', '#5183bb',
+ '#4f81ba', '#4d7fb9', '#4b7db8', '#4a7ab7', '#4878b6', '#4676b5', '#4574b3', '#4471b2',
+ '#436fb1', '#426cb0', '#416aaf', '#4167ad', '#4065ac', '#3f62ab', '#3e60aa', '#3e5ea8',
+ '#3d5ba7', '#3c59a6', '#3b56a5', '#3a54a4', '#3a51a2', '#394fa1', '#384ca0', '#374a9f',
+ '#36479e', '#36459c', '#35429b', '#34409a', '#333d99', '#333b97', '#323896', '#313695'
+]);
diff --git a/engine/esm/layers/fits_image.js b/engine/esm/layers/fits_image.js
new file mode 100644
index 00000000..66676e7a
--- /dev/null
+++ b/engine/esm/layers/fits_image.js
@@ -0,0 +1,430 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A FITS image.
+
+import { ss } from "../ss.js";
+import { registerType } from "../typesystem.js";
+import { WebFile } from "../web_file.js";
+import { Coordinates } from "../coordinates.js";
+import { WcsImage } from "./wcs_image.js";
+
+
+// wwtlib.FitsImage
+
+export function FitsImage(dataset, file, blob, callMeBack) {
+ this.errored = false;
+ this.numAxis = 0;
+ this.histogramMaxCount = 0;
+ this.sourceBlob = null;
+ this.header = {};
+ this.position = 0;
+ this.bufferSize = 1;
+ this._parseSuccessful$1 = false;
+ WcsImage.call(this);
+ this.dataset = dataset;
+ this.fitsProperties = dataset.get_fitsProperties();
+ this._callBack$1 = callMeBack;
+ this.filename = file;
+ if (blob != null) {
+ this._readFromBlob$1(blob);
+ }
+ else {
+ this.getFile(file);
+ }
+}
+
+FitsImage.naN = 0 / 0;
+
+var FitsImage$ = {
+ getFile: function (url) {
+ this._webFile$1 = new WebFile(url);
+ this._webFile$1.responseType = 'blob';
+ this._webFile$1.onStateChange = ss.bind('fileStateChange', this);
+ this._webFile$1.send();
+ },
+
+ fileStateChange: function () {
+ if (this._webFile$1.get_state() === 2) {
+ this.errored = true;
+ if (this._callBack$1 != null) {
+ this._callBack$1(this);
+ }
+ } else if (this._webFile$1.get_state() === 1) {
+ var mainBlob = this._webFile$1.getBlob();
+ this._readFromBlob$1(mainBlob);
+ }
+ },
+ _readFromBlob$1: function (blob) {
+ var $this = this;
+
+ this.sourceBlob = blob;
+ var chunck = new FileReader();
+ chunck.onloadend = function (e) {
+ $this.readFromBin(new DataView(chunck.result));
+ $this.errored = !$this._parseSuccessful$1;
+ if ($this._callBack$1 != null) {
+ $this._callBack$1($this);
+ }
+ };
+ chunck.readAsArrayBuffer(blob);
+ },
+ _readByteString$1: function (dataView, count) {
+ var data = '';
+ for (var i = 0; i < count; i++) {
+ data += String.fromCharCode(dataView.getUint8(this.position));
+ this.position++;
+ }
+ return data;
+ },
+ _validateFitsSimple$1: function (dataView) {
+ var data = this._readByteString$1(dataView, 8);
+ var keyword = ss.trimEnd(data);
+ this.position -= 8;
+ return keyword.toUpperCase() === 'SIMPLE';
+ },
+
+ readFromBin: function (dataView) {
+ if (!this._validateFitsSimple$1(dataView)) {
+ console.log('The requested file is not a valid FITS file.');
+ return;
+ }
+ var foundEnd = false;
+ while (!foundEnd) {
+ for (var i = 0; i < 36; i++) {
+ var data = this._readByteString$1(dataView, 80);
+ if (!foundEnd) {
+ var keyword = ss.trimEnd(data.substring(0, 8));
+ var values = data.substring(10).split('/');
+ if (keyword.toUpperCase() === 'END') {
+ foundEnd = true;
+ // Check for XTENSION
+ i++;
+ data = this._readByteString$1(dataView, 80);
+ while (ss.whitespace(data)) {
+ i++;
+ data = this._readByteString$1(dataView, 80);
+ }
+ keyword = ss.trimEnd(data.substring(0, 8));
+ if (keyword.toUpperCase() === 'XTENSION') {
+ // We have additional headers
+ foundEnd = false;
+ }
+ else {
+ // Rewind these 80 bytes which could be data
+ this.position -= 80;
+ }
+ }
+ else {
+ this._addKeyword$1(keyword, values);
+ }
+ }
+ }
+ }
+ if (!foundEnd) {
+ console.log('Unable to parse requested FITS file.');
+ return;
+ }
+ this.numAxis = parseInt(this.header['NAXIS']);
+ if (ss.keyExists(this.header, 'BLANK')) {
+ this.fitsProperties.blankValue = parseFloat(this.header['BLANK']);
+ this.fitsProperties.containsBlanks = true;
+ }
+ if (ss.keyExists(this.header, 'BZERO')) {
+ this.fitsProperties.bZero = parseFloat(this.header['BZERO']);
+ }
+ if (ss.keyExists(this.header, 'BSCALE')) {
+ this.fitsProperties.bScale = parseFloat(this.header['BSCALE']);
+ }
+ this.axisSize = new Array(this.numAxis);
+ for (var axis = 0; axis < this.numAxis; axis++) {
+ this.axisSize[axis] = parseInt(this.header[ss.format('NAXIS{0}', axis + 1)]);
+ this.bufferSize *= this.axisSize[axis];
+ }
+ var bitpix = parseInt(this.header['BITPIX']);
+ this.readDataUnit(dataView, bitpix);
+ if (this.numAxis > 1) {
+ this.sizeX = this.axisSize[0];
+ this.sizeY = this.axisSize[1];
+ this.histogram = this.computeHistogram(256);
+ this.histogramMaxCount = this.histogram[256];
+ }
+ this.computeWcs();
+ this._parseSuccessful$1 = true;
+ },
+ _addKeyword$1: function (keyword, values) {
+ if (keyword !== 'CONTINUE' && keyword !== 'COMMENT' && keyword !== 'HISTORY' && !ss.emptyString(keyword)) {
+ try {
+ if (ss.keyExists(this.header, keyword)) {
+ this.header[keyword] = ss.trim(values[0]);
+ }
+ else {
+ this.header[keyword.toUpperCase()] = ss.trim(values[0]);
+ }
+ }
+ catch ($e1) {
+ }
+ }
+ },
+
+ readDataUnit: function (dataView, bitpix) {
+ this.dataUnit = new Float32Array(this.bufferSize);
+ switch (bitpix) {
+ case -64:
+ this.readDataUnitFloat64(dataView);
+ break;
+ case -32:
+ this.readDataUnitFloat32(dataView);
+ break;
+ case 8:
+ this.readDataUnitUint8(dataView);
+ break;
+ case 16:
+ this.readDataUnitInt16(dataView);
+ break;
+ case 32:
+ this.readDataUnitInt32(dataView);
+ break;
+ case 64:
+ // 64 bit integers not supported by Safari
+ console.log('64 bit integer FITS are not yet supported');
+ break;
+ }
+ },
+
+ readDataUnitFloat64: function (dataView) {
+ var i = 0;
+ while (this.position < dataView.byteLength) {
+ this.dataUnit[i] = dataView.getFloat64(this.position, false);
+ var physicalValue = this.dataUnit[i] * this.fitsProperties.bScale + this.fitsProperties.bZero;
+ if (this.fitsProperties.minVal > physicalValue) {
+ this.fitsProperties.minVal = physicalValue;
+ }
+ if (this.fitsProperties.maxVal < physicalValue) {
+ this.fitsProperties.maxVal = physicalValue;
+ }
+ i++;
+ this.position += 8;
+ }
+ this.fitsProperties.lowerCut = this.fitsProperties.minVal;
+ this.fitsProperties.upperCut = this.fitsProperties.maxVal;
+ },
+
+ readDataUnitFloat32: function (dataView) {
+ var i = 0;
+ while (this.position < dataView.byteLength) {
+ this.dataUnit[i] = dataView.getFloat32(this.position, false);
+ var physicalValue = this.dataUnit[i] * this.fitsProperties.bScale + this.fitsProperties.bZero;
+ if (this.fitsProperties.minVal > physicalValue) {
+ this.fitsProperties.minVal = physicalValue;
+ }
+ if (this.fitsProperties.maxVal < physicalValue) {
+ this.fitsProperties.maxVal = physicalValue;
+ }
+ i++;
+ this.position += 4;
+ }
+ this.fitsProperties.lowerCut = this.fitsProperties.minVal;
+ this.fitsProperties.upperCut = this.fitsProperties.maxVal;
+ },
+
+ readDataUnitUint8: function (dataView) {
+ var i = 0;
+ while (this.position < dataView.byteLength) {
+ this.dataUnit[i] = dataView.getUint8(this.position);
+ if (this.fitsProperties.minVal > this.dataUnit[i]) {
+ this.fitsProperties.minVal = this.dataUnit[i];
+ }
+ if (this.fitsProperties.maxVal < this.dataUnit[i]) {
+ this.fitsProperties.maxVal = this.dataUnit[i];
+ }
+ i++;
+ this.position += 1;
+ }
+ this.fitsProperties.lowerCut = this.fitsProperties.minVal;
+ this.fitsProperties.upperCut = this.fitsProperties.maxVal;
+ },
+
+ readDataUnitInt16: function (dataView) {
+ var i = 0;
+ while (this.position < dataView.byteLength) {
+ this.dataUnit[i] = dataView.getInt16(this.position, false);
+ if (this.fitsProperties.minVal > this.dataUnit[i]) {
+ this.fitsProperties.minVal = this.dataUnit[i];
+ }
+ if (this.fitsProperties.maxVal < this.dataUnit[i]) {
+ this.fitsProperties.maxVal = this.dataUnit[i];
+ }
+ i++;
+ this.position += 2;
+ }
+ this.fitsProperties.lowerCut = this.fitsProperties.minVal;
+ this.fitsProperties.upperCut = this.fitsProperties.maxVal;
+ },
+
+ readDataUnitInt32: function (dataView) {
+ var i = 0;
+ while (this.position < dataView.byteLength) {
+ this.dataUnit[i] = dataView.getInt32(this.position, false);
+ if (this.fitsProperties.minVal > this.dataUnit[i]) {
+ this.fitsProperties.minVal = this.dataUnit[i];
+ }
+ if (this.fitsProperties.maxVal < this.dataUnit[i]) {
+ this.fitsProperties.maxVal = this.dataUnit[i];
+ }
+ i++;
+ this.position += 4;
+ }
+ this.fitsProperties.lowerCut = this.fitsProperties.minVal;
+ this.fitsProperties.upperCut = this.fitsProperties.maxVal;
+ },
+
+ computeWcs: function () {
+ if (ss.keyExists(this.header, 'CROTA2')) {
+ this.rotation = parseFloat(ss.trim(this.header['CROTA2']));
+ this.hasRotation = true;
+ }
+ if (ss.keyExists(this.header, 'CDELT1')) {
+ this.scaleX = parseFloat(ss.trim(this.header['CDELT1']));
+ if (ss.keyExists(this.header, 'CDELT2')) {
+ this.scaleY = parseFloat(ss.trim(this.header['CDELT2']));
+ this.hasScale = true;
+ }
+ }
+ if (ss.keyExists(this.header, 'CRPIX1')) {
+ // In FITS/ WCS, pixel coordinates are 1 - based and integer pixel
+ // coordinates land on pixel centers. Therefore in standard FITS
+ // orientation, where the "first" pixel is at the lower-left, the
+ // lower-left corner of the image has pixel coordinate (0.5, 0.5). For
+ // the WWT offset parameters, the lower-left corner of the image has
+ // coordinate (0, 0).
+ this.referenceX = parseFloat(ss.trim(this.header['CRPIX1'])) - 0.5;
+ if (ss.keyExists(this.header, 'CRPIX2')) {
+ this.referenceY = parseFloat(ss.trim(this.header['CRPIX2'])) - 0.5;
+ this.hasPixel = true;
+ }
+ }
+ var galactic = false;
+ var tan = false;
+ if (ss.keyExists(this.header, 'CTYPE1')) {
+ if (this.header['CTYPE1'].indexOf('GLON-') > -1) {
+ galactic = true;
+ tan = true;
+ }
+ if (this.header['CTYPE2'].indexOf('GLAT-') > -1) {
+ galactic = true;
+ tan = true;
+ }
+ if (this.header['CTYPE1'].indexOf('-TAN') > -1) {
+ tan = true;
+ }
+ if (this.header['CTYPE1'].indexOf('-SIN') > -1) {
+ tan = true;
+ }
+ }
+ if (!tan) {
+ throw new Error('Only TAN projected images are supported: ');
+ }
+ this.hasSize = true;
+ if (ss.keyExists(this.header, 'CRVAL1')) {
+ this.centerX = parseFloat(ss.trim(this.header['CRVAL1']));
+ if (ss.keyExists(this.header, 'CRVAL2')) {
+ this.centerY = parseFloat(ss.trim(this.header['CRVAL2']));
+ this.hasLocation = true;
+ }
+ }
+ if (galactic) {
+ var result = Coordinates.galactictoJ2000(this.centerX, this.centerY);
+ this.centerX = result[0];
+ this.centerY = result[1];
+ }
+ if (ss.keyExists(this.header, 'CD1_1') && ss.keyExists(this.header, 'CD1_2') && ss.keyExists(this.header, 'CD2_1') && ss.keyExists(this.header, 'CD2_2')) {
+ this.cd1_1 = parseFloat(ss.trim(this.header['CD1_1']));
+ this.cd1_2 = parseFloat(ss.trim(this.header['CD1_2']));
+ this.cd2_1 = parseFloat(ss.trim(this.header['CD2_1']));
+ this.cd2_2 = parseFloat(ss.trim(this.header['CD2_2']));
+ if (!this.hasRotation) {
+ this.calculateRotationFromCD();
+ }
+ if (!this.hasScale) {
+ this.calculateScaleFromCD();
+ }
+ this.hasScale = true;
+ this.hasRotation = true;
+ }
+ this.set_validWcs(this.hasScale && this.hasRotation && this.hasPixel && this.hasLocation);
+ },
+
+ // Modify the FitsProperties object to apply any settings stored in this
+ // FITS image's header keywords. This mechanism gives us a way to set up
+ // the rendering of a tiled FITS image through keywords set on its
+ // level-0 tile file.
+ //
+ // I'm not aware of any standard, or even standard-ish, headers to
+ // define these settings, so we'll roll our own here.
+ applyDisplaySettings: function () {
+ // TODO for tiled FITS: distinguish between datamin in this one tile,
+ // and datamin across the full, un-downsampled original imagery.
+
+ if (ss.keyExists(this.header, 'DATAMIN')) {
+ this.fitsProperties.lowerCut = parseFloat(ss.trim(this.header['DATAMIN']));
+ this.fitsProperties.minVal = this.fitsProperties.lowerCut;
+ }
+ if (ss.keyExists(this.header, 'DATAMAX')) {
+ this.fitsProperties.upperCut = parseFloat(ss.trim(this.header['DATAMAX']));
+ this.fitsProperties.maxVal = this.fitsProperties.upperCut;
+ }
+ if (ss.keyExists(this.header, 'PXCUTMIN')) {
+ this.fitsProperties.lowerCut = parseFloat(ss.trim(this.header['PXCUTMIN']));
+ }
+ if (ss.keyExists(this.header, 'PXCUTMAX')) {
+ this.fitsProperties.upperCut = parseFloat(ss.trim(this.header['PXCUTMAX']));
+ }
+ },
+
+ computeHistogram: function (count) {
+ var histogram = new Array(count + 1);
+ for (var i = 0; i < count + 1; i++) {
+ histogram[i] = 0;
+ }
+ this.populateHistogram(histogram);
+ var maxCounter = 1;
+ var $enum1 = ss.enumerate(histogram);
+ while ($enum1.moveNext()) {
+ var val = $enum1.current;
+ if (val > maxCounter) {
+ maxCounter = val;
+ }
+ }
+ histogram[count] = maxCounter;
+ return histogram;
+ },
+
+ populateHistogram: function (histogram) {
+ var buckets = histogram.length;
+ var factor = (this.fitsProperties.maxVal - this.fitsProperties.minVal) / buckets;
+ for (var i = 0; i < this.dataUnit.length; i++) {
+ if (!(this.dataUnit[i] === FitsImage.naN)) {
+ histogram[Math.min(buckets - 1, ss.truncate(((this.fitsProperties.bZero + this.fitsProperties.bScale * this.dataUnit[i] - this.fitsProperties.minVal) / factor)))]++;
+ }
+ }
+ },
+
+ drawHistogram: function (ctx) {
+ ctx.clearRect(0, 0, 255, 150);
+ ctx.beginPath();
+ ctx.strokeStyle = 'rgba(255,255,255,255)';
+ var logMax = Math.log(this.histogramMaxCount);
+ for (var i = 0; i < this.histogram.length; i++) {
+ var height = Math.log(this.histogram[i]) / logMax;
+ if (height < 0) {
+ height = 0;
+ }
+ ctx.moveTo(i, 150);
+ ctx.lineTo(i, 150 - (height * 150));
+ ctx.stroke();
+ }
+ }
+};
+
+registerType("FitsImage", [FitsImage, FitsImage$, WcsImage]);
diff --git a/engine/esm/layers/fits_image_js.js b/engine/esm/layers/fits_image_js.js
new file mode 100644
index 00000000..b5aba6f7
--- /dev/null
+++ b/engine/esm/layers/fits_image_js.js
@@ -0,0 +1,632 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A FITS image with a pure JavaScript implementation.
+//
+// This class is used when WebGL 2 is not available, as in Safari.
+
+import { ss } from "../ss.js";
+import { registerType, registerEnum } from "../typesystem.js";
+import { BinaryReader } from "../utilities/binary_reader.js";
+import { Bitmap } from "../utilities/bitmap.js";
+import { ColorMapContainer } from "./color_map_container.js";
+import { FitsImage } from "./fits_image.js";
+
+
+// wwtlib.DataTypes
+
+export var DataTypes = {
+ byteT: 0,
+ int16T: 1,
+ int32T: 2,
+ floatT: 3,
+ doubleT: 4,
+ none: 5
+};
+
+registerType("DataTypes", DataTypes);
+registerEnum("DataTypes", DataTypes);
+
+
+// wwtlib.ScaleMap
+
+export function ScaleMap() { }
+
+var ScaleMap$ = {};
+
+registerType("ScaleMap", [ScaleMap, ScaleMap$, null]);
+
+
+// wwtlib.ScaleLinear
+
+export function ScaleLinear(min, max) {
+ this._min$1 = 0;
+ this._max$1 = 0;
+ this._factor$1 = 0;
+ this._logFactor$1 = 0;
+ ScaleMap.call(this);
+ this._min$1 = min;
+ this._max$1 = max;
+ this._factor$1 = max - min;
+}
+
+var ScaleLinear$ = {
+ map: function (val) {
+ return Math.min(255, Math.max(0, ss.truncate(((val - this._min$1) / this._factor$1 * 255))));
+ }
+};
+
+registerType("ScaleLinear", [ScaleLinear, ScaleLinear$, ScaleMap]);
+
+
+// wwtlib.ScaleLog
+
+export function ScaleLog(min, max) {
+ this._min$1 = 0;
+ this._max$1 = 0;
+ this._factor$1 = 0;
+ this._logFactor$1 = 0;
+ ScaleMap.call(this);
+ this._min$1 = min;
+ this._max$1 = max;
+ this._factor$1 = max - min;
+ this._logFactor$1 = 255 / Math.log(255);
+}
+
+var ScaleLog$ = {
+ map: function (val) {
+ return Math.min(255, Math.max(0, ss.truncate((Math.log((val - this._min$1) / this._factor$1 * 255) * this._logFactor$1))));
+ }
+};
+
+registerType("ScaleLog", [ScaleLog, ScaleLog$, ScaleMap]);
+
+
+// wwtlib.ScalePow
+
+export function ScalePow(min, max) {
+ this._min$1 = 0;
+ this._max$1 = 0;
+ this._factor$1 = 0;
+ this._powFactor$1 = 0;
+ ScaleMap.call(this);
+ this._min$1 = min;
+ this._max$1 = max;
+ this._factor$1 = max - min;
+ this._powFactor$1 = 255 / Math.pow(255, 2);
+}
+
+var ScalePow$ = {
+ map: function (val) {
+ return Math.min(255, Math.max(0, ss.truncate((Math.pow((val - this._min$1) / this._factor$1 * 255, 2) * this._powFactor$1))));
+ }
+};
+
+registerType("ScalePow", [ScalePow, ScalePow$, ScaleMap]);
+
+
+// wwtlib.ScaleSqrt
+
+export function ScaleSqrt(min, max) {
+ this._min$1 = 0;
+ this._max$1 = 0;
+ this._factor$1 = 0;
+ this._sqrtFactor$1 = 0;
+ ScaleMap.call(this);
+ this._min$1 = min;
+ this._max$1 = max;
+ this._factor$1 = max - min;
+ this._sqrtFactor$1 = 255 / Math.sqrt(255);
+}
+
+var ScaleSqrt$ = {
+ map: function (val) {
+ return Math.min(255, Math.max(0, ss.truncate((Math.sqrt((val - this._min$1) / this._factor$1 * 255) * this._sqrtFactor$1))));
+ }
+};
+
+registerType("ScaleSqrt", [ScaleSqrt, ScaleSqrt$, ScaleMap]);
+
+
+// wwtlib.HistogramEqualization
+
+export function HistogramEqualization(image, min, max) {
+ this._min$1 = 0;
+ this._max$1 = 0;
+ this._factor$1 = 0;
+ this._maxHistogramValue$1 = 1;
+ ScaleMap.call(this);
+ this._min$1 = min;
+ this._max$1 = max;
+ this._factor$1 = max - min;
+ this._histogram$1 = image.computeHistogram(10000);
+ this._maxHistogramValue$1 = this._histogram$1[10000];
+ this._lookup$1 = new Array(10000);
+ var totalCounts = ss.truncate((image.get_sizeX() * image.get_sizeY()));
+ var sum = 0;
+ for (var i = 0; i < 10000; i++) {
+ sum += this._histogram$1[i];
+ this._lookup$1[i] = (Math.min(255, (sum * 255) / totalCounts) + 0.5);
+ }
+}
+
+var HistogramEqualization$ = {
+ map: function (val) {
+ return this._lookup$1[Math.min(10000 - 1, Math.max(0, ss.truncate(((val - this._min$1) / this._factor$1 * (10000 - 1)))))];
+ }
+};
+
+registerType("HistogramEqualization", [HistogramEqualization, HistogramEqualization$, ScaleMap]);
+
+
+// wwtlib.FitsImageJs
+
+export function FitsImageJs(dataset, file, blob, callMeBack) {
+ this.dataType = DataTypes.none;
+ this._color$2 = false;
+ this.isTiledFits = false;
+ FitsImage.call(this, dataset, file, blob, callMeBack);
+}
+
+FitsImageJs.createTiledFits = function (dataset, file, callMeBack) {
+ var fits = new FitsImageJs(dataset, file, null, callMeBack);
+ fits.isTiledFits = true;
+ return fits;
+};
+
+var FitsImageJs$ = {
+ readFromBin: function (dataView) {
+ FitsImage.prototype.readFromBin.call(this, dataView);
+ if (this.numAxis === 3) {
+ if (this.axisSize[2] === 3) {
+ this._color$2 = true;
+ }
+ }
+ },
+
+ readDataUnit: function (dataView, bitpix) {
+ var br = new BinaryReader(new Uint8Array(dataView.buffer));
+ br.position = this.position;
+ switch (bitpix) {
+ case -64:
+ this.dataType = DataTypes.doubleT;
+ this._readDataUnitFloat64$2(br);
+ break;
+ case -32:
+ this.dataType = DataTypes.floatT;
+ this._readDataUnitFloat32$2(br);
+ break;
+ case 8:
+ this.dataType = DataTypes.byteT;
+ this._readDataUnitUint8$2(br);
+ break;
+ case 16:
+ this.dataType = DataTypes.int16T;
+ this._readDataUnitInt16$2(br);
+ break;
+ case 32:
+ this.dataType = DataTypes.int32T;
+ this._readDataUnitInt32$2(br);
+ break;
+ }
+ this.fitsProperties.lowerCut = this.fitsProperties.minVal;
+ this.fitsProperties.upperCut = this.fitsProperties.maxVal;
+ },
+ _readDataUnitUint8$2: function (br) {
+ var buffer = new Array(this.bufferSize);
+ this._dataBuffer$2 = buffer;
+ for (var i = 0; i < this.bufferSize; i++) {
+ buffer[i] = br.readByte();
+ if (this.fitsProperties.minVal > buffer[i]) {
+ this.fitsProperties.minVal = buffer[i];
+ }
+ if (this.fitsProperties.maxVal < buffer[i]) {
+ this.fitsProperties.maxVal = buffer[i];
+ }
+ }
+ },
+ _readDataUnitInt16$2: function (br) {
+ var buffer = new Array(this.bufferSize);
+ this._dataBuffer$2 = buffer;
+ for (var i = 0; i < this.bufferSize; i++) {
+ buffer[i] = ((br.readSByte() * 256) + br.readByte());
+ if (this.fitsProperties.minVal > buffer[i]) {
+ this.fitsProperties.minVal = buffer[i];
+ }
+ if (this.fitsProperties.maxVal < buffer[i]) {
+ this.fitsProperties.maxVal = buffer[i];
+ }
+ }
+ },
+ _readDataUnitInt32$2: function (br) {
+ var buffer = new Array(this.bufferSize);
+ this._dataBuffer$2 = buffer;
+ for (var i = 0; i < this.bufferSize; i++) {
+ buffer[i] = (br.readSByte() << 24) + (br.readSByte() << 16) + (br.readSByte() << 8) + br.readByte();
+ if (this.fitsProperties.minVal > buffer[i]) {
+ this.fitsProperties.minVal = buffer[i];
+ }
+ if (this.fitsProperties.maxVal < buffer[i]) {
+ this.fitsProperties.maxVal = buffer[i];
+ }
+ }
+ },
+ _readDataUnitFloat32$2: function (br) {
+ var buffer = new Array(this.bufferSize);
+ this._dataBuffer$2 = buffer;
+ var part = new Uint8Array(4);
+ for (var i = 0; i < this.bufferSize; i++) {
+ part[3] = br.readByte();
+ part[2] = br.readByte();
+ part[1] = br.readByte();
+ part[0] = br.readByte();
+ buffer[i] = new Float32Array(part.buffer, 0, 1)[0];
+ if (this.fitsProperties.minVal > buffer[i]) {
+ this.fitsProperties.minVal = buffer[i];
+ }
+ if (this.fitsProperties.maxVal < buffer[i]) {
+ this.fitsProperties.maxVal = buffer[i];
+ }
+ }
+ },
+ _readDataUnitFloat64$2: function (br) {
+ var buffer = new Array(this.bufferSize);
+ var part = new Uint8Array(8);
+ this._dataBuffer$2 = buffer;
+ for (var i = 0; i < this.bufferSize; i++) {
+ part[7] = br.readByte();
+ part[6] = br.readByte();
+ part[5] = br.readByte();
+ part[4] = br.readByte();
+ part[3] = br.readByte();
+ part[2] = br.readByte();
+ part[1] = br.readByte();
+ part[0] = br.readByte();
+ buffer[i] = new Float64Array(part.buffer, 0, 1)[0];
+ if (this.fitsProperties.minVal > buffer[i]) {
+ this.fitsProperties.minVal = buffer[i];
+ }
+ if (this.fitsProperties.maxVal < buffer[i]) {
+ this.fitsProperties.maxVal = buffer[i];
+ }
+ }
+ },
+
+ getBitmap: function () {
+ if (!this.fitsProperties.upperCut && !this.fitsProperties.lowerCut) {
+ this.fitsProperties.lowerCut = this.fitsProperties.minVal;
+ this.fitsProperties.upperCut = this.fitsProperties.maxVal;
+ }
+ return this.getScaledBitmap(this.fitsProperties.lowerCut, this.fitsProperties.upperCut, this.fitsProperties.scaleType, 0, this.fitsProperties.colorMapName);
+ },
+
+ getScaledBitmap: function (min, max, scaleType, z, colorMapperName) {
+ var scale;
+ this.fitsProperties.scaleType = scaleType;
+ this.fitsProperties.lowerCut = min;
+ this.fitsProperties.upperCut = max;
+ this.fitsProperties.colorMapName = colorMapperName;
+ var colorMapper = ColorMapContainer.fromNamedColormap(colorMapperName);
+ switch (scaleType) {
+ case 0:
+ default:
+ scale = new ScaleLinear(min, max);
+ break;
+ case 1:
+ scale = new ScaleLog(min, max);
+ break;
+ case 2:
+ scale = new ScalePow(min, max);
+ break;
+ case 3:
+ scale = new ScaleSqrt(min, max);
+ break;
+ case 4:
+ scale = new HistogramEqualization(this, min, max);
+ break;
+ }
+ try {
+ switch (this.dataType) {
+ case DataTypes.byteT:
+ return this._getBitmapByte$2(min, max, scale, 0, colorMapper);
+ case DataTypes.int16T:
+ return this.getBitmapShort(min, max, scale, 0, colorMapper);
+ case DataTypes.int32T:
+ return this._getBitmapInt$2(min, max, scale, 0, colorMapper);
+ case DataTypes.floatT:
+ return this._getBitmapFloat$2(min, max, scale, 0, colorMapper);
+ case DataTypes.doubleT:
+ return this._getBitmapDouble$2(min, max, scale, 0, colorMapper);
+ case DataTypes.none:
+ default:
+ return Bitmap.create(100, 100);
+ }
+ }
+ catch ($e1) {
+ return Bitmap.create(10, 10);
+ }
+ },
+ _setPixelWithColorMap$2: function (bmp, x, y, val, colorMapper) {
+ if (colorMapper == null) {
+ bmp.setPixel(x, y, val, val, val, (this.fitsProperties.transparentBlack && !val) ? 0 : 255);
+ return;
+ }
+ var pixel_value = val / 255;
+ if (Number.isNaN(pixel_value)) {
+ // This case "can't happen" in C#, but due to JavaScript's numerical
+ // model, it can happen here.
+ bmp.setPixel(x, y, 0, 0, 0, 0);
+ return;
+ }
+ var pixel_color = colorMapper.findClosestColor(pixel_value);
+ bmp.setPixel(x, y, ss.truncate(pixel_color.r), ss.truncate(pixel_color.g), ss.truncate(pixel_color.b), (this.fitsProperties.transparentBlack && !val) ? 0 : 255);
+ },
+ _getBitmapByte$2: function (min, max, scale, z, colorMapper) {
+ var buf = this._dataBuffer$2;
+ var factor = max - min;
+ var stride = this.axisSize[0];
+ var page = this.axisSize[0] * this.axisSize[1] * z;
+ var bmp = Bitmap.create(this.axisSize[0], this.axisSize[1]);
+ for (var y = 0; y < this.axisSize[1]; y++) {
+ var indexY = ((this.axisSize[1] - 1) - y);
+ for (var x = 0; x < this.axisSize[0]; x++) {
+ if (this._color$2) {
+ var datR = buf[(x + indexY * stride)];
+ var datG = buf[(x + indexY * stride) + page];
+ var datB = buf[(x + indexY * stride) + page * 2];
+ if (this.fitsProperties.containsBlanks && datR === this.fitsProperties.blankValue) {
+ bmp.setPixel(x, y, 0, 0, 0, 0);
+ }
+ else {
+ var r = scale.map(datR);
+ var g = scale.map(datG);
+ var b = scale.map(datB);
+ bmp.setPixel(x, y, r, g, b, 255);
+ }
+ }
+ else {
+ var dataValue = buf[x + indexY * stride + page];
+ if (this.fitsProperties.containsBlanks && dataValue === this.fitsProperties.blankValue) {
+ bmp.setPixel(x, y, 0, 0, 0, 0);
+ }
+ else {
+ var val = scale.map(dataValue);
+ this._setPixelWithColorMap$2(bmp, x, y, val, colorMapper);
+ }
+ }
+ }
+ }
+ return bmp;
+ },
+ _getBitmapDouble$2: function (min, max, scale, z, colorMapper) {
+ var buf = this._dataBuffer$2;
+ var factor = max - min;
+ var stride = this.axisSize[0];
+ var page = this.axisSize[0] * this.axisSize[1] * z;
+ var bmp = Bitmap.create(this.axisSize[0], this.axisSize[1]);
+ for (var y = 0; y < this.axisSize[1]; y++) {
+ var indexY = ((this.axisSize[1] - 1) - y);
+ for (var x = 0; x < this.axisSize[0]; x++) {
+ if (this._color$2) {
+ var datR = buf[(x + indexY * stride)];
+ var datG = buf[(x + indexY * stride) + page];
+ var datB = buf[(x + indexY * stride) + page * 2];
+ if (this.fitsProperties.containsBlanks && datR === this.fitsProperties.blankValue) {
+ bmp.setPixel(x, y, 0, 0, 0, 0);
+ }
+ else {
+ var r = scale.map(datR);
+ var g = scale.map(datG);
+ var b = scale.map(datB);
+ bmp.setPixel(x, y, r, g, b, 255);
+ }
+ }
+ else {
+ var dataValue = buf[x + indexY * stride + page];
+ if (this.fitsProperties.containsBlanks && dataValue === this.fitsProperties.blankValue) {
+ bmp.setPixel(x, y, 0, 0, 0, 0);
+ }
+ else {
+ var val = scale.map(dataValue);
+ this._setPixelWithColorMap$2(bmp, x, y, val, colorMapper);
+ }
+ }
+ }
+ }
+ return bmp;
+ },
+ _getBitmapFloat$2: function (min, max, scale, z, colorMapper) {
+ var buf = this._dataBuffer$2;
+ var factor = max - min;
+ var stride = this.axisSize[0];
+ var page = this.axisSize[0] * this.axisSize[1] * z;
+ var bmp = Bitmap.create(this.axisSize[0], this.axisSize[1]);
+ for (var y = 0; y < this.axisSize[1]; y++) {
+ var indexY = ((this.axisSize[1] - 1) - y);
+ for (var x = 0; x < this.axisSize[0]; x++) {
+ if (this._color$2) {
+ var datR = buf[(x + indexY * stride)];
+ var datG = buf[(x + indexY * stride) + page];
+ var datB = buf[(x + indexY * stride) + page * 2];
+ if (this.fitsProperties.containsBlanks && datR === this.fitsProperties.blankValue) {
+ bmp.setPixel(x, y, 0, 0, 0, 0);
+ }
+ else {
+ var r = scale.map(datR);
+ var g = scale.map(datG);
+ var b = scale.map(datB);
+ bmp.setPixel(x, y, r, g, b, 255);
+ }
+ }
+ else {
+ var dataValue = buf[x + indexY * stride + page];
+ if (this.fitsProperties.containsBlanks && dataValue === this.fitsProperties.blankValue) {
+ bmp.setPixel(x, y, 0, 0, 0, 0);
+ }
+ else {
+ var val = scale.map(dataValue);
+ this._setPixelWithColorMap$2(bmp, x, y, val, colorMapper);
+ }
+ }
+ }
+ }
+ return bmp;
+ },
+ _getBitmapInt$2: function (min, max, scale, z, colorMapper) {
+ var buf = this._dataBuffer$2;
+ var factor = max - min;
+ var stride = this.axisSize[0];
+ var page = this.axisSize[0] * this.axisSize[1] * z;
+ var bmp = Bitmap.create(this.axisSize[0], this.axisSize[1]);
+ for (var y = 0; y < this.axisSize[1]; y++) {
+ var indexY = ((this.axisSize[1] - 1) - y);
+ for (var x = 0; x < this.axisSize[0]; x++) {
+ if (this._color$2) {
+ var datR = buf[(x + indexY * stride)];
+ var datG = buf[(x + indexY * stride) + page];
+ var datB = buf[(x + indexY * stride) + page * 2];
+ if (this.fitsProperties.containsBlanks && datR === this.fitsProperties.blankValue) {
+ bmp.setPixel(x, y, 0, 0, 0, 0);
+ }
+ else {
+ var r = scale.map(datR);
+ var g = scale.map(datG);
+ var b = scale.map(datB);
+ bmp.setPixel(x, y, r, g, b, 255);
+ }
+ }
+ else {
+ var dataValue = buf[x + indexY * stride + page];
+ if (this.fitsProperties.containsBlanks && dataValue === this.fitsProperties.blankValue) {
+ bmp.setPixel(x, y, 0, 0, 0, 0);
+ }
+ else {
+ var val = scale.map(dataValue);
+ this._setPixelWithColorMap$2(bmp, x, y, val, colorMapper);
+ }
+ }
+ }
+ }
+ return bmp;
+ },
+
+ getBitmapShort: function (min, max, scale, z, colorMapper) {
+ var buf = this._dataBuffer$2;
+ var factor = max - min;
+ var stride = this.axisSize[0];
+ var page = this.axisSize[0] * this.axisSize[1] * z;
+ var bmp = Bitmap.create(this.axisSize[0], this.axisSize[1]);
+ for (var y = 0; y < this.axisSize[1]; y++) {
+ var indexY = ((this.axisSize[1] - 1) - y);
+ for (var x = 0; x < this.axisSize[0]; x++) {
+ if (this._color$2) {
+ var datR = buf[(x + indexY * stride)];
+ var datG = buf[(x + indexY * stride) + page];
+ var datB = buf[(x + indexY * stride) + page * 2];
+ if (this.fitsProperties.containsBlanks && datR === this.fitsProperties.blankValue) {
+ bmp.setPixel(x, y, 0, 0, 0, 0);
+ }
+ else {
+ var r = scale.map(datR);
+ var g = scale.map(datG);
+ var b = scale.map(datB);
+ bmp.setPixel(x, y, r, g, b, 255);
+ }
+ }
+ else {
+ var dataValue = buf[x + indexY * stride + page];
+ if (this.fitsProperties.containsBlanks && dataValue === this.fitsProperties.blankValue) {
+ bmp.setPixel(x, y, 0, 0, 0, 0);
+ }
+ else {
+ var val = scale.map(dataValue);
+ this._setPixelWithColorMap$2(bmp, x, y, val, colorMapper);
+ }
+ }
+ }
+ }
+ return bmp;
+ },
+
+ computeWcs: function () {
+ if (!this.isTiledFits) {
+ FitsImage.prototype.computeWcs.call(this);
+ }
+ },
+
+ populateHistogram: function (histogram) {
+ switch (this.dataType) {
+ case DataTypes.byteT:
+ this._populateHistogramByte$2(histogram);
+ break;
+ case DataTypes.int16T:
+ this._populateHistogramInt16$2(histogram);
+ break;
+ case DataTypes.int32T:
+ this._populateHistogramInt32$2(histogram);
+ break;
+ case DataTypes.floatT:
+ this._populateHistogramFloat$2(histogram);
+ break;
+ case DataTypes.doubleT:
+ this._populateHistogramDouble$2(histogram);
+ break;
+ }
+ },
+ _populateHistogramDouble$2: function (histogram) {
+ var buckets = histogram.length;
+ var buf = this._dataBuffer$2;
+ var factor = (this.fitsProperties.maxVal - this.fitsProperties.minVal) / buckets;
+ var $enum1 = ss.enumerate(buf);
+ while ($enum1.moveNext()) {
+ var val = $enum1.current;
+ if (!Number.isNaN(val)) {
+ histogram[Math.min(buckets - 1, ss.truncate(((val - this.fitsProperties.minVal) / factor)))]++;
+ }
+ }
+ },
+ _populateHistogramFloat$2: function (histogram) {
+ var buckets = histogram.length;
+ var buf = this._dataBuffer$2;
+ var factor = (this.fitsProperties.maxVal - this.fitsProperties.minVal) / buckets;
+ var $enum1 = ss.enumerate(buf);
+ while ($enum1.moveNext()) {
+ var val = $enum1.current;
+ if (!(val === FitsImage.naN)) {
+ histogram[Math.min(buckets - 1, ss.truncate(((val - this.fitsProperties.minVal) / factor)))]++;
+ }
+ }
+ },
+ _populateHistogramInt32$2: function (histogram) {
+ var buckets = histogram.length;
+ var buf = this._dataBuffer$2;
+ var factor = (this.fitsProperties.maxVal - this.fitsProperties.minVal) / buckets;
+ var $enum1 = ss.enumerate(buf);
+ while ($enum1.moveNext()) {
+ var val = $enum1.current;
+ histogram[Math.min(buckets - 1, ss.truncate(((val - this.fitsProperties.minVal) / factor)))]++;
+ }
+ },
+ _populateHistogramInt16$2: function (histogram) {
+ var buckets = histogram.length;
+ var buf = this._dataBuffer$2;
+ var factor = (this.fitsProperties.maxVal - this.fitsProperties.minVal) / buckets;
+ var $enum1 = ss.enumerate(buf);
+ while ($enum1.moveNext()) {
+ var val = $enum1.current;
+ histogram[Math.min(buckets - 1, ss.truncate(((val - this.fitsProperties.minVal) / factor)))]++;
+ }
+ },
+ _populateHistogramByte$2: function (histogram) {
+ var buckets = histogram.length;
+ var buf = this._dataBuffer$2;
+ var factor = (this.fitsProperties.maxVal - this.fitsProperties.minVal) / buckets;
+ var $enum1 = ss.enumerate(buf);
+ while ($enum1.moveNext()) {
+ var val = $enum1.current;
+ histogram[Math.min(buckets - 1, ss.truncate(((val - this.fitsProperties.minVal) / factor)))]++;
+ }
+ }
+};
+
+registerType("FitsImageJs", [FitsImageJs, FitsImageJs$, FitsImage]);
diff --git a/engine/esm/layers/fits_image_tile.js b/engine/esm/layers/fits_image_tile.js
new file mode 100644
index 00000000..020b4753
--- /dev/null
+++ b/engine/esm/layers/fits_image_tile.js
@@ -0,0 +1,68 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A FITS image used as a tile in a pyramid.
+
+import { registerType } from "../typesystem.js";
+import { FitsImage } from "./fits_image.js";
+
+
+// wwtlib.FitsImageTile
+//
+// Min & Max are already known for pyramid FITS.
+// To improve performance, the below per pixel methods are overriden
+
+export function FitsImageTile(dataset, file, callMeBack) {
+ FitsImage.call(this, dataset, file, null, callMeBack);
+}
+
+var FitsImageTile$ = {
+ readDataUnitFloat64: function (dataView) {
+ var i = 0;
+ while (this.position < dataView.byteLength) {
+ this.dataUnit[i] = dataView.getFloat64(this.position, false);
+ i++;
+ this.position += 8;
+ }
+ },
+
+ readDataUnitFloat32: function (dataView) {
+ var i = 0;
+ while (this.position < dataView.byteLength) {
+ this.dataUnit[i] = dataView.getFloat32(this.position, false);
+ i++;
+ this.position += 4;
+ }
+ },
+
+ readDataUnitUint8: function (dataView) {
+ var i = 0;
+ while (this.position < dataView.byteLength) {
+ this.dataUnit[i] = dataView.getUint8(this.position);
+ i++;
+ this.position += 1;
+ }
+ },
+
+ readDataUnitInt16: function (dataView) {
+ var i = 0;
+ while (this.position < dataView.byteLength) {
+ this.dataUnit[i] = dataView.getInt16(this.position, false);
+ i++;
+ this.position += 2;
+ }
+ },
+
+ readDataUnitInt32: function (dataView) {
+ var i = 0;
+ while (this.position < dataView.byteLength) {
+ this.dataUnit[i] = dataView.getInt32(this.position, false);
+ i++;
+ this.position += 4;
+ }
+ },
+
+ computeWcs: function () { }
+};
+
+registerType("FitsImageTile", [FitsImageTile, FitsImageTile$, FitsImage]);
diff --git a/engine/esm/layers/from_xml.js b/engine/esm/layers/from_xml.js
new file mode 100644
index 00000000..9d3d99c3
--- /dev/null
+++ b/engine/esm/layers/from_xml.js
@@ -0,0 +1,63 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Set up the `Layer.fromXml()` function, which depends on a bunch of Layer
+// subclasses.
+//
+// There are a variety of ways that we could set this up, possibly including
+// just implementing this function in `layer.js`. This is a more conservating
+// approach that tries to avoid circular module imports.
+
+import { ss } from "../ss.js";
+import { Layer } from "./layer.js";
+import { GreatCirlceRouteLayer } from "./great_circle_route_layer.js";
+import { GridLayer } from "./grid_layer.js";
+import { ImageSetLayer } from "./imageset_layer.js";
+import { Object3dLayer } from "./object3d.js";
+import { OrbitLayer } from "./orbit_layer.js";
+import { SpreadSheetLayer } from "./spreadsheet_layer.js";
+import { VoTableLayer } from "./vo_table_layer.js";
+
+
+// The `layerFromXml` function, which we also install as `Layer.fromXml()`. It
+// needs to be aware of a bunch of layer subclasses.
+export function layerFromXml(layerNode, someFlag) {
+ var layerClassName = layerNode.attributes.getNamedItem('Type').nodeValue;
+
+ var overLayType = ss.replaceString(layerClassName, 'TerraViewer.', '');
+ if (overLayType == null) {
+ return null;
+ }
+
+ var newLayer = null;
+ switch (overLayType) {
+ case 'SpreadSheetLayer':
+ newLayer = new SpreadSheetLayer();
+ break;
+ case 'GreatCirlceRouteLayer':
+ newLayer = new GreatCirlceRouteLayer();
+ break;
+ case 'GridLayer':
+ newLayer = new GridLayer();
+ break;
+ case 'ImageSetLayer':
+ newLayer = new ImageSetLayer();
+ break;
+ case 'Object3dLayer':
+ newLayer = new Object3dLayer();
+ break;
+ case 'OrbitLayer':
+ newLayer = new OrbitLayer();
+ break;
+ case 'VoTableLayer':
+ newLayer = new VoTableLayer();
+ break;
+ default:
+ return null;
+ }
+
+ newLayer.initFromXml(layerNode);
+ return newLayer;
+}
+
+Layer.fromXml = layerFromXml;
diff --git a/engine/esm/layers/great_circle_route_layer.js b/engine/esm/layers/great_circle_route_layer.js
new file mode 100644
index 00000000..17e6ab9f
--- /dev/null
+++ b/engine/esm/layers/great_circle_route_layer.js
@@ -0,0 +1,199 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A layer that renders progress along a great circle.
+//
+// Yes, there is an egregious typo in the name of this class. But to maintain
+// API compatibility, we're not fixing it.
+
+import { registerType } from "../typesystem.js";
+import { Vector3d } from "../double3d.js";
+import { Dates, TriangleList } from "../graphics/primitives3d.js";
+import { Coordinates } from "../coordinates.js";
+import { Layer } from "./layer.js";
+
+
+// wwtlib.GreatCirlceRouteLayer
+
+export function GreatCirlceRouteLayer() {
+ this._triangleList$1 = null;
+ this._latStart$1 = 0;
+ this._lngStart$1 = 0;
+ this._latEnd$1 = 0;
+ this._lngEnd$1 = 0;
+ this._width$1 = 4;
+ this._percentComplete$1 = 100;
+ Layer.call(this);
+}
+
+var GreatCirlceRouteLayer$ = {
+ // Even if we fix the typo in this class's name in an API break, we need to
+ // maintain it here to maintain compatibility with existing data files and
+ // older WWT clients.
+ getTypeName: function () {
+ return 'TerraViewer.GreatCirlceRouteLayer';
+ },
+
+ cleanUp: function () {
+ if (this._triangleList$1 != null) {
+ this._triangleList$1.clear();
+ }
+ this._triangleList$1 = null;
+ Layer.prototype.cleanUp.call(this);
+ },
+
+ draw: function (renderContext, opacity, flat) {
+ if (this._triangleList$1 == null) {
+ this._initializeRoute$1(renderContext);
+ }
+ this._triangleList$1.jNow = this._percentComplete$1 / 100;
+ this._triangleList$1.draw(renderContext, opacity * this.get_opacity(), 2);
+ return true;
+ },
+ _initializeRoute$1: function (renderContext) {
+ this._triangleList$1 = new TriangleList();
+ this._triangleList$1.decay = 1000;
+ this._triangleList$1.sky = this.get_astronomical();
+ this._triangleList$1.timeSeries = true;
+ this._triangleList$1.depthBuffered = false;
+ this._triangleList$1.autoTime = false;
+ var steps = 500;
+ var start = Coordinates.geoTo3dDouble(this._latStart$1, this._lngStart$1);
+ var end = Coordinates.geoTo3dDouble(this._latEnd$1, this._lngEnd$1);
+ var dir = Vector3d.subtractVectors(end, start);
+ dir.normalize();
+ var startNormal = start;
+ startNormal.normalize();
+ var left = Vector3d.cross(startNormal, dir);
+ var right = Vector3d.cross(dir, startNormal);
+ left.normalize();
+ right.normalize();
+ left.multiply(0.001 * this._width$1);
+ right.multiply(0.001 * this._width$1);
+ var lastLeft = new Vector3d();
+ var lastRight = new Vector3d();
+ var firstTime = true;
+ for (var i = 0; i <= steps; i++) {
+ var v = Vector3d.lerp(start, end, i / steps);
+ v.normalize();
+ var cl = v;
+ var cr = v;
+ cl.add(left);
+ cr.add(right);
+ if (!firstTime) {
+ this._triangleList$1.addQuad(lastRight, lastLeft, cr, cl, this.get_color(), new Dates(i / steps, 2));
+ }
+ else {
+ firstTime = false;
+ }
+ lastLeft = cl;
+ lastRight = cr;
+ }
+ },
+
+ getParams: function () {
+ return [this._percentComplete$1];
+ },
+
+ getParamNames: function () {
+ return ['Percentage'];
+ },
+
+ setParams: function (paramList) {
+ if (paramList.length > 0) {
+ this._percentComplete$1 = paramList[0];
+ }
+ },
+
+ get_latStart: function () {
+ return this._latStart$1;
+ },
+
+ set_latStart: function (value) {
+ if (this._latStart$1 !== value) {
+ this._latStart$1 = value;
+ this.version++;
+ }
+ return value;
+ },
+
+ get_lngStart: function () {
+ return this._lngStart$1;
+ },
+
+ set_lngStart: function (value) {
+ if (this._lngStart$1 !== value) {
+ this._lngStart$1 = value;
+ this.version++;
+ }
+ return value;
+ },
+
+ get_latEnd: function () {
+ return this._latEnd$1;
+ },
+
+ set_latEnd: function (value) {
+ if (this._latEnd$1 !== value) {
+ this._latEnd$1 = value;
+ this.version++;
+ }
+ return value;
+ },
+
+ get_lngEnd: function () {
+ return this._lngEnd$1;
+ },
+
+ set_lngEnd: function (value) {
+ if (this._lngEnd$1 !== value) {
+ this._lngEnd$1 = value;
+ this.version++;
+ }
+ return value;
+ },
+
+ get_width: function () {
+ return this._width$1;
+ },
+
+ set_width: function (value) {
+ if (this._width$1 !== value) {
+ this._width$1 = value;
+ this.version++;
+ }
+ return value;
+ },
+
+ get_percentComplete: function () {
+ return this._percentComplete$1;
+ },
+
+ set_percentComplete: function (value) {
+ if (this._percentComplete$1 !== value) {
+ this._percentComplete$1 = value;
+ this.version++;
+ }
+ return value;
+ },
+
+ writeLayerProperties: function (xmlWriter) {
+ xmlWriter._writeAttributeString('LatStart', this.get_latStart().toString());
+ xmlWriter._writeAttributeString('LngStart', this.get_lngStart().toString());
+ xmlWriter._writeAttributeString('LatEnd', this.get_latEnd().toString());
+ xmlWriter._writeAttributeString('LngEnd', this.get_lngEnd().toString());
+ xmlWriter._writeAttributeString('Width', this.get_width().toString());
+ xmlWriter._writeAttributeString('PercentComplete', this.get_percentComplete().toString());
+ },
+
+ initializeFromXml: function (node) {
+ this._latStart$1 = parseFloat(node.attributes.getNamedItem('LatStart').nodeValue);
+ this._lngStart$1 = parseFloat(node.attributes.getNamedItem('LngStart').nodeValue);
+ this._latEnd$1 = parseFloat(node.attributes.getNamedItem('LatEnd').nodeValue);
+ this._lngEnd$1 = parseFloat(node.attributes.getNamedItem('LngEnd').nodeValue);
+ this._width$1 = parseFloat(node.attributes.getNamedItem('Width').nodeValue);
+ this._percentComplete$1 = parseFloat(node.attributes.getNamedItem('PercentComplete').nodeValue);
+ }
+};
+
+registerType("GreatCirlceRouteLayer", [GreatCirlceRouteLayer, GreatCirlceRouteLayer$, Layer]);
diff --git a/engine/esm/layers/grid_layer.js b/engine/esm/layers/grid_layer.js
new file mode 100644
index 00000000..1d358572
--- /dev/null
+++ b/engine/esm/layers/grid_layer.js
@@ -0,0 +1,25 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A layer that renders a coordinate grid on a planet.
+
+import { registerType } from "../typesystem.js";
+import { Grids } from "../grids.js";
+import { Layer } from "./layer.js";
+
+
+// wwtlib.GridLayer
+
+export function GridLayer() {
+ Layer.call(this);
+}
+
+var GridLayer$ = {
+ draw: function (renderContext, opacity, flat) {
+ Grids.drawPlanetGrid(renderContext, opacity * this.get_opacity(), this.get_color());
+ Grids.drawPlanetGridText(renderContext, opacity * this.get_opacity(), this.get_color());
+ return true;
+ }
+};
+
+registerType("GridLayer", [GridLayer, GridLayer$, Layer]);
diff --git a/engine/esm/layers/imageset_layer.js b/engine/esm/layers/imageset_layer.js
new file mode 100644
index 00000000..91b14766
--- /dev/null
+++ b/engine/esm/layers/imageset_layer.js
@@ -0,0 +1,236 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A layer that renders an arbitrary imageset
+
+import { ss } from "../ss.js";
+import { registerType, Enums } from "../typesystem.js";
+import { Util } from "../baseutil.js";
+import { useGlVersion2 } from "../render_globals.js";
+import { Histogram } from "../utilities/histogram.js";
+import { ColorMapContainer } from "./color_map_container.js";
+import { FitsImage } from "./fits_image.js";
+import { FitsImageJs } from "./fits_image_js.js";
+import { Imageset } from "../imageset.js";
+import { Layer } from "./layer.js";
+
+
+// wwtlib.ImageSetLayer
+
+export function ImageSetLayer() {
+ this._imageSet$1 = null;
+ this._extension$1 = '.txt';
+ this._overrideDefaultLayer$1 = false;
+ this._loaded$1 = false;
+ Layer.call(this);
+}
+
+ImageSetLayer.create = function (set) {
+ var isl = new ImageSetLayer();
+ isl._imageSet$1 = set;
+ return isl;
+};
+
+var ImageSetLayer$ = {
+ get_imageSet: function () {
+ return this._imageSet$1;
+ },
+
+ set_imageSet: function (value) {
+ this._imageSet$1 = value;
+ return value;
+ },
+
+ get_overrideDefaultLayer: function () {
+ return this._overrideDefaultLayer$1;
+ },
+
+ set_overrideDefaultLayer: function (value) {
+ this._overrideDefaultLayer$1 = value;
+ return value;
+ },
+
+ getFitsImage: function () {
+ return ss.safeCast(this._imageSet$1.get_wcsImage(), FitsImage);
+ },
+
+ // Test whether our underlying imagery is FITS based.
+ //
+ // This can come in two flavors: a single FITS image, or tiled FITS.
+ // Note that even though the FileType/Extension field can currently
+ // specify multiple file formats, the rendering code requires that the
+ // extension is exactly ".fits" for FITS rendering to kick in.
+ _isFitsImageset$1: function () {
+ var hasFitsExt = this._imageSet$1.get_extension() === '.fits';
+ return ss.canCast(this._imageSet$1.get_wcsImage(), FitsImage) || (this._imageSet$1.get_wcsImage() == null && hasFitsExt);
+ },
+
+ initializeFromXml: function (node) {
+ var imageSetNode = Util.selectSingleNode(node, 'ImageSet');
+ this._imageSet$1 = Imageset.fromXMLNode(imageSetNode);
+ if (node.attributes.getNamedItem('Extension') != null) {
+ this._extension$1 = node.attributes.getNamedItem('Extension').nodeValue;
+ }
+ if (node.attributes.getNamedItem('ScaleType') != null) {
+ this.get_imageSet().get_fitsProperties().scaleType = Enums.parse('ScaleTypes', node.attributes.getNamedItem('ScaleType').nodeValue);
+ }
+ if (node.attributes.getNamedItem('MinValue') != null) {
+ this.get_imageSet().get_fitsProperties().minVal = parseFloat(node.attributes.getNamedItem('MinValue').nodeValue);
+ this.get_imageSet().get_fitsProperties().lowerCut = (node.attributes.getNamedItem('LowerCut') != null) ? parseFloat(node.attributes.getNamedItem('LowerCut').nodeValue) : this.get_imageSet().get_fitsProperties().minVal;
+ }
+ if (node.attributes.getNamedItem('MaxValue') != null) {
+ this.get_imageSet().get_fitsProperties().maxVal = parseFloat(node.attributes.getNamedItem('MaxValue').nodeValue);
+ this.get_imageSet().get_fitsProperties().upperCut = (node.attributes.getNamedItem('UpperCut') != null) ? parseFloat(node.attributes.getNamedItem('UpperCut').nodeValue) : this.get_imageSet().get_fitsProperties().maxVal;
+ }
+ if (node.attributes.getNamedItem('ColorMapperName') != null) {
+ this.get_imageSet().get_fitsProperties().colorMapName = node.attributes.getNamedItem('ColorMapperName').nodeValue;
+ }
+ if (node.attributes.getNamedItem('OverrideDefault') != null) {
+ this._overrideDefaultLayer$1 = ss.boolean(node.attributes.getNamedItem('OverrideDefault').nodeValue);
+ }
+ },
+
+ draw: function (renderContext, opacity, flat) {
+ if (!this._loaded$1) {
+ return false;
+ }
+ renderContext.set_worldBase(renderContext.get_world());
+ renderContext.set_viewBase(renderContext.get_view());
+ renderContext.makeFrustum();
+ renderContext.drawImageSet(this._imageSet$1, this.get_opacity() * opacity * 100);
+ return true;
+ },
+
+ writeLayerProperties: function (xmlWriter) {
+ if (this._imageSet$1.get_wcsImage() != null) {
+ if (this._isFitsImageset$1()) {
+ this._extension$1 = '.fit';
+ }
+ else {
+ this._extension$1 = '.png';
+ }
+ xmlWriter._writeAttributeString('Extension', this._extension$1);
+ }
+ if (this._isFitsImageset$1()) {
+ xmlWriter._writeAttributeString('ScaleType', Enums.toXml('ScaleTypes', this._imageSet$1.get_fitsProperties().scaleType));
+ xmlWriter._writeAttributeString('MinValue', this._imageSet$1.get_fitsProperties().minVal.toString());
+ xmlWriter._writeAttributeString('MaxValue', this._imageSet$1.get_fitsProperties().maxVal.toString());
+ xmlWriter._writeAttributeString('LowerCut', this._imageSet$1.get_fitsProperties().lowerCut.toString());
+ xmlWriter._writeAttributeString('UpperCut', this._imageSet$1.get_fitsProperties().upperCut.toString());
+ if (this._imageSet$1.get_fitsProperties().colorMapName != null) {
+ xmlWriter._writeAttributeString('ColorMapperName', this._imageSet$1.get_fitsProperties().colorMapName);
+ }
+ }
+ xmlWriter._writeAttributeString('OverrideDefault', this._overrideDefaultLayer$1.toString());
+ Imageset.saveToXml(xmlWriter, this._imageSet$1, '');
+ Layer.prototype.writeLayerProperties.call(this, xmlWriter);
+ },
+
+ getTypeName: function () {
+ return 'TerraViewer.ImageSetLayer';
+ },
+
+ cleanUp: function () {
+ Layer.prototype.cleanUp.call(this);
+ },
+
+ addFilesToCabinet: function (fc) {
+ if (ss.canCast(this._imageSet$1.get_wcsImage(), FitsImage)) {
+ var fName = (this._imageSet$1.get_wcsImage()).get_filename();
+ var fileName = fc.tempDirectory + ss.format('{0}\\{1}{2}', fc.get_packageID(), this.id.toString(), this._extension$1);
+ fc.addFile(fileName, (this._imageSet$1.get_wcsImage()).sourceBlob);
+ }
+ },
+
+ getParamNames: function () {
+ return Layer.prototype.getParamNames.call(this);
+ },
+
+ getParams: function () {
+ return Layer.prototype.getParams.call(this);
+ },
+
+ setParams: function (paramList) {
+ Layer.prototype.setParams.call(this, paramList);
+ },
+
+ setImageScale: function (scaleType, min, max) {
+ console.warn('SetImageScale is considered deprecated. Use setImageScaleRaw or setImageScalePhysical instead.');
+ this.setImageScaleRaw(scaleType, min, max);
+ },
+
+ setImageScaleRaw: function (scaleType, min, max) {
+ this.get_imageSet().get_fitsProperties().lowerCut = min;
+ this.get_imageSet().get_fitsProperties().upperCut = max;
+ this.get_imageSet().get_fitsProperties().scaleType = scaleType;
+ if (ss.canCast(this._imageSet$1.get_wcsImage(), FitsImageJs)) {
+ Histogram.updateScale(this, scaleType, min, max);
+ }
+ },
+
+ setImageScalePhysical: function (scaleType, min, max) {
+ var newMin = min;
+ var newMax = max;
+ if (this._isFitsImageset$1()) {
+ newMin = (newMin - this._imageSet$1.get_fitsProperties().bZero) / this._imageSet$1.get_fitsProperties().bScale;
+ newMax = (newMax - this._imageSet$1.get_fitsProperties().bZero) / this._imageSet$1.get_fitsProperties().bScale;
+ }
+ this.setImageScaleRaw(scaleType, newMin, newMax);
+ },
+
+ setImageZ: function (z) {
+ if (this._isFitsImageset$1()) {
+ Histogram.updateImage(this, z);
+ }
+ },
+
+ get_colorMapperName: function () {
+ return this.get_imageSet().get_fitsProperties().colorMapName;
+ },
+
+ set_colorMapperName: function (value) {
+ if (ColorMapContainer.fromNamedColormap(value) == null) {
+ throw new Error('Invalid colormap name');
+ }
+ this.version++;
+ if (this._isFitsImageset$1()) {
+ if (useGlVersion2) {
+ this._imageSet$1.get_fitsProperties().colorMapName = value;
+ }
+ else {
+ Histogram.updateColorMapper(this, value);
+ }
+ }
+ return value;
+ },
+
+ get_colorMapper: function () {
+ if (this.get_imageSet().get_fitsProperties().colorMapName == null) {
+ return null;
+ } else {
+ return ColorMapContainer.fromNamedColormap(this.get_imageSet().get_fitsProperties().colorMapName);
+ }
+ },
+
+ loadData: function (tourDoc, filename) {
+ if (ss.startsWith(this._extension$1.toLowerCase(), '.fit')) {
+ var blob = tourDoc.getFileBlob(ss.replaceString(filename, '.txt', this._extension$1));
+ var fi;
+ if (useGlVersion2) {
+ fi = new FitsImage(this._imageSet$1, 'image.fit', blob, ss.bind('doneLoading', this));
+ }
+ else {
+ fi = new FitsImageJs(this._imageSet$1, 'image.fit', blob, ss.bind('doneLoading', this));
+ }
+ this._imageSet$1.set_wcsImage(fi);
+ } else {
+ this._loaded$1 = true;
+ }
+ },
+
+ doneLoading: function (wcsImage) {
+ this._loaded$1 = true;
+ }
+};
+
+registerType("ImageSetLayer", [ImageSetLayer, ImageSetLayer$, Layer]);
diff --git a/engine/esm/layers/iss_layer.js b/engine/esm/layers/iss_layer.js
new file mode 100644
index 00000000..ac2e5ab8
--- /dev/null
+++ b/engine/esm/layers/iss_layer.js
@@ -0,0 +1,97 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A layer that adds the International Space Station (ISS) with an up-to-date orbit.
+
+import { ss } from "../ss.js";
+import { registerType } from "../typesystem.js";
+import { Guid } from "../util.js";
+import { Matrix3d, Vector3d } from "../double3d.js";
+import { freestandingMode, tourDocumentFromUrlRaw } from "../data_globals.js";
+import { Colors } from "../color.js";
+import { URLHelpers } from "../url_helpers.js";
+import { Object3dLayer, Object3d } from "./object3d.js";
+
+
+// wwtlib.ISSLayer
+
+export function ISSLayer() {
+ Object3dLayer.call(this);
+ this.id = ISSLayer.issGuid;
+}
+
+ISSLayer.issGuid = Guid.fromString('00000001-0002-0003-0405-060708090a0b');
+ISSLayer._loading$2 = false;
+ISSLayer._issmodel$2 = null;
+ISSLayer._doc$2 = null;
+
+ISSLayer.loadBackground = function () {
+ // The ISS frame cannot be created in freestanding mode, so I'm not
+ // sure if this function will even get called, but just in case, we
+ // make sure to noop if we're in freestanding mode.
+ if (ISSLayer._loading$2 || freestandingMode) {
+ return;
+ }
+ ISSLayer._loading$2 = true;
+ var url = URLHelpers.singleton.coreStaticUrl('data/iss.wtt');
+ ISSLayer._doc$2 = tourDocumentFromUrlRaw(url, function () {
+ ISSLayer.createSpaceStation();
+ });
+};
+
+ISSLayer.createSpaceStation = function () {
+ ISSLayer._doc$2.set_id('28016047-97a9-4b33-a226-cd820262a151');
+ var filename = '0c10ae54-b6da-4282-bfda-f34562d403bc.3ds';
+ var o3d = new Object3d(ISSLayer._doc$2, filename, true, false, true, Colors.get_white());
+ if (o3d != null) {
+ o3d.issLayer = true;
+ ISSLayer._issmodel$2 = o3d;
+ }
+};
+
+var ISSLayer$ = {
+ draw: function (renderContext, opacity, flat) {
+ if (this.object3d == null && ISSLayer._issmodel$2 == null) {
+ if (!ISSLayer._loading$2) {
+ var worldView = Matrix3d.multiplyMatrix(renderContext.get_world(), renderContext.get_view());
+ var v = worldView.transform(Vector3d.get_empty());
+ var scaleFactor = Math.sqrt(worldView.get_m11() * worldView.get_m11() + worldView.get_m22() * worldView.get_m22() + worldView.get_m33() * worldView.get_m33());
+ var dist = v.length();
+ var radius = scaleFactor;
+
+ // Calculate pixelsPerUnit which is the number of pixels covered
+ // by an object 1 AU at the distance of the planet center from
+ // the camera. This calculation works regardless of the projection
+ // type.
+ var viewportHeight = ss.truncate(renderContext.height);
+ var p11 = renderContext.get_projection().get_m11();
+ var p34 = renderContext.get_projection().get_m34();
+ var p44 = renderContext.get_projection().get_m44();
+ var w = Math.abs(p34) * dist + p44;
+ var pixelsPerUnit = (p11 / w) * viewportHeight;
+ var radiusInPixels = (radius * pixelsPerUnit);
+ if (radiusInPixels > 0.5) {
+ ISSLayer.loadBackground();
+ }
+ }
+ }
+ this.object3d = ISSLayer._issmodel$2;
+ return Object3dLayer.prototype.draw.call(this, renderContext, opacity, flat);
+ },
+
+ getPrimaryUI: function () {
+ return null;
+ },
+
+ addFilesToCabinet: function (fc) {
+ return;
+ },
+
+ loadData: function (doc, filename) {
+ return;
+ },
+
+ cleanUp: function () { }
+};
+
+registerType("ISSLayer", [ISSLayer, ISSLayer$, Object3dLayer]);
diff --git a/engine/esm/layers/layer.js b/engine/esm/layers/layer.js
new file mode 100644
index 00000000..486c1637
--- /dev/null
+++ b/engine/esm/layers/layer.js
@@ -0,0 +1,423 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Top-level information about a tour.
+
+import pako from "pako";
+
+import { ss } from "../ss.js";
+import { registerType, registerEnum } from "../typesystem.js";
+import { Util } from "../baseutil.js";
+import { Color, Colors } from "../color.js";
+import { IUiController } from "../interfaces.js";
+import { Guid } from "../util.js";
+
+
+// wwtlib.AltUnits
+
+export var AltUnits = {
+ meters: 1,
+ feet: 2,
+ inches: 3,
+ miles: 4,
+ kilometers: 5,
+ astronomicalUnits: 6,
+ lightYears: 7,
+ parsecs: 8,
+ megaParsecs: 9,
+ custom: 10
+};
+
+registerType("AltUnits", AltUnits);
+registerEnum("AltUnits", AltUnits);
+
+
+// wwtlib.FadeType
+
+export var FadeType = {
+ fadeIn: 1,
+ fadeOut: 2,
+ both: 3,
+ none: 4
+};
+
+registerType("FadeType", FadeType);
+registerEnum("FadeType", FadeType);
+
+
+// wwtlib.DomainValue
+
+export function DomainValue(text, markerIndex) {
+ this.markerIndex = 4;
+ this.customMarker = null;
+ this.text = text;
+ this.markerIndex = markerIndex;
+}
+
+var DomainValue$ = {};
+
+registerType("DomainValue", [DomainValue, DomainValue$, null]);
+
+
+// wwtlib.Layer
+
+export function Layer() {
+ this.id = Guid.newGuid();
+ this.loadedFromTour = false;
+ this.tourDocument = null;
+ this.opacity = 1;
+ this.opened = false;
+ this._startTime = ss.date('01/01/1900');
+ this._endTime = ss.date('01/01/2100');
+ this._fadeSpan = 0;
+ this._fadeType = 4;
+ this.version = 0;
+ this.color = Colors.get_white();
+ this.enabled = true;
+ this.astronomical = false;
+}
+
+var Layer$ = {
+ getPrimaryUI: function () {
+ return null;
+ },
+
+ getFileStreamUrl: function (filename) {
+ if (this.tourDocument != null) {
+ return this.tourDocument.getFileStream(filename);
+ }
+ return null;
+ },
+
+ get_opacity: function () {
+ return this.opacity;
+ },
+
+ set_opacity: function (value) {
+ if (this.opacity !== value) {
+ this.version++;
+ this.opacity = value;
+ }
+ return value;
+ },
+
+ get_opened: function () {
+ return this.opened;
+ },
+
+ set_opened: function (value) {
+ if (this.opened !== value) {
+ this.version++;
+ this.opened = value;
+ }
+ return value;
+ },
+
+ get_startTime: function () {
+ return this._startTime;
+ },
+
+ set_startTime: function (value) {
+ if (!ss.compareDates(this._startTime, value)) {
+ this.version++;
+ this._startTime = value;
+ }
+ return value;
+ },
+
+ get_endTime: function () {
+ return this._endTime;
+ },
+
+ set_endTime: function (value) {
+ if (!ss.compareDates(this._endTime, value)) {
+ this.version++;
+ this._endTime = value;
+ }
+ return value;
+ },
+
+ get_fadeSpan: function () {
+ return this._fadeSpan;
+ },
+
+ set_fadeSpan: function (value) {
+ this.version++;
+ this._fadeSpan = value;
+ return value;
+ },
+
+ get_fadeType: function () {
+ return this._fadeType;
+ },
+
+ set_fadeType: function (value) {
+ if (this._fadeType !== value) {
+ this.set_version(this.get_version() + 1) - 1;
+ this._fadeType = value;
+ }
+ return value;
+ },
+
+ get_version: function () {
+ return this.version;
+ },
+
+ set_version: function (value) {
+ this.version = value;
+ return value;
+ },
+
+ findClosest: function (target, distance, closestPlace, astronomical) {
+ return closestPlace;
+ },
+
+ hoverCheckScreenSpace: function (cursor) {
+ return false;
+ },
+
+ clickCheckScreenSpace: function (cursor) {
+ return false;
+ },
+
+ draw: function (renderContext, opacity, flat) {
+ return true;
+ },
+
+ preDraw: function (renderContext, opacity) {
+ return true;
+ },
+
+ updateData: function (data, purgeOld, purgeAll, hasHeader) {
+ return true;
+ },
+
+ // "updateData" used to be named this. We add this function as a
+ // compatibility shim just in case there's some JavaScript out there
+ // still using the old name.
+ upadteData: function (data, purgeOld, purgeAll, hasHeader) {
+ return this.updateData(data, purgeOld, purgeAll, hasHeader);
+ },
+
+ canCopyToClipboard: function () {
+ return false;
+ },
+
+ copyToClipboard: function () {
+ return;
+ },
+
+ getParams: function () {
+ var paramList = new Array(5);
+ paramList[0] = this.color.r / 255;
+ paramList[1] = this.color.g / 255;
+ paramList[2] = this.color.b / 255;
+ paramList[3] = this.color.a / 255;
+ paramList[4] = this.opacity;
+ return paramList;
+ },
+
+ setParams: function (paramList) {
+ if (paramList.length === 5) {
+ this.opacity = paramList[4];
+ this.color = Color.fromArgb((paramList[3] * 255), (paramList[0] * 255), (paramList[1] * 255), (paramList[2] * 255));
+ }
+ },
+
+ getParamNames: function () {
+ return ['Color.Red', 'Color.Green', 'Color.Blue', 'Color.Alpha', 'Opacity'];
+ },
+
+ getEditUI: function () {
+ return ss.safeCast(this, IUiController);
+ },
+
+ cleanUp: function () { },
+
+ get_name: function () {
+ return this._name;
+ },
+
+ set_name: function (value) {
+ if (this._name !== value) {
+ this.version++;
+ this._name = value;
+ }
+ return value;
+ },
+
+ toString: function () {
+ return this._name;
+ },
+
+ get_referenceFrame: function () {
+ return this.referenceFrame;
+ },
+
+ set_referenceFrame: function (value) {
+ this.referenceFrame = value;
+ return value;
+ },
+
+ getProps: function () {
+ return '';
+ },
+
+ get_color: function () {
+ return this.color;
+ },
+
+ set_color: function (value) {
+ if (this.color !== value) {
+ this.color = value;
+ this.version++;
+ }
+ return value;
+ },
+
+ colorChanged: function () { },
+
+ get_colorValue: function () {
+ return this.get_color().toString();
+ },
+
+ set_colorValue: function (value) {
+ this.set_color(Color.fromName(value));
+ return value;
+ },
+
+ // These named accessor functions were added so that we can support
+ // `enabled` as a "setting" in our TypeScript framework, without breaking
+ // anything that might rely on `this.enabled` being a genuine bool.
+ get_enabled: function () {
+ return this.enabled;
+ },
+
+ set_enabled: function (value) {
+ this.enabled = value;
+ return value;
+ },
+
+ get_astronomical: function () {
+ return this.astronomical;
+ },
+
+ set_astronomical: function (value) {
+ if (this.astronomical !== value) {
+ this.version++;
+ this.astronomical = value;
+ }
+ return value;
+ },
+
+ getTypeName: function () {
+ return 'TerraViewer.Layer';
+ },
+
+ saveToXml: function (xmlWriter) {
+ xmlWriter._writeStartElement('Layer');
+ xmlWriter._writeAttributeString('Id', this.id.toString());
+ xmlWriter._writeAttributeString('Type', this.getTypeName());
+ xmlWriter._writeAttributeString('Name', this.get_name());
+ xmlWriter._writeAttributeString('ReferenceFrame', this.referenceFrame);
+ xmlWriter._writeAttributeString('Color', this.color.save());
+ xmlWriter._writeAttributeString('Opacity', this.opacity.toString());
+ xmlWriter._writeAttributeString('StartTime', Util.xmlDate(this.get_startTime()));
+ xmlWriter._writeAttributeString('EndTime', Util.xmlDate(this.get_endTime()));
+ xmlWriter._writeAttributeString('FadeSpan', this.get_fadeSpan().toString());
+ xmlWriter._writeAttributeString('FadeType', this.get_fadeType().toString());
+ this.writeLayerProperties(xmlWriter);
+ xmlWriter._writeEndElement();
+ },
+
+ writeLayerProperties: function (xmlWriter) {
+ return;
+ },
+
+ initializeFromXml: function (node) { },
+
+ initFromXml: function (node) {
+ this.id = Guid.fromString(node.attributes.getNamedItem('Id').nodeValue);
+ this.set_name(node.attributes.getNamedItem('Name').nodeValue);
+ this.referenceFrame = node.attributes.getNamedItem('ReferenceFrame').nodeValue;
+ this.color = Color.load(node.attributes.getNamedItem('Color').nodeValue);
+ this.opacity = parseFloat(node.attributes.getNamedItem('Opacity').nodeValue);
+ if (node.attributes.getNamedItem('StartTime') != null) {
+ this.set_startTime(new Date(node.attributes.getNamedItem('StartTime').nodeValue));
+ }
+ if (node.attributes.getNamedItem('EndTime') != null) {
+ this.set_endTime(new Date(node.attributes.getNamedItem('EndTime').nodeValue));
+ }
+ if (node.attributes.getNamedItem('FadeSpan') != null) {
+ this.set_fadeSpan(Util.parseTimeSpan(node.attributes.getNamedItem('FadeSpan').nodeValue));
+ }
+ if (node.attributes.getNamedItem('FadeType') != null) {
+ switch (node.attributes.getNamedItem('FadeType').nodeValue) {
+ case 'In':
+ this.set_fadeType(1);
+ break;
+ case 'Out':
+ this.set_fadeType(2);
+ break;
+ case 'Both':
+ this.set_fadeType(3);
+ break;
+ case 'None':
+ this.set_fadeType(4);
+ break;
+ default:
+ break;
+ }
+ }
+ this.initializeFromXml(node);
+ },
+
+ loadData: function (doc, filename) {
+ return;
+ },
+
+ addFilesToCabinet: function (fc) {
+ return;
+ },
+
+ // This method decompresses a blob into a string, and if the string cannot be decompressed
+ // due to an invalid header, we assume the blob is not compressed and return the string
+ // as-is.
+ getStringFromGzipBlob: function (blob, dataReady) {
+ var reader = new FileReader();
+ reader.onloadend = function (e) {
+ var result = '';
+ try {
+ result = pako.inflate(e.target.result, { to: 'string' });
+ }
+ catch (err) {
+ var errString = err.toString();
+ if (errString === 'incorrect header check' || errString === 'unknown compression method') {
+ result = String.fromCharCode.apply(null, new Uint8Array(e.target.result));
+ }
+ else {
+ throw err;
+ }
+ }
+ dataReady(result);
+ };
+ reader.readAsArrayBuffer(blob);
+ }
+};
+
+registerType("Layer", [Layer, Layer$, null]);
+
+
+// wwtlib.LayerCollection
+
+export function LayerCollection() {
+ Layer.call(this);
+}
+
+var LayerCollection$ = {
+ draw: function (renderContext, opacity, flat) {
+ return Layer.prototype.draw.call(this, renderContext, opacity, false);
+ }
+};
+
+registerType("LayerCollection", [LayerCollection, LayerCollection$, Layer]);
diff --git a/engine/esm/layers/layer_manager.js b/engine/esm/layers/layer_manager.js
new file mode 100644
index 00000000..380153f5
--- /dev/null
+++ b/engine/esm/layers/layer_manager.js
@@ -0,0 +1,1747 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Managing the tree of renderer layers.
+
+import { ss } from "../ss.js";
+import { registerType, registerEnum, Enums } from "../typesystem.js";
+import {
+ freestandingMode,
+ globalScriptInterface,
+ globalWWTControl,
+ set_layerManagerGetAllMaps,
+ set_setManagerVisibleLayerList,
+} from "../data_globals.js";
+import { globalRenderContext } from "../render_globals.js";
+import { Vector2d, Vector3d, Matrix3d } from "../double3d.js";
+import { ELL } from "../astrocalc/elliptical.js";
+import { Histogram } from "../utilities/histogram.js";
+import { SimpleInput } from "../utilities/simple_input.js";
+import { ColorPicker } from "../utilities/color_picker.js";
+import { ContextMenuStrip, ToolStripMenuItem, ToolStripSeparator } from "../utilities/context_menu_strip.js";
+import { Color } from "../color.js";
+import { FitsImage } from "./fits_image.js";
+import { ProjectionType } from "../imageset.js";
+import { Planets } from "../planets.js";
+import { Settings } from "../settings.js";
+import { SpaceTimeController } from "../space_time_controller.js";
+import { URLHelpers } from "../url_helpers.js";
+import { Cursor, Language } from "../util.js";
+import { WebFile } from "../web_file.js";
+import { Layer } from "./layer.js";
+import { ReferenceFrame } from "./reference_frame.js";
+import { GreatCirlceRouteLayer } from "./great_circle_route_layer.js";
+import { GridLayer } from "./grid_layer.js";
+import { ImageSetLayer } from "./imageset_layer.js";
+import { ISSLayer } from "./iss_layer.js";
+import { Orbit } from "./orbit.js";
+import { OrbitLayer } from "./orbit_layer.js";
+import { SpreadSheetLayer, PushPin } from "./spreadsheet_layer.js";
+import { VoTableLayer } from "./vo_table_layer.js";
+import { LayerInfo } from "../tours/tour_stop.js";
+import { TourPlayer } from "../tours/tour_player.js";
+
+
+// wwtlib.ReferenceFrames
+
+export var ReferenceFrames = {
+ sky: 0,
+ ecliptic: 1,
+ galactic: 2,
+ sun: 3,
+ mercury: 4,
+ venus: 5,
+ earth: 6,
+ mars: 7,
+ jupiter: 8,
+ saturn: 9,
+ uranus: 10,
+ neptune: 11,
+ pluto: 12,
+ moon: 13,
+ io: 14,
+ europa: 15,
+ ganymede: 16,
+ callisto: 17,
+ custom: 18,
+ identity: 19,
+ sandbox: 20
+};
+
+registerType("ReferenceFrames", ReferenceFrames);
+registerEnum("ReferenceFrames", ReferenceFrames);
+
+
+// wwtlib.LayerManager
+
+export function LayerManager() { }
+
+LayerManager._version = 0;
+LayerManager._tourLayers = false;
+LayerManager._layerMaps = {};
+LayerManager._layerMapsTours = {};
+LayerManager._allMaps = {};
+LayerManager._allMapsTours = {};
+LayerManager._currentMap = 'Earth';
+LayerManager._layerList = {};
+LayerManager._layerListTours = {};
+LayerManager._moonfile = '';
+LayerManager._selectedLayer = null;
+LayerManager._lastMenuClick = new Vector2d();
+
+LayerManager.get_version = function () {
+ return LayerManager._version;
+};
+
+LayerManager.set_version = function (value) {
+ LayerManager._version = value;
+ return value;
+};
+
+LayerManager.get_frameWizardDialog = function () {
+ return LayerManager._frameWizardDialog;
+};
+
+LayerManager.get_dataVizWizardDialog = function () {
+ return LayerManager._dataVizWizardDialog;
+};
+
+LayerManager.get_referenceFramePropsDialog = function () {
+ return LayerManager._referenceFramePropsDialog;
+};
+
+LayerManager.get_greatCircleDlg = function () {
+ return LayerManager._greatCircleDialog;
+};
+
+LayerManager.get_tourLayers = function () {
+ return LayerManager._tourLayers;
+};
+
+LayerManager.set_tourLayers = function (value) {
+ if (LayerManager._tourLayers !== value && !value) {
+ LayerManager._clearLayers();
+ LayerManager._tourLayers = value;
+ LayerManager.loadTree();
+ }
+ else if (LayerManager._tourLayers !== value && !!value) {
+ LayerManager._tourLayers = value;
+ LayerManager.initLayers();
+ }
+ return value;
+};
+
+LayerManager.loadTree = function () {
+ if (globalScriptInterface != null) {
+ globalScriptInterface.refreshLayerManagerNow();
+ }
+};
+
+LayerManager.get_layerMaps = function () {
+ if (LayerManager.get_tourLayers()) {
+ return LayerManager._layerMapsTours;
+ }
+ else {
+ return LayerManager._layerMaps;
+ }
+};
+
+LayerManager.set_layerMaps = function (value) {
+ if (LayerManager.get_tourLayers()) {
+ LayerManager._layerMapsTours = value;
+ }
+ else {
+ LayerManager._layerMaps = value;
+ }
+ return value;
+};
+
+LayerManager.get_allMaps = function () {
+ if (LayerManager.get_tourLayers()) {
+ return LayerManager._allMapsTours;
+ }
+ else {
+ return LayerManager._allMaps;
+ }
+};
+
+set_layerManagerGetAllMaps(LayerManager.get_allMaps);
+
+LayerManager.set_allMaps = function (value) {
+ if (LayerManager.get_tourLayers()) {
+ LayerManager._allMapsTours = value;
+ }
+ else {
+ LayerManager._allMaps = value;
+ }
+ return value;
+};
+
+LayerManager.get_currentMap = function () {
+ return LayerManager._currentMap;
+};
+
+LayerManager.set_currentMap = function (value) {
+ LayerManager._currentMap = value;
+ return value;
+};
+
+LayerManager.get_layerList = function () {
+ if (LayerManager.get_tourLayers()) {
+ return LayerManager._layerListTours;
+ }
+ else {
+ return LayerManager._layerList;
+ }
+};
+
+LayerManager.set_layerList = function (value) {
+ if (LayerManager.get_tourLayers()) {
+ LayerManager._layerListTours = value;
+ }
+ else {
+ LayerManager._layerList = value;
+ }
+ return value;
+};
+
+// This function *can* be called multiple times safely, but it only
+// needs to be called once upon app startup. The `InitLayers` function
+// can be called more than once, if/when the `TourLayers` setting is
+// toggled.
+LayerManager.oneTimeInitialization = function () {
+ if (LayerManager._webFileMoons == null) {
+ LayerManager.getMoonFile(URLHelpers.singleton.engineAssetUrl('moons.txt'));
+ }
+ PushPin.triggerLoadSprite();
+};
+
+LayerManager.initLayers = function () {
+ LayerManager._clearLayers();
+ var iss = null;
+ var doISS = !LayerManager.get_tourLayers() && !freestandingMode;
+ if (doISS) {
+ iss = new LayerMap('ISS', 18);
+ iss.frame.epoch = SpaceTimeController._twoLineDateToJulian('10184.51609218');
+ iss.frame.semiMajorAxis = 6728829.41;
+ iss.frame.referenceFrameType = 1;
+ iss.frame.inclination = 51.6442;
+ iss.frame.longitudeOfAscendingNode = 147.0262;
+ iss.frame.eccentricity = 0.0009909;
+ iss.frame.meanAnomolyAtEpoch = 325.5563;
+ iss.frame.meanDailyMotion = 360 * 15.72172655;
+ iss.frame.argumentOfPeriapsis = 286.4623;
+ iss.frame.scale = 1;
+ iss.frame.semiMajorAxisUnits = 1;
+ iss.frame.meanRadius = 130;
+ iss.frame.oblateness = 0;
+ iss.frame.showOrbitPath = true;
+ var isstle = new Array(0);
+
+ //This is downloaded now on startup
+ var url = URLHelpers.singleton.coreDynamicUrl('wwtweb/isstle.aspx');
+ var webFile;
+ webFile = new WebFile(url);
+ webFile.onStateChange = function () {
+ if (webFile.get_state() === 1) {
+ var data = webFile.getText();
+ isstle = data.split('\n');
+ if (isstle.length > 1) {
+ iss.frame.fromTLE(isstle[0], isstle[1], 398600441800000);
+ }
+ }
+ };
+ webFile.send();
+ iss.enabled = true;
+ }
+ LayerManager.get_layerMaps()['Sun'] = new LayerMap('Sun', 3);
+ LayerManager.get_layerMaps()['Sun'].addChild(new LayerMap('Mercury', 4));
+ LayerManager.get_layerMaps()['Sun'].addChild(new LayerMap('Venus', 5));
+ LayerManager.get_layerMaps()['Sun'].addChild(new LayerMap('Earth', 6));
+ LayerManager.get_layerMaps()['Sun'].childMaps['Earth'].addChild(new LayerMap('Moon', 13));
+ if (doISS) {
+ LayerManager.get_layerMaps()['Sun'].childMaps['Earth'].addChild(iss);
+ }
+ LayerManager.get_layerMaps()['Sun'].addChild(new LayerMap('Mars', 7));
+ LayerManager.get_layerMaps()['Sun'].addChild(new LayerMap('Jupiter', 8));
+ LayerManager.get_layerMaps()['Sun'].childMaps['Jupiter'].addChild(new LayerMap('Io', 14));
+ LayerManager.get_layerMaps()['Sun'].childMaps['Jupiter'].addChild(new LayerMap('Europa', 15));
+ LayerManager.get_layerMaps()['Sun'].childMaps['Jupiter'].addChild(new LayerMap('Ganymede', 16));
+ LayerManager.get_layerMaps()['Sun'].childMaps['Jupiter'].addChild(new LayerMap('Callisto', 17));
+ LayerManager.get_layerMaps()['Sun'].addChild(new LayerMap('Saturn', 9));
+ LayerManager.get_layerMaps()['Sun'].addChild(new LayerMap('Uranus', 10));
+ LayerManager.get_layerMaps()['Sun'].addChild(new LayerMap('Neptune', 11));
+ LayerManager.get_layerMaps()['Sun'].addChild(new LayerMap('Pluto', 12));
+ LayerManager._addMoons(LayerManager._moonfile);
+ LayerManager.get_layerMaps()['Sky'] = new LayerMap('Sky', 0);
+ LayerManager.get_layerMaps()['Sun'].open = true;
+ LayerManager._allMaps = {};
+ LayerManager._addAllMaps(LayerManager.get_layerMaps(), null);
+ if (doISS) {
+ LayerManager._addIss();
+ }
+ LayerManager._version++;
+ LayerManager.loadTree();
+};
+
+LayerManager._addIss = function () {
+ var layer = new ISSLayer();
+ layer.set_name(Language.getLocalizedText(1314, 'ISS Model (Toshiyuki Takahei)'));
+ layer.enabled = Settings.get_active().get_showISSModel();
+ LayerManager.get_layerList()[layer.id] = layer;
+ layer.set_referenceFrame('ISS');
+ LayerManager.get_allMaps()['ISS'].layers.push(layer);
+ LayerManager.get_allMaps()['ISS'].open = true;
+};
+
+LayerManager._addAllMaps = function (maps, parent) {
+ var $enum1 = ss.enumerate(ss.keys(maps));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var map = maps[key];
+ map.frame.parent = parent;
+ LayerManager.get_allMaps()[map.get_name()] = map;
+ LayerManager._addAllMaps(map.childMaps, map.get_name());
+ }
+};
+
+LayerManager._clearLayers = function () {
+ var $enum1 = ss.enumerate(ss.keys(LayerManager.get_layerList()));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var layer = LayerManager.get_layerList()[key];
+ layer.cleanUp();
+ }
+ ss.clearKeys(LayerManager.get_layerList());
+ ss.clearKeys(LayerManager.get_layerMaps());
+};
+
+LayerManager.getMoonFile = function (url) {
+ LayerManager._webFileMoons = new WebFile(url);
+ LayerManager._webFileMoons.onStateChange = LayerManager.moonFileStateChange;
+ LayerManager._webFileMoons.send();
+};
+
+LayerManager.moonFileStateChange = function () {
+ if (LayerManager._webFileMoons.get_state() === 2) {
+ alert(LayerManager._webFileMoons.get_message());
+ }
+ else if (LayerManager._webFileMoons.get_state() === 1) {
+ LayerManager._moonfile = LayerManager._webFileMoons.getText();
+ LayerManager.initLayers();
+ }
+};
+
+LayerManager._addMoons = function (file) {
+ var data = file.split('\r\n');
+ var first = true;
+ var $enum1 = ss.enumerate(data);
+ while ($enum1.moveNext()) {
+ var line = $enum1.current;
+ if (first) {
+ first = false;
+ continue;
+ }
+ var parts = line.split('\t');
+ if (parts.length > 16) {
+ var planet = parts[0];
+ var frame = new LayerMap(parts[2], 18);
+ frame.frame._systemGenerated = true;
+ frame.frame.epoch = parseFloat(parts[1]);
+ frame.frame.semiMajorAxis = parseFloat(parts[3]) * 1000;
+ frame.frame.referenceFrameType = 1;
+ frame.frame.inclination = parseFloat(parts[7]);
+ frame.frame.longitudeOfAscendingNode = parseFloat(parts[8]);
+ frame.frame.eccentricity = parseFloat(parts[4]);
+ frame.frame.meanAnomolyAtEpoch = parseFloat(parts[6]);
+ frame.frame.meanDailyMotion = parseFloat(parts[9]);
+ frame.frame.argumentOfPeriapsis = parseFloat(parts[5]);
+ frame.frame.scale = 1;
+ frame.frame.semiMajorAxisUnits = 1;
+ frame.frame.meanRadius = parseFloat(parts[16]) * 1000;
+ frame.frame.rotationalPeriod = parseFloat(parts[17]);
+ frame.frame.showAsPoint = false;
+ frame.frame.showOrbitPath = true;
+ frame.frame.set_representativeColor(Color.fromArgb(255, 175, 216, 230));
+ frame.frame.oblateness = 0;
+ LayerManager.get_layerMaps()['Sun'].childMaps[planet].addChild(frame);
+ }
+ }
+};
+
+LayerManager.addVoTableLayer = function (table, title) {
+ return LayerManager.addVoTableLayerWithPlotType(table, title, 2);
+};
+
+LayerManager.addVoTableLayerWithPlotType = function (table, title, plotType) {
+ var layer = VoTableLayer.create(table, plotType);
+ layer.set_name(title);
+ layer.set_astronomical(true);
+ layer.set_referenceFrame('Sky');
+ LayerManager.get_layerList()[layer.id] = layer;
+ LayerManager.get_allMaps()['Sky'].layers.push(layer);
+ LayerManager.get_allMaps()['Sky'].open = true;
+ layer.enabled = true;
+ LayerManager._version++;
+ LayerManager.loadTree();
+ return layer;
+};
+
+LayerManager.addImageSetLayer = function (imageset, title) {
+ var layer = ImageSetLayer.create(imageset);
+ return LayerManager.addFitsImageSetLayer(layer, title);
+};
+
+LayerManager.addImageSetLayerCallback = function (imageset, title, callback) {
+ var layer = ImageSetLayer.create(imageset);
+
+ // The tile rendering codepaths require that "Extension" is exactly
+ // .fits -- multiple extensions are not currently supported.
+ var isNonHipsTiledFits =
+ imageset.get_extension() === '.fits' &&
+ layer.getFitsImage() == null &&
+ imageset.get_projection() !== ProjectionType.healpix;
+
+ // The goal here is to fire the callback once the initial imageset
+ // data have loaded. In particular, for FITS-type imagesets, we
+ // inevitably need to download some data in order to figure out
+ // parameters like FitsProperties.LowerCut.
+ //
+ // At the moment, this is only wired up correctly for non-HiPS tiled
+ // FITS. In a pretty egregious hack, the OnMainImageLoaded callback
+ // below will be fired once the level-0 FITS tile is loaded. We
+ // basically needed to add this new callback hook because there
+ // wasn't any other way to get something to fire when the level-0
+ // tile data actually arrive.
+ //
+ // HiPS FITS datasets will *eventually* get the right FitsProperties
+ // because the fetch of the HipsProperties data sets this up. (This
+ // is triggered by the HipsProperties constructor, used in
+ // Imageset.GetNewTile.) But the timing of the callback here is
+ // uncorrelated with that process. The same is broadly true for
+ // untiled FITS. This function should be improved to make sure that
+ // the callback argument gets fired at the right time for such
+ // datasets.
+
+ if (isNonHipsTiledFits) {
+ imageset.get_fitsProperties().onMainImageLoaded = function (image) {
+ image.applyDisplaySettings();
+ if (callback != null) {
+ callback(layer);
+ }
+ };
+ }
+ LayerManager.addFitsImageSetLayer(layer, title);
+
+ // For everything not yet handled, just trigger the callback now, if
+ // needed.
+ if (callback != null && (!isNonHipsTiledFits || imageset.get_fitsProperties().mainImageLoadedEventHasFired)) {
+ callback(layer);
+ }
+
+ return layer;
+};
+
+// This method is somewhat misnamed - there's nothing FITS-specific about it.
+LayerManager.addFitsImageSetLayer = function (layer, title) {
+ layer.doneLoading(null);
+ layer.set_name(title);
+ layer.set_astronomical(true);
+ layer.set_referenceFrame('Sky');
+ LayerManager.get_layerList()[layer.id] = layer;
+ LayerManager.get_allMaps()['Sky'].layers.push(layer);
+ LayerManager.get_allMaps()['Sky'].open = true;
+ layer.enabled = true;
+ LayerManager._version++;
+ LayerManager.loadTree();
+ return layer;
+};
+
+LayerManager.getNextFitsName = function () {
+ return LayerManager._getNextName('Fits Image');
+};
+
+LayerManager.getNextImageSetName = function () {
+ return LayerManager._getNextName('Image Set');
+};
+
+LayerManager._getNextName = function (type) {
+ var currentNumber = 0;
+ var $enum1 = ss.enumerate(ss.keys(LayerManager.get_allMaps()));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var $enum2 = ss.enumerate(LayerManager.get_allMaps()[key].layers);
+ while ($enum2.moveNext()) {
+ var layer = $enum2.current;
+ if (ss.startsWith(layer.get_name(), type + ' ')) {
+ var number = ss.replaceString(layer.get_name(), type + ' ', '');
+ try {
+ var num = parseInt(number);
+ if (num > currentNumber) {
+ currentNumber = num;
+ }
+ }
+ catch ($e3) {
+ }
+ }
+ }
+ }
+ return ss.format('{0} {1}', type, currentNumber + 1);
+};
+
+LayerManager._closeAllTourLoadedLayers = function () {
+ var purgeTargets = [];
+ var $enum1 = ss.enumerate(ss.keys(LayerManager.get_layerList()));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var layer = LayerManager.get_layerList()[key];
+ if (layer.loadedFromTour) {
+ purgeTargets.push(layer.id);
+ }
+ }
+ var $enum2 = ss.enumerate(purgeTargets);
+ while ($enum2.moveNext()) {
+ var guid = $enum2.current;
+ LayerManager.deleteLayerByID(guid, true, false);
+ }
+ var purgeMapsNames = [];
+ var $enum3 = ss.enumerate(ss.keys(LayerManager.get_allMaps()));
+ while ($enum3.moveNext()) {
+ var key = $enum3.current;
+ var map = LayerManager.get_allMaps()[key];
+ if (map.loadedFromTour && !map.layers.length) {
+ purgeMapsNames.push(map.get_name());
+ }
+ }
+ var $enum4 = ss.enumerate(purgeMapsNames);
+ while ($enum4.moveNext()) {
+ var name = $enum4.current;
+ LayerManager.purgeLayerMapDeep(LayerManager.get_allMaps()[name], true);
+ }
+ LayerManager.set_version(LayerManager.get_version() + 1) - 1;
+ LayerManager.loadTree();
+};
+
+LayerManager.purgeLayerMapDeep = function (target, topLevel) {
+ var $enum1 = ss.enumerate(target.layers);
+ while ($enum1.moveNext()) {
+ var layer = $enum1.current;
+ LayerManager.deleteLayerByID(layer.id, false, false);
+ }
+ target.layers.length = 0;
+ var $enum2 = ss.enumerate(ss.keys(target.childMaps));
+ while ($enum2.moveNext()) {
+ var key = $enum2.current;
+ var map = target.childMaps[key];
+ LayerManager.purgeLayerMapDeep(map, false);
+ }
+ ss.clearKeys(target.childMaps);
+ if (topLevel) {
+ if (!ss.emptyString(target.frame.parent)) {
+ if (ss.keyExists(LayerManager.get_allMaps(), target.frame.parent)) {
+ delete LayerManager.get_allMaps()[target.frame.parent].childMaps[target.get_name()];
+ }
+ } else {
+ if (ss.keyExists(LayerManager.get_layerMaps(), target.get_name())) {
+ delete LayerManager.get_layerMaps()[target.get_name()];
+ }
+ }
+ }
+ delete LayerManager.get_allMaps()[target.get_name()];
+ LayerManager._version++;
+};
+
+LayerManager._cleanAllTourLoadedLayers = function () {
+ var $enum1 = ss.enumerate(ss.keys(LayerManager.get_layerList()));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var layer = LayerManager.get_layerList()[key];
+ if (layer.loadedFromTour) {
+ layer.loadedFromTour = false;
+ }
+ }
+};
+
+// Merge layers from Tour Player Alternate universe into the real layer manager layers list
+LayerManager.mergeToursLayers = function () {
+ LayerManager._tourLayers = false;
+ var OverWrite = false;
+ var CollisionChecked = false;
+ var $enum1 = ss.enumerate(ss.keys(LayerManager._allMapsTours));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var map = LayerManager._allMapsTours[key];
+ if (!ss.keyExists(LayerManager._allMaps, map.get_name())) {
+ var newMap = new LayerMap(map.get_name(), 18);
+ newMap.frame = map.frame;
+ newMap.loadedFromTour = true;
+ LayerManager.get_allMaps()[newMap.get_name()] = newMap;
+ }
+ }
+ LayerManager.connectAllChildren();
+ var $enum2 = ss.enumerate(ss.keys(LayerManager._layerListTours));
+ while ($enum2.moveNext()) {
+ var key = $enum2.current;
+ var layer = LayerManager._layerListTours[key];
+ if (ss.keyExists(LayerManager.get_layerList(), layer.id)) {
+ if (!CollisionChecked) {
+ OverWrite = true;
+ CollisionChecked = true;
+ }
+ if (OverWrite) {
+ LayerManager.deleteLayerByID(layer.id, true, false);
+ }
+ }
+ if (!ss.keyExists(LayerManager.get_layerList(), layer.id)) {
+ if (ss.keyExists(LayerManager.get_allMaps(), layer.get_referenceFrame())) {
+ LayerManager.get_layerList()[layer.id] = layer;
+ LayerManager.get_allMaps()[layer.get_referenceFrame()].layers.push(layer);
+ }
+ } else {
+ layer.cleanUp();
+ }
+ }
+ ss.clearKeys(LayerManager._layerListTours);
+ ss.clearKeys(LayerManager._allMapsTours);
+ ss.clearKeys(LayerManager._layerMapsTours);
+ LayerManager.loadTree();
+};
+
+LayerManager.connectAllChildren = function () {
+ var $enum1 = ss.enumerate(ss.keys(LayerManager.get_allMaps()));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var map = LayerManager.get_allMaps()[key];
+ if (ss.emptyString(map.frame.parent) && !ss.keyExists(LayerManager.get_layerMaps(), map.frame.name)) {
+ LayerManager.get_layerMaps()[map.get_name()] = map;
+ } else if (!ss.emptyString(map.frame.parent) && ss.keyExists(LayerManager.get_allMaps(), map.frame.parent)) {
+ if (!ss.keyExists(LayerManager.get_allMaps()[map.frame.parent].childMaps, map.frame.name)) {
+ LayerManager.get_allMaps()[map.frame.parent].childMaps[map.frame.name] = map;
+ map.parent = LayerManager.get_allMaps()[map.frame.parent];
+ }
+ }
+ }
+};
+
+LayerManager.deleteLayerByID = function (ID, removeFromParent, updateTree) {
+ if (ss.keyExists(LayerManager.get_layerList(), ID)) {
+ var layer = LayerManager.get_layerList()[ID];
+ layer.cleanUp();
+ if (removeFromParent) {
+ ss.remove(LayerManager.get_allMaps()[layer.get_referenceFrame()].layers, layer);
+ }
+ delete LayerManager.get_layerList()[ID];
+ LayerManager._version++;
+ if (updateTree) {
+ LayerManager.loadTree();
+ }
+ return true;
+ }
+ else {
+ return false;
+ }
+};
+
+LayerManager._getFrameTarget = function (renderContext, TrackingFrame) {
+ var target = new FrameTarget();
+ var targetPoint = Vector3d.get_empty();
+ target.target = Vector3d.get_empty();
+ target.matrix = Matrix3d.get_identity();
+ if (!ss.keyExists(LayerManager.get_allMaps(), TrackingFrame)) {
+ return target;
+ }
+ var mapList = [];
+ var current = LayerManager.get_allMaps()[TrackingFrame];
+ mapList.push(current);
+ while (current.frame.reference === 18) {
+ current = current.parent;
+ mapList.splice(0, 0, current);
+ }
+ var matOld = renderContext.get_world().clone();
+ var matOldNonRotating = renderContext.get_worldBaseNonRotating();
+ var matOldBase = renderContext.get_worldBase();
+ var oldNominalRadius = renderContext.get_nominalRadius();
+ var $enum1 = ss.enumerate(mapList);
+ while ($enum1.moveNext()) {
+ var map = $enum1.current;
+ if (map.frame.reference !== 18 && map.frame.reference !== 20) {
+ Planets.setupPlanetMatrix(renderContext, Enums.parse('SolarSystemObjects', map.frame.name), Vector3d.get_empty(), false);
+ } else {
+ map.computeFrame(renderContext);
+ if (map.frame.useRotatingParentFrame()) {
+ renderContext.set_world(Matrix3d.multiplyMatrix(map.frame.worldMatrix, renderContext.get_world()));
+ }
+ else {
+ renderContext.set_world(Matrix3d.multiplyMatrix(map.frame.worldMatrix, renderContext.get_worldBaseNonRotating()));
+ }
+ if (map.frame.referenceFrameType === 3) {
+ renderContext.set_worldBaseNonRotating(renderContext.get_world().clone());
+ }
+ renderContext.set_nominalRadius(map.frame.meanRadius);
+ }
+ }
+ targetPoint = renderContext.get_world().transform(targetPoint);
+ var lookAt = renderContext.get_world().transform(Vector3d.create(0, 0, 1));
+ var lookUp = Vector3d.subtractVectors(renderContext.get_world().transform(Vector3d.create(0, 1, 0)), targetPoint);
+ lookUp.normalize();
+ target.matrix = Matrix3d.lookAtLH(new Vector3d(), Vector3d.subtractVectors(lookAt, targetPoint), lookUp);
+ renderContext.set_nominalRadius(oldNominalRadius);
+ renderContext.set_world(matOld);
+ renderContext.set_worldBaseNonRotating(matOldNonRotating);
+ renderContext.set_worldBase(matOldBase);
+ target.target = targetPoint;
+ return target;
+};
+
+LayerManager._prepTourLayers = function () {
+ if (TourPlayer.get_playing()) {
+ var player = globalWWTControl.uiController;
+ if (player != null) {
+ var tour = player.get_tour();
+ if (tour.get_currentTourStop() != null) {
+ player.updateTweenPosition(-1);
+ if (!tour.get_currentTourStop().get_keyFramed()) {
+ tour.get_currentTourStop()._updateLayerOpacity();
+ var $enum1 = ss.enumerate(ss.keys(tour.get_currentTourStop().layers));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var info = tour.get_currentTourStop().layers[key];
+ if (ss.keyExists(LayerManager.get_layerList(), info.id)) {
+ LayerManager.get_layerList()[info.id].set_opacity(info.frameOpacity);
+ LayerManager.get_layerList()[info.id].setParams(info.frameParams);
+ }
+ }
+ }
+ }
+ }
+ }
+};
+
+LayerManager._draw = function (renderContext, opacity, astronomical, referenceFrame, nested, cosmos) {
+ if (!ss.keyExists(LayerManager.get_allMaps(), referenceFrame)) {
+ return;
+ }
+ var thisMap = LayerManager.get_allMaps()[referenceFrame];
+ if (!thisMap.enabled || (!ss.keyCount(thisMap.childMaps) && !thisMap.layers.length && !(thisMap.frame.showAsPoint || thisMap.frame.showOrbitPath))) {
+ return;
+ }
+ if (TourPlayer.get_playing()) {
+ var player = globalWWTControl.uiController;
+ if (player != null) {
+ var tour = player.get_tour();
+ if (tour.get_currentTourStop() != null) {
+ player.updateTweenPosition(-1);
+ tour.get_currentTourStop()._updateLayerOpacity();
+ var $enum1 = ss.enumerate(ss.keys(tour.get_currentTourStop().layers));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var info = tour.get_currentTourStop().layers[key];
+ if (ss.keyExists(LayerManager.get_layerList(), info.id)) {
+ LayerManager.get_layerList()[info.id].set_opacity(info.frameOpacity);
+ LayerManager.get_layerList()[info.id].setParams(info.frameParams);
+ }
+ }
+ }
+ }
+ }
+ var matOld = renderContext.get_world();
+ var matOldNonRotating = renderContext.get_worldBaseNonRotating();
+ var oldNominalRadius = renderContext.get_nominalRadius();
+ if ((thisMap.frame.reference === 18 | thisMap.frame.reference === 18) === 1) {
+ thisMap.computeFrame(renderContext);
+ if (thisMap.frame.referenceFrameType !== 1 && thisMap.frame.referenceFrameType !== 2) {
+ renderContext.set_world(Matrix3d.multiplyMatrix(thisMap.frame.worldMatrix, renderContext.get_world()));
+ } else {
+ renderContext.set_world(Matrix3d.multiplyMatrix(thisMap.frame.worldMatrix, renderContext.get_worldBaseNonRotating()));
+ }
+ renderContext.set_nominalRadius(thisMap.frame.meanRadius);
+ }
+ if (thisMap.frame.showAsPoint) {
+ // todo Draw point planet...
+ // Planets.DrawPointPlanet(renderContext.Device, new Vector3d(0, 0, 0), (float).2, thisMap.Frame.RepresentativeColor, true);
+ }
+ for (var pass = 0; pass < 2; pass++) {
+ var $enum2 = ss.enumerate(LayerManager.get_allMaps()[referenceFrame].layers);
+ while ($enum2.moveNext()) {
+ var layer = $enum2.current;
+ if ((!pass && ss.canCast(layer, ImageSetLayer)) || (pass === 1 && !(ss.canCast(layer, ImageSetLayer)))) {
+ var skipLayer = false;
+ if (!pass) {
+ // Skip default image set layer so that it's not drawn twice
+ skipLayer = !astronomical && (layer).get_overrideDefaultLayer();
+ }
+ if (layer.enabled && !skipLayer) {
+ var layerStart = SpaceTimeController.utcToJulian(layer.get_startTime());
+ var layerEnd = SpaceTimeController.utcToJulian(layer.get_endTime());
+ var fadeIn = SpaceTimeController.utcToJulian(layer.get_startTime()) - ((layer.get_fadeType() === 1 || layer.get_fadeType() === 3) ? (layer.get_fadeSpan() / 864000000) : 0);
+ var fadeOut = SpaceTimeController.utcToJulian(layer.get_endTime()) + ((layer.get_fadeType() === 2 || layer.get_fadeType() === 3) ? (layer.get_fadeSpan() / 864000000) : 0);
+ if (SpaceTimeController.get_jNow() > fadeIn && SpaceTimeController.get_jNow() < fadeOut) {
+ var fadeOpacity = 1;
+ if (SpaceTimeController.get_jNow() < layerStart) {
+ fadeOpacity = ((SpaceTimeController.get_jNow() - fadeIn) / (layer.get_fadeSpan() / 864000000));
+ }
+ if (SpaceTimeController.get_jNow() > layerEnd) {
+ fadeOpacity = ((fadeOut - SpaceTimeController.get_jNow()) / (layer.get_fadeSpan() / 864000000));
+ }
+ layer.set_astronomical(astronomical);
+ if (ss.canCast(layer, SpreadSheetLayer)) {
+ var tsl = ss.safeCast(layer, SpreadSheetLayer);
+ tsl.draw(renderContext, opacity * fadeOpacity, cosmos);
+ }
+ else {
+ layer.draw(renderContext, opacity * fadeOpacity, cosmos);
+ }
+ }
+ }
+ }
+ }
+ }
+ if (nested) {
+ var $enum3 = ss.enumerate(ss.keys(LayerManager.get_allMaps()[referenceFrame].childMaps));
+ while ($enum3.moveNext()) {
+ var key = $enum3.current;
+ var map = LayerManager.get_allMaps()[referenceFrame].childMaps[key];
+ if (!(ss.canCast(map, LayerMap))) {
+ continue;
+ }
+ if (map.enabled && map.frame.showOrbitPath && Settings.get_active().get_solarSystemOrbits() && Settings.get_active().get_solarSystemMinorOrbits()) {
+ if (map.frame.referenceFrameType === 1) {
+ if (map.frame.get_orbit() == null) {
+ map.frame.set_orbit(new Orbit(map.frame.get_elements(), 360, map.frame.get_representativeColor(), 1, map.parent.frame.meanRadius));
+ }
+ var matSaved = renderContext.get_world();
+ renderContext.set_world(Matrix3d.multiplyMatrix(thisMap.frame.worldMatrix, renderContext.get_worldBaseNonRotating()));
+ map.frame.get_orbit().draw3D(renderContext, 1 * 0.5, Vector3d.create(0, 0, 0));
+ renderContext.set_world(matSaved);
+ }
+ else if (map.frame.referenceFrameType === 2) {
+ }
+ }
+ if ((map.frame.reference === 18 || map.frame.reference === 19)) {
+ LayerManager._draw(renderContext, opacity, astronomical, map.get_name(), nested, cosmos);
+ }
+ }
+ }
+ renderContext.set_nominalRadius(oldNominalRadius);
+ renderContext.set_world(matOld);
+ renderContext.set_worldBaseNonRotating(matOldNonRotating);
+};
+
+LayerManager._getVisibleLayerList = function (previous) {
+ var list = {};
+ var $enum1 = ss.enumerate(ss.keys(LayerManager.get_layerList()));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var layer = LayerManager.get_layerList()[key];
+ if (layer.enabled) {
+ var info = new LayerInfo();
+ info.startOpacity = info.endOpacity = layer.get_opacity();
+ info.id = layer.id;
+ info.startParams = layer.getParams();
+ if (ss.keyExists(previous, info.id)) {
+ info.endOpacity = previous[info.id].endOpacity;
+ info.endParams = previous[info.id].endParams;
+ }
+ else {
+ info.endParams = layer.getParams();
+ }
+ list[layer.id] = info;
+ }
+ }
+ return list;
+};
+
+LayerManager.setVisibleLayerList = function (list) {
+ var $enum1 = ss.enumerate(ss.keys(LayerManager.get_layerList()));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var layer = LayerManager.get_layerList()[key];
+ layer.enabled = ss.keyExists(list, layer.id);
+ try {
+ if (layer.enabled) {
+ layer.set_opacity(list[layer.id].frameOpacity);
+ layer.setParams(list[layer.id].frameParams);
+ }
+ }
+ catch ($e2) {
+ }
+ }
+};
+
+set_setManagerVisibleLayerList(LayerManager.setVisibleLayerList);
+
+LayerManager._preDraw = function (renderContext, opacity, astronomical, referenceFrame, nested) {
+ if (!ss.keyExists(LayerManager.get_allMaps(), referenceFrame)) {
+ return;
+ }
+ var thisMap = LayerManager.get_allMaps()[referenceFrame];
+ if (!ss.keyCount(thisMap.childMaps) && !thisMap.layers.length) {
+ return;
+ }
+ if (TourPlayer.get_playing()) {
+ var player = ss.safeCast(globalWWTControl.uiController, TourPlayer);
+ if (player != null) {
+ var tour = player.get_tour();
+ if (tour.get_currentTourStop() != null) {
+ player.updateTweenPosition(-1);
+ tour.get_currentTourStop()._updateLayerOpacity();
+ var $enum1 = ss.enumerate(ss.keys(tour.get_currentTourStop().layers));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var info = tour.get_currentTourStop().layers[key];
+ if (ss.keyExists(LayerManager.get_layerList(), info.id)) {
+ LayerManager.get_layerList()[info.id].set_opacity(info.frameOpacity);
+ LayerManager.get_layerList()[info.id].setParams(info.frameParams);
+ }
+ }
+ }
+ }
+ }
+ var matOld = renderContext.get_world();
+ var matOldNonRotating = renderContext.get_worldBaseNonRotating();
+ var oldNominalRadius = renderContext.get_nominalRadius();
+ if (thisMap.frame.reference === 18) {
+ thisMap.computeFrame(renderContext);
+ if (thisMap.frame.referenceFrameType !== 1) {
+ renderContext.set_world(Matrix3d.multiplyMatrix(thisMap.frame.worldMatrix, renderContext.get_world()));
+ } else {
+ renderContext.set_world(Matrix3d.multiplyMatrix(thisMap.frame.worldMatrix, renderContext.get_worldBaseNonRotating()));
+ }
+ renderContext.set_nominalRadius(thisMap.frame.meanRadius);
+ }
+ for (var pass = 0; pass < 2; pass++) {
+ var $enum2 = ss.enumerate(LayerManager.get_allMaps()[referenceFrame].layers);
+ while ($enum2.moveNext()) {
+ var layer = $enum2.current;
+ if ((!pass && ss.canCast(layer, ImageSetLayer)) || (pass === 1 && !(ss.canCast(layer, ImageSetLayer)))) {
+ if (layer.enabled) {
+ var layerStart = SpaceTimeController.utcToJulian(layer.get_startTime());
+ var layerEnd = SpaceTimeController.utcToJulian(layer.get_endTime());
+ var fadeIn = SpaceTimeController.utcToJulian(layer.get_startTime()) - ((layer.get_fadeType() === 1 || layer.get_fadeType() === 3) ? (layer.get_fadeSpan() / 864000000) : 0);
+ var fadeOut = SpaceTimeController.utcToJulian(layer.get_endTime()) + ((layer.get_fadeType() === 2 || layer.get_fadeType() === 3) ? (layer.get_fadeSpan() / 864000000) : 0);
+ if (SpaceTimeController.get_jNow() > fadeIn && SpaceTimeController.get_jNow() < fadeOut) {
+ var fadeOpacity = 1;
+ if (SpaceTimeController.get_jNow() < layerStart) {
+ fadeOpacity = ((SpaceTimeController.get_jNow() - fadeIn) / (layer.get_fadeSpan() / 864000000));
+ }
+ if (SpaceTimeController.get_jNow() > layerEnd) {
+ fadeOpacity = ((fadeOut - SpaceTimeController.get_jNow()) / (layer.get_fadeSpan() / 864000000));
+ }
+ if (!thisMap.frame.reference) {
+ layer.set_astronomical(true);
+ }
+ layer.preDraw(renderContext, opacity * fadeOpacity);
+ }
+ }
+ }
+ }
+ }
+ if (nested) {
+ var $enum3 = ss.enumerate(ss.keys(LayerManager.get_allMaps()[referenceFrame].childMaps));
+ while ($enum3.moveNext()) {
+ var key = $enum3.current;
+ var map = LayerManager.get_allMaps()[referenceFrame].childMaps[key];
+ if ((map.frame.reference === 18 || map.frame.reference === 19)) {
+ LayerManager._preDraw(renderContext, opacity, astronomical, map.get_name(), nested);
+ }
+ }
+ }
+ renderContext.set_nominalRadius(oldNominalRadius);
+ renderContext.set_world(matOld);
+ renderContext.set_worldBaseNonRotating(matOldNonRotating);
+};
+
+LayerManager.add = function (layer, updateTree) {
+ if (!ss.keyExists(LayerManager.get_layerList(), layer.id)) {
+ if (ss.keyExists(LayerManager.get_allMaps(), layer.get_referenceFrame())) {
+ LayerManager.get_layerList()[layer.id] = layer;
+ LayerManager.get_allMaps()[layer.get_referenceFrame()].layers.push(layer);
+ LayerManager._version++;
+ if (updateTree) {
+ LayerManager.loadTree();
+ }
+ }
+ }
+};
+
+LayerManager.layerSelectionChanged = function (selected) {
+ LayerManager._selectedLayer = selected;
+ if (LayerManager._selectedLayer != null) {
+ if (ss.canCast(LayerManager._selectedLayer, LayerMap)) {
+ var map = ss.safeCast(LayerManager._selectedLayer, LayerMap);
+ if (map != null) {
+ LayerManager.set_currentMap(map.get_name());
+ }
+ } else {
+ var layer = ss.safeCast(LayerManager._selectedLayer, ImageSetLayer);
+ if (layer != null && ss.canCast(layer.get_imageSet().get_wcsImage(), FitsImage)) {
+ return;
+ }
+ }
+ }
+ globalScriptInterface.setTimeSlider('left', '');
+ globalScriptInterface.setTimeSlider('right', '');
+ globalScriptInterface.setTimeSlider('title', Language.getLocalizedText(667, 'Time Scrubber'));
+};
+
+//Fits time slider not implemented for webgl engine (only Windows version)
+LayerManager.setTimeSliderValue = function (pos) {
+ var layer = ss.safeCast(LayerManager._selectedLayer, ImageSetLayer);
+ if (layer != null && ss.canCast(layer.get_imageSet().get_wcsImage(), FitsImage)) { }
+};
+
+LayerManager.showLayerMenu = function (selected, x, y) {
+ LayerManager._lastMenuClick = Vector2d.create(x, y);
+ LayerManager._selectedLayer = selected;
+ if (ss.canCast(selected, LayerMap)) {
+ LayerManager.set_currentMap((selected).get_name());
+ }
+ else if (ss.canCast(selected, Layer)) {
+ LayerManager.set_currentMap((selected).get_referenceFrame());
+ }
+ if (((ss.canCast(selected, Layer)) && !(ss.canCast(selected, SkyOverlays)))) {
+ var selectedLayer = selected;
+ LayerManager._contextMenu = new ContextMenuStrip();
+ var renameMenu = ToolStripMenuItem.create(Language.getLocalizedText(225, 'Rename'));
+ var Expand = ToolStripMenuItem.create(Language.getLocalizedText(981, 'Expand'));
+ var Collapse = ToolStripMenuItem.create(Language.getLocalizedText(982, 'Collapse'));
+ var copyMenu = ToolStripMenuItem.create(Language.getLocalizedText(428, 'Copy'));
+ var deleteMenu = ToolStripMenuItem.create(Language.getLocalizedText(167, 'Delete'));
+ var saveMenu = ToolStripMenuItem.create(Language.getLocalizedText(960, 'Save...'));
+ var publishMenu = ToolStripMenuItem.create(Language.getLocalizedText(983, 'Publish to Community...'));
+ var colorMenu = ToolStripMenuItem.create(Language.getLocalizedText(458, 'Color/Opacity'));
+ var opacityMenu = ToolStripMenuItem.create(Language.getLocalizedText(305, 'Opacity'));
+ var propertiesMenu = ToolStripMenuItem.create(Language.getLocalizedText(20, 'Properties'));
+ var scaleMenu = ToolStripMenuItem.create(Language.getLocalizedText(1291, 'Scale/Histogram'));
+ var lifeTimeMenu = ToolStripMenuItem.create(Language.getLocalizedText(683, 'Lifetime'));
+ var spacer1 = new ToolStripSeparator();
+ var top = ToolStripMenuItem.create(Language.getLocalizedText(684, 'Move to Top'));
+ var up = ToolStripMenuItem.create(Language.getLocalizedText(685, 'Move Up'));
+ var down = ToolStripMenuItem.create(Language.getLocalizedText(686, 'Move Down'));
+ var bottom = ToolStripMenuItem.create(Language.getLocalizedText(687, 'Move to Bottom'));
+ var showViewer = ToolStripMenuItem.create(Language.getLocalizedText(957, 'VO Table Viewer'));
+ var spacer2 = new ToolStripSeparator();
+ var defaultImageset = ToolStripMenuItem.create(Language.getLocalizedText(1294, 'Background Image Set'));
+ top.click = LayerManager._top_Click;
+ up.click = LayerManager._up_Click;
+ down.click = LayerManager._down_Click;
+ bottom.click = LayerManager._bottom_Click;
+ saveMenu.click = LayerManager._saveMenu_Click;
+ publishMenu.click = LayerManager._publishMenu_Click;
+ Expand.click = LayerManager._expand_Click;
+ Collapse.click = LayerManager._collapse_Click;
+ copyMenu.click = LayerManager._copyMenu_Click;
+ colorMenu.click = LayerManager._colorMenu_Click;
+ deleteMenu.click = LayerManager._deleteMenu_Click;
+ renameMenu.click = LayerManager._renameMenu_Click;
+ propertiesMenu.click = LayerManager._propertiesMenu_Click;
+ scaleMenu.click = LayerManager.scaleMenu_click;
+ defaultImageset.click = LayerManager._defaultImageset_Click;
+ opacityMenu.click = LayerManager._opacityMenu_Click;
+ lifeTimeMenu.click = LayerManager._lifeTimeMenu_Click;
+ showViewer.click = LayerManager._showViewer_Click;
+ LayerManager._contextMenu.items.push(renameMenu);
+ if (!selectedLayer.get_opened() && selectedLayer.getPrimaryUI() != null && selectedLayer.getPrimaryUI().get_hasTreeViewNodes()) {
+ LayerManager._contextMenu.items.push(Expand);
+ }
+ if (selectedLayer.get_opened()) {
+ LayerManager._contextMenu.items.push(Collapse);
+ }
+ if (selectedLayer.canCopyToClipboard()) {
+ }
+ LayerManager._contextMenu.items.push(deleteMenu);
+ LayerManager._contextMenu.items.push(spacer2);
+ LayerManager._contextMenu.items.push(colorMenu);
+ if (ss.canCast(selected, ImageSetLayer)) {
+ LayerManager._contextMenu.items.push(defaultImageset);
+ var isl = ss.safeCast(selected, ImageSetLayer);
+ defaultImageset.checked = isl.get_overrideDefaultLayer();
+ }
+ if (ss.canCast(selected, SpreadSheetLayer) || ss.canCast(selected, GreatCirlceRouteLayer)) {
+ LayerManager._contextMenu.items.push(propertiesMenu);
+ }
+ if (ss.canCast(selected, VoTableLayer)) {
+ LayerManager._contextMenu.items.push(showViewer);
+ }
+ if (ss.canCast(selected, ImageSetLayer)) {
+ var isl = ss.safeCast(selected, ImageSetLayer);
+ LayerManager._contextMenu.items.push(scaleMenu);
+ }
+ if (LayerManager.get_allMaps()[selectedLayer.get_referenceFrame()].layers.length > 1) {
+ LayerManager._contextMenu.items.push(spacer1);
+ LayerManager._contextMenu.items.push(top);
+ LayerManager._contextMenu.items.push(up);
+ LayerManager._contextMenu.items.push(down);
+ LayerManager._contextMenu.items.push(bottom);
+ }
+ LayerManager._contextMenu._show(Vector2d.create(x, y));
+ }
+ else if (ss.canCast(selected, LayerMap)) {
+ var map = ss.safeCast(selected, LayerMap);
+ var sandbox = map.frame.reference.toString() === 'Sandbox';
+ var Dome = map.frame.name === 'Dome';
+ var Sky = map.frame.name === 'Sky';
+ if (Dome) {
+ return;
+ }
+ LayerManager._contextMenu = new ContextMenuStrip();
+ var trackFrame = ToolStripMenuItem.create(Language.getLocalizedText(1298, 'Track this frame'));
+ var goTo = ToolStripMenuItem.create(Language.getLocalizedText(1299, 'Fly Here'));
+ var showOrbit = ToolStripMenuItem.create('Show Orbit');
+ var newMenu = ToolStripMenuItem.create(Language.getLocalizedText(674, 'New Reference Frame'));
+ var newLayerGroupMenu = ToolStripMenuItem.create(Language.getLocalizedText(675, 'New Layer Group'));
+ var addMenu = ToolStripMenuItem.create(Language.getLocalizedText(166, 'Add'));
+ var newLight = ToolStripMenuItem.create('Add Light');
+ var addFeedMenu = ToolStripMenuItem.create(Language.getLocalizedText(956, 'Add OData/table feed as Layer'));
+ var addWmsLayer = ToolStripMenuItem.create(Language.getLocalizedText(987, 'New WMS Layer'));
+ var addGridLayer = ToolStripMenuItem.create(Language.getLocalizedText(1300, 'New Lat/Lng Grid'));
+ var addGreatCircle = ToolStripMenuItem.create(Language.getLocalizedText(988, 'New Great Circle'));
+ var importTLE = ToolStripMenuItem.create(Language.getLocalizedText(989, 'Import Orbital Elements'));
+ var addMpc = ToolStripMenuItem.create(Language.getLocalizedText(1301, 'Add Minor Planet'));
+ var deleteFrameMenu = ToolStripMenuItem.create(Language.getLocalizedText(167, 'Delete'));
+ var pasteMenu = ToolStripMenuItem.create(Language.getLocalizedText(425, 'Paste'));
+ var addToTimeline = ToolStripMenuItem.create(Language.getLocalizedText(1290, 'Add to Timeline'));
+ var addKeyframe = ToolStripMenuItem.create(Language.getLocalizedText(1280, 'Add Keyframe'));
+ var popertiesMenu = ToolStripMenuItem.create(Language.getLocalizedText(20, 'Properties'));
+ var saveMenu = ToolStripMenuItem.create(Language.getLocalizedText(990, 'Save Layers'));
+ var publishLayers = ToolStripMenuItem.create(Language.getLocalizedText(991, 'Publish Layers to Community'));
+ var spacer1 = new ToolStripSeparator();
+ var spacer0 = new ToolStripSeparator();
+ var spacer2 = new ToolStripSeparator();
+ var asReferenceFrame = ToolStripMenuItem.create('As Reference Frame');
+ var asOrbitalLines = ToolStripMenuItem.create('As Orbital Line');
+ trackFrame.click = LayerManager._trackFrame_Click;
+ goTo.click = LayerManager._goTo_Click;
+ asReferenceFrame.click = LayerManager._addMpc_Click;
+ asOrbitalLines.click = LayerManager._asOrbitalLines_Click;
+
+ // Add Sub Menus
+ addMpc.dropDownItems.push(asReferenceFrame);
+ addMpc.dropDownItems.push(asOrbitalLines);
+ addMenu.click = LayerManager._addMenu_Click;
+ newLayerGroupMenu.click = LayerManager._newLayerGroupMenu_Click;
+ pasteMenu.click = LayerManager._pasteLayer_Click;
+ newMenu.click = LayerManager._newMenu_Click;
+ deleteFrameMenu.click = LayerManager._deleteFrameMenu_Click;
+ popertiesMenu.click = LayerManager._framePropertiesMenu_Click;
+ addGreatCircle.click = LayerManager._addGreatCircle_Click;
+ addGridLayer.click = LayerManager._addGirdLayer_Click;
+ var convertToOrbit = ToolStripMenuItem.create('Extract Orbit Layer');
+ if (map.frame.reference !== 19) {
+ if ((globalWWTControl.get_solarSystemMode() | globalWWTControl.sandboxMode) === 1) {
+ var spacerNeeded = false;
+ if (map.frame.reference !== 18 && !globalWWTControl.sandboxMode) {
+ // fly to
+ if (!Sky) {
+ }
+ try {
+ var name = map.frame.reference.toString();
+ if (name !== 'Sandbox') {
+ var ssObj = Enums.parse('SolarSystemObjects', name);
+ var id = ssObj;
+ var bit = Math.pow(2, id);
+ showOrbit.checked = !!(Settings.get_active().get_planetOrbitsFilter() & bit);
+ showOrbit.click = LayerManager._showOrbitPlanet_Click;
+ showOrbit.tag = bit.toString();
+ }
+ }
+ catch ($e1) {
+ }
+ }
+ else {
+ // track
+ if (!sandbox && !Sky) {
+ LayerManager._contextMenu.items.push(trackFrame);
+ spacerNeeded = true;
+ }
+ showOrbit.checked = map.frame.showOrbitPath;
+ showOrbit.click = LayerManager._showOrbit_Click;
+ }
+ if (spacerNeeded) {
+ LayerManager._contextMenu.items.push(spacer2);
+ }
+ if (!Sky && !sandbox) {
+ LayerManager._contextMenu.items.push(showOrbit);
+ LayerManager._contextMenu.items.push(spacer0);
+ }
+ if (map.frame.reference.toString() === 'Sandbox') {
+ LayerManager._contextMenu.items.push(newLight);
+ }
+ }
+ if (!Sky) {
+ LayerManager._contextMenu.items.push(newMenu);
+ }
+ }
+ if (!Sky) {
+ LayerManager._contextMenu.items.push(addGreatCircle);
+ LayerManager._contextMenu.items.push(addGridLayer);
+ }
+ if ((map.frame.reference !== 19 && map.frame.name === 'Sun') || (map.frame.reference === 19 && map.parent != null && map.parent.frame.name === 'Sun')) {
+ LayerManager._contextMenu.items.push(addMpc);
+ }
+ if (map.frame.reference === 18 && map.frame.referenceFrameType === 1 && map.parent != null && map.parent.frame.name === 'Sun') {
+ }
+ if (!Sky) {
+ }
+ LayerManager._contextMenu.items.push(pasteMenu);
+ if (map.frame.reference === 19) {
+ LayerManager._contextMenu.items.push(deleteFrameMenu);
+ }
+ if (map.frame.reference === 18) {
+ LayerManager._contextMenu.items.push(deleteFrameMenu);
+ LayerManager._contextMenu.items.push(popertiesMenu);
+ }
+ LayerManager._contextMenu.items.push(spacer1);
+ LayerManager._contextMenu._show(Vector2d.create(x, y));
+ }
+};
+
+LayerManager._publishMenu_Click = function (sender, e) { };
+
+LayerManager._addGirdLayer_Click = function (sender, e) {
+ var layer = new GridLayer();
+ layer.enabled = true;
+ layer.set_name('Lat-Lng Grid');
+ LayerManager.get_layerList()[layer.id] = layer;
+ layer.set_referenceFrame(LayerManager._currentMap);
+ LayerManager.get_allMaps()[LayerManager._currentMap].layers.push(layer);
+ LayerManager.get_allMaps()[LayerManager._currentMap].open = true;
+ LayerManager._version++;
+ LayerManager.loadTree();
+};
+
+LayerManager._trackFrame_Click = function (sender, e) {
+ var target = LayerManager._selectedLayer;
+ globalRenderContext.set_solarSystemTrack(20);
+ globalRenderContext.set_trackingFrame(target.get_name());
+ globalRenderContext.viewCamera.zoom = globalRenderContext.targetCamera.zoom = 1E-09;
+};
+
+LayerManager._goTo_Click = function (sender, e) { };
+
+LayerManager._saveMenu_Click = function (sender, e) { };
+
+LayerManager._expand_Click = function (sender, e) { };
+
+LayerManager._collapse_Click = function (sender, e) { };
+
+LayerManager._copyMenu_Click = function (sender, e) {
+ if (LayerManager._selectedLayer != null && ss.canCast(LayerManager._selectedLayer, Layer)) {
+ var node = LayerManager._selectedLayer;
+ node.copyToClipboard();
+ }
+};
+
+LayerManager._newLayerGroupMenu_Click = function (sender, e) { };
+
+LayerManager._importTLEFile = function (filename) { };
+
+LayerManager._makeLayerGroupNow = function (name) {
+ var target = LayerManager._selectedLayer;
+ LayerManager._makeLayerGroup(name, target);
+};
+
+LayerManager._makeLayerGroup = function (name, target) {
+ var frame = new ReferenceFrame();
+ frame.name = name;
+ frame.reference = 19;
+ var newMap = new LayerMap(frame.name, 19);
+ newMap.frame = frame;
+ newMap.frame._systemGenerated = false;
+ target.addChild(newMap);
+ newMap.frame.parent = target.get_name();
+ LayerManager.get_allMaps()[frame.name] = newMap;
+ LayerManager._version++;
+};
+
+LayerManager._lifeTimeMenu_Click = function (sender, e) { };
+
+LayerManager._deleteFrameMenu_Click = function (sender, e) { };
+
+LayerManager._framePropertiesMenu_Click = function (sender, e) {
+ var target = LayerManager._selectedLayer;
+ LayerManager.get_referenceFramePropsDialog().show(target.frame, e);
+};
+
+LayerManager._newMenu_Click = function (sender, e) {
+ var frame = new ReferenceFrame();
+ LayerManager.get_frameWizardDialog().show(frame, e);
+};
+
+LayerManager.referenceFrameWizardFinished = function (frame) {
+ var target = LayerManager._selectedLayer;
+ var newMap = new LayerMap(frame.name, 18);
+ if (!ss.keyExists(LayerManager.get_allMaps(), frame.name)) {
+ newMap.frame = frame;
+ target.addChild(newMap);
+ newMap.frame.parent = target.get_name();
+ LayerManager.get_allMaps()[frame.name] = newMap;
+ LayerManager._version++;
+ LayerManager.loadTree();
+ }
+};
+
+LayerManager.pasteFromTle = function (lines, frame) {
+ var line1 = '';
+ var line2 = '';
+ for (var i = 0; i < lines.length; i++) {
+ lines[i] = ss.trim(lines[i]);
+ if (lines[i].length === 69 && ReferenceFrame.isTLECheckSumGood(lines[i])) {
+ if (!line1.length && lines[i].substring(0, 1) === '1') {
+ line1 = lines[i];
+ }
+ if (!line2.length && lines[i].substring(0, 1) === '2') {
+ line2 = lines[i];
+ }
+ }
+ }
+ if (line1.length === 69 && line2.length === 69) {
+ frame.fromTLE(line1, line2, 398600441800000);
+ return true;
+ }
+ return false;
+};
+
+LayerManager._opacityMenu_Click = function (sender, e) { };
+
+LayerManager._defaultImageset_Click = function (sender, e) {
+ var isl = ss.safeCast(LayerManager._selectedLayer, ImageSetLayer);
+ isl.set_overrideDefaultLayer(!isl.get_overrideDefaultLayer());
+};
+
+LayerManager._propertiesMenu_Click = function (sender, e) {
+ if (ss.canCast(LayerManager._selectedLayer, SpreadSheetLayer)) {
+ var target = LayerManager._selectedLayer;
+ LayerManager.get_dataVizWizardDialog().show(target, e);
+ }
+ if (ss.canCast(LayerManager._selectedLayer, GreatCirlceRouteLayer)) {
+ LayerManager.get_greatCircleDlg().show(LayerManager._selectedLayer, new ss.EventArgs());
+ }
+};
+
+LayerManager._renameMenu_Click = function (sender, e) {
+ var layer = LayerManager._selectedLayer;
+ var input = new SimpleInput(Language.getLocalizedText(225, 'Rename'), Language.getLocalizedText(228, 'New Name'), layer.get_name(), 32);
+ input.show(LayerManager._lastMenuClick, function () {
+ if (!ss.emptyString(input.text)) {
+ layer.set_name(input.text);
+ LayerManager._version++;
+ LayerManager.loadTree();
+ }
+ });
+};
+
+LayerManager._colorMenu_Click = function (sender, e) {
+ var layer = LayerManager._selectedLayer;
+ var picker = new ColorPicker();
+ if (layer.get_color() != null) {
+ picker.color = layer.get_color();
+ }
+ picker.callBack = function () {
+ layer.set_color(picker.color);
+ };
+ picker.show(e);
+};
+
+LayerManager._addMenu_Click = function (sender, e) { };
+
+LayerManager._deleteMenu_Click = function (sender, e) {
+ LayerManager._deleteSelectedLayer();
+};
+
+LayerManager._deleteSelectedLayer = function () {
+ if (LayerManager._selectedLayer != null && ss.canCast(LayerManager._selectedLayer, Layer)) {
+ var node = LayerManager._selectedLayer;
+ delete LayerManager.get_layerList()[node.id];
+ ss.remove(LayerManager.get_allMaps()[LayerManager.get_currentMap()].layers, node);
+ node.cleanUp();
+ node.set_version(node.get_version() + 1) - 1;
+ LayerManager.loadTree();
+ LayerManager._version++;
+ }
+};
+
+LayerManager.scaleMenu_click = function (sender, e) {
+ var isl = ss.safeCast(LayerManager._selectedLayer, ImageSetLayer);
+ if (isl != null) {
+ var hist = new Histogram();
+ hist.image = isl.getFitsImage();
+ hist.layer = isl;
+ hist.show(Vector2d.create(200, 200));
+ }
+};
+
+LayerManager._showViewer_Click = function (sender, e) {
+ if (ss.canCast(LayerManager._selectedLayer, VoTableLayer)) {
+ var layer = ss.safeCast(LayerManager._selectedLayer, VoTableLayer);
+ globalScriptInterface.displayVoTableLayer(layer);
+ }
+};
+
+LayerManager._bottom_Click = function (sender, e) {
+ var layer = ss.safeCast(LayerManager._selectedLayer, Layer);
+ if (layer != null) {
+ ss.remove(LayerManager.get_allMaps()[layer.get_referenceFrame()].layers, layer);
+ LayerManager.get_allMaps()[layer.get_referenceFrame()].layers.push(layer);
+ }
+ LayerManager._version++;
+ LayerManager.loadTree();
+};
+
+LayerManager._down_Click = function (sender, e) {
+ var layer = ss.safeCast(LayerManager._selectedLayer, Layer);
+ if (layer != null) {
+ var index = LayerManager.get_allMaps()[layer.get_referenceFrame()].layers.lastIndexOf(layer);
+ if (index < (LayerManager.get_allMaps()[layer.get_referenceFrame()].layers.length - 1)) {
+ ss.remove(LayerManager.get_allMaps()[layer.get_referenceFrame()].layers, layer);
+ LayerManager.get_allMaps()[layer.get_referenceFrame()].layers.splice(index + 1, 0, layer);
+ }
+ }
+ LayerManager._version++;
+ LayerManager.loadTree();
+};
+
+LayerManager._up_Click = function (sender, e) {
+ var layer = ss.safeCast(LayerManager._selectedLayer, Layer);
+ if (layer != null) {
+ var index = LayerManager.get_allMaps()[layer.get_referenceFrame()].layers.lastIndexOf(layer);
+ if (index > 0) {
+ ss.remove(LayerManager.get_allMaps()[layer.get_referenceFrame()].layers, layer);
+ LayerManager.get_allMaps()[layer.get_referenceFrame()].layers.splice(index - 1, 0, layer);
+ }
+ }
+ LayerManager._version++;
+ LayerManager.loadTree();
+};
+
+LayerManager._top_Click = function (sender, e) {
+ var layer = ss.safeCast(LayerManager._selectedLayer, Layer);
+ if (layer != null) {
+ ss.remove(LayerManager.get_allMaps()[layer.get_referenceFrame()].layers, layer);
+ LayerManager.get_allMaps()[layer.get_referenceFrame()].layers.splice(0, 0, layer);
+ }
+ LayerManager._version++;
+ LayerManager.loadTree();
+};
+
+LayerManager._pasteLayer_Click = function (sender, e) {
+ LayerManager.get_dataVizWizardDialog().show(LayerManager.get_currentMap(), e);
+};
+
+LayerManager.createSpreadsheetLayer = function (frame, name, data) {
+ var layer = new SpreadSheetLayer();
+ layer.loadFromString(data, false, false, false, true);
+ layer.set_name(name);
+ LayerManager.addSpreadsheetLayer(layer, frame);
+ return layer;
+};
+
+LayerManager.addSpreadsheetLayer = function (layer, frame) {
+ layer.enabled = true;
+ layer.set_referenceFrame(frame);
+ LayerManager.add(layer, true);
+};
+
+LayerManager._showOrbitPlanet_Click = function (sender, e) {
+ try {
+ var bit = parseInt((sender).tag.toString());
+ // Flip the state
+ if (!(Settings.get_globalSettings().get_planetOrbitsFilter() & bit)) {
+ Settings.get_globalSettings().set_planetOrbitsFilter(Settings.get_globalSettings().get_planetOrbitsFilter() | bit);
+ } else {
+ Settings.get_globalSettings().set_planetOrbitsFilter(Settings.get_globalSettings().get_planetOrbitsFilter() & ~bit);
+ }
+ }
+ catch ($e1) { }
+};
+
+LayerManager._showOrbit_Click = function (sender, e) {
+ // Flip the state
+ var map = ss.safeCast(LayerManager._selectedLayer, LayerMap);
+ map.frame.showOrbitPath = !map.frame.showOrbitPath;
+};
+
+LayerManager._addGreatCircle_Click = function (sender, e) {
+ LayerManager._addGreatCircleLayer();
+};
+
+LayerManager._addMpc_Click = function (sender, e) {
+ var target = LayerManager._selectedLayer;
+ var input = new SimpleInput(Language.getLocalizedText(1302, 'Minor planet name or designation'), Language.getLocalizedText(238, 'Name'), '', 32);
+ var retry = false;
+ do {
+ if (input.showDialog() === 1) {
+ if (ss.keyExists(target.childMaps, input.text)) {
+ retry = true;
+ }
+ else {
+ try {
+ LayerManager._getMpc(input.text, target);
+ retry = false;
+ }
+ catch ($e1) {
+ retry = true;
+ }
+ }
+ } else {
+ retry = false;
+ }
+ } while (retry);
+ return;
+};
+
+LayerManager._asOrbitalLines_Click = function (sender, e) {
+ var target = LayerManager._selectedLayer;
+ var input = new SimpleInput(Language.getLocalizedText(1302, 'Minor planet name or designation'), Language.getLocalizedText(238, 'Name'), '', 32);
+ input.show(Cursor.get_position(), function () {
+ if (ss.keyExists(target.childMaps, input.text)) {
+ } else {
+ LayerManager._getMpcAsTLE(input.text, target);
+ }
+ });
+};
+
+LayerManager._getMpcAsTLE = function (id, target) {
+ var file = new WebFile('https://www.minorplanetcenter.net/db_search/show_object?object_id=' + id);
+ file.onStateChange = function () {
+ if (file.get_state() !== 1) {
+ return;
+ }
+ var data = file.getText();
+ var startform = data.indexOf('show-orbit-button');
+ var lastForm = data.indexOf('/form', startform);
+ var formpart = data.substring(startform, lastForm);
+ var name = id;
+ var frame = new ReferenceFrame();
+ frame.oblateness = 0;
+ frame.showOrbitPath = true;
+ frame.showAsPoint = true;
+ frame.epoch = SpaceTimeController.utcToJulian(ss.date(LayerManager._getValueByID(formpart, 'epoch').substring(0, 10)));
+ frame.semiMajorAxis = parseFloat(LayerManager._getValueByID(formpart, 'a')) * 149598000 * 1000;
+ frame.referenceFrameType = 1;
+ frame.inclination = parseFloat(LayerManager._getValueByID(formpart, 'incl'));
+ frame.longitudeOfAscendingNode = parseFloat(LayerManager._getValueByID(formpart, 'node'));
+ frame.eccentricity = parseFloat(LayerManager._getValueByID(formpart, 'e'));
+ frame.meanAnomolyAtEpoch = parseFloat(LayerManager._getValueByID(formpart, 'm'));
+ frame.meanDailyMotion = ELL.meanMotionFromSemiMajorAxis(parseFloat(LayerManager._getValueByID(formpart, 'a')));
+ frame.argumentOfPeriapsis = parseFloat(LayerManager._getValueByID(formpart, 'peri'));
+ frame.scale = 1;
+ frame.semiMajorAxisUnits = 1;
+ frame.meanRadius = 10;
+ frame.oblateness = 0;
+ var TLE = name + '\n' + frame.toTLE();
+ LayerManager._loadOrbitsFile(id, TLE, target.get_name());
+ LayerManager.loadTree();
+ };
+ file.send();
+};
+
+LayerManager._getMpc = function (id, target) {
+ var file = new WebFile('https://www.minorplanetcenter.net/db_search/show_object?object_id=' + id);
+ file.onStateChange = function () {
+ var data = file.getText();
+ var startform = data.indexOf('show-orbit-button');
+ var lastForm = data.indexOf('/form', startform);
+ var formpart = data.substring(startform, lastForm);
+ var name = id;
+ var orbit = new LayerMap(ss.trim(name), 18);
+ orbit.frame.oblateness = 0;
+ orbit.frame.showOrbitPath = true;
+ orbit.frame.showAsPoint = true;
+ orbit.frame.epoch = SpaceTimeController.utcToJulian(ss.date(LayerManager._getValueByID(formpart, 'epoch').substring(0, 10)));
+ orbit.frame.semiMajorAxis = parseFloat(LayerManager._getValueByID(formpart, 'a')) * 149598000 * 1000;
+ orbit.frame.referenceFrameType = 1;
+ orbit.frame.inclination = parseFloat(LayerManager._getValueByID(formpart, 'incl'));
+ orbit.frame.longitudeOfAscendingNode = parseFloat(LayerManager._getValueByID(formpart, 'node'));
+ orbit.frame.eccentricity = parseFloat(LayerManager._getValueByID(formpart, 'e'));
+ orbit.frame.meanAnomolyAtEpoch = parseFloat(LayerManager._getValueByID(formpart, 'm'));
+ orbit.frame.meanDailyMotion = ELL.meanMotionFromSemiMajorAxis(parseFloat(LayerManager._getValueByID(formpart, 'a')));
+ orbit.frame.argumentOfPeriapsis = parseFloat(LayerManager._getValueByID(formpart, 'peri'));
+ orbit.frame.scale = 1;
+ orbit.frame.semiMajorAxisUnits = 1;
+ orbit.frame.meanRadius = 10;
+ orbit.frame.oblateness = 0;
+ if (!ss.keyExists(LayerManager.get_allMaps()[target.get_name()].childMaps, ss.trim(name))) {
+ LayerManager.get_allMaps()[target.get_name()].addChild(orbit);
+ }
+ LayerManager.get_allMaps()[orbit.get_name()] = orbit;
+ orbit.frame.parent = target.get_name();
+ LayerManager._makeLayerGroup('Minor Planet', orbit);
+ LayerManager.loadTree();
+ };
+};
+
+LayerManager._getValueByID = function (data, id) {
+ var valStart = data.indexOf('id="' + id + '"');
+ valStart = data.indexOf('value=', valStart) + 7;
+ var valEnd = data.indexOf('"', valStart);
+ return data.substr(valStart, valEnd - valStart);
+};
+
+LayerManager._addGreatCircleLayer = function () {
+ var layer = new GreatCirlceRouteLayer();
+ var camera = globalRenderContext.viewCamera;
+ layer.set_latStart(camera.lat);
+ layer.set_latEnd(camera.lat - 5);
+ layer.set_lngStart(camera.lng);
+ layer.set_lngEnd(camera.lng + 5);
+ layer.set_width(4);
+ layer.enabled = true;
+ layer.set_name(Language.getLocalizedText(1144, 'Great Circle Route'));
+ LayerManager.get_layerList()[layer.id] = layer;
+ layer.set_referenceFrame(LayerManager._currentMap);
+ LayerManager.get_allMaps()[LayerManager._currentMap].layers.push(layer);
+ LayerManager.get_allMaps()[LayerManager._currentMap].open = true;
+ LayerManager._version++;
+ LayerManager.loadTree();
+ LayerManager.get_greatCircleDlg().show(layer, new ss.EventArgs());
+};
+
+LayerManager._loadOrbitsFile = function (name, data, currentMap) {
+ var layer = new OrbitLayer();
+ layer.loadString(data);
+ layer.enabled = true;
+ layer.set_name(name);
+ LayerManager.get_layerList()[layer.id] = layer;
+ layer.set_referenceFrame(currentMap);
+ LayerManager.get_allMaps()[currentMap].layers.push(layer);
+ LayerManager.get_allMaps()[currentMap].open = true;
+ LayerManager._version++;
+ LayerManager.loadTree();
+ return layer;
+};
+
+var LayerManager$ = {};
+
+registerType("LayerManager", [LayerManager, LayerManager$, null]);
+
+
+// wwtlib.LayerMap
+
+export function LayerMap(name, reference) {
+ this.childMaps = {};
+ this.parent = null;
+ this.layers = [];
+ this.open = false;
+ this.enabled = true;
+ this.loadedFromTour = false;
+ this.frame = new ReferenceFrame();
+ this.set_name(name);
+ this.frame.reference = reference;
+ var radius = 6371000;
+ switch (reference) {
+ case 0:
+ break;
+ case 1:
+ break;
+ case 2:
+ break;
+ case 3:
+ radius = 696000000;
+ break;
+ case 4:
+ radius = 2439700;
+ break;
+ case 5:
+ radius = 6051800;
+ break;
+ case 6:
+ radius = 6371000;
+ break;
+ case 7:
+ radius = 3390000;
+ break;
+ case 8:
+ radius = 69911000;
+ break;
+ case 9:
+ radius = 58232000;
+ break;
+ case 10:
+ radius = 25362000;
+ break;
+ case 11:
+ radius = 24622000;
+ break;
+ case 12:
+ radius = 1161000;
+ break;
+ case 13:
+ radius = 1737100;
+ break;
+ case 14:
+ radius = 1821500;
+ break;
+ case 15:
+ radius = 1561000;
+ break;
+ case 16:
+ radius = 2631200;
+ break;
+ case 17:
+ radius = 2410300;
+ break;
+ case 18:
+ break;
+ case 19:
+ break;
+ default:
+ break;
+ }
+ this.frame.meanRadius = radius;
+}
+
+var LayerMap$ = {
+ addChild: function (child) {
+ child.parent = this;
+ this.childMaps[child.get_name()] = child;
+ },
+
+ get_name: function () {
+ return this.frame.name;
+ },
+
+ set_name: function (value) {
+ this.frame.name = value;
+ return value;
+ },
+
+ computeFrame: function (renderContext) {
+ if (this.frame.reference === 18) {
+ this.frame.computeFrame(renderContext);
+ }
+ },
+
+ toString: function () {
+ return this.get_name();
+ }
+};
+
+registerType("LayerMap", [LayerMap, LayerMap$, null]);
+
+
+// wwtlib.SkyOverlays
+
+export function SkyOverlays() { }
+
+var SkyOverlays$ = {};
+
+registerType("SkyOverlays", [SkyOverlays, SkyOverlays$, null]);
+
+
+// wwtlib.GroundOverlayLayer
+
+export function GroundOverlayLayer() { }
+
+var GroundOverlayLayer$ = {};
+
+registerType("GroundOverlayLayer", [GroundOverlayLayer, GroundOverlayLayer$, null]);
+
+
+// wwtlib.FrameTarget
+
+export function FrameTarget() { }
+
+var FrameTarget$ = {};
+
+registerType("FrameTarget", [FrameTarget, FrameTarget$, null]);
diff --git a/engine/esm/layers/layer_ui.js b/engine/esm/layers/layer_ui.js
new file mode 100644
index 00000000..a3605f3b
--- /dev/null
+++ b/engine/esm/layers/layer_ui.js
@@ -0,0 +1,290 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A framework for constructing UIs associated with specific layers. Largely
+// unused in the web engine context.
+
+import { ss } from "../ss.js";
+import { registerType } from "../typesystem.js";
+import { Colors } from "../color.js";
+
+
+// wwtlib.LayerUI
+
+export function LayerUI() { }
+
+LayerUI._type = null;
+
+var LayerUI$ = {
+ get_hasTreeViewNodes: function () {
+ return false;
+ },
+
+ getTreeNodes: function () {
+ return null;
+ },
+
+ getNodeContextMenu: function (node) {
+ return null;
+ },
+
+ setUICallbacks: function (callbacks) { }
+};
+
+registerType("LayerUI", [LayerUI, LayerUI$, null]);
+
+
+// wwtlib.LayerUIMenuItem
+
+export function LayerUIMenuItem() {
+ this._tag = null;
+ this._isChecked = false;
+ this._isEnabled = true;
+ this._subMenus = null;
+}
+
+var LayerUIMenuItem$ = {
+ get_name: function () {
+ return this._name;
+ },
+
+ set_name: function (value) {
+ this._name = value;
+ return value;
+ },
+
+ get_tag: function () {
+ return this._tag;
+ },
+
+ set_tag: function (value) {
+ this._tag = value;
+ return value;
+ },
+
+ get_checked: function () {
+ return this._isChecked;
+ },
+
+ set_checked: function (value) {
+ this._isChecked = value;
+ return value;
+ },
+
+ get_enabled: function () {
+ return this._isEnabled;
+ },
+
+ set_enabled: function (value) {
+ this._isEnabled = value;
+ return value;
+ },
+
+ add_menuItemSelected: function (value) {
+ this.__menuItemSelected = ss.bindAdd(this.__menuItemSelected, value);
+ },
+
+ remove_menuItemSelected: function (value) {
+ this.__menuItemSelected = ss.bindSub(this.__menuItemSelected, value);
+ },
+
+ fireMenuItemSelected: function () {
+ if (this.__menuItemSelected != null) {
+ this.__menuItemSelected(this);
+ }
+ },
+
+ get_subMenus: function () {
+ if (this._subMenus == null) {
+ this._subMenus = [];
+ }
+ return this._subMenus;
+ }
+};
+
+registerType("LayerUIMenuItem", [LayerUIMenuItem, LayerUIMenuItem$, null]);
+
+
+// wwtlib.LayerUITreeNode
+
+export function LayerUITreeNode() {
+ this._parent = null;
+ this._level = 0;
+ this._open = false;
+ this._isChecked = false;
+ this._bold = false;
+ this._color = Colors.get_white();
+ this._nodes = null;
+}
+
+var LayerUITreeNode$ = {
+ add_nodeChecked: function (value) {
+ this.__nodeChecked = ss.bindAdd(this.__nodeChecked, value);
+ },
+
+ remove_nodeChecked: function (value) {
+ this.__nodeChecked = ss.bindSub(this.__nodeChecked, value);
+ },
+
+ fireNodeChecked: function (newState) {
+ if (this.__nodeChecked != null) {
+ this.__nodeChecked(this, newState);
+ }
+ },
+
+ add_nodeUpdated: function (value) {
+ this.__nodeUpdated = ss.bindAdd(this.__nodeUpdated, value);
+ },
+
+ remove_nodeUpdated: function (value) {
+ this.__nodeUpdated = ss.bindSub(this.__nodeUpdated, value);
+ },
+
+ fireNodeUpdated: function () {
+ if (this.__nodeUpdated != null) {
+ this.__nodeUpdated(this);
+ }
+ },
+
+ add_nodeSelected: function (value) {
+ this.__nodeSelected = ss.bindAdd(this.__nodeSelected, value);
+ },
+
+ remove_nodeSelected: function (value) {
+ this.__nodeSelected = ss.bindSub(this.__nodeSelected, value);
+ },
+
+ fireNodeSelected: function () {
+ if (this.__nodeSelected != null) {
+ this.__nodeSelected(this);
+ }
+ },
+
+ add_nodeActivated: function (value) {
+ this.__nodeActivated = ss.bindAdd(this.__nodeActivated, value);
+ },
+
+ remove_nodeActivated: function (value) {
+ this.__nodeActivated = ss.bindSub(this.__nodeActivated, value);
+ },
+
+ fireNodeActivated: function () {
+ if (this.__nodeActivated != null) {
+ this.__nodeActivated(this);
+ }
+ },
+
+ get_name: function () {
+ return this._name;
+ },
+
+ set_name: function (value) {
+ if (this._name !== value) {
+ this._name = value;
+ this.fireNodeUpdated();
+ }
+ return value;
+ },
+
+ get_parent: function () {
+ return this._parent;
+ },
+
+ set_parent: function (value) {
+ this._parent = value;
+ return value;
+ },
+
+ get_level: function () {
+ return this._level;
+ },
+
+ set_level: function (value) {
+ this._level = value;
+ return value;
+ },
+
+ get_tag: function () {
+ return this._tag;
+ },
+
+ set_tag: function (value) {
+ this._tag = value;
+ return value;
+ },
+
+ get_referenceTag: function () {
+ return this._referenceTag;
+ },
+
+ set_referenceTag: function (value) {
+ this._referenceTag = value;
+ return value;
+ },
+
+ get_opened: function () {
+ return this._open;
+ },
+
+ set_opened: function (value) {
+ if (this._open !== value) {
+ this._open = value;
+ this.fireNodeUpdated();
+ }
+ return value;
+ },
+
+ get_checked: function () {
+ return this._isChecked;
+ },
+
+ set_checked: function (value) {
+ if (this._isChecked !== value) {
+ this._isChecked = value;
+ this.fireNodeUpdated();
+ }
+ return value;
+ },
+
+ get_bold: function () {
+ return this._bold;
+ },
+
+ set_bold: function (value) {
+ if (this._bold !== value) {
+ this._bold = value;
+ this.fireNodeUpdated();
+ }
+ return value;
+ },
+
+ get_color: function () {
+ return this._color;
+ },
+
+ set_color: function (value) {
+ if (this._color !== value) {
+ this._color = value;
+ this.fireNodeUpdated();
+ }
+ return value;
+ },
+
+ add: function (name) {
+ var node = new LayerUITreeNode();
+ node.set_name(name);
+ node.set_parent(this);
+ node.set_level(this.get_level() + 1);
+ this.get_nodes().push(node);
+ return node;
+ },
+
+ get_nodes: function () {
+ if (this._nodes == null) {
+ this._nodes = [];
+ }
+ return this._nodes;
+ }
+};
+
+registerType("LayerUITreeNode", [LayerUITreeNode, LayerUITreeNode$, null]);
diff --git a/engine/esm/layers/manager_dialogs.js b/engine/esm/layers/manager_dialogs.js
new file mode 100644
index 00000000..d3db8fd3
--- /dev/null
+++ b/engine/esm/layers/manager_dialogs.js
@@ -0,0 +1,83 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Types defining UI elements associated with the layer manager.
+//
+// These don't do anything in the web client, but to preserve API compatibility,
+// we keep them hanging around.
+
+import { registerType } from "../typesystem.js";
+import { Dialog } from "../utilities/dialog.js";
+import { LayerManager } from "./layer_manager.js";
+
+
+// wwtlib.FrameWizard
+//
+// This was originally defined in `Utilities/Dialog.cs`.
+
+export function FrameWizard() {
+ Dialog.call(this);
+}
+
+var FrameWizard$ = {
+ OK: function (frame) {
+ LayerManager.referenceFrameWizardFinished(frame);
+ }
+};
+
+registerType("FrameWizard", [FrameWizard, FrameWizard$, Dialog]);
+
+
+// wwtlib.ReferenceFrameProps
+//
+// This was originally defined in `Utilities/Dialog.cs`.
+
+export function ReferenceFrameProps() {
+ Dialog.call(this);
+}
+
+var ReferenceFrameProps$ = {
+ OK: function (frame) {
+ LayerManager.loadTree();
+ }
+};
+
+registerType("ReferenceFrameProps", [ReferenceFrameProps, ReferenceFrameProps$, Dialog]);
+
+
+// wwtlib.GreatCircleDialog
+//
+// This was originally defined in `Utilities/Dialog.cs`.
+
+export function GreatCircleDialog() {
+ Dialog.call(this);
+}
+
+var GreatCircleDialog$ = {
+ OK: function (frame) { }
+};
+
+registerType("GreatCircleDialog", [GreatCircleDialog, GreatCircleDialog$, Dialog]);
+
+
+// wwtlib.DataVizWizard
+//
+// This was originally defined in `Utilities/Dialog.cs`.
+
+export function DataVizWizard() {
+ Dialog.call(this);
+}
+
+var DataVizWizard$ = {
+ OK: function () { }
+};
+
+registerType("DataVizWizard", [DataVizWizard, DataVizWizard$, Dialog]);
+
+
+// Initialize:
+
+LayerManager._frameWizardDialog = new FrameWizard();
+LayerManager._dataVizWizardDialog = new DataVizWizard();
+LayerManager._referenceFramePropsDialog = new ReferenceFrameProps();
+LayerManager._greatCircleDialog = new GreatCircleDialog();
diff --git a/engine/esm/layers/object3d.js b/engine/esm/layers/object3d.js
new file mode 100644
index 00000000..73b21c90
--- /dev/null
+++ b/engine/esm/layers/object3d.js
@@ -0,0 +1,2583 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A layer adding a 3D object model, and supporting code.
+
+import { ss } from "../ss.js";
+import { registerType } from "../typesystem.js";
+import { Color, Colors } from "../color.js";
+import {
+ Vector2d,
+ Vector3d,
+ Matrix3d,
+ PositionNormalTextured,
+ PositionNormalTexturedTangent,
+ SphereHull,
+ ConvexHull,
+} from "../double3d.js";
+import { globalRenderContext } from "../render_globals.js";
+import { WEBGL } from "../graphics/webgl_constants.js";
+import { Dates, LineList, TriangleList } from "../graphics/primitives3d.js";
+import { IndexBuffer, PositionNormalTexturedVertexBuffer, PositionNormalTexturedTangentVertexBuffer } from "../graphics/gl_buffers.js";
+import { ModelShader } from "../graphics/shaders.js";
+import { BinaryReader } from "../utilities/binary_reader.js";
+import { BasePlanets } from "../baseplanets.js";
+import { IUiController } from "../interfaces.js";
+import { Settings } from "../settings.js";
+import { Cursor, Cursors } from "../util.js";
+import { Layer } from "./layer.js";
+import { LayerUI, LayerUITreeNode } from "./layer_ui.js";
+
+
+// wwtlib.Material
+//
+// This was defined in `RenderContext.cs` in the C# code, but that really didn't
+// make any sense, so we've moved it here.
+
+export function Material() {
+ this.specularSharpness = 0;
+ this.opacity = 0;
+ this.isDefault = false;
+}
+
+var Material$ = {};
+
+registerType("Material", [Material, Material$, null]);
+
+
+// wwtlib.Object3dLayer
+
+export function Object3dLayer() {
+ this._primaryUI$1 = null;
+ this._heading$1 = 0;
+ this._flipV$1 = true;
+ this._flipHandedness$1 = false;
+ this._smooth$1 = true;
+ this._twoSidedGeometry$1 = false;
+ this._pitch$1 = 0;
+ this._roll$1 = 0;
+ this._scale$1 = Vector3d.create(1, 1, 1);
+ this._translate$1 = Vector3d.create(0, 0, 0);
+ this._lightID$1 = 0;
+ this._dirty$1 = false;
+ this.objType = false;
+ this._xHandle$1 = new Vector2d();
+ this._yHandle$1 = new Vector2d();
+ this._zHandle$1 = new Vector2d();
+ this._hprHandles$1 = new Array(6);
+ this._uiScale$1 = 1;
+ this._showEditUi$1 = false;
+ this._dragMode$1 = 0;
+ this._pntDown$1 = new Vector2d();
+ this._valueOnDown$1 = 0;
+ this._valueOnDown2$1 = 0;
+ this._hitDist$1 = 20;
+ this._lockPreferedAxis$1 = false;
+ this._preferY$1 = false;
+ Layer.call(this);
+}
+
+Object3dLayer._translateUI$1 = null;
+Object3dLayer._translateUILines$1 = null;
+Object3dLayer._scaleUI$1 = null;
+Object3dLayer._rotateUi$1 = null;
+
+Object3dLayer._initTranslateUI$1 = function () {
+ Object3dLayer._translateUILines$1 = new LineList();
+ Object3dLayer._translateUILines$1.timeSeries = false;
+ Object3dLayer._translateUILines$1.set_depthBuffered(false);
+ Object3dLayer._translateUILines$1.showFarSide = true;
+ Object3dLayer._translateUI$1 = new TriangleList();
+ Object3dLayer._translateUI$1.depthBuffered = false;
+ Object3dLayer._translateUI$1.timeSeries = false;
+ Object3dLayer._translateUI$1.writeZbuffer = false;
+ var twoPi = Math.PI * 2;
+ var step = twoPi / 45;
+ var rad = 0.05;
+
+ // X
+
+ for (var a = 0; a < twoPi; a += step) {
+ var pnt1 = Vector3d.create(1 - rad * 4, 0, 0);
+ var pnt2 = Vector3d.create(1 - rad * 4, Math.cos(a) * rad, Math.sin(a) * rad);
+ var pnt3 = Vector3d.create(1 - rad * 4, Math.cos(a + step) * rad, Math.sin(a + step) * rad);
+ Object3dLayer._translateUI$1.addTriangle(pnt1, pnt2, pnt3, Colors.get_red(), Dates.empty());
+ }
+ for (var a = 0; a < twoPi; a += step) {
+ var pnt1 = Vector3d.create(1, 0, 0);
+ var pnt3 = Vector3d.create(1 - rad * 4, Math.cos(a) * rad, Math.sin(a) * rad);
+ var pnt2 = Vector3d.create(1 - rad * 4, Math.cos(a + step) * rad, Math.sin(a + step) * rad);
+ Object3dLayer._translateUI$1.addTriangle(pnt1, pnt2, pnt3, Color.fromArgb(255, 255, Math.max(0, (Math.sin(a) * 128)), Math.max(0, (Math.sin(a) * 128))), Dates.empty());
+ }
+ Object3dLayer._translateUILines$1.addLine(Vector3d.create(0, 0, 0), Vector3d.create(1, 0, 0), Colors.get_red(), Dates.empty());
+
+ // Y
+
+ for (var a = 0; a < twoPi; a += step) {
+ var pnt1 = Vector3d.create(0, 1 - rad * 4, 0);
+ var pnt3 = Vector3d.create(Math.cos(a) * rad, 1 - rad * 4, Math.sin(a) * rad);
+ var pnt2 = Vector3d.create(Math.cos(a + step) * rad, 1 - rad * 4, Math.sin(a + step) * rad);
+ Object3dLayer._translateUI$1.addTriangle(pnt1, pnt2, pnt3, Colors.get_green(), Dates.empty());
+ }
+ for (var a = 0; a < twoPi; a += step) {
+ var pnt1 = Vector3d.create(0, 1, 0);
+ var pnt2 = Vector3d.create(Math.cos(a) * rad, 1 - rad * 4, Math.sin(a) * rad);
+ var pnt3 = Vector3d.create(Math.cos(a + step) * rad, 1 - rad * 4, Math.sin(a + step) * rad);
+ Object3dLayer._translateUI$1.addTriangle(pnt1, pnt2, pnt3, Color.fromArgb(255, Math.max(0, (Math.sin(a) * 128)), 255, Math.max(0, (Math.sin(a) * 128))), Dates.empty());
+ }
+ Object3dLayer._translateUILines$1.addLine(Vector3d.create(0, 0, 0), Vector3d.create(0, 1, 0), Colors.get_green(), Dates.empty());
+
+ // Z
+
+ for (var a = 0; a < twoPi; a += step) {
+ var pnt1 = Vector3d.create(0, 0, 1 - rad * 4);
+ var pnt2 = Vector3d.create(Math.cos(a) * rad, Math.sin(a) * rad, 1 - rad * 4);
+ var pnt3 = Vector3d.create(Math.cos(a + step) * rad, Math.sin(a + step) * rad, 1 - rad * 4);
+ Object3dLayer._translateUI$1.addTriangle(pnt1, pnt2, pnt3, Colors.get_blue(), Dates.empty());
+ }
+ for (var a = 0; a < twoPi; a += step) {
+ var pnt1 = Vector3d.create(0, 0, 1);
+ var pnt3 = Vector3d.create(Math.cos(a) * rad, Math.sin(a) * rad, 1 - rad * 4);
+ var pnt2 = Vector3d.create(Math.cos(a + step) * rad, Math.sin(a + step) * rad, 1 - rad * 4);
+ Object3dLayer._translateUI$1.addTriangle(pnt1, pnt2, pnt3, Color.fromArgb(255, Math.max(0, (Math.sin(a) * 128)), Math.max(0, (Math.sin(a) * 128)), 255), Dates.empty());
+ }
+ Object3dLayer._translateUILines$1.addLine(Vector3d.create(0, 0, 0), Vector3d.create(0, 0, 1), Colors.get_blue(), Dates.empty());
+ Object3dLayer._initRotateUI$1();
+ Object3dLayer._initScaleUI$1();
+};
+
+Object3dLayer._initScaleUI$1 = function () {
+ Object3dLayer._scaleUI$1 = new TriangleList();
+ Object3dLayer._scaleUI$1.depthBuffered = false;
+ Object3dLayer._scaleUI$1.timeSeries = false;
+ Object3dLayer._scaleUI$1.writeZbuffer = false;
+ var twoPi = Math.PI * 2;
+ var step = twoPi / 45;
+ var rad = 0.05;
+ Object3dLayer._makeCube$1(Object3dLayer._scaleUI$1, Vector3d.create(1 - rad * 2, 0, 0), rad * 2, Colors.get_red());
+ Object3dLayer._makeCube$1(Object3dLayer._scaleUI$1, Vector3d.create(0, 1 - rad * 2, 0), rad * 2, Colors.get_green());
+ Object3dLayer._makeCube$1(Object3dLayer._scaleUI$1, Vector3d.create(0, 0, 1 - rad * 2), rad * 2, Colors.get_blue());
+};
+
+Object3dLayer._makeCube$1 = function (tl, center, size, color) {
+ var dark = Color.fromArgb(255, ss.truncate((color.r * 0.6)), color.g, ss.truncate((color.b * 0.6)));
+ var med = Color.fromArgb(255, ss.truncate((color.r * 0.8)), ss.truncate((color.g * 0.8)), ss.truncate((color.b * 0.8)));
+ tl.addQuad(Vector3d.create(center.x + size, center.y + size, center.z + size), Vector3d.create(center.x + size, center.y + size, center.z - size), Vector3d.create(center.x - size, center.y + size, center.z + size), Vector3d.create(center.x - size, center.y + size, center.z - size), color, Dates.empty());
+ tl.addQuad(Vector3d.create(center.x + size, center.y - size, center.z + size), Vector3d.create(center.x - size, center.y - size, center.z + size), Vector3d.create(center.x + size, center.y - size, center.z - size), Vector3d.create(center.x - size, center.y - size, center.z - size), color, Dates.empty());
+ tl.addQuad(Vector3d.create(center.x - size, center.y + size, center.z + size), Vector3d.create(center.x - size, center.y + size, center.z - size), Vector3d.create(center.x - size, center.y - size, center.z + size), Vector3d.create(center.x - size, center.y - size, center.z - size), dark, Dates.empty());
+ tl.addQuad(Vector3d.create(center.x + size, center.y + size, center.z + size), Vector3d.create(center.x + size, center.y - size, center.z + size), Vector3d.create(center.x + size, center.y + size, center.z - size), Vector3d.create(center.x + size, center.y - size, center.z - size), dark, Dates.empty());
+ tl.addQuad(Vector3d.create(center.x + size, center.y + size, center.z + size), Vector3d.create(center.x - size, center.y + size, center.z + size), Vector3d.create(center.x + size, center.y - size, center.z + size), Vector3d.create(center.x - size, center.y - size, center.z + size), med, Dates.empty());
+ tl.addQuad(Vector3d.create(center.x + size, center.y + size, center.z - size), Vector3d.create(center.x + size, center.y - size, center.z - size), Vector3d.create(center.x - size, center.y + size, center.z - size), Vector3d.create(center.x - size, center.y - size, center.z - size), med, Dates.empty());
+};
+
+Object3dLayer._initRotateUI$1 = function () {
+ Object3dLayer._rotateUi$1 = new TriangleList();
+ Object3dLayer._rotateUi$1.depthBuffered = false;
+ Object3dLayer._rotateUi$1.timeSeries = false;
+ Object3dLayer._rotateUi$1.writeZbuffer = false;
+ var twoPi = Math.PI * 2;
+ var step = twoPi / 40;
+ var rad = 0.05;
+ var index = 0;
+ for (var a = 0; a < twoPi; a += step) {
+ var start = !(index % 10);
+ var end = !((index + 1) % 10);
+ var pnt1 = Vector3d.create(rad * ((start) ? 0 : ((end) ? 1.5 : 1)), Math.cos(a), Math.sin(a));
+ var pnt2 = Vector3d.create(-rad * ((start) ? 0 : ((end) ? 1.5 : 1)), Math.cos(a), Math.sin(a));
+ var pnt3 = Vector3d.create(rad * ((start) ? 1.5 : ((end) ? 0 : 1)), Math.cos(a + step), Math.sin(a + step));
+ var pnt4 = Vector3d.create(-rad * ((start) ? 1.5 : ((end) ? 0 : 1)), Math.cos(a + step), Math.sin(a + step));
+ Object3dLayer._rotateUi$1.addQuad(pnt1, pnt3, pnt2, pnt4, Color._fromArgbColor(192, Colors.get_red()), Dates.empty());
+ index++;
+ }
+ index = 0;
+ for (var a = 0; a < twoPi; a += step) {
+ var start = !(index % 10);
+ var end = !((index + 1) % 10);
+ var pnt1 = Vector3d.create(Math.cos(a), Math.sin(a), rad * ((start) ? 0 : ((end) ? 1.5 : 1)));
+ var pnt2 = Vector3d.create(Math.cos(a), Math.sin(a), -rad * ((start) ? 0 : ((end) ? 1.5 : 1)));
+ var pnt3 = Vector3d.create(Math.cos(a + step), Math.sin(a + step), rad * ((start) ? 1.5 : ((end) ? 0 : 1)));
+ var pnt4 = Vector3d.create(Math.cos(a + step), Math.sin(a + step), -rad * ((start) ? 1.5 : ((end) ? 0 : 1)));
+ Object3dLayer._rotateUi$1.addQuad(pnt1, pnt3, pnt2, pnt4, Color._fromArgbColor(192, Colors.get_blue()), Dates.empty());
+ index++;
+ }
+ index = 0;
+ for (var a = 0; a < twoPi; a += step) {
+ var start = !(index % 10);
+ var end = !((index + 1) % 10);
+ var pnt1 = Vector3d.create(Math.cos(a), rad * ((start) ? 0 : ((end) ? 1.5 : 1)), Math.sin(a));
+ var pnt2 = Vector3d.create(Math.cos(a), -rad * ((start) ? 0 : ((end) ? 1.5 : 1)), Math.sin(a));
+ var pnt3 = Vector3d.create(Math.cos(a + step), rad * ((start) ? 1.5 : ((end) ? 0 : 1)), Math.sin(a + step));
+ var pnt4 = Vector3d.create(Math.cos(a + step), -rad * ((start) ? 1.5 : ((end) ? 0 : 1)), Math.sin(a + step));
+ Object3dLayer._rotateUi$1.addQuad(pnt1, pnt2, pnt3, pnt4, Color._fromArgbColor(192, Colors.get_green()), Dates.empty());
+ index++;
+ }
+
+ // X
+
+ index = 0;
+ for (var a = 0; a < twoPi; a += step) {
+ var start = !(index % 10);
+ var end = !((index + 1) % 10);
+ var pnt1 = Vector3d.create(-rad * ((start) ? 0 : ((end) ? 1.5 : 1)), Math.cos(a), Math.sin(a));
+ var pnt2 = Vector3d.create(rad * ((start) ? 0 : ((end) ? 1.5 : 1)), Math.cos(a), Math.sin(a));
+ var pnt3 = Vector3d.create(-rad * ((start) ? 1.5 : ((end) ? 0 : 1)), Math.cos(a + step), Math.sin(a + step));
+ var pnt4 = Vector3d.create(rad * ((start) ? 1.5 : ((end) ? 0 : 1)), Math.cos(a + step), Math.sin(a + step));
+ Object3dLayer._rotateUi$1.addQuad(pnt1, pnt3, pnt2, pnt4, Colors.get_red(), Dates.empty());
+ index++;
+ }
+
+ // Y
+
+ index = 0;
+ for (var a = 0; a < twoPi; a += step) {
+ var start = !(index % 10);
+ var end = !((index + 1) % 10);
+ var pnt1 = Vector3d.create(Math.cos(a), Math.sin(a), -rad * ((start) ? 0 : ((end) ? 1.5 : 1)));
+ var pnt2 = Vector3d.create(Math.cos(a), Math.sin(a), rad * ((start) ? 0 : ((end) ? 1.5 : 1)));
+ var pnt3 = Vector3d.create(Math.cos(a + step), Math.sin(a + step), -rad * ((start) ? 1.5 : ((end) ? 0 : 1)));
+ var pnt4 = Vector3d.create(Math.cos(a + step), Math.sin(a + step), rad * ((start) ? 1.5 : ((end) ? 0 : 1)));
+ Object3dLayer._rotateUi$1.addQuad(pnt1, pnt3, pnt2, pnt4, Colors.get_blue(), Dates.empty());
+ index++;
+ }
+
+ // Z
+
+ index = 0;
+ for (var a = 0; a < twoPi; a += step) {
+ var start = !(index % 10);
+ var end = !((index + 1) % 10);
+ var pnt1 = Vector3d.create(Math.cos(a), -rad * ((start) ? 0 : ((end) ? 1.5 : 1)), Math.sin(a));
+ var pnt2 = Vector3d.create(Math.cos(a), rad * ((start) ? 0 : ((end) ? 1.5 : 1)), Math.sin(a));
+ var pnt3 = Vector3d.create(Math.cos(a + step), -rad * ((start) ? 1.5 : ((end) ? 0 : 1)), Math.sin(a + step));
+ var pnt4 = Vector3d.create(Math.cos(a + step), rad * ((start) ? 1.5 : ((end) ? 0 : 1)), Math.sin(a + step));
+ Object3dLayer._rotateUi$1.addQuad(pnt1, pnt2, pnt3, pnt4, Colors.get_green(), Dates.empty());
+ index++;
+ }
+};
+
+var Object3dLayer$ = {
+ getPrimaryUI: function () {
+ if (this._primaryUI$1 == null) {
+ this._primaryUI$1 = new Object3dLayerUI(this);
+ }
+ return this._primaryUI$1;
+ },
+
+ get_flipV: function () {
+ return this._flipV$1;
+ },
+
+ set_flipV: function (value) {
+ if (this._flipV$1 !== value) {
+ this._flipV$1 = value;
+ if (this.object3d != null) {
+ this.object3d.flipV = this._flipV$1;
+ this.object3d._reload();
+ }
+ this.version++;
+ }
+ return value;
+ },
+
+ get_flipHandedness: function () {
+ return this._flipHandedness$1;
+ },
+
+ set_flipHandedness: function (value) {
+ if (this._flipHandedness$1 !== value) {
+ this._flipHandedness$1 = value;
+ if (this.object3d != null) {
+ this.object3d.flipHandedness = this._flipHandedness$1;
+ this.object3d._reload();
+ }
+ this.version++;
+ }
+ return value;
+ },
+
+ get_smooth: function () {
+ return this._smooth$1;
+ },
+
+ set_smooth: function (value) {
+ if (this._smooth$1 !== value) {
+ this._smooth$1 = value;
+ if (this.object3d != null) {
+ this.object3d.smooth = this._smooth$1;
+ this.object3d._reload();
+ }
+ this.version++;
+ }
+ return value;
+ },
+
+ get_twoSidedGeometry: function () {
+ return this._twoSidedGeometry$1;
+ },
+
+ set_twoSidedGeometry: function (value) {
+ if (this._twoSidedGeometry$1 !== value) {
+ this._twoSidedGeometry$1 = value;
+ this.version++;
+ }
+ return value;
+ },
+
+ get_heading: function () {
+ return this._heading$1;
+ },
+
+ set_heading: function (value) {
+ if (this._heading$1 !== value) {
+ this.version++;
+ this._heading$1 = value;
+ }
+ return value;
+ },
+
+ get_pitch: function () {
+ return this._pitch$1;
+ },
+
+ set_pitch: function (value) {
+ if (this._pitch$1 !== value) {
+ this.version++;
+ this._pitch$1 = value;
+ }
+ return value;
+ },
+
+ get_roll: function () {
+ return this._roll$1;
+ },
+
+ set_roll: function (value) {
+ if (this._roll$1 !== value) {
+ this.version++;
+ this._roll$1 = value;
+ }
+ return value;
+ },
+
+ get_scale: function () {
+ return this._scale$1;
+ },
+
+ set_scale: function (value) {
+ if (this._scale$1 !== value) {
+ this.version++;
+ this._scale$1 = value;
+ }
+ return value;
+ },
+
+ get_translate: function () {
+ return this._translate$1;
+ },
+
+ set_translate: function (value) {
+ if (this._translate$1 !== value) {
+ this.version++;
+ this._translate$1 = value;
+ }
+ return value;
+ },
+
+ get_lightID: function () {
+ return this._lightID$1;
+ },
+
+ set_lightID: function (value) {
+ this._lightID$1 = value;
+ return value;
+ },
+
+ cleanUp: function () {
+ this._dirty$1 = true;
+ },
+
+ colorChanged: function () {
+ if (this.object3d != null) {
+ this.object3d.color = this.get_color();
+ }
+ },
+
+ writeLayerProperties: function (xmlWriter) {
+ xmlWriter._writeAttributeString('FlipV', this.get_flipV().toString());
+ xmlWriter._writeAttributeString('FlipHandedness', this.get_flipHandedness().toString());
+ xmlWriter._writeAttributeString('Smooth', this.get_smooth().toString());
+ xmlWriter._writeAttributeString('TwoSidedGeometry', this.get_twoSidedGeometry().toString());
+ xmlWriter._writeAttributeString('Heading', this.get_heading().toString());
+ xmlWriter._writeAttributeString('Pitch', this.get_pitch().toString());
+ xmlWriter._writeAttributeString('Roll', this.get_roll().toString());
+ xmlWriter._writeAttributeString('Scale', this.get_scale().toString());
+ xmlWriter._writeAttributeString('Translate', this.get_translate().toString());
+ xmlWriter._writeAttributeString('LightID', this.get_lightID().toString());
+ xmlWriter._writeAttributeString('Obj', this.objType.toString());
+ },
+
+ getParams: function () {
+ var paramList = new Array(14);
+ paramList[0] = this._heading$1;
+ paramList[1] = this._pitch$1;
+ paramList[2] = this._roll$1;
+ paramList[3] = this._scale$1.x;
+ paramList[4] = this._scale$1.y;
+ paramList[5] = this._scale$1.z;
+ paramList[6] = this._translate$1.x;
+ paramList[7] = this._translate$1.y;
+ paramList[8] = this._translate$1.z;
+ paramList[9] = this.get_color().r / 255;
+ paramList[10] = this.get_color().g / 255;
+ paramList[11] = this.get_color().b / 255;
+ paramList[12] = this.get_color().a / 255;
+ paramList[13] = this.get_opacity();
+ return paramList;
+ },
+
+ getParamNames: function () {
+ return ['Heading', 'Pitch', 'Roll', 'Scale.X', 'Scale.Y', 'Scale.Z', 'Translate.X', 'Translate.Y', 'Translate.Z', 'Colors.Red', 'Colors.Green', 'Colors.Blue', 'Colors.Alpha', 'Opacity'];
+ },
+
+ setParams: function (paramList) {
+ if (paramList.length === 14) {
+ this._heading$1 = paramList[0];
+ this._pitch$1 = paramList[1];
+ this._roll$1 = paramList[2];
+ this._scale$1.x = paramList[3];
+ this._scale$1.y = paramList[4];
+ this._scale$1.z = paramList[5];
+ this._translate$1.x = paramList[6];
+ this._translate$1.y = paramList[7];
+ this._translate$1.z = paramList[8];
+ this.set_opacity(paramList[13]);
+ var color = Color.fromArgb(ss.truncate((paramList[12] * 255)), ss.truncate((paramList[9] * 255)), ss.truncate((paramList[10] * 255)), ss.truncate((paramList[11] * 255)));
+ this.set_color(color);
+ }
+ },
+
+ add_propertiesChanged: function (value) {
+ this.__propertiesChanged$1 = ss.bindAdd(this.__propertiesChanged$1, value);
+ },
+
+ remove_propertiesChanged: function (value) {
+ this.__propertiesChanged$1 = ss.bindSub(this.__propertiesChanged$1, value);
+ },
+
+ fireChanged: function () {
+ if (this.__propertiesChanged$1 != null) {
+ this.__propertiesChanged$1(this, new ss.EventArgs());
+ }
+ },
+
+ getEditUI: function () {
+ return ss.safeCast(this, IUiController);
+ },
+
+ initializeFromXml: function (node) {
+ this.set_flipV(ss.boolean(node.attributes.getNamedItem('FlipV').nodeValue));
+ if (node.attributes.getNamedItem('FlipHandedness') != null) {
+ this.set_flipHandedness(ss.boolean(node.attributes.getNamedItem('FlipHandedness').nodeValue));
+ } else {
+ this.set_flipHandedness(false);
+ }
+ if (node.attributes.getNamedItem('Smooth') != null) {
+ this.set_smooth(ss.boolean(node.attributes.getNamedItem('Smooth').nodeValue));
+ } else {
+ this.set_smooth(true);
+ }
+ if (node.attributes.getNamedItem('TwoSidedGeometry') != null) {
+ this.set_twoSidedGeometry(ss.boolean(node.attributes.getNamedItem('TwoSidedGeometry').nodeValue));
+ } else {
+ this.set_twoSidedGeometry(false);
+ }
+ if (node.attributes.getNamedItem('Obj') != null) {
+ this.objType = ss.boolean(node.attributes.getNamedItem('Obj').nodeValue);
+ } else {
+ this.objType = false;
+ }
+ this.set_heading(parseFloat(node.attributes.getNamedItem('Heading').nodeValue));
+ this.set_pitch(parseFloat(node.attributes.getNamedItem('Pitch').nodeValue));
+ this.set_roll(parseFloat(node.attributes.getNamedItem('Roll').nodeValue));
+ this.set_scale(Vector3d.parse(node.attributes.getNamedItem('Scale').nodeValue));
+ this.set_translate(Vector3d.parse(node.attributes.getNamedItem('Translate').nodeValue));
+ if (node.attributes.getNamedItem('LightID') != null) {
+ this.set_lightID(parseInt(node.attributes.getNamedItem('LightID').nodeValue));
+ }
+ },
+
+ draw: function (renderContext, opacity, flat) {
+ var oldWorld = renderContext.get_world();
+ var rotation = Matrix3d.multiplyMatrix(Matrix3d.multiplyMatrix(Matrix3d._rotationZ(-this._roll$1 / 180 * Math.PI), Matrix3d._rotationX(-this._pitch$1 / 180 * Math.PI)), Matrix3d._rotationY(this._heading$1 / 180 * Math.PI));
+ renderContext.set_world(Matrix3d.multiplyMatrix(Matrix3d.multiplyMatrix(Matrix3d.multiplyMatrix(rotation, Matrix3d._scaling(this._scale$1.x, this._scale$1.y, this._scale$1.z)), Matrix3d.translation(this._translate$1)), oldWorld));
+ renderContext.set_twoSidedLighting(this.get_twoSidedGeometry());
+ BasePlanets.drawPointPlanet(renderContext, new Vector3d(), 1, Colors.get_red(), false);
+ if (this._lightID$1 > 0) {
+ // draw light
+ } else {
+ if (this.object3d != null) {
+ this.object3d.color = this.get_color();
+ this.object3d.render(renderContext, opacity * this.get_opacity());
+ }
+ }
+
+ // todo enable edit UI
+
+ renderContext.set_twoSidedLighting(false);
+ renderContext.set_world(oldWorld);
+ return true;
+ },
+
+ addFilesToCabinet: function (fc) {
+ // todo: implement
+ },
+
+ loadData: function (doc, filename) {
+ if (ss.endsWith(filename.toLowerCase(), '.obj')) {
+ this.objType = true;
+ }
+ if (!this._lightID$1) {
+ if (this.objType) {
+ this.object3d = new Object3d(doc, ss.replaceString(filename, '.txt', '.obj'), this.get_flipV(), this._flipHandedness$1, true, this.get_color());
+ }
+ else {
+ this.object3d = new Object3d(doc, ss.replaceString(filename, '.txt', '.3ds'), this.get_flipV(), this._flipHandedness$1, true, this.get_color());
+ }
+ }
+ },
+
+ pointToView: function (pnt) {
+ var clientHeight = globalRenderContext.height;
+ var clientWidth = globalRenderContext.width;
+ var viewWidth = (globalRenderContext.width / globalRenderContext.height) * 1116;
+ var x = ((pnt.x) / (clientWidth) * viewWidth) - ((viewWidth - 1920) / 2);
+ var y = (pnt.y) / clientHeight * 1116;
+ return Vector2d.create(x, y);
+ },
+
+ render: function (renderEngine) {
+ this._showEditUi$1 = true;
+ return;
+ },
+
+ preRender: function (renderEngine) {
+ this._showEditUi$1 = true;
+ return;
+ },
+
+ mouseDown: function (sender, e) {
+ var location = this.pointToView(Vector2d.create(e.offsetX, e.offsetY));
+ this._pntDown$1 = location;
+ var pnt = location;
+ if (e.shiftKey) {
+ if (Vector2d.subtract(pnt, this._xHandle$1).get_length() < this._hitDist$1) {
+ this._dragMode$1 = 10;
+ this._valueOnDown$1 = this._scale$1.x;
+ return true;
+ }
+ if (Vector2d.subtract(pnt, this._yHandle$1).get_length() < this._hitDist$1) {
+ this._dragMode$1 = 10;
+ this._valueOnDown$1 = this._scale$1.y;
+ return true;
+ }
+ if (Vector2d.subtract(pnt, this._zHandle$1).get_length() < this._hitDist$1) {
+ this._dragMode$1 = 10;
+ this._valueOnDown$1 = this._scale$1.z;
+ return true;
+ }
+ } else {
+ if (Vector2d.subtract(pnt, this._xHandle$1).get_length() < this._hitDist$1) {
+ this._dragMode$1 = 1;
+ this._valueOnDown$1 = this._translate$1.x;
+ return true;
+ }
+ if (Vector2d.subtract(pnt, this._yHandle$1).get_length() < this._hitDist$1) {
+ this._dragMode$1 = 2;
+ this._valueOnDown$1 = this._translate$1.y;
+ return true;
+ }
+ if (Vector2d.subtract(pnt, this._zHandle$1).get_length() < this._hitDist$1) {
+ this._dragMode$1 = 3;
+ this._valueOnDown$1 = this._translate$1.z;
+ return true;
+ }
+ }
+ for (var i = 0; i < this._hprHandles$1.length; i++) {
+ if (Vector2d.subtract(pnt, this._hprHandles$1[i]).get_length() < this._hitDist$1) {
+ switch (i) {
+ case 0:
+ this._dragMode$1 = 4;
+ this._valueOnDown$1 = this._heading$1;
+ this._valueOnDown2$1 = this._pitch$1;
+ return true;
+ case 1:
+ this._dragMode$1 = 7;
+ this._valueOnDown$1 = this._heading$1;
+ this._valueOnDown2$1 = this._pitch$1;
+ return true;
+ case 2:
+ this._dragMode$1 = 5;
+ this._valueOnDown$1 = this._pitch$1;
+ this._valueOnDown2$1 = this._roll$1;
+ return true;
+ case 3:
+ this._dragMode$1 = 8;
+ this._valueOnDown$1 = this._pitch$1;
+ this._valueOnDown2$1 = this._roll$1;
+ return true;
+ case 4:
+ this._dragMode$1 = 6;
+ this._valueOnDown$1 = this._roll$1;
+ this._valueOnDown2$1 = this._heading$1;
+ return true;
+ case 5:
+ this._dragMode$1 = 9;
+ this._valueOnDown$1 = this._roll$1;
+ this._valueOnDown2$1 = this._heading$1;
+ return true;
+ default:
+ break;
+ }
+ }
+ }
+ return false;
+ },
+
+ mouseUp: function (sender, e) {
+ if (!!this._dragMode$1) {
+ this._dragMode$1 = 0;
+ this._lockPreferedAxis$1 = false;
+ return true;
+ }
+ return false;
+ },
+
+ mouseMove: function (sender, e) {
+ var location = this.pointToView(Vector2d.create(e.offsetX, e.offsetY));
+ if (!!this._dragMode$1) {
+ var dist = 0;
+ var distX = location.x - this._pntDown$1.x;
+ var distY = -(location.y - this._pntDown$1.y);
+ if (this._lockPreferedAxis$1) {
+ if (this._preferY$1) {
+ dist = distY;
+ this._preferY$1 = true;
+ Cursor.set_current(Cursors.get_sizeNS());
+ }
+ else {
+ dist = distX;
+ this._preferY$1 = false;
+ Cursor.set_current(Cursors.get_sizeWE());
+ }
+ }
+ else {
+ if (Math.abs(distX) > Math.abs(distY)) {
+ dist = distX;
+ this._preferY$1 = false;
+ }
+ else {
+ dist = distY;
+ this._preferY$1 = true;
+ }
+ if (dist > 5) {
+ this._lockPreferedAxis$1 = true;
+ }
+ }
+ switch (this._dragMode$1) {
+ case 0:
+ break;
+ case 1:
+ this._translate$1.x = this._valueOnDown$1 + (12 * this._uiScale$1 * (dist / globalRenderContext.width));
+ break;
+ case 2:
+ this._translate$1.y = this._valueOnDown$1 + (12 * this._uiScale$1 * (dist / globalRenderContext.width));
+ break;
+ case 3:
+ this._translate$1.z = this._valueOnDown$1 + (12 * this._uiScale$1 * (dist / globalRenderContext.width));
+ break;
+ case 4:
+ this._heading$1 = this._valueOnDown$1 - distX / 4;
+ this._pitch$1 = this._valueOnDown2$1 + distY / 4;
+ break;
+ case 5:
+ this._pitch$1 = this._valueOnDown$1 + distY / 4;
+ this._roll$1 = this._valueOnDown2$1 - distX / 4;
+ break;
+ case 6:
+ this._roll$1 = this._valueOnDown$1 + distY / 4;
+ this._heading$1 = this._valueOnDown2$1 - distX / 4;
+ break;
+ case 7:
+ this._heading$1 = this._valueOnDown$1 - distX / 4;
+ this._pitch$1 = this._valueOnDown2$1 - distY / 4;
+ break;
+ case 8:
+ this._pitch$1 = this._valueOnDown$1 + distY / 4;
+ this._roll$1 = this._valueOnDown2$1 + distX / 4;
+ break;
+ case 9:
+ this._roll$1 = this._valueOnDown$1 - distY / 4;
+ this._heading$1 = this._valueOnDown2$1 - distX / 4;
+ break;
+ case 10:
+ this._scale$1.x = this._scale$1.y = this._scale$1.z = this._valueOnDown$1 * Math.pow(2, (dist / 100));
+ break;
+ default:
+ break;
+ }
+ this.fireChanged();
+ return true;
+ } else {
+ var pnt = location;
+ if (Vector2d.subtract(pnt, this._xHandle$1).get_length() < this._hitDist$1) {
+ Cursor.set_current(Cursors.get_sizeAll());
+ return true;
+ }
+ if (Vector2d.subtract(pnt, this._yHandle$1).get_length() < this._hitDist$1) {
+ Cursor.set_current(Cursors.get_sizeAll());
+ return true;
+ }
+ if (Vector2d.subtract(pnt, this._zHandle$1).get_length() < this._hitDist$1) {
+ Cursor.set_current(Cursors.get_sizeAll());
+ return true;
+ }
+ for (var i = 0; i < this._hprHandles$1.length; i++) {
+ if (Vector2d.subtract(pnt, this._hprHandles$1[i]).get_length() < this._hitDist$1) {
+ Cursor.set_current(Cursors.get_sizeAll());
+ return true;
+ }
+ }
+ }
+ return false;
+ },
+
+ mouseClick: function (sender, e) {
+ return false;
+ },
+
+ click: function (sender, e) {
+ return false;
+ },
+
+ mouseDoubleClick: function (sender, e) {
+ return false;
+ },
+
+ keyDown: function (sender, e) {
+ return false;
+ },
+
+ keyUp: function (sender, e) {
+ return false;
+ },
+
+ hover: function (pnt) {
+ return false;
+ }
+};
+
+registerType("Object3dLayer", [Object3dLayer, Object3dLayer$, Layer, IUiController]);
+
+
+// wwtlib.Group
+
+export function Group() {
+ this.startIndex = 0;
+ this.indexCount = 0;
+ this.materialIndex = 0;
+}
+
+var Group$ = {};
+
+registerType("Group", [Group, Group$, null]);
+
+// wwtlib.Mesh
+
+export function Mesh() {
+ this.boundingSphere = new SphereHull();
+}
+
+Mesh.create = function (vertices, indices) {
+ var mesh = new Mesh();
+ mesh.vertices = vertices;
+ mesh.indices = indices;
+ var points = new Array(vertices.length);
+ for (var i = 0; i < vertices.length; ++i) {
+ points[i] = vertices[i].get_position();
+ }
+ mesh.boundingSphere = ConvexHull.findEnclosingSphereFast(points);
+ return mesh;
+};
+
+Mesh.createTangent = function (vertices, indices) {
+ var mesh = new Mesh();
+ mesh.tangentVertices = vertices;
+ mesh.indices = indices;
+ var points = new Array(mesh.tangentVertices.length);
+ for (var i = 0; i < mesh.tangentVertices.length; ++i) {
+ points[i] = mesh.tangentVertices[i].get_position();
+ }
+ mesh.boundingSphere = ConvexHull.findEnclosingSphereFast(points);
+ return mesh;
+};
+
+var Mesh$ = {
+ dispose: function () {
+ if (this.vertexBuffer != null) {
+ this.vertexBuffer.dispose();
+ this.vertexBuffer = null;
+ }
+ if (this.tangentVertexBuffer != null) {
+ this.tangentVertexBuffer.dispose();
+ this.tangentVertexBuffer = null;
+ }
+ if (this.indexBuffer != null) {
+ this.indexBuffer.dispose();
+ this.indexBuffer = null;
+ }
+ },
+
+ setObjects: function (objects) {
+ this._objects = objects;
+ },
+
+ // Convert the vertex data to a GPU vertex buffer
+ commitToDevice: function () {
+ if (this.vertices != null) {
+ this.vertexBuffer = PositionNormalTexturedVertexBuffer.create(this.vertices);
+ } else if (this.tangentVertices != null) {
+ this.tangentVertexBuffer = PositionNormalTexturedTangentVertexBuffer.create(this.tangentVertices);
+ }
+ this.indexBuffer = new IndexBuffer(new Uint32Array(this.indices));
+ },
+
+ beginDrawing: function (renderContext) {
+ if (this.vertexBuffer != null) {
+ renderContext._setVertexBuffer(this.vertexBuffer);
+ } else if (this.tangentVertexBuffer != null) {
+ renderContext._setVertexBuffer(this.tangentVertexBuffer);
+ }
+ if (this.indexBuffer != null) {
+ renderContext._setIndexBuffer(this.indexBuffer);
+ }
+ },
+
+ drawSubset: function (renderContext, materialIndex) {
+ if (this.indexBuffer == null || this._objects == null) {
+ return;
+ }
+ this.drawHierarchy(this._objects, materialIndex, renderContext, 0);
+ },
+
+ drawHierarchy: function (nodes, materialIndex, renderContext, depth) {
+ if (depth > 1212) {
+ return;
+ }
+ var $enum1 = ss.enumerate(nodes);
+ while ($enum1.moveNext()) {
+ var node = $enum1.current;
+ if (node.drawGroup != null && node.enabled) {
+ var $enum2 = ss.enumerate(node.drawGroup);
+ while ($enum2.moveNext()) {
+ var group = $enum2.current;
+ if (group.materialIndex === materialIndex) {
+ renderContext.gl.drawElements(WEBGL.TRIANGLES, group.indexCount, WEBGL.UNSIGNED_INT, group.startIndex * 4);
+ }
+ }
+ }
+ this.drawHierarchy(node.children, materialIndex, renderContext, depth + 1);
+ }
+ },
+
+ get_objects: function () {
+ return this._objects;
+ },
+
+ set_objects: function (value) {
+ this._objects = value;
+ return value;
+ }
+};
+
+registerType("Mesh", [Mesh, Mesh$, null, ss.IDisposable]);
+
+
+// wwtlib.VertexPosition
+
+export function VertexPosition() {
+ this.index = 0;
+}
+
+var VertexPosition$ = {};
+
+registerType("VertexPosition", [VertexPosition, VertexPosition$, null]);
+
+
+// wwtlib.Object3d
+
+export function Object3d(tourDoc, filename, flipV, flipHandedness, smooth, color) {
+ this.flipHandedness = false;
+ this.flipV = true;
+ this.smooth = true;
+ this._mesh = null; // Our mesh object in sysmem
+ this._meshMaterials = [];
+ this._meshTextures = [];
+ this._meshSpecularTextures = [];
+ this._meshNormalMaps = [];
+ this.meshFilenames = [];
+ this.color = Colors.get_white();
+ this._textureCache = {};
+ this._matFiles = new Array(0);
+ this._matFileIndex = 0;
+ this.objects = [];
+ this._matLib = {};
+ this._textureLib = {};
+ this._tourDocument = null;
+ this.issLayer = false;
+ this._readyToRender = false;
+ this.useCurrentAmbient = false;
+ this._dirty = true;
+ this.color = color;
+ this.smooth = smooth;
+ this.flipV = flipV;
+ this.flipHandedness = flipHandedness;
+ this.filename = filename;
+ if (ss.endsWith(this.filename.toLowerCase(), '.obj')) {
+ this._loadMeshFromObj(tourDoc, this.filename);
+ }
+ else {
+ this._loadMeshFrom3ds(tourDoc, this.filename, 1);
+ }
+}
+
+Object3d._compareVector3 = function (v0, v1) {
+ if (v0.x < v1.x) {
+ return -1;
+ }
+ else if (v0.x > v1.x) {
+ return 1;
+ }
+ else if (v0.y < v1.y) {
+ return -1;
+ }
+ else if (v0.y > v1.y) {
+ return 1;
+ }
+ else if (v0.z < v1.z) {
+ return -1;
+ }
+ else if (v0.z > v1.z) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+};
+
+Object3d._compareVector = function (v0, v1) {
+ if (v0.x < v1.x) {
+ return -1;
+ }
+ else if (v0.x > v1.x) {
+ return 1;
+ }
+ else if (v0.y < v1.y) {
+ return -1;
+ }
+ else if (v0.y > v1.y) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+};
+
+Object3d._getMaterialID = function (material, materialNames) {
+ var index = 0;
+ var $enum1 = ss.enumerate(materialNames);
+ while ($enum1.moveNext()) {
+ var mat = $enum1.current;
+ if (mat === material) {
+ return index;
+ }
+ index++;
+ }
+ return -1;
+};
+
+Object3d._disposeTextureList = function (textures) {
+ if (textures != null) {
+ for (var i = 0; i < textures.length; ++i) {
+ if (textures[i] != null) {
+ textures[i].dispose();
+ textures[i] = null;
+ }
+ }
+ textures.length = 0;
+ }
+};
+
+var Object3d$ = {
+ _reload: function () {
+ if (!this.issLayer) {
+ this.dispose();
+ if (ss.endsWith(this.filename.toLowerCase(), '.obj')) {
+ this._loadMeshFromObj(this._tourDocument, this.filename);
+ }
+ else {
+ this._loadMeshFrom3ds(this._tourDocument, this.filename, 1);
+ }
+ }
+ },
+
+ // Calculate per-vertex normals by averaging face normals. Normals of adjacent faces with an
+ // angle of greater than crease angle are not included in the average. CalculateVertexNormalsMerged
+ // is slower than the other normal generation method, CalculateVertexNormals, but it produces better
+ // results. Vertices with identical positions (bot possibly different texture coordinates) are treated
+ // as the same vertex for purposes of normal calculation. This allows smooth normals across texture
+ // wrap seams.
+ //
+ // This method returns an array of vertex normals, one for each index in the index list
+ _calculateVertexNormalsMerged: function (vertexList, indexList, creaseAngleRad) {
+ if (!vertexList.length) {
+ return null;
+ }
+ var vertexCount = vertexList.length;
+ var triangleCount = Math.floor(indexList.length / 3);
+
+ // Create a list of vertices sorted by their positions. This will be used to
+ // produce a list of vertices with unique positions.
+ var vertexPositions = [];
+ for (var vertexIndex = 0; vertexIndex < vertexList.length; ++vertexIndex) {
+ var vp = new VertexPosition();
+ vp.position = vertexList[vertexIndex].get_position();
+ vp.index = vertexIndex;
+ vertexPositions.push(vp);
+ }
+ vertexPositions.sort(function (v0, v1) {
+ return Object3d._compareVector3(v0.position, v1.position);
+ });
+
+ // vertexMap will map a vertex index to the index of a vertex with a unique position
+ var vertexMap = new Array(vertexPositions.length);
+ var uniqueVertexCount = 0;
+ for (var vertexIndex = 0; vertexIndex < vertexPositions.length; vertexIndex++) {
+ if (!vertexIndex || !!Object3d._compareVector3(vertexPositions[vertexIndex].position, vertexPositions[vertexIndex - 1].position)) {
+ ++uniqueVertexCount;
+ }
+ vertexMap[vertexPositions[vertexIndex].index] = uniqueVertexCount - 1;
+ }
+ var vertexInstanceCounts = new Array(uniqueVertexCount);
+ for (var i = 0; i < uniqueVertexCount; i++) {
+ vertexInstanceCounts[i] = 0;
+ }
+ var $enum1 = ss.enumerate(indexList);
+ while ($enum1.moveNext()) {
+ var vertexIndex = $enum1.current;
+ var uniqueIndex = vertexMap[vertexIndex];
+ vertexInstanceCounts[uniqueIndex]++;
+ }
+
+ // vertexInstances contains the list of faces each vertex is referenced in
+ var vertexInstances = new Array(uniqueVertexCount);
+ for (var i = 0; i < uniqueVertexCount; ++i) {
+ var count = vertexInstanceCounts[i];
+ if (count > 0) {
+ vertexInstances[i] = new Array(count);
+ for (var j = 0; j < count; j++) {
+ vertexInstances[i][j] = 0;
+ }
+ }
+ }
+
+ // For each vertex, record all faces which include it
+ for (var i = 0; i < indexList.length; ++i) {
+ var faceIndex = Math.floor(i / 3);
+ var uniqueIndex = vertexMap[indexList[i]];
+ vertexInstances[uniqueIndex][--vertexInstanceCounts[uniqueIndex]] = faceIndex;
+ }
+
+ // At this point, vertexInstanceCounts should contain nothing but zeroes
+
+ // Compute normals for all faces
+ var faceNormals = new Array(triangleCount);
+ for (var i = 0; i < triangleCount; ++i) {
+ // The face normal is just the cross product of the two edge vectors
+ var i0 = indexList[i * 3 + 0];
+ var i1 = indexList[i * 3 + 1];
+ var i2 = indexList[i * 3 + 2];
+ var edge0 = Vector3d.subtractVectors(vertexList[i1].get_position(), vertexList[i0].get_position());
+ var edge1 = Vector3d.subtractVectors(vertexList[i2].get_position(), vertexList[i1].get_position());
+ faceNormals[i] = Vector3d.cross(edge0, edge1);
+ faceNormals[i].normalize();
+ }
+
+ // Finally, average the face normals
+ var newVertexCount = triangleCount * 3;
+ var vertexNormals = new Array(newVertexCount);
+ var cosCreaseAngle = Math.min(0.9999, Math.cos(creaseAngleRad));
+ for (var i = 0; i < newVertexCount; ++i) {
+ var vertexIndex = indexList[i];
+ var uniqueIndex = vertexMap[vertexIndex];
+ var faceNormal = faceNormals[Math.floor(i / 3)];
+ var sum = new Vector3d();
+ var $enum2 = ss.enumerate(vertexInstances[uniqueIndex]);
+ while ($enum2.moveNext()) {
+ var faceIndex = $enum2.current;
+ var n = faceNormals[faceIndex];
+ if (Vector3d.dot(faceNormal, n) > cosCreaseAngle) {
+ sum.add(n);
+ }
+ }
+ vertexNormals[i] = sum;
+ vertexNormals[i].normalize();
+ }
+ return vertexNormals;
+ },
+
+ // Calculate tangent vectors at each vertex. The 'face tangent' is a direction in the plane of the
+ // triangle and parallel to the direction of increasing tex coord u, i.e. the partial derivative
+ // with respect to u of the triangle's plane equation expressed in terms of the texture coordinate
+ // (u, v). Partial derivatives of the triangles containing a vertex are averaged to compute the
+ // vertex tangent. Faces are not included in the when the angle formed with the test face is
+ // greater than the crease angle, or when the texture texture coordinates are not continuous.
+ //
+ // This method returns an array of vertex normals, one for each index in the index list
+ _calculateVertexTangents: function (vertexList, indexList, creaseAngleRad) {
+ if (!vertexList.length) {
+ return null;
+ }
+ var vertexCount = vertexList.length;
+ var triangleCount = Math.floor(indexList.length / 3);
+
+ // Create a list of vertices sorted by their positions. This will be used to
+ // produce a list of vertices with unique positions.
+ var vertexPositions = [];
+ for (var vertexIndex = 0; vertexIndex < vertexList.length; ++vertexIndex) {
+ var vp = new VertexPosition();
+ vp.position = vertexList[vertexIndex].get_position();
+ vp.index = vertexIndex;
+ vertexPositions.push(vp);
+ }
+ vertexPositions.sort(function (v0, v1) {
+ return Object3d._compareVector3(v0.position, v1.position);
+ });
+
+ // vertexMap will map a vertex index to the index of a vertex with a unique position
+ var vertexMap = new Array(vertexPositions.length);
+ var uniqueVertexCount = 0;
+ for (var vertexIndex = 0; vertexIndex < vertexPositions.length; vertexIndex++) {
+ if (!vertexIndex || !!Object3d._compareVector3(vertexPositions[vertexIndex].position, vertexPositions[vertexIndex - 1].position)) {
+ ++uniqueVertexCount;
+ }
+ vertexMap[vertexPositions[vertexIndex].index] = (uniqueVertexCount - 1);
+ }
+ var vertexInstanceCounts = new Array(uniqueVertexCount);
+ for (var i = 0; i < uniqueVertexCount; i++) {
+ vertexInstanceCounts[i] = 0;
+ }
+ var $enum1 = ss.enumerate(indexList);
+ while ($enum1.moveNext()) {
+ var vertexIndex = $enum1.current;
+ var uniqueIndex = vertexMap[vertexIndex];
+ vertexInstanceCounts[uniqueIndex]++;
+ }
+
+ // vertexInstances contains the list of faces each vertex is referenced in
+ var vertexInstances = new Array(uniqueVertexCount);
+ for (var i = 0; i < uniqueVertexCount; ++i) {
+ var count = vertexInstanceCounts[i];
+ if (count > 0) {
+ vertexInstances[i] = new Array(count);
+ for (var j = 0; j < count; j++) {
+ vertexInstances[i][j] = 0;
+ }
+ }
+ }
+
+ // For each vertex, record all faces which include it
+ for (var i = 0; i < indexList.length; ++i) {
+ var faceIndex = Math.floor(i / 3);
+ var uniqueIndex = vertexMap[indexList[i]];
+ vertexInstances[uniqueIndex][--vertexInstanceCounts[uniqueIndex]] = faceIndex;
+ }
+
+ // At this point, vertexInstanceCounts should contain nothing but zeroes
+
+ // Compute partial derivatives for all faces
+ var partials = new Array(triangleCount);
+ for (var i = 0; i < triangleCount; ++i) {
+ var v0 = vertexList[indexList[i * 3 + 0]];
+ var v1 = vertexList[indexList[i * 3 + 1]];
+ var v2 = vertexList[indexList[i * 3 + 2]];
+ var edge0 = Vector3d.subtractVectors(v1.get_position(), v0.get_position());
+ var edge1 = Vector3d.subtractVectors(v2.get_position(), v0.get_position());
+ var m00 = v1.tu - v0.tu;
+ var m01 = v1.tv - v0.tv;
+ var m10 = v2.tu - v0.tu;
+ var m11 = v2.tv - v0.tv;
+ var determinant = m00 * m11 - m01 * m10;
+ if (Math.abs(determinant) < 1E-06) {
+ if (edge0.lengthSq() > 0) {
+ // No unique vector; just select one of the edges
+ partials[i] = edge0;
+ partials[i].normalize();
+ }
+ else {
+ // Degenerate edge; just use the unit x vector
+ partials[i] = Vector3d.create(1, 0, 0);
+ }
+ }
+ else {
+ // Matrix n is the inverse of m
+ var invDeterminant = 1 / determinant;
+ var n00 = m11 * invDeterminant;
+ var n01 = -m01 * invDeterminant;
+ var n10 = -m10 * invDeterminant;
+ var n11 = m00 * invDeterminant;
+ partials[i] = Vector3d.addVectors(Vector3d.multiplyScalar(edge0, n00), Vector3d.multiplyScalar(edge1, n01));
+ partials[i].normalize();
+ }
+ }
+
+ // Finally, average the partial derivatives
+ var newVertexCount = triangleCount * 3;
+ var tangents = new Array(newVertexCount);
+ var cosCreaseAngle = Math.min(0.9999, Math.cos(creaseAngleRad));
+ for (var i = 0; i < newVertexCount; ++i) {
+ var vertexIndex = indexList[i];
+ var uniqueIndex = vertexMap[vertexIndex];
+ var du = partials[Math.floor(i / 3)];
+ var sum = new Vector3d();
+ var $enum2 = ss.enumerate(vertexInstances[uniqueIndex]);
+ while ($enum2.moveNext()) {
+ var faceIndex = $enum2.current;
+ var T = partials[faceIndex];
+ if (Vector3d.dot(du, T) > cosCreaseAngle) {
+ sum.add(T);
+ }
+ }
+ var N = vertexList[vertexIndex].get_normal();
+
+ // Make the tangent orthogonal to the vertex normal
+ tangents[i] = Vector3d.subtractVectors(sum, Vector3d.multiplyScalar(N, Vector3d.dot(N, sum)));
+ tangents[i].normalize();
+ }
+ return tangents;
+ },
+
+ // Calculate per-vertex normals by averaging face normals. Normals of adjacent faces with an
+ // angle of greater than crease angle are not included in the average.
+ //
+ // This method returns an array of vertex normals, one for each index in the index list
+ _calculateVertexNormals: function (vertexList, indexList, creaseAngleRad) {
+ var vertexCount = vertexList.length;
+ var triangleCount = Math.floor(indexList.length / 3);
+
+ // vertexInstanceCounts contains the number of times each vertex is referenced in the mesh
+ var vertexInstanceCounts = new Array(vertexCount);
+ var $enum1 = ss.enumerate(indexList);
+ while ($enum1.moveNext()) {
+ var vertexIndex = $enum1.current;
+ vertexInstanceCounts[vertexIndex]++;
+ }
+
+ // vertexInstances contains the list of faces each vertex is referenced in
+ var vertexInstances = new Array(vertexCount);
+ for (var i = 0; i < vertexCount; ++i) {
+ var count = vertexInstanceCounts[i];
+ if (count > 0) {
+ vertexInstances[i] = new Array(count);
+ }
+ }
+
+ // For each vertex, record all faces which include it
+ for (var i = 0; i < indexList.length; ++i) {
+ var faceIndex = Math.floor(i / 3);
+ var vertexIndex = indexList[i];
+ vertexInstances[vertexIndex][--vertexInstanceCounts[vertexIndex]] = faceIndex;
+ }
+
+ // At this point, vertexInstanceCounts should contain nothing but zeroes
+
+ // Compute normals for all faces
+ var faceNormals = new Array(triangleCount);
+ for (var i = 0; i < triangleCount; ++i) {
+ // The face normal is just the cross product of the two edge vectors
+ var i0 = indexList[i * 3 + 0];
+ var i1 = indexList[i * 3 + 1];
+ var i2 = indexList[i * 3 + 2];
+ var edge0 = Vector3d.subtractVectors(vertexList[i1].get_position(), vertexList[i0].get_position());
+ var edge1 = Vector3d.subtractVectors(vertexList[i2].get_position(), vertexList[i1].get_position());
+ faceNormals[i] = Vector3d.cross(edge0, edge1);
+ faceNormals[i].normalize();
+ }
+
+ // Finally, average the face normals
+ var newVertexCount = triangleCount * 3;
+ var vertexNormals = new Array(newVertexCount);
+ var cosCreaseAngle = Math.min(0.9999, Math.cos(creaseAngleRad));
+ for (var i = 0; i < newVertexCount; ++i) {
+ var vertexIndex = indexList[i];
+ var faceNormal = faceNormals[Math.floor(i / 3)];
+ var sum = new Vector3d();
+ var $enum2 = ss.enumerate(vertexInstances[vertexIndex]);
+ while ($enum2.moveNext()) {
+ var faceIndex = $enum2.current;
+ var n = faceNormals[faceIndex];
+ if (Vector3d.dot(faceNormal, n) > cosCreaseAngle) {
+ sum.add(n);
+ }
+ }
+ vertexNormals[i] = sum;
+ vertexNormals[i].normalize();
+ }
+ return vertexNormals;
+ },
+
+ // Add textures to ensure that we have as many textures as [...]
+ _addMaterial: function (material) {
+ this._meshMaterials.push(material);
+ while (this._meshTextures.length < this._meshMaterials.length) {
+ this._meshTextures.push(null);
+ }
+ while (this._meshSpecularTextures.length < this._meshMaterials.length) {
+ this._meshSpecularTextures.push(null);
+ }
+ while (this._meshNormalMaps.length < this._meshMaterials.length) {
+ this._meshNormalMaps.push(null);
+ }
+ },
+
+ // Load a color chunk from a 3ds file`
+ // Colors may be stored in a 3ds file either as 3 floats or 3 bytes
+ _loadColorChunk: function (br) {
+ var chunkID = br.readUInt16();
+ var chunkLength = br.readUInt32();
+ var color = Colors.get_black();
+ if ((chunkID === 16 || chunkID === 19) && chunkLength === 18) {
+ // Need to guard against values outside of [0, 1], otherwise Colors.FromArgb
+ // will throw an exception.
+ var r = Math.max(0, Math.min(1, br.readSingle()));
+ var g = Math.max(0, Math.min(1, br.readSingle()));
+ var b = Math.max(0, Math.min(1, br.readSingle()));
+ color = Color.fromArgb(255, ss.truncate((255 * r)), ss.truncate((255 * g)), ss.truncate((255 * b)));
+ } else if ((chunkID === 17 || chunkID === 18) && chunkLength === 9) {
+ color = Color.fromArgb(255, br.readByte(), br.readByte(), br.readByte());
+ } else {
+ // Unknown color block; ignore it
+ br.readBytes(chunkLength - 6);
+ }
+ return color;
+ },
+
+ // Load a percentage chunk from a 3ds file
+ // A percentage may be stored as either a float or a 16-bit integer
+ _loadPercentageChunk: function (br) {
+ var chunkID = br.readUInt16();
+ var chunkLength = br.readUInt32();
+ var percentage = 0;
+ if (chunkID === 48 && chunkLength === 8) {
+ percentage = br.readUInt16();
+ } else if (chunkID === 49 && chunkLength === 10) {
+ percentage = br.readSingle();
+ } else {
+ // Unknown percentage block; ignore it
+ br.readBytes(chunkLength - 6);
+ }
+ return percentage;
+ },
+
+ _loadMeshFromObj: function (doc, filename) {
+ var $this = this;
+
+ this.filename = filename;
+ this._tourDocument = doc;
+ var blob = doc.getFileBlob(filename);
+ var chunck = new FileReader();
+ chunck.onloadend = function (e) {
+ $this._matFiles = $this._readObjMaterialsFromBin(ss.safeCast(chunck.result, String));
+ $this._matFileIndex = 0;
+
+ // pass data to LoadMatLib. It will chain load all the material
+ // files, then load the obj from this data - hack for having no
+ // synchronous blob reading in javascript
+ $this._loadMatLib(ss.safeCast(chunck.result, String));
+ };
+ chunck.readAsText(blob);
+ },
+
+ _readObjMaterialsFromBin: function (data) {
+ var matFiles = [];
+ var lines = data.split('\n');
+ var $enum1 = ss.enumerate(lines);
+ while ($enum1.moveNext()) {
+ var lineraw = $enum1.current;
+ var line = ss.replaceString(lineraw, ' ', ' ');
+ var parts = ss.trim(line).split(' ');
+ if (parts.length > 0) {
+ switch (parts[0]) {
+ case 'mtllib':
+ var path = this.filename.substring(0, this.filename.lastIndexOf('\\') + 1);
+ var matFile = path + parts[1];
+ matFiles.push(matFile);
+ break;
+ }
+ }
+ }
+ return matFiles;
+ },
+
+ _readObjFromBin: function (data) {
+ var objectFound = false;
+ var objects = [];
+ var currentObject = new ObjectNode();
+ currentObject.name = 'Default';
+ var triangleCount = 0;
+ var vertexCount = 0;
+ var vertexList = [];
+ var vertList = [];
+ var normList = [];
+ var uvList = [];
+ vertList.push(new Vector3d());
+ normList.push(new Vector3d());
+ uvList.push(new Vector2d());
+ var indexList = [];
+ var attribList = [];
+ var applyLists = [];
+ var applyListsIndex = [];
+ var materialNames = [];
+ var currentMaterialIndex = -1;
+ var currentMaterial = new Material();
+ var currentGroup = new Group();
+ var currentIndex = 0;
+
+ // initialize the default material
+ currentMaterial = new Material();
+ currentMaterial.diffuse = this.color;
+ currentMaterial.ambient = this.color;
+ currentMaterial.specular = Colors.get_white();
+ currentMaterial.specularSharpness = 30;
+ currentMaterial.opacity = 1;
+ currentMaterial.isDefault = true;
+
+ // initialize the group
+ currentGroup.startIndex = 0;
+ currentGroup.indexCount = 0;
+ currentGroup.materialIndex = 0;
+ var lines = data.split('\n');
+ var $enum1 = ss.enumerate(lines);
+ while ($enum1.moveNext()) {
+ var lineraw = $enum1.current;
+ var line = ss.replaceString(lineraw, ' ', ' ');
+ var parts = ss.trim(line).split(' ');
+ if (parts.length > 0) {
+ switch (parts[0]) {
+ case 'mtllib':
+ // We have to pre-load these now in JavaScript, since we
+ // can't synchronously load the file and we need file
+ // contents to interpret the rest of this file
+ break;
+ case 'usemtl':
+ var materialName = parts[1];
+ if (ss.keyExists(this._matLib, materialName)) {
+ if (currentMaterialIndex === -1 && currentIndex > 0) {
+ this._addMaterial(currentMaterial);
+ currentMaterialIndex++;
+ }
+ if (currentMaterialIndex > -1) {
+ currentGroup.indexCount = currentIndex - currentGroup.startIndex;
+ currentObject.drawGroup.push(currentGroup);
+ }
+ currentMaterialIndex++;
+ if (ss.keyExists(this._matLib, materialName)) {
+ currentMaterial = this._matLib[materialName];
+ if (ss.keyExists(this._textureLib, materialName)) {
+ try {
+ if (!ss.keyExists(this._textureCache, this._textureLib[materialName])) {
+ var path = this.filename.substring(0, this.filename.lastIndexOf('\\') + 1);
+ var tex = this._tourDocument.getCachedTexture2d(path + this._textureLib[materialName]);
+ if (tex != null) {
+ this.meshFilenames.push(this._textureLib[materialName]);
+ this._textureCache[this._textureLib[materialName]] = tex;
+ }
+ }
+ this._meshTextures.push(this._textureCache[this._textureLib[materialName]]);
+ }
+ catch ($e2) {
+ }
+ }
+ this._addMaterial(currentMaterial);
+ currentGroup = new Group();
+ currentGroup.startIndex = currentIndex;
+ currentGroup.indexCount = 0;
+ currentGroup.materialIndex = currentMaterialIndex;
+ }
+ }
+ break;
+ case 'v':
+ vertexCount++;
+ if (this.flipHandedness) {
+ vertList.push(Vector3d.create(-parseFloat(parts[1]), parseFloat(parts[2]), parseFloat(parts[3])));
+ }
+ else {
+ vertList.push(Vector3d.create(parseFloat(parts[1]), parseFloat(parts[2]), parseFloat(parts[3])));
+ }
+ break;
+ case 'vn':
+ if (this.flipHandedness) {
+ normList.push(Vector3d.create(-parseFloat(parts[1]), parseFloat(parts[2]), parseFloat(parts[3])));
+ }
+ else {
+ normList.push(Vector3d.create(parseFloat(parts[1]), parseFloat(parts[2]), parseFloat(parts[3])));
+ }
+ break;
+ case 'vt':
+ uvList.push(Vector2d.create(parseFloat(parts[1]), (this.flipV) ? (1 - parseFloat(parts[2])) : parseFloat(parts[2])));
+ break;
+ case 'g':
+ case 'o':
+ if (objectFound) {
+ if (currentMaterialIndex > -1) {
+ currentGroup.indexCount = currentIndex - currentGroup.startIndex;
+ currentObject.drawGroup.push(currentGroup);
+ currentGroup = new Group();
+ currentGroup.startIndex = currentIndex;
+ currentGroup.indexCount = 0;
+ currentGroup.materialIndex = currentMaterialIndex;
+ }
+ currentObject = new ObjectNode();
+ }
+ objectFound = true;
+ if (parts.length > 1) {
+ currentObject.name = parts[1];
+ }
+ else {
+ currentObject.name = 'Unnamed';
+ }
+ objects.push(currentObject);
+ break;
+ case 'f':
+ var indexiesA = this._getIndexies(parts[1]);
+ var indexiesB = this._getIndexies(parts[2]);
+ var indexiesC = this._getIndexies(parts[3]);
+ vertexList.push(PositionNormalTextured.createUV(vertList[indexiesA[0]], normList[indexiesA[2]], uvList[indexiesA[1]]));
+ vertexList.push(PositionNormalTextured.createUV(vertList[indexiesB[0]], normList[indexiesB[2]], uvList[indexiesB[1]]));
+ vertexList.push(PositionNormalTextured.createUV(vertList[indexiesC[0]], normList[indexiesC[2]], uvList[indexiesC[1]]));
+ if (this.flipHandedness) {
+ indexList.push(currentIndex);
+ indexList.push(currentIndex + 2);
+ indexList.push(currentIndex + 1);
+ }
+ else {
+ indexList.push(currentIndex);
+ indexList.push(currentIndex + 1);
+ indexList.push(currentIndex + 2);
+ }
+ triangleCount++;
+ currentIndex += 3;
+ if (parts.length > 4) {
+ var partIndex = 4;
+ while (partIndex < parts.length) {
+ if (this.flipHandedness) {
+ indexiesA = this._getIndexies(parts[1]);
+ indexiesC = this._getIndexies(parts[partIndex]);
+ indexiesB = this._getIndexies(parts[partIndex - 1]);
+ }
+ else {
+ indexiesA = this._getIndexies(parts[1]);
+ indexiesB = this._getIndexies(parts[partIndex - 1]);
+ indexiesC = this._getIndexies(parts[partIndex]);
+ }
+ vertexList.push(PositionNormalTextured.createUV(vertList[indexiesA[0]], normList[indexiesA[2]], uvList[indexiesA[1]]));
+ vertexList.push(PositionNormalTextured.createUV(vertList[indexiesB[0]], normList[indexiesB[2]], uvList[indexiesB[1]]));
+ vertexList.push(PositionNormalTextured.createUV(vertList[indexiesC[0]], normList[indexiesC[2]], uvList[indexiesC[1]]));
+ indexList.push(currentIndex);
+ indexList.push(currentIndex + 1);
+ indexList.push(currentIndex + 2);
+ triangleCount++;
+ currentIndex += 3;
+ partIndex++;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if (!objectFound) {
+ // add the default object
+ objects.push(currentObject);
+ }
+
+ if (currentMaterialIndex === -1 && currentIndex > 0) {
+ this._addMaterial(currentMaterial);
+ currentMaterialIndex++;
+ }
+
+ if (currentMaterialIndex > -1) {
+ currentGroup.indexCount = (currentIndex - currentGroup.startIndex);
+ currentObject.drawGroup.push(currentGroup);
+ }
+
+ if (normList.length < 2) {
+ var degtorag = Math.PI / 180;
+ var creaseAngleRad = ((this.smooth) ? 170 * degtorag : 45 * degtorag);
+ var vertexNormals = this._calculateVertexNormalsMerged(vertexList, indexList, creaseAngleRad);
+ var newVertexList = [];
+ var newVertexCount = indexList.length;
+ for (var vertexIndex = 0; vertexIndex < newVertexCount; ++vertexIndex) {
+ var v = vertexList[indexList[vertexIndex]];
+ v.set_normal(vertexNormals[vertexIndex]);
+ newVertexList.push(v);
+ }
+ vertexList = newVertexList;
+ }
+ this._mesh = Mesh.create(vertexList, indexList);
+ var rootDummy = new ObjectNode();
+ rootDummy.name = 'Root';
+ rootDummy.parent = null;
+ rootDummy.level = -1;
+ rootDummy.drawGroup = null;
+ rootDummy.children = objects;
+ this.objects = [];
+ this.objects.push(rootDummy);
+ this._mesh.setObjects(this.objects);
+ this._mesh.commitToDevice();
+ this._dirty = false;
+ this._readyToRender = true;
+ },
+
+ _loadMatLib: function (data) {
+ var $this = this;
+
+ if (this._matFileIndex < this._matFiles.length) {
+ var filename = this._matFiles[this._matFileIndex++];
+ var blob = this._tourDocument.getFileBlob(filename);
+ var chunck = new FileReader();
+ chunck.onloadend = function (e) {
+ $this._readMatLibFromBin(ss.safeCast(chunck.result, String));
+ $this._loadMatLib(data);
+ };
+ chunck.readAsText(blob);
+ } else {
+ this._readObjFromBin(data);
+ }
+ },
+
+ _readMatLibFromBin: function (data) {
+ try {
+ var currentMaterial = new Material();
+ var materialName = '';
+ this._matLib = {};
+ this._textureLib = {};
+ var lines = data.split('\n');
+ var $enum1 = ss.enumerate(lines);
+ while ($enum1.moveNext()) {
+ var lineraw = $enum1.current;
+ var line = lineraw;
+ var parts = ss.trim(line).split(' ');
+ if (parts.length > 0) {
+ switch (parts[0]) {
+ case 'newmtl':
+ if (!ss.emptyString(materialName)) {
+ this._matLib[materialName] = currentMaterial;
+ }
+ currentMaterial = new Material();
+ currentMaterial.diffuse = Colors.get_white();
+ currentMaterial.ambient = Colors.get_white();
+ currentMaterial.specular = Colors.get_black();
+ currentMaterial.specularSharpness = 30;
+ currentMaterial.opacity = 1;
+ materialName = parts[1];
+ break;
+ case 'Ka':
+ currentMaterial.ambient = Color.fromArgb(255, Math.min(parseFloat(parts[1]) * 255, 255), Math.min(parseFloat(parts[2]) * 255, 255), Math.min(parseFloat(parts[3]) * 255, 255));
+ break;
+ case 'map_Kd':
+ //ENDURE TEXTURES ARE NOT BLACK!
+ currentMaterial.diffuse = Colors.get_white();
+ var textureFilename = parts[1];
+ for (var i = 2; i < parts.length; i++) {
+ textureFilename += ' ' + parts[i];
+ }
+ var path = this.filename.substring(0, this.filename.lastIndexOf('\\') + 1);
+ textureFilename = ss.replaceString(textureFilename, '/', '\\');
+ if (textureFilename.indexOf('\\') !== -1) {
+ textureFilename = textureFilename.substring(textureFilename.lastIndexOf('\\') + 1);
+ }
+ this._textureLib[materialName] = textureFilename;
+ break;
+ case 'Kd':
+ currentMaterial.diffuse = Color.fromArgb(255, Math.min(parseFloat(parts[1]) * 255, 255), Math.min(parseFloat(parts[2]) * 255, 255), Math.min(parseFloat(parts[3]) * 255, 255));
+ break;
+ case 'Ks':
+ currentMaterial.specular = Color.fromArgb(255, Math.min(parseFloat(parts[1]) * 255, 255), Math.min(parseFloat(parts[2]) * 255, 255), Math.min(parseFloat(parts[3]) * 255, 255));
+ break;
+ case 'd':
+ // Where does this map?
+ currentMaterial.opacity = parseFloat(parts[1]);
+ break;
+ case 'Tr':
+ // Where does this map?
+ currentMaterial.opacity = 1 - parseFloat(parts[1]);
+ break;
+ case 'illum':
+ // Where does this map?
+ var illuminationMode = parseInt(parts[1]);
+ break;
+ case 'sharpness':
+ currentMaterial.specularSharpness = parseFloat(parts[1]);
+ break;
+ case 'Ns':
+ currentMaterial.specularSharpness = 1 + 2 * parseFloat(parts[1]);
+ currentMaterial.specularSharpness = Math.max(10, currentMaterial.specularSharpness);
+ break;
+ }
+ }
+ }
+ if (!ss.emptyString(materialName)) {
+ this._matLib[materialName] = currentMaterial;
+ }
+ }
+ catch ($e2) {
+ }
+ },
+
+ _getIndexies: function (data) {
+ var parts = ss.trim(data).split('/');
+ var indecies = new Array(3);
+ if (ss.emptyString(data)) {
+ return indecies;
+ }
+ if (parts.length > 0) {
+ indecies[0] = parseInt(parts[0]);
+ }
+ if (parts.length > 1) {
+ if (ss.emptyString(parts[1])) {
+ indecies[1] = 0;
+ }
+ else {
+ indecies[1] = parseInt(parts[1]);
+ }
+ }
+ if (parts.length > 2) {
+ indecies[2] = parseInt(parts[2]);
+ }
+ return indecies;
+ },
+
+ _loadMeshFrom3ds: function (doc, filename, scale) {
+ var $this = this;
+
+ this._tourDocument = doc;
+ var blob = doc.getFileBlob(filename);
+ var chunck = new FileReader();
+ chunck.onloadend = function (e) {
+ $this._read3dsFromBin(new BinaryReader(new Uint8Array(chunck.result)), scale);
+ };
+ chunck.readAsArrayBuffer(blob);
+ },
+
+ _read3dsFromBin: function (br, scale) {
+ var i;
+ var sectionID;
+ var sectionLength;
+ var name = '';
+ var material = '';
+ var triangleCount = 0;
+ var vertexCount = 0;
+ var vertexList = [];
+ var indexList = [];
+ var attribList = [];
+ var materialNames = [];
+ var currentMaterialIndex = -1;
+ var currentMaterial = new Material();
+ var attributeID = 0;
+ var count = 0;
+ var lastID = 0;
+ var exit = false;
+ var normalMapFound = false;
+ var offsetX = 0;
+ var offsetY = 0;
+ var offsetZ = 0;
+ var objects = [];
+ var currentObject = null;
+ var objHierarchy = [];
+ var objNames = [];
+ var objectTable = {};
+ var dummyCount = 0;
+ var length = br.get_length() - 1;
+ var startMapIndex = 0;
+ var startTriangleIndex = 0;
+
+ // Loop to scan the whole file
+ while (br.get_position() < length && !exit) {
+ sectionID = br.readUInt16();
+ sectionLength = br.readUInt32();
+ switch (sectionID) {
+ //This section the begining of the file
+ case 0x4D4D:
+ break;
+
+ // This section marks the edit section containing the 3d models (3d3d get it? very punny!)
+ case 0x3D3D:
+ break;
+
+ // Object section contains meshes, etc.
+ case 0x4000:
+ name = '';
+ var b;
+ do {
+ b = br.readByte();
+ if (b > 0) {
+ name += String.fromCharCode(b);
+ }
+ } while (!!b);
+ currentObject = new ObjectNode();
+ currentObject.name = name;
+ objects.push(currentObject);
+ if (!ss.keyExists(objectTable, currentObject.name)) {
+ objectTable[currentObject.name] = currentObject;
+ }
+ break;
+
+ // Marks the start of a mesh section
+ case 0x4100:
+ startMapIndex = vertexList.length;
+ startTriangleIndex = Math.floor(indexList.length / 3);
+ break;
+
+ // This section has the vertex list.. Maps to Vertext buffer in Direct3d
+ case 0x4110:
+ vertexCount = br.readUInt16();
+ for (i = 0; i < vertexCount; i++) {
+ var x = br.readSingle() - offsetX;
+ var y = br.readSingle() - offsetY;
+ var z = br.readSingle() - offsetZ;
+ var vert = PositionNormalTextured._create(x * scale, z * scale, y * scale, 0, 0, 0, 0, 0);
+ vertexList.push(vert);
+ }
+ break;
+
+ // This section is a triangle index list. Maps to Index Buffer in Direct3d
+ case 0x4120:
+ var triCount = br.readUInt16();
+ triangleCount += triCount;
+ for (i = 0; i < triCount; i++) {
+ var aa = br.readUInt16() + startMapIndex;
+ var bb = br.readUInt16() + startMapIndex;
+ var cc = br.readUInt16() + startMapIndex;
+ indexList.push(cc);
+ indexList.push(bb);
+ indexList.push(aa);
+ var flags = br.readUInt16();
+ }
+ break;
+
+ // Material for face from start face to triCount
+ case 0x4130:
+ material = '';
+ i = 0;
+ var b1;
+ do {
+ b1 = br.readByte();
+ if (b1 > 0) {
+ material += String.fromCharCode(b1);
+ }
+ i++;
+ } while (!!b1);
+ var triCount = br.readUInt16();
+ var applyList = new Array(triCount);
+ attributeID = Object3d._getMaterialID(material, materialNames);
+ for (i = 0; i < triCount; i++) {
+ applyList[i] = br.readUInt16() + startTriangleIndex;
+ }
+ currentObject.applyLists.push(applyList);
+ currentObject.applyListsIndex.push(attributeID);
+ break;
+
+ // Section for UV texture maps
+ case 0x4140:
+ count = br.readUInt16();
+ for (i = 0; i < count; i++) {
+ var vert = vertexList[startMapIndex + i];
+ var texCoord = Vector2d.create(br.readSingle(), (this.flipV) ? (1 - br.readSingle()) : br.readSingle());
+ vertexList[startMapIndex + i] = PositionNormalTextured.createUV(vert.get_position(), new Vector3d(), texCoord);
+ }
+ break;
+
+ // Section for Smoothing Groups ??
+ case 0x4160:
+ var mat = new Array(12);
+ for (i = 0; i < 12; i++) {
+ mat[i] = br.readSingle();
+ }
+ if (ss.keyExists(objectTable, name)) {
+ objectTable[name].localMat = Matrix3d.create(mat[0], mat[1], mat[2], 0, mat[3], mat[4], mat[5], 0, mat[6], mat[7], mat[8], 0, mat[9], mat[10], mat[11], 1);
+ objectTable[name].localMat.invert();
+ }
+ break;
+
+ // Materials library section
+ case 0xAFFF:
+ break;
+
+ // Material Name
+ case 0xA000:
+ var matName = '';
+ i = 0;
+ var b2;
+ do {
+ b2 = br.readByte();
+ if (b2 > 0) {
+ matName += String.fromCharCode(b2);
+ }
+ i++;
+ } while (!!b2);
+ materialNames.push(matName);
+ if (currentMaterialIndex > -1) {
+ this._addMaterial(currentMaterial);
+ }
+ currentMaterialIndex++;
+ currentMaterial = new Material();
+ currentMaterial.diffuse = Colors.get_white();
+ currentMaterial.ambient = Colors.get_white();
+ currentMaterial.specular = Colors.get_black();
+ currentMaterial.specularSharpness = 30;
+ currentMaterial.opacity = 1;
+ break;
+
+ // Ambient color
+ case 0xA010:
+ currentMaterial.ambient = this._loadColorChunk(br);
+ break;
+
+ // Diffuse color
+ case 0xA020:
+ currentMaterial.diffuse = this._loadColorChunk(br);
+ break;
+
+ // Specular color
+ case 0xA030:
+ currentMaterial.specular = this._loadColorChunk(br);
+ break;
+
+ // Specular power
+ case 0xA040:
+ // This is just a reasonable guess at the mapping from percentage to
+ // specular exponent used by 3D Studio.
+ currentMaterial.specularSharpness = 1 + 2 * this._loadPercentageChunk(br);
+
+ // Minimum sharpness of 10 enforced here because of bad specular exponents
+ // in ISS model.
+ // TODO: Fix ISS and permit lower specular exponents here
+ currentMaterial.specularSharpness = Math.max(10, currentMaterial.specularSharpness);
+ break;
+
+ //Texture map file
+ case 0xA200:
+ break;
+
+ // Texture file name
+ case 0xA300:
+ var textureFilename = '';
+ i = 0;
+ var b2;
+ do {
+ b2 = br.readByte();
+ if (b2 > 0) {
+ textureFilename += String.fromCharCode(b2);
+ }
+ i++;
+ } while (!!b2);
+ var path = this.filename.substring(0, this.filename.lastIndexOf('\\') + 1);
+ try {
+ var tex = this._tourDocument.getCachedTexture2d(path + textureFilename);
+ if (tex != null) {
+ this._meshTextures.push(tex);
+ this.meshFilenames.push(textureFilename);
+ // The ISS model has black for the diffuse color; to work around this
+ // we'll set the diffuse color to white when there's a texture present.
+ // The correct fix is to modify the 3ds model of ISS.
+ currentMaterial.diffuse = Colors.get_white();
+ }
+ else {
+ this._meshTextures.push(null);
+ }
+ }
+ catch ($e1) {
+ this._meshTextures.push(null);
+ }
+ break;
+
+ // Bump map
+ case 0xA230:
+ var percentage = this._loadPercentageChunk(br);
+ var nameId = br.readUInt16();
+ var nameBlockLength = br.readUInt32();
+ var textureFilename = '';
+ i = 0;
+ var b2;
+ do {
+ b2 = br.readByte();
+ if (b2 > 0) {
+ textureFilename += String.fromCharCode(b2);
+ }
+ i++;
+ } while (!!b2);
+ var path = this.filename.substring(0, this.filename.lastIndexOf('\\') + 1);
+ try {
+ var tex = this._tourDocument.getCachedTexture2d(path + textureFilename);
+ if (tex != null) {
+ this._meshNormalMaps.push(tex);
+ this.meshFilenames.push(textureFilename);
+ // Indicate that we have a normal map so that we know to generate tangent vectors for the mesh
+ normalMapFound = true;
+ }
+ else {
+ this._meshNormalMaps.push(null);
+ }
+ }
+ catch ($e2) {
+ this._meshNormalMaps.push(null);
+ }
+ break;
+
+ // Specular map
+ case 0xA204:
+ var strength = this._loadPercentageChunk(br);
+ var nameId = br.readUInt16();
+ var nameBlockLength = br.readUInt32();
+ var textureFilename = '';
+ i = 0;
+ var b2;
+ do {
+ b2 = br.readByte();
+ if (b2 > 0) {
+ textureFilename += String.fromCharCode(b2);
+ }
+ i++;
+ } while (!!b2);
+ var path = this.filename.substring(0, this.filename.lastIndexOf('\\') + 1);
+ try {
+ var tex = this._tourDocument.getCachedTexture2d(path + textureFilename);
+ if (tex != null) {
+ this._meshSpecularTextures.push(tex);
+ this.meshFilenames.push(textureFilename);
+ // Set the current specular color from the specular texture strength
+ var gray = ss.truncate((255.99 * strength / 100));
+ currentMaterial.specular = Color.fromArgb(255, gray, gray, gray);
+ }
+ else {
+ this._meshSpecularTextures.push(null);
+ }
+ }
+ catch ($e3) {
+ this._meshSpecularTextures.push(null);
+ }
+ break;
+
+ case 0xB000:
+ break;
+ case 0xB002:
+ break;
+ case 0xB010:
+ name = '';
+ i = 0;
+ var b1;
+ do {
+ b1 = br.readByte();
+ if (b1 > 0) {
+ name += String.fromCharCode(b1);
+ }
+ i++;
+ } while (!!b1);
+ var dum1 = br.readUInt16();
+ var dum2 = br.readUInt16();
+ var level = br.readUInt16();
+ if (level === 65535) {
+ level = -1;
+ }
+ if (ss.startsWith(name, '$')) {
+ dummyCount++;
+ }
+ else {
+ objNames.push(name);
+ }
+ objHierarchy.push(level);
+ if (ss.keyExists(objectTable, name)) {
+ objectTable[name].level = level;
+ }
+ break;
+
+ case 0xB011:
+ name = '';
+ i = 0;
+ var b1;
+ do {
+ b1 = br.readByte();
+ if (b1 > 0) {
+ name += String.fromCharCode(b1);
+ }
+ i++;
+ } while (!!b1);
+ objNames.push('$$$' + name);
+ break;
+
+ case 0xB013:
+ // pivot point
+ var points = new Array(3);
+ for (i = 0; i < 3; i++) {
+ points[i] = br.readSingle();
+ }
+ if (ss.keyExists(objectTable, name)) {
+ objectTable[name].pivotPoint = Vector3d.create(-points[0], -points[1], -points[2]);
+ }
+ break;
+
+ case 0xB020:
+ var pos = new Array(8);
+ for (i = 0; i < 8; i++) {
+ pos[i] = br.readSingle();
+ }
+ break;
+
+ // If we don't recognize a section then jump over it. Subract the header from the section length
+ default:
+ br.seekRelative((sectionLength - 6));
+ break;
+ }
+
+ lastID = sectionID;
+ }
+
+ br.close();
+ if (currentMaterialIndex > -1) {
+ this._addMaterial(currentMaterial);
+ }
+
+ // Generate vertex normals
+
+ // Vertex normals are computed by averaging the normals of all faces
+ // with an angle between them less than the crease angle. By setting
+ // the crease angle to 0 degrees, the model will have a faceted appearance.
+ // Right now, the smooth flag selects between one of two crease angles,
+ // but some smoothing is always applied.
+
+ var degtorag = Math.PI / 180;
+ var creaseAngleRad = ((this.smooth) ? 70 * degtorag : 45 * degtorag);
+ var vertexNormals = this._calculateVertexNormalsMerged(vertexList, indexList, creaseAngleRad);
+ var newVertexList = [];
+ var newVertexCount = triangleCount * 3;
+ for (var vertexIndex = 0; vertexIndex < newVertexCount; ++vertexIndex) {
+ var v = vertexList[indexList[vertexIndex]];
+ v.set_normal(vertexNormals[vertexIndex]);
+ newVertexList.push(v);
+ }
+
+ // Use the triangle mesh and material assignments to create a single
+ // index list for the mesh.
+ var newIndexList = [];
+ var $enum4 = ss.enumerate(objects);
+ while ($enum4.moveNext()) {
+ var node = $enum4.current;
+ var materialGroups = [];
+ for (i = 0; i < node.applyLists.length; i++) {
+ var matId = node.applyListsIndex[i];
+ var startIndex = newIndexList.length;
+ var $enum5 = ss.enumerate(node.applyLists[i]);
+ while ($enum5.moveNext()) {
+ var triangleIndex = $enum5.current;
+ newIndexList.push((triangleIndex * 3));
+ newIndexList.push((triangleIndex * 3 + 1));
+ newIndexList.push((triangleIndex * 3 + 2));
+ }
+ var group = new Group();
+ group.startIndex = startIndex;
+ group.indexCount = node.applyLists[i].length * 3;
+ group.materialIndex = matId;
+ materialGroups.push(group);
+ }
+ node.drawGroup = materialGroups;
+ }
+
+ // Turn objects into tree
+ var nodeStack = new ss.Stack();
+ var nodeTreeRoot = [];
+ var rootDummy = new ObjectNode();
+ rootDummy.name = 'Root';
+ rootDummy.parent = null;
+ rootDummy.level = -1;
+ rootDummy.drawGroup = null;
+ var currentLevel = -1;
+ nodeStack.push(rootDummy);
+ nodeTreeRoot.push(rootDummy);
+ for (i = 0; i < objHierarchy.length; i++) {
+ var level = objHierarchy[i];
+ if (level <= currentLevel) {
+ // pop out all the nodes to intended parent
+ while (level <= nodeStack.peek().level && nodeStack.count > 1) {
+ nodeStack.pop();
+ }
+ currentLevel = level;
+ }
+ if (ss.startsWith(objNames[i], '$$$')) {
+ var dummy = new ObjectNode();
+ dummy.name = ss.replaceString(objNames[i], '$$$', '');
+ dummy.parent = nodeStack.peek();
+ dummy.parent.children.push(dummy);
+ dummy.level = currentLevel = level;
+ dummy.drawGroup = null;
+ nodeStack.push(dummy);
+ }
+ else {
+ objectTable[objNames[i]].level = currentLevel = level;
+ objectTable[objNames[i]].parent = nodeStack.peek();
+ objectTable[objNames[i]].parent.children.push(objectTable[objNames[i]]);
+ nodeStack.push(objectTable[objNames[i]]);
+ }
+ }
+ if (!objHierarchy.length) {
+ var $enum6 = ss.enumerate(objects);
+ while ($enum6.moveNext()) {
+ var node = $enum6.current;
+ rootDummy.children.push(node);
+ node.parent = rootDummy;
+ }
+ }
+ if (normalMapFound) {
+ // If we've got a normal map, we want to generate tangent vectors for the mesh
+
+ // Mapping of vertices to geometry is extremely straightforward now, but this could
+ // change when a mesh optimization step is introduced.
+ var tangentIndexList = [];
+ for (var tangentIndex = 0; tangentIndex < newVertexCount; ++tangentIndex) {
+ tangentIndexList.push(tangentIndex);
+ }
+ var tangents = this._calculateVertexTangents(newVertexList, tangentIndexList, creaseAngleRad);
+
+ // Copy the tangents in the vertex data list
+ var vertices = new Array(newVertexList.length);
+ var vertexIndex = 0;
+ var $enum7 = ss.enumerate(newVertexList);
+ while ($enum7.moveNext()) {
+ var v = $enum7.current;
+ var tvertex = new PositionNormalTexturedTangent(v.get_position(), v.get_normal(), Vector2d.create(v.tu, v.tv), tangents[vertexIndex]);
+ vertices[vertexIndex] = tvertex;
+ ++vertexIndex;
+ }
+ this._mesh = Mesh.createTangent(vertices, newIndexList);
+ } else {
+ this._mesh = Mesh.create(newVertexList, newIndexList);
+ }
+ this.objects = nodeTreeRoot;
+ this._mesh.setObjects(nodeTreeRoot);
+ this._mesh.commitToDevice();
+ this._dirty = false;
+ this._readyToRender = true;
+ },
+
+ _offsetObjects: function (vertList, objects, offsetMat, offsetPoint) {
+ var $enum1 = ss.enumerate(objects);
+ while ($enum1.moveNext()) {
+ var node = $enum1.current;
+ var matLoc = node.localMat;
+ this._offsetObjects(vertList, node.children, matLoc, Vector3d.addVectors(node.pivotPoint, offsetPoint));
+ var $enum2 = ss.enumerate(node.drawGroup);
+ while ($enum2.moveNext()) {
+ var group = $enum2.current;
+ var end = group.startIndex + group.indexCount;
+ for (var i = group.startIndex; i < end; i++) {
+ var vert = vertList[i];
+ vert.set_position(Vector3d.addVectors(vert.get_position(), Vector3d.addVectors(node.pivotPoint, offsetPoint)));
+ vertList[i] = vert;
+ }
+ }
+ }
+ },
+
+ // Set up lighting state to account for:
+ // - Light reflected from a nearby planet
+ // - Shadows cast by nearby planets
+ setupLighting: function (renderContext) {
+ var objPosition = Vector3d.create(renderContext.get_world().get_offsetX(), renderContext.get_world().get_offsetY(), renderContext.get_world().get_offsetZ());
+ var objToLight = Vector3d.subtractVectors(objPosition, renderContext.get_reflectedLightPosition());
+ var sunPosition = Vector3d.subtractVectors(renderContext.get_sunPosition(), renderContext.get_reflectedLightPosition());
+ var cosPhaseAngle = (sunPosition.length() <= 0) ? 1 : Vector3d.dot(objToLight, sunPosition) / (objToLight.length() * sunPosition.length());
+ var reflectedLightFactor = Math.max(0, cosPhaseAngle);
+ reflectedLightFactor = Math.sqrt(reflectedLightFactor); // Tweak falloff of reflected light
+ var hemiLightFactor = 0;
+
+ // 1. Reduce the amount of sunlight when the object is in the shadow of a planet
+ // 2. Introduce some lighting due to scattering by the planet's atmosphere if it's
+ // close to the surface.
+ var sunlightFactor = 1;
+ if (renderContext.get_occludingPlanetRadius() > 0) {
+ var objAltitude = Vector3d.subtractVectors(objPosition, renderContext.get_occludingPlanetPosition()).length() - renderContext.get_occludingPlanetRadius();
+ hemiLightFactor = Math.max(0, Math.min(1, 1 - (objAltitude / renderContext.get_occludingPlanetRadius()) * 300));
+ reflectedLightFactor *= (1 - hemiLightFactor);
+
+ // Compute the distance from the center of the object to the line between the sun and occluding planet
+ // We're assuming that the radius of the object is very small relative to Earth;
+ // for large objects the amount of shadow will vary, and we should use circular
+ // eclipse shadows.
+ var sunToPlanet = Vector3d.subtractVectors(renderContext.get_occludingPlanetPosition(), renderContext.get_sunPosition());
+ var objToPlanet = Vector3d.subtractVectors(renderContext.get_occludingPlanetPosition(), objPosition);
+ var hemiLightDirection = Vector3d.create(-objToPlanet.x, -objToPlanet.y, -objToPlanet.z);
+ hemiLightDirection.normalize();
+ renderContext.set_hemisphereLightUp(hemiLightDirection);
+ var objToSun = Vector3d.subtractVectors(renderContext.get_sunPosition(), objPosition);
+ var sunPlanetDistance = sunToPlanet.length();
+ var t = -Vector3d.dot(objToSun, sunToPlanet) / (sunPlanetDistance * sunPlanetDistance);
+ if (t > 1) {
+ // Object is on the side of the planet opposite the sun, so a shadow is possible
+
+ // Compute the position of the object projected onto the shadow axis
+ var shadowAxisPoint = Vector3d.addVectors(renderContext.get_sunPosition(), Vector3d.multiplyScalar(sunToPlanet, t));
+
+ // d is the distance to the shadow axis
+ var d = Vector3d.subtractVectors(shadowAxisPoint, objPosition).length();
+
+ // s is the distance from the sun along the shadow axis
+ var s = Vector3d.subtractVectors(shadowAxisPoint, renderContext.get_sunPosition()).length();
+
+ // Use the sun's radius to accurately compute the penumbra and umbra cones
+ var solarRadius = 0.004645784;
+ var penumbraRadius = renderContext.get_occludingPlanetRadius() + (t - 1) * (renderContext.get_occludingPlanetRadius() + solarRadius);
+ var umbraRadius = renderContext.get_occludingPlanetRadius() + (t - 1) * (renderContext.get_occludingPlanetRadius() - solarRadius);
+ if (d < penumbraRadius) {
+ // The object is inside the penumbra, so it is at least partly shadowed
+ var minimumShadow = 0;
+ if (umbraRadius < 0) {
+ // No umbra at this point; degree of shadowing is limited because the
+ // planet doesn't completely cover the sun even when the object is positioned
+ // exactly on the shadow axis.
+ var occlusion = Math.pow(1 / (1 - umbraRadius), 2);
+ umbraRadius = 0;
+ minimumShadow = 1 - occlusion;
+ }
+
+ // Approximate the amount of shadow with linear interpolation. The accurate
+ // calculation involves computing the area of the intersection of two circles.
+ var u = Math.max(0, umbraRadius);
+ sunlightFactor = Math.max(minimumShadow, (d - u) / (penumbraRadius - u));
+ var gray = ss.truncate((255.99 * sunlightFactor));
+ renderContext.set_sunlightColor(Color.fromArgb(255, gray, gray, gray));
+
+ // Reduce sky-scattered light as well
+ hemiLightFactor *= sunlightFactor;
+ }
+ }
+ }
+ renderContext.set_reflectedLightColor(Color.fromArgb(255, ss.truncate((renderContext.get_reflectedLightColor().r * reflectedLightFactor)), ss.truncate((renderContext.get_reflectedLightColor().g * reflectedLightFactor)), ss.truncate((renderContext.get_reflectedLightColor().b * reflectedLightFactor))));
+ renderContext.set_hemisphereLightColor(Color.fromArgb(255, ss.truncate((renderContext.get_hemisphereLightColor().r * hemiLightFactor)), ss.truncate((renderContext.get_hemisphereLightColor().g * hemiLightFactor)), ss.truncate((renderContext.get_hemisphereLightColor().b * hemiLightFactor))));
+ },
+
+ render: function (renderContext, opacity) {
+ if (!this._readyToRender) {
+ return;
+ }
+ if (this._dirty && !this.issLayer) {
+ this._reload();
+ }
+ var oldWorld = renderContext.get_world();
+ var offset = this._mesh.boundingSphere.center;
+ var unitScale = 1;
+ if (this._mesh.boundingSphere.radius > 0) {
+ unitScale = 1 / this._mesh.boundingSphere.radius;
+ }
+ renderContext.set_world(Matrix3d.multiplyMatrix(Matrix3d.multiplyMatrix(Matrix3d.translation(Vector3d.create(-offset.x, -offset.y, -offset.z)), Matrix3d._scaling(unitScale, unitScale, unitScale)), oldWorld));
+ var worldView = Matrix3d.multiplyMatrix(renderContext.get_world(), renderContext.get_view());
+ var v = worldView.transform(Vector3d.get_empty());
+ var scaleFactor = Math.sqrt(worldView.get_m11() * worldView.get_m11() + worldView.get_m22() * worldView.get_m22() + worldView.get_m33() * worldView.get_m33()) / unitScale;
+ var dist = v.length();
+ var radius = scaleFactor;
+
+ // Calculate pixelsPerUnit which is the number of pixels covered
+ // by an object 1 AU at the distance of the planet center from
+ // the camera. This calculation works regardless of the projection
+ // type.
+ var viewportHeight = ss.truncate(renderContext.height);
+ var p11 = renderContext.get_projection().get_m11();
+ var p34 = renderContext.get_projection().get_m34();
+ var p44 = renderContext.get_projection().get_m44();
+ var w = Math.abs(p34) * dist + p44;
+ var pixelsPerUnit = (p11 / w) * viewportHeight;
+ var radiusInPixels = (radius * pixelsPerUnit);
+ if (radiusInPixels < 0.5) {
+ // Too small to be visible; skip rendering
+ return;
+ }
+
+ // These colors can be modified by shadows, distance from planet, etc. Restore
+ // the original values after rendering.
+ var savedSunlightColor = renderContext.get_sunlightColor();
+ var savedReflectedColor = renderContext.get_reflectedLightColor();
+ var savedHemiColor = renderContext.get_hemisphereLightColor();
+ if (Settings.get_current().get_solarSystemLighting()) {
+ this.setupLighting(renderContext);
+ if (!this.useCurrentAmbient) {
+ renderContext.set_ambientLightColor(Color.fromArgb(255, 11, 11, 11));
+ }
+ } else {
+ // No lighting: set ambient light to white and turn off all other light sources
+ renderContext.set_sunlightColor(Colors.get_black());
+ renderContext.set_reflectedLightColor(Colors.get_black());
+ renderContext.set_hemisphereLightColor(Colors.get_black());
+ renderContext.set_ambientLightColor(Colors.get_white());
+ }
+ if (this._mesh == null) {
+ return;
+ }
+ ModelShader.minLightingBrightness = 0.1;
+ var count = this._meshMaterials.length;
+ this._mesh.beginDrawing(renderContext);
+ if (count > 0) {
+ for (var i = 0; i < this._meshMaterials.length; i++) {
+ if (this._meshMaterials[i].isDefault) {
+ var mat = this._meshMaterials[i];
+ mat.diffuse = this.color;
+ mat.ambient = this.color;
+ this._meshMaterials[i] = mat;
+ }
+
+ // Set the material and texture for this subset
+ renderContext.setMaterial(this._meshMaterials[i], this._meshTextures[i], this._meshSpecularTextures[i], this._meshNormalMaps[i], opacity);
+ if (this._mesh.vertexBuffer != null) {
+ ModelShader.use(renderContext, this._mesh.vertexBuffer.vertexBuffer, this._mesh.indexBuffer.buffer, (this._meshTextures[i] != null) ? this._meshTextures[i].texture2d : null, opacity, false, 32);
+ }
+ else {
+ ModelShader.use(renderContext, this._mesh.tangentVertexBuffer.vertexBuffer, this._mesh.indexBuffer.buffer, (this._meshTextures[i] != null) ? this._meshTextures[i].texture2d : null, opacity, false, 44);
+ }
+ renderContext.preDraw();
+ this._mesh.drawSubset(renderContext, i);
+ }
+ } else {
+ renderContext.preDraw();
+ for (var i = 0; i < this._meshTextures.length; i++) {
+ if (this._meshTextures[i] != null) {
+ renderContext.set_mainTexture(this._meshTextures[i]);
+ if (this._mesh.vertexBuffer != null) {
+ ModelShader.use(renderContext, this._mesh.vertexBuffer.vertexBuffer, this._mesh.indexBuffer.buffer, (this._meshTextures[i] != null) ? this._meshTextures[i].texture2d : null, opacity, false, 32);
+ }
+ else {
+ ModelShader.use(renderContext, this._mesh.tangentVertexBuffer.vertexBuffer, this._mesh.indexBuffer.buffer, (this._meshTextures[i] != null) ? this._meshTextures[i].texture2d : null, opacity, false, 44);
+ }
+ }
+ renderContext.preDraw();
+ this._mesh.drawSubset(renderContext, i);
+ }
+ }
+ renderContext.set_world(oldWorld);
+ renderContext.set_sunlightColor(savedSunlightColor);
+ renderContext.set_reflectedLightColor(savedReflectedColor);
+ renderContext.set_hemisphereLightColor(savedHemiColor);
+ renderContext.set_ambientLightColor(Colors.get_black());
+ },
+
+ dispose: function () {
+ if (this._mesh != null) {
+ this._mesh.dispose();
+ this._mesh = null;
+ }
+ var $enum1 = ss.enumerate(ss.keys(this._textureCache));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var tex = this._textureCache[key];
+ if (tex != null) {
+ tex.dispose();
+ }
+ }
+ ss.clearKeys(this._textureCache);
+ Object3d._disposeTextureList(this._meshTextures);
+ Object3d._disposeTextureList(this._meshSpecularTextures);
+ Object3d._disposeTextureList(this._meshNormalMaps);
+ this._meshMaterials.length = 0;
+ this._dirty = true;
+ }
+};
+
+registerType("Object3d", [Object3d, Object3d$, null]);
+
+
+// wwtlib.ObjectNode
+
+export function ObjectNode() {
+ this.level = -1;
+ this.children = [];
+ this.enabled = true;
+ this.drawGroup = [];
+ this.applyLists = [];
+ this.applyListsIndex = [];
+}
+
+var ObjectNode$ = {};
+
+registerType("ObjectNode", [ObjectNode, ObjectNode$, null]);
+
+
+// wwtlib.Object3dLayerUI
+
+export function Object3dLayerUI(layer) {
+ this._layer$1 = null;
+ this._opened$1 = true;
+ this._callbacks$1 = null;
+ LayerUI.call(this);
+ this._layer$1 = layer;
+}
+
+var Object3dLayerUI$ = {
+ setUICallbacks: function (callbacks) {
+ this._callbacks$1 = callbacks;
+ },
+
+ get_hasTreeViewNodes: function () {
+ return true;
+ },
+
+ getTreeNodes: function () {
+ var nodes = [];
+ if (this._layer$1.object3d.objects.length > 0 && this._layer$1.object3d.objects[0].children != null) {
+ this._loadTree$1(nodes, this._layer$1.object3d.objects[0].children);
+ }
+ return nodes;
+ },
+ _loadTree$1: function (nodes, children) {
+ var $enum1 = ss.enumerate(children);
+ while ($enum1.moveNext()) {
+ var child = $enum1.current;
+ var node = new LayerUITreeNode();
+ node.set_name(child.name);
+ node.set_tag(child);
+ node.set_checked(child.enabled);
+ node.add_nodeSelected(ss.bind('_node_NodeSelected$1', this));
+ node.add_nodeChecked(ss.bind('_node_NodeChecked$1', this));
+ nodes.push(node);
+ this._loadTree$1(node.get_nodes(), child.children);
+ }
+ },
+ _node_NodeChecked$1: function (node, newState) {
+ var child = node.get_tag();
+ if (child != null) {
+ child.enabled = newState;
+ }
+ },
+ _node_NodeSelected$1: function (node) {
+ if (this._callbacks$1 != null) {
+ var child = node.get_tag();
+ var rowData = {};
+ rowData['Name'] = child.name;
+ rowData['Pivot.X'] = child.pivotPoint.x.toString();
+ rowData['Pivot.Y'] = child.pivotPoint.y.toString();
+ rowData['Pivot.Z'] = child.pivotPoint.z.toString();
+ this._callbacks$1.showRowData(rowData);
+ }
+ },
+
+ getNodeContextMenu: function (node) {
+ return LayerUI.prototype.getNodeContextMenu.call(this, node);
+ }
+};
+
+registerType("Object3dLayerUI", [Object3dLayerUI, Object3dLayerUI$, LayerUI]);
diff --git a/engine/esm/layers/orbit.js b/engine/esm/layers/orbit.js
new file mode 100644
index 00000000..46bef442
--- /dev/null
+++ b/engine/esm/layers/orbit.js
@@ -0,0 +1,157 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Arbitrary orbits and how we render them.
+
+import { ss } from "../ss.js";
+import { registerType } from "../typesystem.js";
+import { Vector3d, Matrix3d } from "../double3d.js";
+import { WEBGL } from "../graphics/webgl_constants.js";
+import { EllipseShader } from "../graphics/shaders.js";
+import { PositionVertexBuffer } from "../graphics/gl_buffers.js";
+import { Color, Colors } from "../color.js";
+import { Coordinates } from "../coordinates.js";
+import { SpaceTimeController } from "../space_time_controller.js";
+
+
+// wwtlib.Orbit
+
+export function Orbit(elements, segments, color, thickness, scale) {
+ this._elements = null;
+ this._orbitColor = Colors.get_white();
+ this._scale = 0;
+ this._segmentCount = 0;
+ this._elements = elements;
+ this._segmentCount = segments;
+ this._orbitColor = color;
+ this._scale = scale;
+}
+
+// Convert from standard coordinate system with z normal to the orbital plane
+// to WWT's system where y is the normal. Note that this transformation is not
+// a pure rotation: it incorporates a reflection, because the two systems have
+// different handedness.
+Orbit._orbitalToWwt = Matrix3d.create(1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1);
+Orbit._initBegun = false;
+
+var Orbit$ = {
+ cleanUp: function () { },
+
+ // Get the radius of a sphere (centered at a focus of the ellipse) that is
+ // large enough to contain the orbit. The value returned has units of the orbit scale.
+ get_boundingRadius: function () {
+ if (this._elements != null) {
+ return (this._elements.a * (1 + this._elements.e)) / this._scale;
+ } else {
+ return 0;
+ }
+ },
+
+ draw3D: function (renderContext, opacity, centerPoint) {
+ // Extra transformation required because the ellipse shader uses the xy-plane, but WWT uses the
+ // xz-plane as the reference.
+ var orbitalPlaneOrientation = Matrix3d.multiplyMatrix(Matrix3d._rotationZ(Coordinates.degreesToRadians(this._elements.w)), Matrix3d.multiplyMatrix(Matrix3d._rotationX(Coordinates.degreesToRadians(this._elements.i)), Matrix3d._rotationZ(Coordinates.degreesToRadians(this._elements.omega))));
+ orbitalPlaneOrientation = Matrix3d.multiplyMatrix(orbitalPlaneOrientation, Orbit._orbitalToWwt);
+
+ var worldMatrix = Matrix3d.multiplyMatrix(Matrix3d.multiplyMatrix(orbitalPlaneOrientation, Matrix3d.translation(centerPoint)), renderContext.get_world());
+ var M = this._elements.n * (SpaceTimeController.get_jNow() - this._elements.t);
+ var F = 1;
+ if (M < 0) {
+ F = -1;
+ }
+ M = Math.abs(M) / 360;
+ M = (M - ss.truncate(M)) * 360 * F;
+ var color = Color._fromArgbColor(ss.truncate((opacity * 255)), this._orbitColor);
+
+ // Newton-Raphson iteration to solve Kepler's equation.
+ // This is faster than calling CAAKepler.Calculate(), and 5 steps
+ // is more than adequate for draw the orbit paths of small satellites
+ // (which are ultimately rendered using single-precision floating point.)
+ M = Coordinates.degreesToRadians(M);
+ var E = M;
+ for (var i = 0; i < 5; i++) {
+ E += (M - E + this._elements.e * Math.sin(E)) / (1 - this._elements.e * Math.cos(E));
+ }
+ EllipseRenderer.drawEllipse(renderContext, this._elements.a / this._scale, this._elements.e, E, color, worldMatrix);
+ }
+};
+
+registerType("Orbit", [Orbit, Orbit$, null]);
+
+
+// wwtlib.EllipseRenderer
+
+export function EllipseRenderer() { }
+
+// Draw an ellipse with the specified semi-major axis and eccentricity. The orbit is drawn over a single period,
+// fading from full brightness at the given eccentric anomaly.
+//
+// In order to match exactly the position at which a planet is drawn, the planet's position at the current time
+// must be passed as a parameter. positionNow is in the current coordinate system of the render context, not the
+// translated and rotated system of the orbital plane.
+EllipseRenderer.drawEllipseWithPosition = function (renderContext, semiMajorAxis, eccentricity, eccentricAnomaly, color, worldMatrix, positionNow) {
+ if (EllipseRenderer._ellipseShader == null) {
+ EllipseRenderer._ellipseShader = new EllipseShader();
+ }
+ if (EllipseRenderer._ellipseVertexBuffer == null) {
+ EllipseRenderer._ellipseVertexBuffer = EllipseRenderer.createEllipseVertexBuffer(500);
+ }
+ var savedWorld = renderContext.get_world();
+ renderContext.set_world(worldMatrix);
+ renderContext.gl.bindBuffer(WEBGL.ARRAY_BUFFER, EllipseRenderer._ellipseVertexBuffer.vertexBuffer);
+ renderContext.gl.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, null);
+ EllipseShader.use(renderContext, semiMajorAxis, eccentricity, eccentricAnomaly, color, 1, savedWorld, positionNow);
+ renderContext.gl.drawArrays(WEBGL.LINE_STRIP, 0, EllipseRenderer._ellipseVertexBuffer.count);
+ renderContext.set_world(savedWorld);
+};
+
+// This version of DrawEllipse works without a 'head' point
+EllipseRenderer.drawEllipse = function (renderContext, semiMajorAxis, eccentricity, eccentricAnomaly, color, worldMatrix) {
+ if (EllipseRenderer._ellipseShader == null) {
+ EllipseRenderer._ellipseShader = new EllipseShader();
+ }
+ if (EllipseRenderer._ellipseWithoutStartPointVertexBuffer == null) {
+ EllipseRenderer._ellipseWithoutStartPointVertexBuffer = EllipseRenderer.createEllipseVertexBufferWithoutStartPoint(360);
+ }
+ var savedWorld = renderContext.get_world();
+ renderContext.set_world(worldMatrix);
+ renderContext.gl.bindBuffer(WEBGL.ARRAY_BUFFER, EllipseRenderer._ellipseWithoutStartPointVertexBuffer.vertexBuffer);
+ renderContext.gl.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, null);
+ EllipseShader.use(renderContext, semiMajorAxis, eccentricity, eccentricAnomaly, color, 1, savedWorld, Vector3d.create(0, 0, 0));
+ renderContext.gl.drawArrays(WEBGL.LINE_STRIP, 0, EllipseRenderer._ellipseWithoutStartPointVertexBuffer.count - 1);
+ renderContext.set_world(savedWorld);
+};
+
+EllipseRenderer.createEllipseVertexBuffer = function (vertexCount) {
+ var vb = new PositionVertexBuffer(vertexCount);
+ var verts = vb.lock();
+ var index = 0;
+
+ // Pack extra samples into the front of the orbit to avoid obvious segmentation
+ // when viewed from near the planet or moon.
+ for (var i = 0; i < vertexCount / 2; ++i) {
+ verts[index++] = Vector3d.create(2 * i / vertexCount * 0.05, 0, 0);
+ }
+ for (var i = 0; i < vertexCount / 2; ++i) {
+ verts[index++] = Vector3d.create(2 * i / vertexCount * 0.95 + 0.05, 0, 0);
+ }
+ vb.unlock();
+ return vb;
+};
+
+EllipseRenderer.createEllipseVertexBufferWithoutStartPoint = function (vertexCount) {
+ var vb = new PositionVertexBuffer(vertexCount);
+ var verts = vb.lock();
+
+ // Setting a non-zero value will prevent the ellipse shader from using the 'head' point
+ verts[0] = Vector3d.create(1E-06, 0, 0);
+ for (var i = 1; i < vertexCount; ++i) {
+ verts[i] = Vector3d.create(2 * i / vertexCount, 0, 0);
+ }
+ vb.unlock();
+ return vb;
+};
+
+var EllipseRenderer$ = {};
+
+registerType("EllipseRenderer", [EllipseRenderer, EllipseRenderer$, null]);
diff --git a/engine/esm/layers/orbit_layer.js b/engine/esm/layers/orbit_layer.js
new file mode 100644
index 00000000..dff864b6
--- /dev/null
+++ b/engine/esm/layers/orbit_layer.js
@@ -0,0 +1,257 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A layer that renders an orbit.
+
+import { ss } from "../ss.js";
+import { registerType } from "../typesystem.js";
+import { Vector3d } from "../double3d.js";
+import { Color, Colors } from "../color.js";
+import { Layer } from "./layer.js";
+import { LayerUI, LayerUITreeNode } from "./layer_ui.js";
+import { Orbit } from "./orbit.js";
+import { ReferenceFrame } from "./reference_frame.js";
+
+
+// wwtlib.OrbitLayer
+
+export function OrbitLayer() {
+ this._frames$1 = [];
+ this._primaryUI$1 = null;
+ this._pointOpacity$1 = 1;
+ this._pointColor$1 = Colors.get_yellow();
+ this._filename$1 = '';
+ this._dataFile$1 = '';
+ Layer.call(this);
+}
+
+var OrbitLayer$ = {
+ get_frames: function () {
+ return this._frames$1;
+ },
+
+ set_frames: function (value) {
+ this._frames$1 = value;
+ return value;
+ },
+
+ getPrimaryUI: function () {
+ if (this._primaryUI$1 == null) {
+ this._primaryUI$1 = new OrbitLayerUI(this);
+ }
+ return this._primaryUI$1;
+ },
+
+ cleanUp: function () {
+ var $enum1 = ss.enumerate(this._frames$1);
+ while ($enum1.moveNext()) {
+ var frame = $enum1.current;
+ if (frame.get_orbit() != null) {
+ frame.get_orbit().cleanUp();
+ frame.set_orbit(null);
+ }
+ }
+ },
+
+ writeLayerProperties: function (xmlWriter) {
+ xmlWriter._writeAttributeString('PointOpacity', this.get_pointOpacity().toString());
+ xmlWriter._writeAttributeString('PointColor', this._pointColor$1.save());
+ },
+
+ get_pointOpacity: function () {
+ return this._pointOpacity$1;
+ },
+
+ set_pointOpacity: function (value) {
+ if (this._pointOpacity$1 !== value) {
+ this.version++;
+ this._pointOpacity$1 = value;
+ }
+ return value;
+ },
+
+ get_pointColor: function () {
+ return this._pointColor$1;
+ },
+
+ set_pointColor: function (value) {
+ if (this._pointColor$1 !== value) {
+ this.version++;
+ this._pointColor$1 = value;
+ }
+ return value;
+ },
+
+ getParams: function () {
+ var paramList = new Array(6);
+ paramList[0] = this._pointOpacity$1;
+ paramList[1] = this.get_color().r / 255;
+ paramList[2] = this.get_color().g / 255;
+ paramList[3] = this.get_color().b / 255;
+ paramList[4] = this.get_color().a / 255;
+ paramList[5] = this.get_opacity();
+ return paramList;
+ },
+
+ getParamNames: function () {
+ return ['PointOpacity', 'Color.Red', 'Color.Green', 'Color.Blue', 'Color.Alpha', 'Opacity'];
+ },
+
+ setParams: function (paramList) {
+ if (paramList.length === 6) {
+ this._pointOpacity$1 = paramList[0];
+ this.set_opacity(paramList[5]);
+ var color = Color.fromArgb(ss.truncate((paramList[4] * 255)), ss.truncate((paramList[1] * 255)), ss.truncate((paramList[2] * 255)), ss.truncate((paramList[3] * 255)));
+ this.set_color(color);
+ }
+ },
+
+ initializeFromXml: function (node) {
+ this.set_pointOpacity(parseFloat(node.attributes.getNamedItem('PointOpacity').nodeValue));
+ this.set_pointColor(Color.load(node.attributes.getNamedItem('PointColor').nodeValue));
+ },
+
+ draw: function (renderContext, opacity, flat) {
+ var matSaved = renderContext.get_world();
+ renderContext.set_world(renderContext.get_worldBaseNonRotating());
+ var $enum1 = ss.enumerate(this._frames$1);
+ while ($enum1.moveNext()) {
+ var frame = $enum1.current;
+ if (frame.showOrbitPath) {
+ if (frame.get_orbit() == null) {
+ frame.set_orbit(new Orbit(frame.get_elements(), 360, this.get_color(), 1, renderContext.get_nominalRadius()));
+ }
+ frame.get_orbit().draw3D(renderContext, opacity * this.get_opacity(), new Vector3d());
+ }
+ }
+ renderContext.set_world(matSaved);
+ return true;
+ },
+
+ addFilesToCabinet: function (fc) {
+ this._filename$1 = fc.tempDirectory + ss.format('{0}\\{1}.txt', fc.get_packageID(), this.id.toString());
+ var dir = this._filename$1.substring(0, this._filename$1.lastIndexOf('\\'));
+ var blob = new Blob([this._dataFile$1]);
+ fc.addFile(this._filename$1, blob);
+ Layer.prototype.addFilesToCabinet.call(this, fc);
+ },
+
+ loadData: function (tourDoc, filename) {
+ var $this = this;
+
+ var blob = tourDoc.getFileBlob(filename);
+ var doc = new FileReader();
+ doc.onloadend = function (ee) {
+ $this._dataFile$1 = ss.safeCast(doc.result, String);
+ $this.loadString($this._dataFile$1);
+ };
+ doc.readAsText(blob);
+ },
+
+ loadString: function (dataFile) {
+ var data = dataFile.split('\n');
+ this._frames$1.length = 0;
+ for (var i = 0; i < data.length; i += 2) {
+ var line1 = i;
+ var line2 = i + 1;
+ if (data[i].length > 0) {
+ var frame = new ReferenceFrame();
+ if (data[i].substring(0, 1) !== '1') {
+ line1++;
+ line2++;
+ frame.name = ss.trim(data[i]);
+ i++;
+ }
+ else if (data[i].substring(0, 1) === '1') {
+ frame.name = data[i].substring(2, 5);
+ }
+ else {
+ i -= 2;
+ continue;
+ }
+ frame.reference = 18;
+ frame.oblateness = 0;
+ frame.showOrbitPath = true;
+ frame.showAsPoint = true;
+ frame.referenceFrameType = 1;
+ frame.scale = 1;
+ frame.semiMajorAxisUnits = 1;
+ frame.meanRadius = 10;
+ frame.oblateness = 0;
+ frame.fromTLE(data[line1], data[line2], 398600441800000);
+ this._frames$1.push(frame);
+ }
+ else {
+ i -= 1;
+ }
+ }
+ }
+};
+
+registerType("OrbitLayer", [OrbitLayer, OrbitLayer$, Layer]);
+
+
+// wwtlib.OrbitLayerUI
+
+export function OrbitLayerUI(layer) {
+ this._layer$1 = null;
+ this._opened$1 = true;
+ this._callbacks$1 = null;
+ LayerUI.call(this);
+ this._layer$1 = layer;
+}
+
+var OrbitLayerUI$ = {
+ setUICallbacks: function (callbacks) {
+ this._callbacks$1 = callbacks;
+ },
+
+ get_hasTreeViewNodes: function () {
+ return true;
+ },
+
+ getTreeNodes: function () {
+ var nodes = [];
+ var $enum1 = ss.enumerate(this._layer$1.get_frames());
+ while ($enum1.moveNext()) {
+ var frame = $enum1.current;
+ var node = new LayerUITreeNode();
+ node.set_name(frame.name);
+ node.set_tag(frame);
+ node.set_checked(frame.showOrbitPath);
+ node.add_nodeSelected(ss.bind('_node_NodeSelected$1', this));
+ node.add_nodeChecked(ss.bind('_node_NodeChecked$1', this));
+ nodes.push(node);
+ }
+ return nodes;
+ },
+ _node_NodeChecked$1: function (node, newState) {
+ var frame = node.get_tag();
+ if (frame != null) {
+ frame.showOrbitPath = newState;
+ }
+ },
+ _node_NodeSelected$1: function (node) {
+ if (this._callbacks$1 != null) {
+ var frame = node.get_tag();
+ var rowData = {};
+ rowData['Name'] = frame.name;
+ rowData['SemiMajor Axis'] = frame.semiMajorAxis.toString();
+ rowData['SMA Units'] = frame.semiMajorAxisUnits.toString();
+ rowData['Inclination'] = frame.inclination.toString();
+ rowData['Eccentricity'] = frame.eccentricity.toString();
+ rowData['Long of Asc. Node'] = frame.longitudeOfAscendingNode.toString();
+ rowData['Argument Of Periapsis'] = frame.argumentOfPeriapsis.toString();
+ rowData['Epoch'] = frame.epoch.toString();
+ rowData['Mean Daily Motion'] = frame.meanDailyMotion.toString();
+ rowData['Mean Anomoly at Epoch'] = frame.meanAnomolyAtEpoch.toString();
+ this._callbacks$1.showRowData(rowData);
+ }
+ },
+
+ getNodeContextMenu: function (node) {
+ return LayerUI.prototype.getNodeContextMenu.call(this, node);
+ }
+};
+
+registerType("OrbitLayerUI", [OrbitLayerUI, OrbitLayerUI$, LayerUI]);
diff --git a/engine/esm/layers/reference_frame.js b/engine/esm/layers/reference_frame.js
new file mode 100644
index 00000000..db14d446
--- /dev/null
+++ b/engine/esm/layers/reference_frame.js
@@ -0,0 +1,480 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A reference frame for the 3D mode.
+
+import { ss } from "../ss.js";
+import { registerType, registerEnum, Enums } from "../typesystem.js";
+import { EOE, ELL } from "../astrocalc/elliptical.js";
+import { Vector3d, Matrix3d } from "../double3d.js";
+import { Color, Colors } from "../color.js";
+import { SpaceTimeController } from "../space_time_controller.js";
+
+
+// wwtlib.ReferenceFrameTypes
+
+export var ReferenceFrameTypes = {
+ fixedSherical: 0,
+ orbital: 1,
+ trajectory: 2,
+ synodic: 3
+};
+
+registerType("ReferenceFrameTypes", ReferenceFrameTypes);
+registerEnum("ReferenceFrameTypes", ReferenceFrameTypes);
+
+
+// wwtlib.ReferenceFrame
+
+export function ReferenceFrame() {
+ this._systemGenerated = false;
+
+ // Calclulated
+ this.meanAnomoly = 0;
+ this.orbitalYears = 0;
+
+ // Serialized
+ this.observingLocation = false;
+ this.reference = 18;
+ this.parentsRoationalBase = false;
+ this.referenceFrameType = 0;
+ this.meanRadius = 6371000;
+ this.oblateness = 0.0033528;
+ this.heading = 0;
+ this.pitch = 0;
+ this.roll = 0;
+ this.scale = 1;
+ this.tilt = 0;
+ this.translation = new Vector3d();
+
+ // For Spherical Offset
+ this.lat = 0;
+ this.lng = 0;
+ this.altitude = 0;
+
+ // For Rotating frames
+ this.rotationalPeriod = 0; // days
+ this.zeroRotationDate = 0; // julian decimal
+
+ // For representing orbits & distant point location
+ this.representativeColor = Colors.get_white(); // Used for orbits and points
+ this.showAsPoint = false;
+ this.showOrbitPath = false;
+ this.stationKeeping = true;
+
+ this.semiMajorAxis = 0; // a Au's
+ this.semiMajorAxisUnits = 1; // AltUnits
+ this.eccentricity = 0; // e
+ this.inclination = 0; // i
+ this.argumentOfPeriapsis = 0; // w
+ this.longitudeOfAscendingNode = 0; // Omega
+ this.meanAnomolyAtEpoch = 0; // M
+ this.meanDailyMotion = 0; // n .degrees day
+ this.epoch = 0; // standard equinox
+
+ this._orbit = null;
+ this._elements = new EOE();
+ this.worldMatrix = new Matrix3d();
+ this.worldMatrix = Matrix3d.get_identity();
+}
+
+ReferenceFrame.isTLECheckSumGood = function (line) {
+ if (line.length !== 69) {
+ return false;
+ }
+ var checksum = 0;
+ for (var i = 0; i < 68; i++) {
+ switch (line.substr(i, 1)) {
+ case '1':
+ checksum += 1;
+ break;
+ case '2':
+ checksum += 2;
+ break;
+ case '3':
+ checksum += 3;
+ break;
+ case '4':
+ checksum += 4;
+ break;
+ case '5':
+ checksum += 5;
+ break;
+ case '6':
+ checksum += 6;
+ break;
+ case '7':
+ checksum += 7;
+ break;
+ case '8':
+ checksum += 8;
+ break;
+ case '9':
+ checksum += 9;
+ break;
+ case '-':
+ checksum += 1;
+ break;
+ }
+ }
+ return (checksum % 10).toString() === line.charAt(68).toString();
+};
+
+ReferenceFrame.toTLEExponential = function (num, size) {
+ var exp = num.toExponential(size);
+ if (exp.length < size + 6) {
+ exp = exp.substring(0, size + 4) + '0' + exp.substr(size + 4, 1);
+ }
+ return exp;
+};
+
+ReferenceFrame.tleNumberString = function (num, left, right) {
+ var formated = num.toFixed(right);
+ var point = formated.indexOf('.');
+ if (point === -1) {
+ point = formated.length;
+ formated += '.0';
+ }
+ var len = formated.length - point - 1;
+ var fill = '00000000';
+ formated = fill.substr(0, left - point) + formated + fill.substr(0, right - len);
+ return formated;
+};
+
+ReferenceFrame.computeTLECheckSum = function (line) {
+ if (line.length !== 68) {
+ return '0';
+ }
+ var checksum = 0;
+ for (var i = 0; i < 68; i++) {
+ switch (line[i]) {
+ case '1':
+ checksum += 1;
+ break;
+ case '2':
+ checksum += 2;
+ break;
+ case '3':
+ checksum += 3;
+ break;
+ case '4':
+ checksum += 4;
+ break;
+ case '5':
+ checksum += 5;
+ break;
+ case '6':
+ checksum += 6;
+ break;
+ case '7':
+ checksum += 7;
+ break;
+ case '8':
+ checksum += 8;
+ break;
+ case '9':
+ checksum += 9;
+ break;
+ case '-':
+ checksum += 1;
+ break;
+ }
+ }
+ return ((checksum % 10));
+};
+
+var ReferenceFrame$ = {
+ get_representativeColor: function () {
+ return this.representativeColor;
+ },
+
+ set_representativeColor: function (value) {
+ if (value !== this.representativeColor) {
+ this.representativeColor = value;
+ this._orbit = null;
+ }
+ return value;
+ },
+
+ get_orbit: function () {
+ return this._orbit;
+ },
+
+ set_orbit: function (value) {
+ this._orbit = value;
+ return value;
+ },
+
+ getIndentifier: function () {
+ return this.name;
+ },
+
+ importTrajectory: function (filename) { },
+
+ saveToXml: function (xmlWriter) {
+ xmlWriter._writeStartElement('ReferenceFrame');
+ xmlWriter._writeAttributeString('Name', this.name);
+ xmlWriter._writeAttributeString('Parent', this.parent);
+ xmlWriter._writeAttributeString('ReferenceFrameType', Enums.toXml('ReferenceFrameTypes', this.referenceFrameType));
+ xmlWriter._writeAttributeString('Reference', Enums.toXml('ReferenceFrames', this.reference));
+ xmlWriter._writeAttributeString('ParentsRoationalBase', this.parentsRoationalBase.toString());
+ xmlWriter._writeAttributeString('MeanRadius', this.meanRadius.toString());
+ xmlWriter._writeAttributeString('Oblateness', this.oblateness.toString());
+ xmlWriter._writeAttributeString('Heading', this.heading.toString());
+ xmlWriter._writeAttributeString('Pitch', this.pitch.toString());
+ xmlWriter._writeAttributeString('Roll', this.roll.toString());
+ xmlWriter._writeAttributeString('Scale', this.scale.toString());
+ xmlWriter._writeAttributeString('Tilt', this.tilt.toString());
+ xmlWriter._writeAttributeString('Translation', this.translation.toString());
+ if (!this.referenceFrameType) {
+ xmlWriter._writeAttributeString('Lat', this.lat.toString());
+ xmlWriter._writeAttributeString('Lng', this.lng.toString());
+ xmlWriter._writeAttributeString('Altitude', this.altitude.toString());
+ }
+ xmlWriter._writeAttributeString('RotationalPeriod', this.rotationalPeriod.toString());
+ xmlWriter._writeAttributeString('ZeroRotationDate', this.zeroRotationDate.toString());
+ xmlWriter._writeAttributeString('RepresentativeColor', this.get_representativeColor().save());
+ xmlWriter._writeAttributeString('ShowAsPoint', this.showAsPoint.toString());
+ xmlWriter._writeAttributeString('ShowOrbitPath', this.showOrbitPath.toString());
+ xmlWriter._writeAttributeString('StationKeeping', this.stationKeeping.toString());
+ if (this.referenceFrameType === 1) {
+ xmlWriter._writeAttributeString('SemiMajorAxis', this.semiMajorAxis.toString());
+ xmlWriter._writeAttributeString('SemiMajorAxisScale', Enums.toXml('AltUnits', this.semiMajorAxisUnits));
+ xmlWriter._writeAttributeString('Eccentricity', this.eccentricity.toString());
+ xmlWriter._writeAttributeString('Inclination', this.inclination.toString());
+ xmlWriter._writeAttributeString('ArgumentOfPeriapsis', this.argumentOfPeriapsis.toString());
+ xmlWriter._writeAttributeString('LongitudeOfAscendingNode', this.longitudeOfAscendingNode.toString());
+ xmlWriter._writeAttributeString('MeanAnomolyAtEpoch', this.meanAnomolyAtEpoch.toString());
+ xmlWriter._writeAttributeString('MeanDailyMotion', this.meanDailyMotion.toString());
+ xmlWriter._writeAttributeString('Epoch', this.epoch.toString());
+ }
+ xmlWriter._writeEndElement();
+ },
+
+ initializeFromXml: function (node) {
+ this.name = node.attributes.getNamedItem('Name').nodeValue;
+ this.parent = node.attributes.getNamedItem('Parent').nodeValue;
+ this.referenceFrameType = Enums.parse('ReferenceFrameTypes', node.attributes.getNamedItem('ReferenceFrameType').nodeValue);
+ this.reference = Enums.parse('ReferenceFrames', node.attributes.getNamedItem('Reference').nodeValue);
+ this.parentsRoationalBase = ss.boolean(node.attributes.getNamedItem('ParentsRoationalBase').nodeValue);
+ this.meanRadius = parseFloat(node.attributes.getNamedItem('MeanRadius').nodeValue);
+ this.oblateness = parseFloat(node.attributes.getNamedItem('Oblateness').nodeValue);
+ this.heading = parseFloat(node.attributes.getNamedItem('Heading').nodeValue);
+ this.pitch = parseFloat(node.attributes.getNamedItem('Pitch').nodeValue);
+ this.roll = parseFloat(node.attributes.getNamedItem('Roll').nodeValue);
+ this.scale = parseFloat(node.attributes.getNamedItem('Scale').nodeValue);
+ this.tilt = parseFloat(node.attributes.getNamedItem('Tilt').nodeValue);
+ this.translation = Vector3d.parse(node.attributes.getNamedItem('Translation').nodeValue);
+ if (!this.referenceFrameType) {
+ this.lat = parseFloat(node.attributes.getNamedItem('Lat').nodeValue);
+ this.lng = parseFloat(node.attributes.getNamedItem('Lng').nodeValue);
+ this.altitude = parseFloat(node.attributes.getNamedItem('Altitude').nodeValue);
+ }
+ this.rotationalPeriod = parseFloat(node.attributes.getNamedItem('RotationalPeriod').nodeValue);
+ this.zeroRotationDate = parseFloat(node.attributes.getNamedItem('ZeroRotationDate').nodeValue);
+ this.set_representativeColor(Color.load(node.attributes.getNamedItem('RepresentativeColor').nodeValue));
+ this.showAsPoint = ss.boolean(node.attributes.getNamedItem('ShowAsPoint').nodeValue);
+ if (node.attributes.getNamedItem('StationKeeping') != null) {
+ this.stationKeeping = ss.boolean(node.attributes.getNamedItem('StationKeeping').nodeValue);
+ }
+ if (this.referenceFrameType === 1) {
+ this.showOrbitPath = ss.boolean(node.attributes.getNamedItem('ShowOrbitPath').nodeValue);
+ this.semiMajorAxis = parseFloat(node.attributes.getNamedItem('SemiMajorAxis').nodeValue);
+ this.semiMajorAxisUnits = Enums.parse('AltUnits', node.attributes.getNamedItem('SemiMajorAxisScale').nodeValue);
+ this.eccentricity = parseFloat(node.attributes.getNamedItem('Eccentricity').nodeValue);
+ this.inclination = parseFloat(node.attributes.getNamedItem('Inclination').nodeValue);
+ this.argumentOfPeriapsis = parseFloat(node.attributes.getNamedItem('ArgumentOfPeriapsis').nodeValue);
+ this.longitudeOfAscendingNode = parseFloat(node.attributes.getNamedItem('LongitudeOfAscendingNode').nodeValue);
+ this.meanAnomolyAtEpoch = parseFloat(node.attributes.getNamedItem('MeanAnomolyAtEpoch').nodeValue);
+ this.meanDailyMotion = parseFloat(node.attributes.getNamedItem('MeanDailyMotion').nodeValue);
+ this.epoch = parseFloat(node.attributes.getNamedItem('Epoch').nodeValue);
+ }
+ },
+
+ fromTLE: function (line1, line2, gravity) {
+ this.epoch = SpaceTimeController._twoLineDateToJulian(line1.substr(18, 14));
+ this.eccentricity = parseFloat('0.' + line2.substr(26, 7));
+ this.inclination = parseFloat(line2.substr(8, 8));
+ this.longitudeOfAscendingNode = parseFloat(line2.substr(17, 8));
+ this.argumentOfPeriapsis = parseFloat(line2.substr(34, 8));
+ var revs = parseFloat(line2.substr(52, 11));
+ this.meanAnomolyAtEpoch = parseFloat(line2.substr(43, 8));
+ this.meanDailyMotion = revs * 360;
+ var part = (86400 / revs) / (Math.PI * 2);
+ this.semiMajorAxis = Math.pow((part * part) * gravity, 1 / 3);
+ this.semiMajorAxisUnits = 1;
+ },
+
+ toTLE: function () {
+ // Epoch need to convert to TLE time string.
+ // Ecentricity remove "0." from the begin and trim to 7 digits
+ // Inclination decimal degrees 8 digits max
+ // LOAN decimal degrees 8 digits
+ // AOP
+ // mean anomoly at epoch 8 digits
+ // Mean motion (revs per day) Compute
+ // Convert Semi-major-axis to meters from storage unit
+ // Compute revs
+ var line1 = new ss.StringBuilder();
+ line1.append('1 99999U 00111AAA ');
+ line1.append(SpaceTimeController.julianToTwoLineDate(this.epoch));
+ line1.append(' ');
+ line1.append(this.semiMajorAxis.toExponential(4));
+ line1.append(' 00000-0 ');
+ line1.append(ReferenceFrame.toTLEExponential(this.meanDailyMotion, 5));
+ line1.append(' 001');
+ line1.append(ReferenceFrame.computeTLECheckSum(line1.toString()));
+ line1.appendLine('');
+ var line2 = new ss.StringBuilder();
+ line2.append('2 99999 ');
+ line2.append(ReferenceFrame.tleNumberString(this.inclination, 3, 4) + ' ');
+ line2.append(ReferenceFrame.tleNumberString(this.longitudeOfAscendingNode, 3, 4) + ' ');
+ line2.append((ReferenceFrame.tleNumberString(this.eccentricity, 1, 7) + ' ').substring(2));
+ line2.append(ReferenceFrame.tleNumberString(this.argumentOfPeriapsis, 3, 4) + ' ');
+ line2.append(ReferenceFrame.tleNumberString(this.meanAnomolyAtEpoch, 3, 4) + ' ');
+ line2.append(ReferenceFrame.toTLEExponential(this.meanDailyMotion / 207732, 5));
+ line2.append('00001');
+ line2.append(ReferenceFrame.computeTLECheckSum(line2.toString()));
+ line2.appendLine('');
+ return line1.toString() + line2.toString();
+ },
+
+ get_elements: function () {
+ this._elements.a = this.semiMajorAxis;
+ this._elements.e = this.eccentricity;
+ this._elements.i = this.inclination;
+ this._elements.w = this.argumentOfPeriapsis;
+ this._elements.omega = this.longitudeOfAscendingNode;
+ this._elements.jdEquinox = this.epoch;
+ if (!this.meanDailyMotion) {
+ this._elements.n = ELL.meanMotionFromSemiMajorAxis(this._elements.a);
+ } else {
+ this._elements.n = this.meanDailyMotion;
+ }
+ this._elements.t = this.epoch - (this.meanAnomolyAtEpoch / this._elements.n);
+ return this._elements;
+ },
+
+ set_elements: function (value) {
+ this._elements = value;
+ return value;
+ },
+
+ computeFrame: function (renderContext) {
+ switch (this.referenceFrameType) {
+ case 1:
+ this._computeOrbital(renderContext);
+ break;
+ case 0:
+ this._computeFixedSherical(renderContext);
+ break;
+ case 2:
+ this._computeFrameTrajectory(renderContext);
+ break;
+ default:
+ break;
+ }
+ },
+
+ useRotatingParentFrame: function () {
+ switch (this.referenceFrameType) {
+ case 1:
+ case 2:
+ case 3:
+ return false;
+ default:
+ return true;
+ }
+ },
+
+ _computeFixedRectangular: function (renderContext) { },
+
+ _computeFixedSherical: function (renderContext) {
+ if (this.observingLocation) {
+ this.lat = SpaceTimeController.get_location().get_lat();
+ this.lng = SpaceTimeController.get_location().get_lng();
+ this.altitude = SpaceTimeController.get_altitude();
+ }
+ this.worldMatrix = Matrix3d.get_identity();
+ this.worldMatrix.translate(this.translation);
+ var localScale = (1 / renderContext.get_nominalRadius()) * this.scale * this.meanRadius;
+ this.worldMatrix.scale(Vector3d.create(localScale, localScale, localScale));
+ this.worldMatrix._multiply(Matrix3d.rotationYawPitchRoll((this.heading / 180 * Math.PI), (this.pitch / 180 * Math.PI), (this.roll / 180 * Math.PI)));
+ this.worldMatrix._multiply(Matrix3d._rotationZ(-90 / 180 * Math.PI));
+ if (!!this.rotationalPeriod) {
+ var rotationCurrent = (((SpaceTimeController.get_jNow() - this.zeroRotationDate) / this.rotationalPeriod) * Math.PI * 2) % (Math.PI * 2);
+ this.worldMatrix._multiply(Matrix3d._rotationX(-rotationCurrent));
+ }
+ this.worldMatrix.translate(Vector3d.create(1 + (this.altitude / renderContext.get_nominalRadius()), 0, 0));
+ this.worldMatrix._multiply(Matrix3d._rotationZ(this.lat / 180 * Math.PI));
+ this.worldMatrix._multiply(Matrix3d._rotationY(-(this.lng + 180) / 180 * Math.PI));
+ },
+
+ _computeFrameTrajectory: function (renderContext) { },
+
+ _computeOrbital: function (renderContext) {
+ var ee = this.get_elements();
+ var point = ELL.calculateRectangularJD(SpaceTimeController.get_jNow(), ee);
+ this.meanAnomoly = ee.meanAnnomolyOut;
+ var pointInstantLater = ELL.calculateRectangular(ee, this.meanAnomoly + 0.001);
+ var direction = Vector3d.subtractVectors(point, pointInstantLater);
+ var up = point.copy();
+ up.normalize();
+ direction.normalize();
+ var dist = point.length();
+ var scaleFactor = 1;
+ switch (this.semiMajorAxisUnits) {
+ case 1:
+ scaleFactor = 1;
+ break;
+ case 2:
+ scaleFactor = 1 / 3.2808399;
+ break;
+ case 3:
+ scaleFactor = (1 / 3.2808399) / 12;
+ break;
+ case 4:
+ scaleFactor = 1609.344;
+ break;
+ case 5:
+ scaleFactor = 1000;
+ break;
+ case 6:
+ scaleFactor = 149598000 * 1000;
+ break;
+ case 7:
+ scaleFactor = 63239.6717 * 149598000 * 1000;
+ break;
+ case 8:
+ scaleFactor = 206264.806 * 149598000 * 1000;
+ break;
+ case 9:
+ scaleFactor = 206264.806 * 149598000 * 1000 * 1000000;
+ break;
+ case 10:
+ scaleFactor = 1;
+ break;
+ default:
+ break;
+ }
+ scaleFactor *= 1 / renderContext.get_nominalRadius();
+ var look = Matrix3d.lookAtLH(Vector3d.create(0, 0, 0), direction, up);
+ look.invert();
+ this.worldMatrix = Matrix3d.get_identity();
+ this.worldMatrix.translate(this.translation);
+ var localScale = (1 / renderContext.get_nominalRadius()) * this.scale * this.meanRadius;
+ this.worldMatrix.scale(Vector3d.create(localScale, localScale, localScale));
+ this.worldMatrix._multiply(Matrix3d.rotationYawPitchRoll((this.heading / 180 * Math.PI), (this.pitch / 180 * Math.PI), (this.roll / 180 * Math.PI)));
+ if (!!this.rotationalPeriod) {
+ var rotationCurrent = (((SpaceTimeController.get_jNow() - this.zeroRotationDate) / this.rotationalPeriod) * Math.PI * 2) % (Math.PI * 2);
+ this.worldMatrix._multiply(Matrix3d._rotationX(-rotationCurrent));
+ }
+ point = Vector3d.scale(point, scaleFactor);
+ this.worldMatrix.translate(point);
+ if (this.stationKeeping) {
+ this.worldMatrix = Matrix3d.multiplyMatrix(look, this.worldMatrix);
+ }
+ }
+};
+
+registerType("ReferenceFrame", [ReferenceFrame, ReferenceFrame$, null]);
diff --git a/engine/esm/layers/spreadsheet_layer.js b/engine/esm/layers/spreadsheet_layer.js
new file mode 100644
index 00000000..cb9508ef
--- /dev/null
+++ b/engine/esm/layers/spreadsheet_layer.js
@@ -0,0 +1,2071 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A layer that renders tabular data.
+
+import { ss } from "../ss.js";
+import { registerType, Enums } from "../typesystem.js";
+import { Util } from "../baseutil.js";
+import { Vector3d, Vector4d } from "../double3d.js";
+import { layerManagerGetAllMaps } from "../data_globals.js";
+import { globalRenderContext, tilePrepDevice } from "../render_globals.js";
+import { WEBGL } from "../graphics/webgl_constants.js";
+import { Dates, LineList, TriangleList, PointList } from "../graphics/primitives3d.js";
+import { Texture } from "../graphics/texture.js";
+import { Tessellator } from "../graphics/tessellator.js";
+import { Color, Colors } from "../color.js";
+import { Coordinates } from "../coordinates.js";
+import { SpaceTimeController } from "../space_time_controller.js";
+import { UiTools } from "../ui_tools.js";
+import { URLHelpers } from "../url_helpers.js";
+import { ColorMapContainer } from "./color_map_container.js";
+import { Layer } from "./layer.js";
+import { Table } from "./table.js";
+
+
+// wwtlib.KmlCoordinate
+
+export function KmlCoordinate() {
+ this.lat = 0;
+ this.lng = 0;
+ this.alt = 0;
+}
+
+var KmlCoordinate$ = {};
+
+registerType("KmlCoordinate", [KmlCoordinate, KmlCoordinate$, null]);
+
+
+// wwtlib.KmlLineList
+
+export function KmlLineList() {
+ this.extrude = false;
+ this.astronomical = false;
+ this.meanRadius = 6371000;
+ this.pointList = [];
+}
+
+var KmlLineList$ = {
+ parseWkt: function (geoText, option, alt, date) {
+ var parts = UiTools.split(geoText, '(,)');
+ var $enum1 = ss.enumerate(parts);
+ while ($enum1.moveNext()) {
+ var part = $enum1.current;
+ var coordinates = ss.trim(part).split(' ');
+ if (coordinates.length > 1) {
+ var pnt = new KmlCoordinate();
+ pnt.lng = parseFloat(coordinates[0]);
+ if (this.astronomical) {
+ pnt.lng -= 180;
+ }
+ pnt.lat = parseFloat(coordinates[1]);
+ if (coordinates.length > 2 && !alt) {
+ pnt.alt = parseFloat(coordinates[2]);
+ }
+ else {
+ pnt.alt = alt;
+ }
+ pnt.date = date;
+ this.pointList.push(pnt);
+ }
+ }
+ },
+
+ getCenterPoint: function () {
+ var point = new KmlCoordinate();
+ point.lat = 0;
+ point.lng = 0;
+ point.alt = 0;
+ var $enum1 = ss.enumerate(this.pointList);
+ while ($enum1.moveNext()) {
+ var pnt = $enum1.current;
+ point.lat += pnt.lat;
+ point.lng += pnt.lng;
+ point.alt += pnt.alt;
+ }
+ point.lat /= this.pointList.length;
+ point.lng /= this.pointList.length;
+ point.alt /= this.pointList.length;
+ return point;
+ }
+};
+
+registerType("KmlLineList", [KmlLineList, KmlLineList$, null]);
+
+
+// wwtlib.PushPin
+
+export function PushPin() { }
+
+PushPin._pinTextureCache = {};
+PushPin._pins = null;
+
+PushPin.triggerLoadSprite = function () {
+ if (PushPin._pins == null) {
+ PushPin._pins = Texture.fromUrl(URLHelpers.singleton.engineAssetUrl('pins.png'));
+ }
+};
+
+PushPin.getPushPinTexture = function (pinId) {
+ var texture = null;
+ if (ss.keyExists(PushPin._pinTextureCache, pinId)) {
+ return PushPin._pinTextureCache[pinId];
+ }
+ try {
+ texture = tilePrepDevice.createTexture();
+ tilePrepDevice.bindTexture(WEBGL.TEXTURE_2D, texture);
+ var row = Math.floor(pinId / 16);
+ var col = pinId % 16;
+ var temp = document.createElement('canvas');
+ temp.height = 32;
+ temp.width = 32;
+ var ctx = temp.getContext('2d');
+ //Substitute the resized image
+ ctx.drawImage(PushPin._pins.imageElement, (col * 32), (row * 32), 32, 32, 0, 0, 32, 32);
+ var image = temp;
+ tilePrepDevice.texParameteri(WEBGL.TEXTURE_2D, WEBGL.TEXTURE_WRAP_S, WEBGL.CLAMP_TO_EDGE);
+ tilePrepDevice.texParameteri(WEBGL.TEXTURE_2D, WEBGL.TEXTURE_WRAP_T, WEBGL.CLAMP_TO_EDGE);
+ tilePrepDevice.texImage2D(WEBGL.TEXTURE_2D, 0, WEBGL.RGBA, WEBGL.RGBA, WEBGL.UNSIGNED_BYTE, image);
+ tilePrepDevice.texParameteri(WEBGL.TEXTURE_2D, WEBGL.TEXTURE_MIN_FILTER, WEBGL.LINEAR_MIPMAP_NEAREST);
+ tilePrepDevice.generateMipmap(WEBGL.TEXTURE_2D);
+ tilePrepDevice.bindTexture(WEBGL.TEXTURE_2D, null);
+ PushPin._pinTextureCache[pinId] = texture;
+ }
+ catch ($e1) { }
+ return texture;
+};
+
+var PushPin$ = {};
+
+registerType("PushPin", [PushPin, PushPin$, null]);
+
+
+// wwtlib.SpreadSheetLayer
+
+export function SpreadSheetLayer() {
+ this._dataDirty$1 = false;
+ this._lastNormalizeSizeColumnIndex$1 = -1;
+ this._lastDynamicColorColumnIndex$1 = -1;
+ this._table_backcompat$1 = null;
+ this._barChartBitmask$1 = 0;
+ this._barScaleFactor$1 = 20;
+ this._meanRadius$1 = 6371000;
+ this._table$1 = new Table();
+ this.isLongIndex = false;
+ this.shapeVertexCount = 0;
+ this.lines = false;
+ this.latColumn = -1;
+ this.fixedSize = 1;
+ this.decay = 16;
+ this.timeSeries = false;
+ this._dynamicData$1 = false;
+ this._autoUpdate$1 = false;
+ this._dataSourceUrl$1 = '';
+ this._beginRange$1 = new Date('1/1/2100');
+ this._endRange$1 = new Date('01/01/1800');
+ this.markerDomainValues = {};
+ this.colorDomainValues = {};
+ this._coordinatesType$1 = 0;
+ this.lngColumn = -1;
+ this.geometryColumn = -1;
+ this._xAxisColumn$1 = -1;
+ this._yAxisColumn$1 = -1;
+ this._zAxisColumn$1 = -1;
+ this._xAxisReverse$1 = false;
+ this._yAxisReverse$1 = false;
+ this._zAxisReverse$1 = false;
+ this._altType$1 = 3;
+ this._markerMix$1 = 0;
+ this._raUnits$1 = 0;
+ this.colorMap = 3;
+ this.colorMapperName = 'Greys';
+
+ // The following attributes control whether and how to map values from
+ // the ColorMapColumn to colors. The overall option DynamicColor
+ // determines whether colors should be determined on-the-fly from column
+ // values. In this case, first, if NormalizeColorMap is true, the values
+ // are normalized to the range [0:1] using:
+ //
+ // new_value = (value - NormalizeColorMapMin) / (NormalizeColorMapMax - NormalizeColorMapMin)
+ //
+ // Whether or not the values are normalized, they are then mapped to colors using
+ // the color map with the name given by ColorMapName.
+
+ // Note that we use a hard-coded UUID since we need it to always be the same across
+ // all WWT sessions so that we can remove it when it isn't needed.
+
+ this._dynamicColorColumnName$1 = '2efc32e3-b9d9-47ff-8036-8cc344c585bd';
+ this.dynamicColor = false;
+ this.normalizeColorMap = false;
+ this.normalizeColorMapMin = 0;
+ this.normalizeColorMapMax = 1;
+ this._markerColumn$1 = -1;
+ this.colorMapColumn = -1;
+ this._plotType$1 = 0;
+ this._markerIndex$1 = 0;
+ this._showFarSide$1 = false;
+ this._markerScale$1 = 1;
+ this._altUnit$1 = 1;
+ this._cartesianScale$1 = 1;
+ this._cartesianCustomScale$1 = 1;
+ this.altColumn = -1;
+ this.startDateColumn = -1;
+ this.endDateColumn = -1;
+ this.sizeColumn = -1;
+
+ // The following attributes control whether the point sizes should be normalized before
+ // being used. When NormalizeSize is true, the point sizes are scaled using
+ //
+ // new_size = (size - NormalizeSizeMin) / (NormalizeSizeMax - NormalizeSizeMin)
+ //
+ // The NormalizeSizeClip attribute can be used to determine whether the sizes should
+ // be clipped to the range [0:1]. At this time, normalization is only applied if
+ // PointScaleTypes is Linear or Power.
+
+ // Note that we use a hard-coded UUID since we need it to always be the same across
+ // all WWT sessions so that we can remove it when it isn't needed.
+
+ this._normalizeSizeColumnName$1 = 'dfe78b4c-f972-4796-b04f-68c5efd4ecb0';
+ this.normalizeSize = false;
+ this.normalizeSizeClip = false;
+ this.normalizeSizeMin = 0;
+ this.normalizeSizeMax = 1;
+ this.nameColumn = 0;
+ this._hyperlinkFormat$1 = '';
+ this._hyperlinkColumn$1 = -1;
+ this.scaleFactor = 1;
+ this.pointScaleType = 1;
+ this.positions = [];
+ this.bufferIsFlat = false;
+ this.baseDate = new Date(2010, 0, 1, 12, 0, 0);
+ this.dirty = true;
+ this.lastVersion = 0;
+ Layer.call(this);
+}
+
+SpreadSheetLayer._circleTexture$1 = null;
+
+SpreadSheetLayer._getDatafromFeed$1 = function (url) {
+ return '';
+};
+
+SpreadSheetLayer._executeQuery$1 = function (url) {
+ return '';
+};
+
+SpreadSheetLayer.parseDate = function (date) {
+ var dt = ss.now();
+ try {
+ dt = new Date(date);
+ }
+ catch ($e1) {
+ try {
+ return SpreadSheetLayer.execlToDateTime(parseFloat(date));
+ }
+ catch ($e2) {
+ }
+ }
+ return dt;
+};
+
+SpreadSheetLayer.execlToDateTime = function (excelDate) {
+ if (excelDate > 59) {
+ excelDate -= 1;
+ }
+ if (excelDate > 730000) {
+ excelDate = 730000;
+ }
+ var es = new Date(1899, 12, 31);
+ return new Date(es.getDate() + ss.truncate((excelDate * 24 * 60 * 60 * 1000)));
+};
+
+SpreadSheetLayer.get__circleTexture$1 = function () {
+ if (SpreadSheetLayer._circleTexture$1 == null) {
+ var url = URLHelpers.singleton.engineAssetUrl('circle.png');
+ SpreadSheetLayer._circleTexture$1 = Texture.fromUrl(url);
+ }
+ return SpreadSheetLayer._circleTexture$1;
+};
+
+var SpreadSheetLayer$ = {
+ getTypeName: function () {
+ return 'TerraViewer.SpreadSheetLayer';
+ },
+
+ get_header: function () {
+ return this._table$1.header;
+ },
+
+ canCopyToClipboard: function () {
+ return true;
+ },
+
+ copyToClipboard: function () { },
+
+ dynamicUpdate: function () {
+ var data = SpreadSheetLayer._getDatafromFeed$1(this.get_dataSourceUrl());
+ if (data != null) {
+ this.updateData(data, false, true, true);
+ this.guessHeaderAssignments();
+ return true;
+ }
+ return false;
+ },
+
+ updateData: function (data, purgeOld, purgeAll, hasHeader) {
+ this.loadFromString(ss.safeCast(data, String), true, purgeOld, purgeAll, hasHeader);
+ this.computeDateDomainRange(-1, -1);
+ this._dataDirty$1 = true;
+ this.dirty = true;
+ return true;
+ },
+
+ loadData: function (tourDoc, filename) {
+ var $this = this;
+
+ this._table$1 = new Table();
+ var blob = tourDoc.getFileBlob(filename);
+ this.getStringFromGzipBlob(blob, function (data) {
+ $this._table$1.loadFromString(data, false, true, true);
+
+ // The NormalizeSizeColumnName column is only present for backward-compatibility
+ // and should be removed in this version of SpreadSheetLayer, otherwise we might
+ // keep adding it several times if exporting to XML again.
+ if ($this._table$1.header.indexOf($this._normalizeSizeColumnName$1) > -1) {
+ $this._table$1.removeColumn($this._normalizeSizeColumnName$1);
+ }
+ $this.computeDateDomainRange(-1, -1);
+ if ($this.get_dynamicData() && $this.get_autoUpdate()) {
+ $this.dynamicUpdate();
+ }
+ $this._dataDirty$1 = true;
+ $this.dirty = true;
+ });
+ },
+
+ addFilesToCabinet: function (fc) {
+ this._fileName$1 = fc.tempDirectory + ss.format('{0}\\{1}.txt', fc.get_packageID(), this.id.toString());
+ var dir = this._fileName$1.substring(0, this._fileName$1.lastIndexOf('\\'));
+ var data = '';
+
+ // See PrepareBackCompatTable for an explanation of the
+ // circumstances under which table_backcompat is used.
+ if (this._table_backcompat$1 == null) {
+ data = this._table$1.save();
+ } else {
+ data = this._table_backcompat$1.save();
+ }
+ var blob = new Blob([data]);
+ fc.addFile(this._fileName$1, blob);
+ Layer.prototype.addFilesToCabinet.call(this, fc);
+ },
+ _prepareBackCompatTable$1: function () {
+ // In this this layer class we implement dynamic normalization of the
+ // points based on one of the existing numerical columns. However, we
+ // need to produce XML files that are backward-compatible with older
+ // versions of WWT, so the approach we take is to add a column with
+ // the computed sizes for versions of WWT that can't do the dynamic
+ // scaling - while in newer versions we ignore this additional column
+ // and use the dynamic scaling.
+
+ // Take a shortcut to avoid copying the table if possible
+ if ((this.sizeColumn === -1 || !this.get_normalizeSize()) && (this.colorMapColumn === -1 || !this.get_dynamicColor())) {
+ this._lastNormalizeSizeColumnIndex$1 = -1;
+ this._lastDynamicColorColumnIndex$1 = -1;
+ return;
+ }
+ this._table_backcompat$1 = this._table$1.clone();
+ if (this.sizeColumn > -1 && this.get_normalizeSize()) {
+ var normalizedPointSize = [];
+ var $enum1 = ss.enumerate(this._table_backcompat$1.rows);
+ while ($enum1.moveNext()) {
+ var row = $enum1.current;
+ normalizedPointSize.push(this.normalizePointSize(parseFloat(row[this.sizeColumn])).toString());
+ }
+ this._table_backcompat$1.addColumn(this._normalizeSizeColumnName$1, normalizedPointSize);
+ this._lastNormalizeSizeColumnIndex$1 = this._table_backcompat$1.header.length - 1;
+ } else {
+ this._lastNormalizeSizeColumnIndex$1 = -1;
+ }
+ if (this.colorMapColumn > -1 && this.get_dynamicColor()) {
+ var pointColors = [];
+ var $enum2 = ss.enumerate(this._table_backcompat$1.rows);
+ while ($enum2.moveNext()) {
+ var row = $enum2.current;
+ pointColors.push(this.get_colorMapper().findClosestColor(this.normalizeColorMapValue(parseFloat(row[this.get_colorMapColumn()]))).toSimpleHex());
+ }
+ this._table_backcompat$1.addColumn(this._dynamicColorColumnName$1, pointColors);
+ this._lastDynamicColorColumnIndex$1 = this._table_backcompat$1.header.length - 1;
+ } else {
+ this._lastDynamicColorColumnIndex$1 = -1;
+ }
+ },
+
+ guessHeaderAssignments: function () {
+ var index = 0;
+ var $enum1 = ss.enumerate(this._table$1.header);
+ while ($enum1.moveNext()) {
+ var headerName = $enum1.current;
+ this._guessHeaderAssignment$1(headerName, index++);
+ }
+ if (this._table$1.header.length > 0) {
+ this.nameColumn = 0;
+ }
+ },
+
+ guessHeaderAssignmentsFromVoTable: function (votable) {
+ var decColumn = votable.getDecColumn();
+ if (decColumn != null) {
+ this.latColumn = decColumn.index;
+ this.astronomical = true;
+ }
+ var raColumn = votable.getRAColumn();
+ if (raColumn != null) {
+ this.lngColumn = raColumn.index;
+ this.astronomical = true;
+ this.pointScaleType = 4;
+ }
+ var magColumn = votable.getMagColumn();
+ if (magColumn != null) {
+ this.sizeColumn = magColumn.index;
+ }
+ var index = 0;
+ var $enum1 = ss.enumerate(votable.column);
+ while ($enum1.moveNext()) {
+ var column = $enum1.current;
+ this._guessHeaderAssignment$1(column.name, index++);
+ }
+ if (this._table$1.header.length > 0) {
+ this.nameColumn = 0;
+ }
+ },
+ _guessHeaderAssignment$1: function (name, index) {
+ name = name.toLowerCase();
+ if (name.indexOf('lat') > -1 && this.latColumn === -1) {
+ this.latColumn = index;
+ }
+ if ((name.indexOf('lon') > -1 || name.indexOf('lng') > -1) && this.lngColumn === -1) {
+ this.lngColumn = index;
+ }
+ if (name.indexOf('dec') > -1 && this.latColumn === -1) {
+ this.latColumn = index;
+ this.astronomical = true;
+ }
+ if ((name.indexOf('ra') > -1 || name.indexOf('ascen') > -1) && this.lngColumn === -1) {
+ this.lngColumn = index;
+ this.astronomical = true;
+ this.pointScaleType = 4;
+ }
+ if ((name.indexOf('mag') > -1 || name.indexOf('size') > -1) && this.sizeColumn === -1) {
+ this.sizeColumn = index;
+ }
+ if ((name.indexOf('date') > -1 || name.indexOf('time') > -1 || name.indexOf('dt') > -1 || name.indexOf('tm') > -1)) {
+ if (name.indexOf('end') > -1 && this.endDateColumn === -1) {
+ this.endDateColumn = index;
+ }
+ else if (this.startDateColumn === -1) {
+ this.startDateColumn = index;
+ }
+ }
+ if ((name.indexOf('altitude') > -1 || name.indexOf('alt') > -1) && this.altColumn === -1) {
+ this.altColumn = index;
+ this.set_altType(1);
+ this.set_altUnit(1);
+ }
+ if (name.indexOf('depth') > -1 && this.altColumn === -1) {
+ this.altColumn = index;
+ this.set_altType(0);
+ this.set_altUnit(5);
+ }
+ if (ss.startsWith(name, 'x') && this.get_xAxisColumn() === -1) {
+ this.set_xAxisColumn(index);
+ }
+ if (ss.startsWith(name, 'y') && this.get_yAxisColumn() === -1) {
+ this.set_yAxisColumn(index);
+ }
+ if (ss.startsWith(name, 'z') && this.get_zAxisColumn() === -1) {
+ this.set_zAxisColumn(index);
+ }
+ if (name.indexOf('color') > -1 && this.get_colorMapColumn() === -1) {
+ this.set_colorMapColumn(index);
+ }
+ if ((name.indexOf('geometry') > -1 || name.indexOf('geography') > -1) && this.geometryColumn === -1) {
+ this.geometryColumn = index;
+ }
+ },
+
+ computeDateDomainRange: function (columnStart, columnEnd) {
+ if (columnStart === -1) {
+ columnStart = this.startDateColumn;
+ }
+ if (columnEnd === -1) {
+ columnEnd = this.endDateColumn;
+ }
+ if (columnEnd === -1) {
+ columnEnd = columnStart;
+ }
+ this.set_beginRange(new Date('12/31/2100'));
+ this.set_endRange(new Date('12/31/1890'));
+ var $enum1 = ss.enumerate(this._table$1.rows);
+ while ($enum1.moveNext()) {
+ var row = $enum1.current;
+ try {
+ if (columnStart > -1) {
+ var sucsess = true;
+ var dateTimeStart = new Date('12/31/2100');
+ try {
+ dateTimeStart = new Date(row[columnStart]);
+ if (dateTimeStart < this.get_beginRange()) {
+ this.set_beginRange(dateTimeStart);
+ }
+ }
+ catch ($e2) {
+ }
+ try {
+ var dateTimeEnd = new Date('12/31/1890');
+ if (columnEnd > -1) {
+ dateTimeEnd = new Date(row[columnEnd]);
+ if (sucsess && dateTimeEnd > this.get_endRange()) {
+ this.set_endRange(dateTimeEnd);
+ }
+ }
+ }
+ catch ($e3) {
+ }
+ }
+ }
+ catch ($e4) {
+ }
+ }
+ },
+
+ checkState: function () { },
+
+ getMaxValue: function (column) {
+ var max = 0;
+ this._table$1.lock();
+ var $enum1 = ss.enumerate(this._table$1.rows);
+ while ($enum1.moveNext()) {
+ var row = $enum1.current;
+ try {
+ if (column > -1) {
+ var sucsess = true;
+ try {
+ var val = parseFloat(row[column]);
+ if (sucsess && val > max) {
+ max = val;
+ }
+ }
+ catch ($e2) {
+ }
+ }
+ }
+ catch ($e3) {
+ }
+ }
+ this._table$1.unlock();
+ return max;
+ },
+
+ getDomainValues: function (column) {
+ var domainValues = [];
+ this._table$1.lock();
+ var $enum1 = ss.enumerate(this._table$1.rows);
+ while ($enum1.moveNext()) {
+ var row = $enum1.current;
+ try {
+ if (column > -1) {
+ if (!(domainValues.indexOf(row[column]) >= 0)) {
+ domainValues.push(row[column]);
+ }
+ }
+ }
+ catch ($e2) {
+ }
+ }
+ domainValues.sort();
+ this._table$1.unlock();
+ return domainValues;
+ },
+
+ get_barChartBitmask: function () {
+ return this._barChartBitmask$1;
+ },
+
+ set_barChartBitmask: function (value) {
+ this._barChartBitmask$1 = value;
+ return value;
+ },
+ _isPointInFrustum$1: function (position, frustum) {
+ var centerV4 = new Vector4d(position.x, position.y, position.z, 1);
+ for (var i = 0; i < 6; i++) {
+ if (frustum[i].dot(centerV4) < 0) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ getTableDataInView: function () {
+ var data = '';
+ var first = true;
+ var $enum1 = ss.enumerate(this.get_header());
+ while ($enum1.moveNext()) {
+ var col = $enum1.current;
+ if (!first) {
+ data += '\t';
+ }
+ else {
+ first = false;
+ }
+ data += col;
+ }
+ data += '\r\n';
+ var $enum2 = ss.enumerate(this.get__table().rows);
+ while ($enum2.moveNext()) {
+ var row = $enum2.current;
+ var ra = parseFloat(row[this.get_lngColumn()]);
+ var dec = parseFloat(row[this.get_latColumn()]);
+ var position = Coordinates.geoTo3dDouble(dec, ra);
+ if (!this._isPointInFrustum$1(position, globalRenderContext.get_frustum())) {
+ continue;
+ }
+ first = true;
+ var $enum3 = ss.enumerate(row);
+ while ($enum3.moveNext()) {
+ var col = $enum3.current;
+ if (!first) {
+ data += '\t';
+ }
+ else {
+ first = false;
+ }
+ data += col;
+ }
+ data += '\r\n';
+ }
+ return data;
+ },
+
+ prepVertexBuffer: function (renderContext, opacity) {
+ this._table$1.lock();
+ if (this.lineList != null) {
+ this.lineList.clear();
+ }
+ if (this.lineList2d != null) {
+ this.lineList2d.clear();
+ }
+ if (this.triangleList != null) {
+ this.triangleList.clear();
+ }
+ if (this.pointList != null) {
+ this.pointList.clear();
+ }
+ if (this.triangleList2d != null) {
+ this.triangleList2d.clear();
+ }
+ if (this.lineList == null) {
+ this.lineList = new LineList();
+ }
+ if (this.pointList == null) {
+ this.pointList = new PointList(renderContext);
+ }
+ this.lineList.timeSeries = this.timeSeries;
+ if (this.lineList2d == null) {
+ this.lineList2d = new LineList();
+ this.lineList2d.set_depthBuffered(false);
+ }
+ this.lineList.timeSeries = this.timeSeries;
+ if (this.triangleList == null) {
+ this.triangleList = new TriangleList();
+ }
+ if (this.triangleList2d == null) {
+ this.triangleList2d = new TriangleList();
+ this.triangleList2d.depthBuffered = false;
+ }
+ this.positions.length = 0;
+ var currentIndex = 0;
+ var colorLocal = this.get_color();
+
+ // for space 3d
+ var ecliptic = Coordinates.meanObliquityOfEcliptic(SpaceTimeController.get_jNow()) / 180 * Math.PI;
+ var selectDomain = {};
+ var mr = layerManagerGetAllMaps()[this.get_referenceFrame()].frame.meanRadius;
+ if (!!mr) {
+ this._meanRadius$1 = mr;
+ }
+ var position = new Vector3d();
+ var pointSize = 0.0002;
+ var pointColor = Colors.get_white();
+ var pointStartTime = 0;
+ var pointEndTime = 0;
+ var $enum1 = ss.enumerate(this._table$1.rows);
+ while ($enum1.moveNext()) {
+ var row = $enum1.current;
+ try {
+ if (this.geometryColumn > -1 || (!this.get_coordinatesType() && (this.lngColumn > -1 && this.latColumn > -1)) || ((this.get_coordinatesType() === 1) && (this.get_xAxisColumn() > -1 && this.get_yAxisColumn() > -1))) {
+ var Xcoord = 0;
+ var Ycoord = 0;
+ var Zcoord = 0;
+ var alt = 1;
+ var altitude = 0;
+ var distParces = 0;
+ var factor = this.getScaleFactor(this.get_altUnit(), 1);
+ if (this.altColumn === -1 || this.get_altType() === 3 || this.bufferIsFlat) {
+ alt = 1;
+ if ((this.astronomical & !this.bufferIsFlat) === 1) {
+ alt = 63239.6717 * 100;
+ }
+ }
+ else {
+ if (!this.get_altType()) {
+ factor = -factor;
+ }
+ alt = 0;
+ try {
+ alt = parseFloat(row[this.altColumn]);
+ }
+ catch ($e2) {
+ }
+ if (this.astronomical) {
+ factor = factor / (1000 * 149598000);
+ distParces = (alt * factor) / 206264.806;
+ altitude = (factor * alt);
+ alt = (factor * alt);
+ }
+ else if (this.get_altType() === 2) {
+ altitude = (factor * alt);
+ alt = (factor * alt / this._meanRadius$1);
+ }
+ else {
+ altitude = (factor * alt);
+ alt = 1 + (factor * alt / this._meanRadius$1);
+ }
+ }
+ if (!this.get_coordinatesType() && this.lngColumn > -1 && this.latColumn > -1) {
+ Xcoord = parseFloat(row[this.lngColumn]);
+ Ycoord = parseFloat(row[this.latColumn]);
+ if (this.astronomical) {
+ if (!this.get_raUnits()) {
+ Xcoord *= 15;
+ }
+ if (this.bufferIsFlat) {
+ }
+ }
+ else {
+ Xcoord += 180;
+ }
+ var pos = Coordinates.geoTo3dRad(Ycoord, Xcoord, alt);
+ if (this.astronomical && !this.bufferIsFlat) {
+ pos.rotateX(ecliptic);
+ }
+ position = pos;
+ this.positions.push(position);
+ }
+ else if (this.get_coordinatesType() === 1) {
+ var xyzScale = this.getScaleFactor(this.get_cartesianScale(), this.get_cartesianCustomScale());
+ if (this.astronomical) {
+ xyzScale /= (1000 * 149598000);
+ }
+ else {
+ xyzScale /= this._meanRadius$1;
+ }
+ if (this.get_zAxisColumn() > -1) {
+ Zcoord = parseFloat(row[this.get_zAxisColumn()]);
+ }
+ Xcoord = parseFloat(row[this.get_xAxisColumn()]);
+ Ycoord = parseFloat(row[this.get_yAxisColumn()]);
+ if (this.get_xAxisReverse()) {
+ Xcoord = -Xcoord;
+ }
+ if (this.get_yAxisReverse()) {
+ Ycoord = -Ycoord;
+ }
+ if (this.get_zAxisReverse()) {
+ Zcoord = -Zcoord;
+ }
+ position = Vector3d.create((Xcoord * xyzScale), (Zcoord * xyzScale), (Ycoord * xyzScale));
+ this.positions.push(position);
+ }
+ switch (this.get_colorMap()) {
+ case 0:
+ pointColor = colorLocal;
+ break;
+ case 3:
+ if (this.get_colorMapColumn() > -1) {
+ if (this.get_dynamicColor()) {
+ pointColor = this.get_colorMapper().findClosestColor(this.normalizeColorMapValue(parseFloat(row[this.get_colorMapColumn()])));
+ }
+ else {
+ pointColor = this._parseColor$1(row[this.get_colorMapColumn()], colorLocal);
+ }
+ }
+ else {
+ pointColor = colorLocal;
+ }
+ break;
+ default:
+ break;
+ }
+ if (pointColor == null) {
+ pointColor = Colors.get_transparent();
+ }
+ if (this.sizeColumn > -1) {
+ switch (this.pointScaleType) {
+ case 0:
+ pointSize = parseFloat(row[this.sizeColumn]);
+ pointSize = this.normalizePointSize(pointSize);
+ break;
+ case 2:
+ pointSize = parseFloat(row[this.sizeColumn]);
+ pointSize = Math.log(pointSize);
+ break;
+ case 1:
+ try {
+ pointSize = parseFloat(row[this.sizeColumn]);
+ pointSize = this.normalizePointSize(pointSize);
+ pointSize = Math.pow(2, pointSize);
+ }
+ catch ($e3) {
+ pointSize = 0;
+ }
+ break;
+ case 4:
+ var size = 0;
+ try {
+ size = parseFloat(row[this.sizeColumn]);
+ if (!this.bufferIsFlat) {
+ size = size - 5 * (Util.logN(distParces, 10) - 1);
+ pointSize = (120000000 / Math.pow(1.6, size));
+ }
+ else {
+ pointSize = (40 / Math.pow(1.6, size));
+ }
+ }
+ catch ($e4) {
+ pointSize = 0;
+ }
+ break;
+ case 3:
+ pointSize = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ else {
+ pointSize = 0.2;
+ }
+ if (this.get_plotType() === 1) {
+ pointSize = 1;
+ }
+ if ((this.astronomical & !this.bufferIsFlat) === 1) {
+ }
+ if (this.startDateColumn > -1) {
+ var dateTime = new Date(row[this.startDateColumn]);
+ pointStartTime = (SpaceTimeController.utcToJulian(dateTime) - SpaceTimeController.utcToJulian(this.baseDate));
+ if (this.endDateColumn > -1) {
+ dateTime = new Date(row[this.endDateColumn]);
+ pointEndTime = (SpaceTimeController.utcToJulian(dateTime) - SpaceTimeController.utcToJulian(this.baseDate));
+ }
+ else {
+ pointEndTime = pointStartTime;
+ }
+ }
+ this.pointList.addPoint(position, pointColor, new Dates(pointStartTime, pointEndTime), pointSize);
+ if (this.geometryColumn > -1) {
+ this._parseGeometry$1(row[this.geometryColumn], pointColor, pointColor, altitude, new Dates(pointStartTime, pointEndTime));
+ }
+ currentIndex++;
+ }
+ }
+ catch ($e5) {
+ }
+ this.lines = false;
+ }
+ this._table$1.unlock();
+ this._dataDirty$1 = false;
+ this.dirty = false;
+ return false;
+ },
+ _parseGeometry$1: function (gs, lineColor, polyColor, alt, date) {
+ gs = ss.trim(gs).toLowerCase();
+ var index = gs.indexOf('(');
+ if (index < 0) {
+ return;
+ }
+ if (!ss.endsWith(gs, ')')) {
+ return;
+ }
+ var commandPart = ss.trim(gs.substring(0, index));
+ var parens = gs.substr(index);
+ var parts = commandPart.split(' ');
+ var command = null;
+ var mods = null;
+ if (parts.length > 0) {
+ var $enum1 = ss.enumerate(parts);
+ while ($enum1.moveNext()) {
+ var item = $enum1.current;
+ if (ss.emptyString(command)) {
+ command = item;
+ }
+ else if (ss.emptyString(mods)) {
+ mods = item;
+ }
+ }
+ }
+ switch (command) {
+ case 'multipolygon':
+ case 'polygon':
+ this._parsePolygon$1(parens, mods, lineColor, polyColor, alt, date);
+ break;
+ case 'multilinestring':
+ this._parseLineString$1(parens, mods, lineColor, alt, false, date);
+ break;
+ case 'linestring':
+ this._parseLineString$1(parens, mods, lineColor, alt, true, date);
+ break;
+ case 'geometrycollection':
+ parens = parens.substring(1, parens.length - 2);
+ var shapes = UiTools.splitString(parens, ',');
+ var $enum2 = ss.enumerate(shapes);
+ while ($enum2.moveNext()) {
+ var shape = $enum2.current;
+ this._parseGeometry$1(shape, lineColor, polyColor, alt, date);
+ }
+ break;
+ default:
+ break;
+ }
+ },
+ _parsePolygon$1: function (parens, mods, lineColor, polyColor, alt, date) {
+ if (!ss.startsWith(parens, '(') && ss.endsWith(parens, ')')) {
+ return;
+ }
+
+ // string the top level of parens
+ parens = parens.substring(1, parens.length - 2);
+ var shapes = UiTools.splitString(parens, ',');
+ var $enum1 = ss.enumerate(shapes);
+ while ($enum1.moveNext()) {
+ var shape = $enum1.current;
+ var lineList = new KmlLineList();
+ lineList.astronomical = this.astronomical;
+ lineList.meanRadius = this._meanRadius$1;
+ lineList.parseWkt(shape, mods, alt, date);
+ if (!alt) {
+ this._addPolygonFlat$1(false, lineList, 1, polyColor, lineColor, true, true, date);
+ }
+ else {
+ this._addPolygon$1(false, lineList, 1, polyColor, lineColor, true, true, date);
+ }
+ }
+ },
+ _parseLineString$1: function (parens, mods, lineColor, alt, single, date) {
+ if (!ss.startsWith(parens, '(') && ss.endsWith(parens, ')')) {
+ return;
+ }
+ if (!single) {
+ // string the top level of parens
+ parens = parens.substring(1, parens.length - 2);
+ }
+ var shapes = UiTools.splitString(parens, ',');
+ var $enum1 = ss.enumerate(shapes);
+ while ($enum1.moveNext()) {
+ var shape = $enum1.current;
+ var lineList = new KmlLineList();
+ lineList.astronomical = this.astronomical;
+ lineList.meanRadius = this._meanRadius$1;
+ lineList.parseWkt(shape, mods, alt, date);
+ this._addPolygon$1(false, lineList, 1, Colors.get_white(), lineColor, false, false, date);
+ }
+ },
+ _splitShapes$1: function (shapes) {
+ var shapeList = [];
+ var nesting = 0;
+ var current = 0;
+ while (current < shapes.length) {
+ if (shapes.substr(current, 1) === '(') {
+ nesting++;
+ }
+ }
+ return shapeList;
+ },
+ _addPolygon$1: function (sky, geo, lineWidth, polyColor, lineColor, extrude, fill, date) {
+ //todo can we save this work for later?
+ var vertexList = [];
+ var vertexListGround = [];
+ for (var i = 0; i < geo.pointList.length; i++) {
+ vertexList.push(Coordinates.geoTo3dRad(geo.pointList[i].lat, geo.pointList[i].lng, 1 + (geo.pointList[i].alt / this._meanRadius$1)));
+ vertexListGround.push(Coordinates.geoTo3dRad(geo.pointList[i].lat, geo.pointList[i].lng, 1));
+ }
+ for (var i = 0; i < (geo.pointList.length - 1); i++) {
+ if (sky) {
+ // todo reenable this
+ }
+ else {
+ if (extrude) {
+ this.triangleList.addQuad(vertexList[i], vertexList[i + 1], vertexListGround[i], vertexListGround[i + 1], polyColor, date);
+ }
+ if (lineWidth > 0) {
+ if (extrude) {
+ this.lineList.addLine(vertexList[i], vertexList[i + 1], lineColor, date);
+ }
+ else {
+ this.lineList2d.addLine(vertexList[i], vertexList[i + 1], lineColor, date);
+ }
+ if (extrude) {
+ this.lineList.addLine(vertexListGround[i], vertexListGround[i + 1], lineColor, date);
+ this.lineList.addLine(vertexList[i], vertexListGround[i], lineColor, date);
+ this.lineList.addLine(vertexList[i + 1], vertexListGround[i + 1], lineColor, date);
+ }
+ }
+ }
+ }
+ if (fill) {
+ var indexes = Tessellator.tesselateSimplePoly(vertexList);
+ for (var i = 0; i < indexes.length; i += 3) {
+ this.triangleList.addTriangle(vertexList[indexes[i]], vertexList[indexes[i + 1]], vertexList[indexes[i + 2]], polyColor, date);
+ }
+ }
+ },
+ _addPolygonFlat$1: function (sky, geo, lineWidth, polyColor, lineColor, extrude, fill, date) {
+ var vertexList = [];
+ for (var i = 0; i < geo.pointList.length; i++) {
+ vertexList.push(Coordinates.geoTo3dRad(geo.pointList[i].lat, geo.pointList[i].lng, 1 + (geo.pointList[i].alt / this._meanRadius$1)));
+ }
+ for (var i = 0; i < (geo.pointList.length - 1); i++) {
+ if (sky) {
+ }
+ else {
+ if (lineWidth > 0) {
+ this.lineList2d.addLine(vertexList[i], vertexList[i + 1], lineColor, date);
+ }
+ }
+ }
+ if (fill) {
+ var indexes = Tessellator.tesselateSimplePoly(vertexList);
+ for (var i = 0; i < indexes.length; i += 3) {
+ this.triangleList2d.addSubdividedTriangles(vertexList[indexes[i]], vertexList[indexes[i + 1]], vertexList[indexes[i + 2]], polyColor, date, 2);
+ }
+ }
+ },
+ _parseColor$1: function (colorText, defaultColor) {
+ return Color.load(colorText);
+ },
+
+ getScaleFactor: function (AltUnit, custom) {
+ var factor = 1;
+ switch (AltUnit) {
+ case 1:
+ factor = 1;
+ break;
+ case 2:
+ factor = 1 * 0.3048;
+ break;
+ case 3:
+ factor = (1 / 12) * 0.3048;
+ break;
+ case 4:
+ factor = 5280 * 0.3048;
+ break;
+ case 5:
+ factor = 1000;
+ break;
+ case 6:
+ factor = 1000 * 149598000;
+ break;
+ case 7:
+ factor = 1000 * 149598000 * 63239.6717;
+ break;
+ case 8:
+ factor = 1000 * 149598000 * 206264.806;
+ break;
+ case 9:
+ factor = 1000 * 149598000 * 206264.806 * 1000000;
+ break;
+ case 10:
+ factor = custom;
+ break;
+ default:
+ break;
+ }
+ return factor;
+ },
+
+ get__table: function () {
+ return this._table$1;
+ },
+
+ set__table: function (value) {
+ this._table$1 = value;
+ return value;
+ },
+
+ useHeadersFromVoTable: function (voTable) {
+ var $enum1 = ss.enumerate(voTable.column);
+ while ($enum1.moveNext()) {
+ var column = $enum1.current;
+ this.get_header().push(column.name);
+ }
+ this.guessHeaderAssignmentsFromVoTable(voTable);
+ if (voTable.getRAColumn() != null && voTable.getRAColumn().unit.toLowerCase() === 'deg') {
+ this.set_raUnits(1);
+ }
+ },
+
+ loadFromString: function (data, isUpdate, purgeOld, purgeAll, hasHeader) {
+ if (!isUpdate) {
+ this._table$1 = new Table();
+ }
+ this._table$1.lock();
+ this._table$1.loadFromString(data, isUpdate, purgeAll, hasHeader);
+ if (!isUpdate) {
+ this.guessHeaderAssignments();
+ if (this.astronomical && this.lngColumn > -1) {
+ var max = this.getMaxValue(this.lngColumn);
+ if (max > 24) {
+ this.set_raUnits(1);
+ }
+ }
+ }
+ if (purgeOld) {
+ this.purgeByTime();
+ }
+ this._table$1.unlock();
+ },
+
+ purgeByTime: function () {
+ if (this.startDateColumn < 0) {
+ return;
+ }
+ var columnToUse = this.startDateColumn;
+ if (this.endDateColumn > -1) {
+ columnToUse = this.endDateColumn;
+ }
+ var threasholdTime = SpaceTimeController.get_now();
+ var ts = ss.truncate(this.decay) * 24 * 60 * 60 * 1000;
+ threasholdTime = new Date(threasholdTime.getDate() - ts);
+ var count = this._table$1.rows.length;
+ for (var i = 0; i < count; i++) {
+ try {
+ var row = this._table$1.rows[i];
+ var colDate = new Date(row[columnToUse]);
+ if (colDate < threasholdTime) {
+ this._table$1.rows.splice(i, 1);
+ count--;
+ i--;
+ }
+ }
+ catch ($e1) {
+ }
+ }
+ },
+
+ cleanUp: function () {
+ this.cleanUpBase();
+ this._table$1.lock();
+ Layer.prototype.cleanUp.call(this);
+ this._table$1.unlock();
+ this.dirty = true;
+ },
+
+ writeLayerProperties: function (xmlWriter) {
+ xmlWriter._writeAttributeString('TimeSeries', this.get_timeSeries().toString());
+ xmlWriter._writeAttributeString('BeginRange', Util.xmlDate(this.get_beginRange()));
+ xmlWriter._writeAttributeString('EndRange', Util.xmlDate(this.get_endRange()));
+ xmlWriter._writeAttributeString('Decay', this.get_decay().toString());
+ xmlWriter._writeAttributeString('CoordinatesType', Enums.toXml('CoordinatesTypes', this.get_coordinatesType()));
+ xmlWriter._writeAttributeString('LatColumn', this.get_latColumn().toString());
+ xmlWriter._writeAttributeString('LngColumn', this.get_lngColumn().toString());
+ xmlWriter._writeAttributeString('GeometryColumn', this.get_geometryColumn().toString());
+ xmlWriter._writeAttributeString('AltType', Enums.toXml('AltTypes', this.get_altType()));
+ xmlWriter._writeAttributeString('MarkerMix', Enums.toXml('MarkerMixes', this.get_markerMix()));
+ xmlWriter._writeAttributeString('ColorMap', Enums.toXml('ColorMaps', this.get_colorMap()));
+ xmlWriter._writeAttributeString('MarkerColumn', this.get_markerColumn().toString());
+ xmlWriter._writeAttributeString('PlotType', Enums.toXml('PlotTypes', this.get_plotType()));
+ xmlWriter._writeAttributeString('MarkerIndex', this.get_markerIndex().toString());
+ xmlWriter._writeAttributeString('MarkerScale', Enums.toXml('MarkerScales', this.get_markerScale()));
+ xmlWriter._writeAttributeString('AltUnit', Enums.toXml('AltUnits', this.get_altUnit()));
+ xmlWriter._writeAttributeString('AltColumn', this.get_altColumn().toString());
+ xmlWriter._writeAttributeString('StartDateColumn', this.get_startDateColumn().toString());
+ xmlWriter._writeAttributeString('EndDateColumn', this.get_endDateColumn().toString());
+
+ // In this layer class we implement dynamic scaling and coloring of the points
+ // based on one of the existing numerical columns. However, we need to produce
+ // XML files that are backward-compatible with older versions of WWT. If
+ // dynamic scaling/coloring is used, we therefore point sizeColumn and/or
+ // colorMapColumn to the hard-coded sizes/colors, and then if we detect
+ // normalization arguments when reading in the XML, we switch sizeColumn
+ // and/or colorMapColumn to the original one.
+
+ // Note that we need to call this here since WriteLayerProperties
+ // gets called before AddFilesToCabinet.
+ this._prepareBackCompatTable$1();
+ if (this._lastNormalizeSizeColumnIndex$1 > -1) {
+ xmlWriter._writeAttributeString('SizeColumn', this._lastNormalizeSizeColumnIndex$1);
+ xmlWriter._writeAttributeString('NormalizeSizeColumn', this.sizeColumn.toString());
+ } else {
+ xmlWriter._writeAttributeString('SizeColumn', this.get_sizeColumn().toString());
+ }
+ xmlWriter._writeAttributeString('NormalizeSize', this.get_normalizeSize().toString());
+ xmlWriter._writeAttributeString('NormalizeSizeClip', this.get_normalizeSizeClip().toString());
+ xmlWriter._writeAttributeString('NormalizeSizeMin', this.get_normalizeSizeMin().toString());
+ xmlWriter._writeAttributeString('NormalizeSizeMax', this.get_normalizeSizeMax().toString());
+ if (this._lastDynamicColorColumnIndex$1 > -1) {
+ xmlWriter._writeAttributeString('ColorMapColumn', this._lastDynamicColorColumnIndex$1);
+ xmlWriter._writeAttributeString('DynamicColorColumn', this.get_colorMapColumn().toString());
+ } else {
+ xmlWriter._writeAttributeString('ColorMapColumn', this.get_colorMapColumn().toString());
+ }
+ xmlWriter._writeAttributeString('DynamicColor', this.get_dynamicColor().toString());
+ xmlWriter._writeAttributeString('ColorMapperName', this.get_colorMapperName());
+ xmlWriter._writeAttributeString('NormalizeColorMap', this.get_normalizeColorMap().toString());
+ xmlWriter._writeAttributeString('NormalizeColorMapMin', this.get_normalizeColorMapMin().toString());
+ xmlWriter._writeAttributeString('NormalizeColorMapMax', this.get_normalizeColorMapMax().toString());
+ xmlWriter._writeAttributeString('HyperlinkFormat', this.get_hyperlinkFormat());
+ xmlWriter._writeAttributeString('HyperlinkColumn', this.get_hyperlinkColumn().toString());
+ xmlWriter._writeAttributeString('ScaleFactor', this.get_scaleFactor().toString());
+ xmlWriter._writeAttributeString('PointScaleType', Enums.toXml('PointScaleTypes', this.get_pointScaleType()));
+ xmlWriter._writeAttributeString('ShowFarSide', this.get_showFarSide().toString());
+ xmlWriter._writeAttributeString('RaUnits', Enums.toXml('RAUnits', this.get_raUnits()));
+ xmlWriter._writeAttributeString('HoverTextColumn', this.get_nameColumn().toString());
+ xmlWriter._writeAttributeString('XAxisColumn', this.get_xAxisColumn().toString());
+ xmlWriter._writeAttributeString('XAxisReverse', this.get_xAxisReverse().toString());
+ xmlWriter._writeAttributeString('YAxisColumn', this.get_yAxisColumn().toString());
+ xmlWriter._writeAttributeString('YAxisReverse', this.get_yAxisReverse().toString());
+ xmlWriter._writeAttributeString('ZAxisColumn', this.get_zAxisColumn().toString());
+ xmlWriter._writeAttributeString('ZAxisReverse', this.get_zAxisReverse().toString());
+ xmlWriter._writeAttributeString('CartesianScale', Enums.toXml('AltUnits', this.get_cartesianScale()));
+ xmlWriter._writeAttributeString('CartesianCustomScale', this.get_cartesianCustomScale().toString());
+ xmlWriter._writeAttributeString('DynamicData', this.get_dynamicData().toString());
+ xmlWriter._writeAttributeString('AutoUpdate', this.get_autoUpdate().toString());
+ xmlWriter._writeAttributeString('DataSourceUrl', this.get_dataSourceUrl());
+ },
+
+ get_dynamicData: function () {
+ return this._dynamicData$1;
+ },
+
+ set_dynamicData: function (value) {
+ this._dynamicData$1 = value;
+ return value;
+ },
+
+ get_autoUpdate: function () {
+ return this._autoUpdate$1;
+ },
+
+ set_autoUpdate: function (value) {
+ this._autoUpdate$1 = value;
+ return value;
+ },
+
+ get_dataSourceUrl: function () {
+ return this._dataSourceUrl$1;
+ },
+
+ set_dataSourceUrl: function (value) {
+ this._dataSourceUrl$1 = value;
+ return value;
+ },
+
+ get_timeSeries: function () {
+ return this.timeSeries;
+ },
+
+ set_timeSeries: function (value) {
+ if (this.timeSeries !== value) {
+ this.version++;
+ this.timeSeries = value;
+ }
+ return value;
+ },
+
+ get_beginRange: function () {
+ return this._beginRange$1;
+ },
+
+ set_beginRange: function (value) {
+ if (!ss.compareDates(this._beginRange$1, value)) {
+ this.version++;
+ this._beginRange$1 = value;
+ }
+ return value;
+ },
+
+ get_endRange: function () {
+ return this._endRange$1;
+ },
+
+ set_endRange: function (value) {
+ if (!ss.compareDates(this._endRange$1, value)) {
+ this.version++;
+ this._endRange$1 = value;
+ }
+ return value;
+ },
+
+ initializeFromXml: function (node) {
+ this.set_timeSeries(ss.boolean(node.attributes.getNamedItem('TimeSeries').nodeValue));
+ this.set_beginRange(new Date(node.attributes.getNamedItem('BeginRange').nodeValue));
+ this.set_endRange(new Date(node.attributes.getNamedItem('EndRange').nodeValue));
+ this.set_decay(parseFloat(node.attributes.getNamedItem('Decay').nodeValue));
+ this.set_coordinatesType(Enums.parse('CoordinatesTypes', node.attributes.getNamedItem('CoordinatesType').nodeValue));
+ if (this.get_coordinatesType() < 0) {
+ this.set_coordinatesType(0);
+ }
+ this.set_latColumn(parseInt(node.attributes.getNamedItem('LatColumn').nodeValue));
+ this.set_lngColumn(parseInt(node.attributes.getNamedItem('LngColumn').nodeValue));
+ if (node.attributes.getNamedItem('GeometryColumn') != null) {
+ this.set_geometryColumn(parseInt(node.attributes.getNamedItem('GeometryColumn').nodeValue));
+ }
+ this.set_altType(Enums.parse('AltTypes', node.attributes.getNamedItem('AltType').nodeValue));
+ this.set_markerMix(0);
+ this.set_colorMap(Enums.parse('ColorMaps', node.attributes.getNamedItem('ColorMap').nodeValue));
+ this.set_markerColumn(parseInt(node.attributes.getNamedItem('MarkerColumn').nodeValue));
+ this.set_colorMapColumn(parseInt(node.attributes.getNamedItem('ColorMapColumn').nodeValue));
+ this.set_plotType(Enums.parse('PlotTypes', node.attributes.getNamedItem('PlotType').nodeValue));
+ this.set_markerIndex(parseInt(node.attributes.getNamedItem('MarkerIndex').nodeValue));
+ this.set_markerScale(Enums.parse('MarkerScales', node.attributes.getNamedItem('MarkerScale').nodeValue));
+ this.set_altUnit(Enums.parse('AltUnits', node.attributes.getNamedItem('AltUnit').nodeValue));
+ this.set_altColumn(parseInt(node.attributes.getNamedItem('AltColumn').nodeValue));
+ this.set_startDateColumn(parseInt(node.attributes.getNamedItem('StartDateColumn').nodeValue));
+ this.set_endDateColumn(parseInt(node.attributes.getNamedItem('EndDateColumn').nodeValue));
+
+ // In this layer class we implement dynamic scaling and coloring of the points
+ // based on one of the existing numerical columns. However, we need to produce
+ // XML files that are backward-compatible with older versions of WWT. Since we
+ // can deal with size/color scaling here, we ignore SizeColumn and ColorMapColumn
+ // and use NormalizeSizeColumn and DynamicColorColumn instead, if present.
+
+ if (node.attributes.getNamedItem('NormalizeSizeColumn') != null) {
+ this.set_sizeColumn(parseInt(node.attributes.getNamedItem('NormalizeSizeColumn').nodeValue));
+ } else {
+ this.set_sizeColumn(parseInt(node.attributes.getNamedItem('SizeColumn').nodeValue));
+ }
+
+ // Only recent files have normalization parameters
+
+ if (node.attributes.getNamedItem('NormalizeSize') != null) {
+ this.set_normalizeSize(ss.boolean(node.attributes.getNamedItem('NormalizeSize').nodeValue));
+ this.set_normalizeSizeClip(ss.boolean(node.attributes.getNamedItem('NormalizeSizeClip').nodeValue));
+ this.set_normalizeSizeMin(parseFloat(node.attributes.getNamedItem('NormalizeSizeMin').nodeValue));
+ this.set_normalizeSizeMax(parseFloat(node.attributes.getNamedItem('NormalizeSizeMax').nodeValue));
+ }
+ if (node.attributes.getNamedItem('DynamicColorColumn') != null) {
+ this.set_colorMapColumn(parseInt(node.attributes.getNamedItem('DynamicColorColumn').nodeValue));
+ } else {
+ this.set_colorMapColumn(parseInt(node.attributes.getNamedItem('ColorMapColumn').nodeValue));
+ }
+
+ // Only recent files have normalization parameters
+
+ if (node.attributes.getNamedItem('DynamicColor') != null) {
+ this.set_dynamicColor(ss.boolean(node.attributes.getNamedItem('DynamicColor').nodeValue));
+ this.set_colorMapperName(node.attributes.getNamedItem('ColorMapperName').nodeValue);
+ this.set_normalizeColorMap(ss.boolean(node.attributes.getNamedItem('NormalizeColorMap').nodeValue));
+ this.set_normalizeColorMapMin(parseFloat(node.attributes.getNamedItem('NormalizeColorMapMin').nodeValue));
+ this.set_normalizeColorMapMax(parseFloat(node.attributes.getNamedItem('NormalizeColorMapMax').nodeValue));
+ }
+ this.set_hyperlinkFormat(node.attributes.getNamedItem('HyperlinkFormat').nodeValue);
+ this.set_hyperlinkColumn(parseInt(node.attributes.getNamedItem('HyperlinkColumn').nodeValue));
+ this.set_scaleFactor(parseFloat(node.attributes.getNamedItem('ScaleFactor').nodeValue));
+ this.set_pointScaleType(Enums.parse('PointScaleTypes', node.attributes.getNamedItem('PointScaleType').nodeValue));
+ if (node.attributes.getNamedItem('ShowFarSide') != null) {
+ this.set_showFarSide(ss.boolean(node.attributes.getNamedItem('ShowFarSide').nodeValue));
+ }
+ if (node.attributes.getNamedItem('RaUnits') != null) {
+ this.set_raUnits(Enums.parse('RAUnits', node.attributes.getNamedItem('RaUnits').nodeValue));
+ }
+ if (node.attributes.getNamedItem('HoverTextColumn') != null) {
+ this.set_nameColumn(parseInt(node.attributes.getNamedItem('HoverTextColumn').nodeValue));
+ }
+ if (node.attributes.getNamedItem('XAxisColumn') != null) {
+ this.set_xAxisColumn(parseInt(node.attributes.getNamedItem('XAxisColumn').nodeValue));
+ this.set_xAxisReverse(ss.boolean(node.attributes.getNamedItem('XAxisReverse').nodeValue));
+ this.set_yAxisColumn(parseInt(node.attributes.getNamedItem('YAxisColumn').nodeValue));
+ this.set_yAxisReverse(ss.boolean(node.attributes.getNamedItem('YAxisReverse').nodeValue));
+ this.set_zAxisColumn(parseInt(node.attributes.getNamedItem('ZAxisColumn').nodeValue));
+ this.set_zAxisReverse(ss.boolean(node.attributes.getNamedItem('ZAxisReverse').nodeValue));
+ this.set_cartesianScale(Enums.parse('AltUnits', node.attributes.getNamedItem('CartesianScale').nodeValue));
+ this.set_cartesianCustomScale(parseFloat(node.attributes.getNamedItem('CartesianCustomScale').nodeValue));
+ }
+ if (node.attributes.getNamedItem('DynamicData') != null) {
+ this.set_dynamicData(ss.boolean(node.attributes.getNamedItem('DynamicData').nodeValue));
+ this.set_autoUpdate(ss.boolean(node.attributes.getNamedItem('AutoUpdate').nodeValue));
+ this.set_dataSourceUrl(node.attributes.getNamedItem('DataSourceUrl').nodeValue);
+ }
+ },
+
+ get_decay: function () {
+ return this.decay;
+ },
+
+ set_decay: function (value) {
+ if (this.decay !== value) {
+ this.version++;
+ this.decay = value;
+ }
+ return value;
+ },
+
+ get_coordinatesType: function () {
+ return this._coordinatesType$1;
+ },
+
+ set_coordinatesType: function (value) {
+ if (this._coordinatesType$1 !== value) {
+ this.version++;
+ this._coordinatesType$1 = value;
+ }
+ return value;
+ },
+
+ get_latColumn: function () {
+ return this.latColumn;
+ },
+
+ set_latColumn: function (value) {
+ if (this.latColumn !== value) {
+ this.version++;
+ this.latColumn = value;
+ }
+ return value;
+ },
+
+ get_lngColumn: function () {
+ return this.lngColumn;
+ },
+
+ set_lngColumn: function (value) {
+ if (this.lngColumn !== value) {
+ this.version++;
+ this.lngColumn = value;
+ }
+ return value;
+ },
+
+ get_geometryColumn: function () {
+ return this.geometryColumn;
+ },
+
+ set_geometryColumn: function (value) {
+ if (this.geometryColumn !== value) {
+ this.version++;
+ this.geometryColumn = value;
+ }
+ return value;
+ },
+
+ get_xAxisColumn: function () {
+ return this._xAxisColumn$1;
+ },
+
+ set_xAxisColumn: function (value) {
+ if (this._xAxisColumn$1 !== value) {
+ this.version++;
+ this._xAxisColumn$1 = value;
+ }
+ return value;
+ },
+
+ get_yAxisColumn: function () {
+ return this._yAxisColumn$1;
+ },
+
+ set_yAxisColumn: function (value) {
+ if (this._yAxisColumn$1 !== value) {
+ this.version++;
+ this._yAxisColumn$1 = value;
+ }
+ return value;
+ },
+
+ get_zAxisColumn: function () {
+ return this._zAxisColumn$1;
+ },
+
+ set_zAxisColumn: function (value) {
+ if (this._zAxisColumn$1 !== value) {
+ this.version++;
+ this._zAxisColumn$1 = value;
+ }
+ return value;
+ },
+
+ get_xAxisReverse: function () {
+ return this._xAxisReverse$1;
+ },
+
+ set_xAxisReverse: function (value) {
+ if (this._xAxisReverse$1 !== value) {
+ this.version++;
+ this._xAxisReverse$1 = value;
+ }
+ return value;
+ },
+
+ get_yAxisReverse: function () {
+ return this._yAxisReverse$1;
+ },
+
+ set_yAxisReverse: function (value) {
+ if (this._yAxisReverse$1 !== value) {
+ this.version++;
+ this._yAxisReverse$1 = value;
+ }
+ return value;
+ },
+
+ get_zAxisReverse: function () {
+ return this._zAxisReverse$1;
+ },
+
+ set_zAxisReverse: function (value) {
+ if (this._zAxisReverse$1 !== value) {
+ this.version++;
+ this._zAxisReverse$1 = value;
+ }
+ return value;
+ },
+
+ get_altType: function () {
+ return this._altType$1;
+ },
+
+ set_altType: function (value) {
+ if (this._altType$1 !== value) {
+ this.version++;
+ this._altType$1 = value;
+ }
+ return value;
+ },
+
+ get_markerMix: function () {
+ return this._markerMix$1;
+ },
+
+ set_markerMix: function (value) {
+ if (this._markerMix$1 !== value) {
+ this.version++;
+ this._markerMix$1 = value;
+ }
+ return value;
+ },
+
+ get_raUnits: function () {
+ return this._raUnits$1;
+ },
+
+ set_raUnits: function (value) {
+ if (this._raUnits$1 !== value) {
+ this.version++;
+ this._raUnits$1 = value;
+ }
+ return value;
+ },
+
+ get_colorMap: function () {
+ return this.colorMap;
+ },
+
+ set_colorMap: function (value) {
+ if (this.colorMap !== value) {
+ this.version++;
+ this.colorMap = value;
+ }
+ return value;
+ },
+
+ get_colorMapperName: function () {
+ return this.colorMapperName;
+ },
+
+ set_colorMapperName: function (value) {
+ if (ColorMapContainer.fromNamedColormap(value) == null) {
+ throw new Error('Invalid colormap name');
+ }
+ this.version++;
+ this.colorMapperName = value;
+ return value;
+ },
+
+ get_colorMapper: function () {
+ return ColorMapContainer.fromNamedColormap(this.colorMapperName);
+ },
+
+ get_dynamicColor: function () {
+ return this.dynamicColor;
+ },
+
+ set_dynamicColor: function (value) {
+ this.version++;
+ this.dynamicColor = value;
+ return value;
+ },
+
+ get_normalizeColorMap: function () {
+ return this.normalizeColorMap;
+ },
+
+ set_normalizeColorMap: function (value) {
+ this.version++;
+ this.normalizeColorMap = value;
+ return value;
+ },
+
+ get_normalizeColorMapMin: function () {
+ return this.normalizeColorMapMin;
+ },
+
+ set_normalizeColorMapMin: function (value) {
+ this.version++;
+ this.normalizeColorMapMin = value;
+ return value;
+ },
+
+ get_normalizeColorMapMax: function () {
+ return this.normalizeColorMapMax;
+ },
+
+ set_normalizeColorMapMax: function (value) {
+ this.version++;
+ this.normalizeColorMapMax = value;
+ return value;
+ },
+
+ normalizeColorMapValue: function (value) {
+ if (!this.get_normalizeColorMap()) {
+ return value;
+ }
+ var new_value = (value - this.get_normalizeColorMapMin()) / (this.get_normalizeColorMapMax() - this.get_normalizeColorMapMin());
+ if (new_value < 0) {
+ new_value = 0;
+ } else if (new_value > 1) {
+ new_value = 1;
+ }
+ return new_value;
+ },
+
+ get_markerColumn: function () {
+ return this._markerColumn$1;
+ },
+
+ set_markerColumn: function (value) {
+ if (this._markerColumn$1 !== value) {
+ this.version++;
+ this._markerColumn$1 = value;
+ }
+ return value;
+ },
+
+ get_colorMapColumn: function () {
+ return this.colorMapColumn;
+ },
+
+ set_colorMapColumn: function (value) {
+ if (this.colorMapColumn !== value) {
+ this.version++;
+ this.colorMapColumn = value;
+ }
+ return value;
+ },
+
+ get_plotType: function () {
+ return this._plotType$1;
+ },
+
+ set_plotType: function (value) {
+ if (this._plotType$1 !== value) {
+ this.version++;
+ this._plotType$1 = value;
+ }
+ return value;
+ },
+
+ get_markerIndex: function () {
+ return this._markerIndex$1;
+ },
+
+ set_markerIndex: function (value) {
+ if (this._markerIndex$1 !== value) {
+ this.version++;
+ this._markerIndex$1 = value;
+ }
+ return value;
+ },
+
+ get_showFarSide: function () {
+ return this._showFarSide$1;
+ },
+
+ set_showFarSide: function (value) {
+ if (this._showFarSide$1 !== value) {
+ this.version++;
+ this._showFarSide$1 = value;
+ }
+ return value;
+ },
+
+ get_markerScale: function () {
+ return this._markerScale$1;
+ },
+
+ set_markerScale: function (value) {
+ if (this._markerScale$1 !== value) {
+ this.version++;
+ this._markerScale$1 = value;
+ }
+ return value;
+ },
+
+ get_altUnit: function () {
+ return this._altUnit$1;
+ },
+
+ set_altUnit: function (value) {
+ if (this._altUnit$1 !== value) {
+ this.version++;
+ this._altUnit$1 = value;
+ }
+ return value;
+ },
+
+ get_cartesianScale: function () {
+ return this._cartesianScale$1;
+ },
+
+ set_cartesianScale: function (value) {
+ if (this._cartesianScale$1 !== value) {
+ this.version++;
+ this._cartesianScale$1 = value;
+ }
+ return value;
+ },
+
+ get_cartesianCustomScale: function () {
+ return this._cartesianCustomScale$1;
+ },
+
+ set_cartesianCustomScale: function (value) {
+ if (this._cartesianCustomScale$1 !== value) {
+ this.version++;
+ this._cartesianCustomScale$1 = value;
+ }
+ return value;
+ },
+
+ get_altColumn: function () {
+ return this.altColumn;
+ },
+
+ set_altColumn: function (value) {
+ if (this.altColumn !== value) {
+ this.version++;
+ this.altColumn = value;
+ }
+ return value;
+ },
+
+ get_startDateColumn: function () {
+ return this.startDateColumn;
+ },
+
+ set_startDateColumn: function (value) {
+ if (this.startDateColumn !== value) {
+ this.version++;
+ this.startDateColumn = value;
+ }
+ return value;
+ },
+
+ get_endDateColumn: function () {
+ return this.endDateColumn;
+ },
+
+ set_endDateColumn: function (value) {
+ if (this.endDateColumn !== value) {
+ this.version++;
+ this.endDateColumn = value;
+ }
+ return value;
+ },
+
+ get_sizeColumn: function () {
+ return this.sizeColumn;
+ },
+
+ set_sizeColumn: function (value) {
+ if (this.sizeColumn !== value) {
+ this.version++;
+ this.sizeColumn = value;
+ }
+ return value;
+ },
+
+ get_normalizeSize: function () {
+ return this.normalizeSize;
+ },
+
+ set_normalizeSize: function (value) {
+ if (this.normalizeSize !== value) {
+ this.version++;
+ this.normalizeSize = value;
+ }
+ return value;
+ },
+
+ get_normalizeSizeClip: function () {
+ return this.normalizeSizeClip;
+ },
+
+ set_normalizeSizeClip: function (value) {
+ if (this.normalizeSizeClip !== value) {
+ this.version++;
+ this.normalizeSizeClip = value;
+ }
+ return value;
+ },
+
+ get_normalizeSizeMin: function () {
+ return this.normalizeSizeMin;
+ },
+
+ set_normalizeSizeMin: function (value) {
+ if (this.normalizeSizeMin !== value) {
+ this.version++;
+ this.normalizeSizeMin = value;
+ }
+ return value;
+ },
+
+ get_normalizeSizeMax: function () {
+ return this.normalizeSizeMax;
+ },
+
+ set_normalizeSizeMax: function (value) {
+ if (this.normalizeSizeMax !== value) {
+ this.version++;
+ this.normalizeSizeMax = value;
+ }
+ return value;
+ },
+
+ normalizePointSize: function (value) {
+ if (!this.get_normalizeSize()) {
+ return value;
+ }
+ var new_value = (value - this.get_normalizeSizeMin()) / (this.get_normalizeSizeMax() - this.get_normalizeSizeMin());
+ if (this.get_normalizeSizeClip()) {
+ if (new_value < 0) {
+ new_value = 0;
+ }
+ else if (new_value > 1) {
+ new_value = 1;
+ }
+ }
+ return new_value;
+ },
+
+ get_nameColumn: function () {
+ return this.nameColumn;
+ },
+
+ set_nameColumn: function (value) {
+ if (this.nameColumn !== value) {
+ this.version++;
+ this.nameColumn = value;
+ }
+ return value;
+ },
+
+ get_hyperlinkFormat: function () {
+ return this._hyperlinkFormat$1;
+ },
+
+ set_hyperlinkFormat: function (value) {
+ if (this._hyperlinkFormat$1 !== value) {
+ this.version++;
+ this._hyperlinkFormat$1 = value;
+ }
+ return value;
+ },
+
+ get_hyperlinkColumn: function () {
+ return this._hyperlinkColumn$1;
+ },
+
+ set_hyperlinkColumn: function (value) {
+ if (this._hyperlinkColumn$1 !== value) {
+ this.version++;
+ this._hyperlinkColumn$1 = value;
+ }
+ return value;
+ },
+
+ get_scaleFactor: function () {
+ return this.scaleFactor;
+ },
+
+ set_scaleFactor: function (value) {
+ if (this.scaleFactor !== value) {
+ this.version++;
+ this.scaleFactor = value;
+ }
+ return value;
+ },
+
+ get_pointScaleType: function () {
+ return this.pointScaleType;
+ },
+
+ set_pointScaleType: function (value) {
+ if (this.pointScaleType !== value) {
+ this.version++;
+ this.pointScaleType = value;
+ }
+ return value;
+ },
+
+ draw: function (renderContext, opacity, flat) {
+ var device = renderContext;
+ if (this.version !== this.lastVersion) {
+ this.cleanUp();
+ }
+ this.lastVersion = this.version;
+ if (this.bufferIsFlat !== flat) {
+ this.cleanUp();
+ this.bufferIsFlat = flat;
+ }
+ if (this.dirty) {
+ this.prepVertexBuffer(device, opacity);
+ }
+ var jNow = SpaceTimeController.get_jNow() - SpaceTimeController.utcToJulian(this.baseDate);
+ var adjustedScale = this.scaleFactor * 3;
+ if (flat && this.astronomical && (this._markerScale$1 === 1)) {
+ adjustedScale = (this.scaleFactor / (renderContext.viewCamera.zoom / 360));
+ }
+ if (this.triangleList2d != null) {
+ this.triangleList2d.decay = this.decay;
+ this.triangleList2d.sky = this.get_astronomical();
+ this.triangleList2d.timeSeries = this.timeSeries;
+ this.triangleList2d.jNow = jNow;
+ this.triangleList2d.draw(renderContext, opacity * this.get_opacity(), 1);
+ }
+ if (this.triangleList != null) {
+ this.triangleList.decay = this.decay;
+ this.triangleList.sky = this.get_astronomical();
+ this.triangleList.timeSeries = this.timeSeries;
+ this.triangleList.jNow = jNow;
+ this.triangleList.draw(renderContext, opacity * this.get_opacity(), 1);
+ }
+ if (this.pointList != null) {
+ this.pointList.depthBuffered = false;
+ this.pointList.showFarSide = this.get_showFarSide();
+ this.pointList.decay = (this.timeSeries) ? this.decay : 0;
+ this.pointList.sky = this.get_astronomical();
+ this.pointList.timeSeries = this.timeSeries;
+ this.pointList.jNow = jNow;
+ this.pointList.scale = (this._markerScale$1 === 1) ? adjustedScale : -adjustedScale;
+ switch (this._plotType$1) {
+ case 0:
+ this.pointList.draw(renderContext, opacity * this.get_opacity(), false);
+ break;
+ case 2:
+ this.pointList.drawTextured(renderContext, SpreadSheetLayer.get__circleTexture$1().texture2d, opacity * this.get_opacity());
+ break;
+ case 1:
+ this.pointList.drawTextured(renderContext, PushPin.getPushPinTexture(19), opacity * this.get_opacity());
+ break;
+ case 3:
+ this.pointList.drawTextured(renderContext, PushPin.getPushPinTexture(35), opacity * this.get_opacity());
+ break;
+ case 5:
+ case 4:
+ this.pointList.drawTextured(renderContext, PushPin.getPushPinTexture(this._markerIndex$1), opacity * this.get_opacity());
+ break;
+ default:
+ break;
+ }
+ }
+ if (this.lineList != null) {
+ this.lineList.sky = this.get_astronomical();
+ this.lineList.decay = this.decay;
+ this.lineList.timeSeries = this.timeSeries;
+ this.lineList.jNow = jNow;
+ this.lineList.drawLines(renderContext, opacity * this.get_opacity());
+ }
+ if (this.lineList2d != null) {
+ this.lineList2d.sky = this.get_astronomical();
+ this.lineList2d.decay = this.decay;
+ this.lineList2d.timeSeries = this.timeSeries;
+ this.lineList2d.showFarSide = this.get_showFarSide();
+ this.lineList2d.jNow = jNow;
+ this.lineList2d.drawLines(renderContext, opacity * this.get_opacity());
+ }
+ return true;
+ },
+
+ cleanUpBase: function () {
+ if (this.lineList != null) {
+ this.lineList.clear();
+ }
+ if (this.lineList2d != null) {
+ this.lineList2d.clear();
+ }
+ if (this.triangleList2d != null) {
+ this.triangleList2d.clear();
+ }
+ if (this.pointList != null) {
+ this.pointList.clear();
+ }
+ if (this.triangleList != null) {
+ this.triangleList.clear();
+ }
+ }
+};
+
+registerType("SpreadSheetLayer", [SpreadSheetLayer, SpreadSheetLayer$, Layer]);
+
+
+// wwtlib.CatalogSpreadSheetLayer
+
+export function CatalogSpreadSheetLayer() {
+ this._addedTiles$2 = {};
+ SpreadSheetLayer.call(this);
+}
+
+var CatalogSpreadSheetLayer$ = {
+ addTileRows: function (tileKey, catalogRows) {
+ if (!ss.keyExists(this._addedTiles$2, tileKey)) {
+ var $enum1 = ss.enumerate(catalogRows);
+ while ($enum1.moveNext()) {
+ var row = $enum1.current;
+ this.get__table().rows.push(row);
+ }
+ this.dirty = true;
+ this._addedTiles$2[tileKey] = true;
+ }
+ },
+
+ removeTileRows: function (tileKey, catalogRows) {
+ if (ss.keyExists(this._addedTiles$2, tileKey)) {
+ var $enum1 = ss.enumerate(catalogRows);
+ while ($enum1.moveNext()) {
+ var row = $enum1.current;
+ ss.remove(this.get__table().rows, row);
+ }
+ this.dirty = true;
+ delete this._addedTiles$2[tileKey];
+ }
+ },
+
+ cleanUp: function () {
+ SpreadSheetLayer.prototype.cleanUp.call(this);
+ ss.clearKeys(this._addedTiles$2);
+ this.get__table().rows.length = 0;
+ }
+};
+
+registerType("CatalogSpreadSheetLayer", [CatalogSpreadSheetLayer, CatalogSpreadSheetLayer$, SpreadSheetLayer]);
diff --git a/engine/esm/layers/table.js b/engine/esm/layers/table.js
new file mode 100644
index 00000000..11adc2c0
--- /dev/null
+++ b/engine/esm/layers/table.js
@@ -0,0 +1,135 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Tabular data.
+
+import { ss } from "../ss.js";
+import { registerType } from "../typesystem.js";
+import { Guid } from "../util.js";
+import { UiTools } from "../ui_tools.js";
+
+
+// wwtlib.Table
+
+export function Table() {
+ this.guid = new Guid();
+ this.header = [];
+ this.rows = [];
+ this.delimiter = '\t';
+ this.locked = false;
+}
+
+var Table$ = {
+ lock: function () {
+ this.locked = true;
+ },
+
+ unlock: function () {
+ this.locked = false;
+ },
+
+ save: function () {
+ var data = '';
+ var first = true;
+ var $enum1 = ss.enumerate(this.header);
+ while ($enum1.moveNext()) {
+ var col = $enum1.current;
+ if (!first) {
+ data += '\t';
+ }
+ else {
+ first = false;
+ }
+ data += col;
+ }
+ data += '\r\n';
+ var $enum2 = ss.enumerate(this.rows);
+ while ($enum2.moveNext()) {
+ var row = $enum2.current;
+ first = true;
+ var $enum3 = ss.enumerate(row);
+ while ($enum3.moveNext()) {
+ var col = $enum3.current;
+ if (!first) {
+ data += '\t';
+ }
+ else {
+ first = false;
+ }
+ data += col;
+ }
+ data += '\r\n';
+ }
+ return data;
+ },
+
+ loadFromString: function (data, isUpdate, purge, hasHeader) {
+ var count = 0;
+ var lines = data.split('\r\n');
+ if (!isUpdate || hasHeader) {
+ if (lines.length > 0) {
+ var headerLine = lines[0];
+ count++;
+ if (headerLine.indexOf('\t') === -1 && headerLine.indexOf(',') > -1) {
+ this.delimiter = ',';
+ }
+ if (!isUpdate) {
+ this.rows.length = 0;
+ }
+ this.header = UiTools.splitString(headerLine, this.delimiter);
+ }
+ else {
+ this.header = [];
+ }
+ }
+ var temp = [];
+ if (!purge) {
+ temp = this.rows;
+ }
+ while (count < lines.length) {
+ var line = lines[count];
+ var rowData = UiTools.splitString(line, this.delimiter);
+ if (rowData.length < 1) {
+ break;
+ }
+ temp.push(rowData);
+ count++;
+ }
+ if (purge) {
+ this.rows = temp;
+ }
+ },
+
+ clone: function () {
+ var cloned_table = new Table();
+ for (var i = 0; i < this.header.length; i++) {
+ cloned_table.header.push(this.header[i]);
+ }
+ for (var j = 0; j < this.rows.length; j++) {
+ cloned_table.rows.push([]);
+ for (var i = 0; i < this.rows[j].length; i++) {
+ cloned_table.rows[j].push(this.rows[j][i]);
+ }
+ }
+ return cloned_table;
+ },
+
+ addColumn: function (name, data) {
+ this.header.push(name);
+ for (var i = 0; i < data.length; i++) {
+ this.rows[i].push(data[i]);
+ }
+ },
+
+ removeColumn: function (name) {
+ var remove_index = this.header.indexOf(name);
+ if (remove_index > -1) {
+ this.header.splice(remove_index, 1);
+ for (var i = 0; i < this.rows.length; i++) {
+ this.rows[i].splice(remove_index, 1);
+ }
+ }
+ }
+};
+
+registerType("Table", [Table, Table$, null]);
diff --git a/engine/esm/layers/time_series_layer.js b/engine/esm/layers/time_series_layer.js
new file mode 100644
index 00000000..8e413e33
--- /dev/null
+++ b/engine/esm/layers/time_series_layer.js
@@ -0,0 +1,924 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A layer for rendering time-series data.
+//
+// This layer is essentially unimplemented in the WWT WebGL engine. See
+// "spreadsheetlayer" and "votablelayer" for functionality that is actually
+// available.
+
+import { ss } from "../ss.js";
+import { registerType, registerEnum, Enums } from "../typesystem.js";
+import { SpaceTimeController } from "../space_time_controller.js";
+import { Layer } from "./layer.js";
+
+
+// wwtlib.CoordinatesTypes
+
+export var CoordinatesTypes = {
+ spherical: 0,
+ rectangular: 1,
+ orbital: 2
+};
+
+registerType("CoordinatesTypes", CoordinatesTypes);
+registerEnum("CoordinatesTypes", CoordinatesTypes);
+
+
+// wwtlib.AltTypes
+
+export var AltTypes = {
+ depth: 0,
+ altitude: 1,
+ distance: 2,
+ seaLevel: 3,
+ terrain: 4
+};
+
+registerType("AltTypes", AltTypes);
+registerEnum("AltTypes", AltTypes);
+
+
+// wwtlib.MarkerMixes
+
+export var MarkerMixes = {
+ same_For_All: 0
+};
+
+registerType("MarkerMixes", MarkerMixes);
+registerEnum("MarkerMixes", MarkerMixes);
+
+
+// wwtlib.ColorMaps
+
+export var ColorMaps = {
+ same_For_All: 0,
+ group_by_Values: 2,
+ per_Column_Literal: 3
+};
+
+registerType("ColorMaps", ColorMaps);
+registerEnum("ColorMaps", ColorMaps);
+
+
+// wwtlib.PlotTypes
+
+export var PlotTypes = {
+ gaussian: 0,
+ point: 1,
+ circle: 2,
+ square: 3,
+ pushPin: 4,
+ custom: 5
+};
+
+registerType("PlotTypes", PlotTypes);
+registerEnum("PlotTypes", PlotTypes);
+
+
+// wwtlib.MarkerScales
+
+export var MarkerScales = {
+ screen: 0,
+ world: 1
+};
+
+registerType("MarkerScales", MarkerScales);
+registerEnum("MarkerScales", MarkerScales);
+
+
+// wwtlib.RAUnits
+
+export var RAUnits = {
+ hours: 0,
+ degrees: 1
+};
+
+registerType("RAUnits", RAUnits);
+registerEnum("RAUnits", RAUnits);
+
+
+// wwtlib.TimeSeriesLayer
+
+export function TimeSeriesLayer() {
+ this.isLongIndex = false;
+ this.shapeVertexCount = 0;
+ this.lines = false;
+ this.latColumn = -1;
+ this.fixedSize = 1;
+ this.decay = 16;
+ this.timeSeries = false;
+ this._dynamicData$1 = false;
+ this._autoUpdate$1 = false;
+ this._dataSourceUrl$1 = '';
+ this._beginRange$1 = new Date('1/1/2100');
+ this._endRange$1 = new Date('01/01/1800');
+ this.markerDomainValues = {};
+ this.colorDomainValues = {};
+ this._coordinatesType$1 = 0;
+ this.lngColumn = -1;
+ this.geometryColumn = -1;
+ this._xAxisColumn$1 = -1;
+ this._yAxisColumn$1 = -1;
+ this._zAxisColumn$1 = -1;
+ this._xAxisReverse$1 = false;
+ this._yAxisReverse$1 = false;
+ this._zAxisReverse$1 = false;
+ this._altType$1 = 3;
+ this._markerMix$1 = 0;
+ this._raUnits$1 = 0;
+ this._colorMap$1 = 3;
+ this._markerColumn$1 = -1;
+ this._colorMapColumn$1 = -1;
+ this._plotType$1 = 0;
+ this._markerIndex$1 = 0;
+ this._showFarSide$1 = false;
+ this._markerScale$1 = 1;
+ this._altUnit$1 = 1;
+ this._cartesianScale$1 = 1;
+ this._cartesianCustomScale$1 = 1;
+ this.altColumn = -1;
+ this.startDateColumn = -1;
+ this.endDateColumn = -1;
+ this.sizeColumn = -1;
+ this.nameColumn = 0;
+ this._hyperlinkFormat$1 = '';
+ this._hyperlinkColumn$1 = -1;
+ this.scaleFactor = 1;
+ this.pointScaleType = 1;
+ this.positions = [];
+ this.bufferIsFlat = false;
+ this.baseDate = new Date(2010, 0, 1, 12, 0, 0);
+ this.dirty = true;
+ this.lastVersion = 0;
+ Layer.call(this);
+}
+
+TimeSeriesLayer._circleTexture$1 = null;
+
+TimeSeriesLayer.get__circleTexture$1 = function () {
+ return TimeSeriesLayer._circleTexture$1;
+};
+
+var TimeSeriesLayer$ = {
+ get_dynamicData: function () {
+ return this._dynamicData$1;
+ },
+
+ set_dynamicData: function (value) {
+ this._dynamicData$1 = value;
+ return value;
+ },
+
+ get_autoUpdate: function () {
+ return this._autoUpdate$1;
+ },
+
+ set_autoUpdate: function (value) {
+ this._autoUpdate$1 = value;
+ return value;
+ },
+
+ get_dataSourceUrl: function () {
+ return this._dataSourceUrl$1;
+ },
+
+ set_dataSourceUrl: function (value) {
+ this._dataSourceUrl$1 = value;
+ return value;
+ },
+
+ get_timeSeries: function () {
+ return this.timeSeries;
+ },
+
+ set_timeSeries: function (value) {
+ if (this.timeSeries !== value) {
+ this.version++;
+ this.timeSeries = value;
+ }
+ return value;
+ },
+
+ get_header: function () {
+ return null;
+ },
+
+ get_beginRange: function () {
+ return this._beginRange$1;
+ },
+
+ set_beginRange: function (value) {
+ if (!ss.compareDates(this._beginRange$1, value)) {
+ this.version++;
+ this._beginRange$1 = value;
+ }
+ return value;
+ },
+
+ get_endRange: function () {
+ return this._endRange$1;
+ },
+
+ set_endRange: function (value) {
+ if (!ss.compareDates(this._endRange$1, value)) {
+ this.version++;
+ this._endRange$1 = value;
+ }
+ return value;
+ },
+
+ initializeFromXml: function (node) {
+ this.set_timeSeries(ss.boolean(node.attributes.getNamedItem('TimeSeries').nodeValue));
+ this.set_beginRange(new Date(node.attributes.getNamedItem('BeginRange').nodeValue));
+ this.set_endRange(new Date(node.attributes.getNamedItem('EndRange').nodeValue));
+ this.set_decay(parseFloat(node.attributes.getNamedItem('Decay').nodeValue));
+ this.set_coordinatesType(Enums.parse('CoordinatesTypes', node.attributes.getNamedItem('CoordinatesType').nodeValue));
+ if (this.get_coordinatesType() < 0) {
+ this.set_coordinatesType(0);
+ }
+ this.set_latColumn(parseInt(node.attributes.getNamedItem('LatColumn').nodeValue));
+ this.set_lngColumn(parseInt(node.attributes.getNamedItem('LngColumn').nodeValue));
+ if (node.attributes.getNamedItem('GeometryColumn') != null) {
+ this.set_geometryColumn(parseInt(node.attributes.getNamedItem('GeometryColumn').nodeValue));
+ }
+ switch (node.attributes.getNamedItem('AltType').nodeValue) {
+ case 'Depth':
+ this.set_altType(0);
+ break;
+ case 'Altitude':
+ this.set_altType(1);
+ break;
+ case 'Distance':
+ this.set_altType(2);
+ break;
+ case 'SeaLevel':
+ this.set_altType(3);
+ break;
+ case 'Terrain':
+ this.set_altType(4);
+ break;
+ default:
+ break;
+ }
+ this.set_markerMix(0);
+ switch (node.attributes.getNamedItem('ColorMap').nodeValue) {
+ case 'Same_For_All':
+ this.set__colorMap(0);
+ break;
+ case 'Group_by_Values':
+ this.set__colorMap(2);
+ break;
+ case 'Per_Column_Literal':
+ this.set__colorMap(3);
+ break;
+ default:
+ break;
+ }
+ this.set_markerColumn(parseInt(node.attributes.getNamedItem('MarkerColumn').nodeValue));
+ this.set_colorMapColumn(parseInt(node.attributes.getNamedItem('ColorMapColumn').nodeValue));
+ switch (node.attributes.getNamedItem('PlotType').nodeValue) {
+ case 'Gaussian':
+ this.set_plotType(0);
+ break;
+ case 'Point':
+ this.set_plotType(1);
+ break;
+ case 'Circle':
+ this.set_plotType(2);
+ break;
+ case 'PushPin':
+ this.set_plotType(4);
+ break;
+ default:
+ break;
+ }
+ this.set_markerIndex(parseInt(node.attributes.getNamedItem('MarkerIndex').nodeValue));
+ switch (node.attributes.getNamedItem('MarkerScale').nodeValue) {
+ case 'Screen':
+ this.set_markerScale(0);
+ break;
+ case 'World':
+ this.set_markerScale(1);
+ break;
+ default:
+ break;
+ }
+ switch (node.attributes.getNamedItem('AltUnit').nodeValue) {
+ case 'Meters':
+ this.set_altUnit(1);
+ break;
+ case 'Feet':
+ this.set_altUnit(2);
+ break;
+ case 'Inches':
+ this.set_altUnit(3);
+ break;
+ case 'Miles':
+ this.set_altUnit(4);
+ break;
+ case 'Kilometers':
+ this.set_altUnit(5);
+ break;
+ case 'AstronomicalUnits':
+ this.set_altUnit(6);
+ break;
+ case 'LightYears':
+ this.set_altUnit(7);
+ break;
+ case 'Parsecs':
+ this.set_altUnit(8);
+ break;
+ case 'MegaParsecs':
+ this.set_altUnit(9);
+ break;
+ case 'Custom':
+ this.set_altUnit(10);
+ break;
+ default:
+ break;
+ }
+ this.set_altColumn(parseInt(node.attributes.getNamedItem('AltColumn').nodeValue));
+ this.set_startDateColumn(parseInt(node.attributes.getNamedItem('StartDateColumn').nodeValue));
+ this.set_endDateColumn(parseInt(node.attributes.getNamedItem('EndDateColumn').nodeValue));
+ this.set_sizeColumn(parseInt(node.attributes.getNamedItem('SizeColumn').nodeValue));
+ this.set_hyperlinkFormat(node.attributes.getNamedItem('HyperlinkFormat').nodeValue);
+ this.set_hyperlinkColumn(parseInt(node.attributes.getNamedItem('HyperlinkColumn').nodeValue));
+ this.set_scaleFactor(parseFloat(node.attributes.getNamedItem('ScaleFactor').nodeValue));
+ switch (node.attributes.getNamedItem('PointScaleType').nodeValue) {
+ case 'Linear':
+ this.set_pointScaleType(0);
+ break;
+ case 'Power':
+ this.set_pointScaleType(1);
+ break;
+ case 'Log':
+ this.set_pointScaleType(2);
+ break;
+ case 'Constant':
+ this.set_pointScaleType(3);
+ break;
+ case 'StellarMagnitude':
+ this.set_pointScaleType(4);
+ break;
+ default:
+ break;
+ }
+ if (node.attributes.getNamedItem('ShowFarSide') != null) {
+ this.set_showFarSide(ss.boolean(node.attributes.getNamedItem('ShowFarSide').nodeValue));
+ }
+ if (node.attributes.getNamedItem('RaUnits') != null) {
+ switch (node.attributes.getNamedItem('RaUnits').nodeValue) {
+ case 'Hours':
+ this.set_raUnits(0);
+ break;
+ case 'Degrees':
+ this.set_raUnits(1);
+ break;
+ }
+ }
+ if (node.attributes.getNamedItem('HoverTextColumn') != null) {
+ this.set_nameColumn(parseInt(node.attributes.getNamedItem('HoverTextColumn').nodeValue));
+ }
+ if (node.attributes.getNamedItem('XAxisColumn') != null) {
+ this.set_xAxisColumn(parseInt(node.attributes.getNamedItem('XAxisColumn').nodeValue));
+ this.set_xAxisReverse(ss.boolean(node.attributes.getNamedItem('XAxisReverse').nodeValue));
+ this.set_yAxisColumn(parseInt(node.attributes.getNamedItem('YAxisColumn').nodeValue));
+ this.set_yAxisReverse(ss.boolean(node.attributes.getNamedItem('YAxisReverse').nodeValue));
+ this.set_zAxisColumn(parseInt(node.attributes.getNamedItem('ZAxisColumn').nodeValue));
+ this.set_zAxisReverse(ss.boolean(node.attributes.getNamedItem('ZAxisReverse').nodeValue));
+ switch (node.attributes.getNamedItem('CartesianScale').nodeValue) {
+ case 'Meters':
+ this.set_cartesianScale(1);
+ break;
+ case 'Feet':
+ this.set_cartesianScale(2);
+ break;
+ case 'Inches':
+ this.set_cartesianScale(3);
+ break;
+ case 'Miles':
+ this.set_cartesianScale(4);
+ break;
+ case 'Kilometers':
+ this.set_cartesianScale(5);
+ break;
+ case 'AstronomicalUnits':
+ this.set_cartesianScale(6);
+ break;
+ case 'LightYears':
+ this.set_cartesianScale(7);
+ break;
+ case 'Parsecs':
+ this.set_cartesianScale(8);
+ break;
+ case 'MegaParsecs':
+ this.set_cartesianScale(9);
+ break;
+ case 'Custom':
+ this.set_cartesianScale(10);
+ break;
+ default:
+ break;
+ }
+ this.set_cartesianCustomScale(parseFloat(node.attributes.getNamedItem('CartesianCustomScale').nodeValue));
+ }
+ if (node.attributes.getNamedItem('DynamicData') != null) {
+ this.set_dynamicData(ss.boolean(node.attributes.getNamedItem('DynamicData').nodeValue));
+ this.set_autoUpdate(ss.boolean(node.attributes.getNamedItem('AutoUpdate').nodeValue));
+ this.set_dataSourceUrl(node.attributes.getNamedItem('DataSourceUrl').nodeValue);
+ }
+ },
+
+ computeDateDomainRange: function (columnStart, columnEnd) { },
+
+ getDomainValues: function (column) {
+ return [];
+ },
+
+ get_decay: function () {
+ return this.decay;
+ },
+
+ set_decay: function (value) {
+ if (this.decay !== value) {
+ this.version++;
+ this.decay = value;
+ }
+ return value;
+ },
+
+ get_coordinatesType: function () {
+ return this._coordinatesType$1;
+ },
+
+ set_coordinatesType: function (value) {
+ if (this._coordinatesType$1 !== value) {
+ this.version++;
+ this._coordinatesType$1 = value;
+ }
+ return value;
+ },
+
+ get_latColumn: function () {
+ return this.latColumn;
+ },
+
+ set_latColumn: function (value) {
+ if (this.latColumn !== value) {
+ this.version++;
+ this.latColumn = value;
+ }
+ return value;
+ },
+
+ get_lngColumn: function () {
+ return this.lngColumn;
+ },
+
+ set_lngColumn: function (value) {
+ if (this.lngColumn !== value) {
+ this.version++;
+ this.lngColumn = value;
+ }
+ return value;
+ },
+
+ get_geometryColumn: function () {
+ return this.geometryColumn;
+ },
+
+ set_geometryColumn: function (value) {
+ if (this.geometryColumn !== value) {
+ this.version++;
+ this.geometryColumn = value;
+ }
+ return value;
+ },
+
+ get_xAxisColumn: function () {
+ return this._xAxisColumn$1;
+ },
+
+ set_xAxisColumn: function (value) {
+ if (this._xAxisColumn$1 !== value) {
+ this.version++;
+ this._xAxisColumn$1 = value;
+ }
+ return value;
+ },
+
+ get_yAxisColumn: function () {
+ return this._yAxisColumn$1;
+ },
+
+ set_yAxisColumn: function (value) {
+ if (this._yAxisColumn$1 !== value) {
+ this.version++;
+ this._yAxisColumn$1 = value;
+ }
+ return value;
+ },
+
+ get_zAxisColumn: function () {
+ return this._zAxisColumn$1;
+ },
+
+ set_zAxisColumn: function (value) {
+ if (this._zAxisColumn$1 !== value) {
+ this.version++;
+ this._zAxisColumn$1 = value;
+ }
+ return value;
+ },
+
+ get_xAxisReverse: function () {
+ return this._xAxisReverse$1;
+ },
+
+ set_xAxisReverse: function (value) {
+ if (this._xAxisReverse$1 !== value) {
+ this.version++;
+ this._xAxisReverse$1 = value;
+ }
+ return value;
+ },
+
+ get_yAxisReverse: function () {
+ return this._yAxisReverse$1;
+ },
+
+ set_yAxisReverse: function (value) {
+ if (this._yAxisReverse$1 !== value) {
+ this.version++;
+ this._yAxisReverse$1 = value;
+ }
+ return value;
+ },
+
+ get_zAxisReverse: function () {
+ return this._zAxisReverse$1;
+ },
+
+ set_zAxisReverse: function (value) {
+ if (this._zAxisReverse$1 !== value) {
+ this.version++;
+ this._zAxisReverse$1 = value;
+ }
+ return value;
+ },
+
+ get_altType: function () {
+ return this._altType$1;
+ },
+
+ set_altType: function (value) {
+ if (this._altType$1 !== value) {
+ this.version++;
+ this._altType$1 = value;
+ }
+ return value;
+ },
+
+ get_markerMix: function () {
+ return this._markerMix$1;
+ },
+
+ set_markerMix: function (value) {
+ if (this._markerMix$1 !== value) {
+ this.version++;
+ this._markerMix$1 = value;
+ }
+ return value;
+ },
+
+ get_raUnits: function () {
+ return this._raUnits$1;
+ },
+
+ set_raUnits: function (value) {
+ if (this._raUnits$1 !== value) {
+ this.version++;
+ this._raUnits$1 = value;
+ }
+ return value;
+ },
+
+ get__colorMap: function () {
+ return this._colorMap$1;
+ },
+
+ set__colorMap: function (value) {
+ if (this._colorMap$1 !== value) {
+ this.version++;
+ this._colorMap$1 = value;
+ }
+ return value;
+ },
+
+ get_markerColumn: function () {
+ return this._markerColumn$1;
+ },
+
+ set_markerColumn: function (value) {
+ if (this._markerColumn$1 !== value) {
+ this.version++;
+ this._markerColumn$1 = value;
+ }
+ return value;
+ },
+
+ get_colorMapColumn: function () {
+ return this._colorMapColumn$1;
+ },
+
+ set_colorMapColumn: function (value) {
+ if (this._colorMapColumn$1 !== value) {
+ this.version++;
+ this._colorMapColumn$1 = value;
+ }
+ return value;
+ },
+
+ get_plotType: function () {
+ return this._plotType$1;
+ },
+
+ set_plotType: function (value) {
+ if (this._plotType$1 !== value) {
+ this.version++;
+ this._plotType$1 = value;
+ }
+ return value;
+ },
+
+ get_markerIndex: function () {
+ return this._markerIndex$1;
+ },
+
+ set_markerIndex: function (value) {
+ if (this._markerIndex$1 !== value) {
+ this.version++;
+ this._markerIndex$1 = value;
+ }
+ return value;
+ },
+
+ get_showFarSide: function () {
+ return this._showFarSide$1;
+ },
+
+ set_showFarSide: function (value) {
+ if (this._showFarSide$1 !== value) {
+ this.version++;
+ this._showFarSide$1 = value;
+ }
+ return value;
+ },
+
+ get_markerScale: function () {
+ return this._markerScale$1;
+ },
+
+ set_markerScale: function (value) {
+ if (this._markerScale$1 !== value) {
+ this.version++;
+ this._markerScale$1 = value;
+ }
+ return value;
+ },
+
+ get_altUnit: function () {
+ return this._altUnit$1;
+ },
+
+ set_altUnit: function (value) {
+ if (this._altUnit$1 !== value) {
+ this.version++;
+ this._altUnit$1 = value;
+ }
+ return value;
+ },
+
+ get_cartesianScale: function () {
+ return this._cartesianScale$1;
+ },
+
+ set_cartesianScale: function (value) {
+ if (this._cartesianScale$1 !== value) {
+ this.version++;
+ this._cartesianScale$1 = value;
+ }
+ return value;
+ },
+
+ get_cartesianCustomScale: function () {
+ return this._cartesianCustomScale$1;
+ },
+
+ set_cartesianCustomScale: function (value) {
+ if (this._cartesianCustomScale$1 !== value) {
+ this.version++;
+ this._cartesianCustomScale$1 = value;
+ }
+ return value;
+ },
+
+ get_altColumn: function () {
+ return this.altColumn;
+ },
+
+ set_altColumn: function (value) {
+ if (this.altColumn !== value) {
+ this.version++;
+ this.altColumn = value;
+ }
+ return value;
+ },
+
+ get_startDateColumn: function () {
+ return this.startDateColumn;
+ },
+
+ set_startDateColumn: function (value) {
+ if (this.startDateColumn !== value) {
+ this.version++;
+ this.startDateColumn = value;
+ }
+ return value;
+ },
+
+ get_endDateColumn: function () {
+ return this.endDateColumn;
+ },
+
+ set_endDateColumn: function (value) {
+ if (this.endDateColumn !== value) {
+ this.version++;
+ this.endDateColumn = value;
+ }
+ return value;
+ },
+
+ get_sizeColumn: function () {
+ return this.sizeColumn;
+ },
+
+ set_sizeColumn: function (value) {
+ if (this.sizeColumn !== value) {
+ this.version++;
+ this.sizeColumn = value;
+ }
+ return value;
+ },
+
+ get_nameColumn: function () {
+ return this.nameColumn;
+ },
+
+ set_nameColumn: function (value) {
+ if (this.nameColumn !== value) {
+ this.version++;
+ this.nameColumn = value;
+ }
+ return value;
+ },
+
+ get_hyperlinkFormat: function () {
+ return this._hyperlinkFormat$1;
+ },
+
+ set_hyperlinkFormat: function (value) {
+ if (this._hyperlinkFormat$1 !== value) {
+ this.version++;
+ this._hyperlinkFormat$1 = value;
+ }
+ return value;
+ },
+
+ get_hyperlinkColumn: function () {
+ return this._hyperlinkColumn$1;
+ },
+
+ set_hyperlinkColumn: function (value) {
+ if (this._hyperlinkColumn$1 !== value) {
+ this.version++;
+ this._hyperlinkColumn$1 = value;
+ }
+ return value;
+ },
+
+ get_scaleFactor: function () {
+ return this.scaleFactor;
+ },
+
+ set_scaleFactor: function (value) {
+ if (this.scaleFactor !== value) {
+ this.version++;
+ this.scaleFactor = value;
+ }
+ return value;
+ },
+
+ get_pointScaleType: function () {
+ return this.pointScaleType;
+ },
+
+ set_pointScaleType: function (value) {
+ if (this.pointScaleType !== value) {
+ this.version++;
+ this.pointScaleType = value;
+ }
+ return value;
+ },
+
+ prepVertexBuffer: function (renderContext, opacity) {
+ return true;
+ },
+
+ draw: function (renderContext, opacity, flat) {
+ var device = renderContext;
+ if (this.version !== this.lastVersion) {
+ this.cleanUp();
+ }
+ if (this.bufferIsFlat !== flat) {
+ this.cleanUp();
+ this.bufferIsFlat = flat;
+ }
+ if (this.dirty) {
+ this.prepVertexBuffer(device, opacity);
+ }
+ var jNow = SpaceTimeController.get_jNow() - SpaceTimeController.utcToJulian(this.baseDate);
+ var adjustedScale = this.scaleFactor;
+ if (flat && this.astronomical && (this._markerScale$1 === 1)) {
+ adjustedScale = (this.scaleFactor / (renderContext.viewCamera.zoom / 360));
+ }
+ if (this.triangleList2d != null) {
+ this.triangleList2d.decay = this.decay;
+ this.triangleList2d.sky = this.get_astronomical();
+ this.triangleList2d.timeSeries = this.timeSeries;
+ this.triangleList2d.jNow = jNow;
+ this.triangleList2d.draw(renderContext, opacity * this.get_opacity(), 1);
+ }
+ if (this.triangleList != null) {
+ this.triangleList.decay = this.decay;
+ this.triangleList.sky = this.get_astronomical();
+ this.triangleList.timeSeries = this.timeSeries;
+ this.triangleList.jNow = jNow;
+ this.triangleList.draw(renderContext, opacity * this.get_opacity(), 1);
+ }
+ if (this.pointList != null) {
+ this.pointList.depthBuffered = false;
+ this.pointList.decay = this.decay;
+ this.pointList.sky = this.get_astronomical();
+ this.pointList.timeSeries = this.timeSeries;
+ this.pointList.jNow = jNow;
+ this.pointList.scale = (this._markerScale$1 === 1) ? adjustedScale : -adjustedScale;
+ this.pointList.draw(renderContext, opacity * this.get_opacity(), false);
+ }
+ if (this.lineList != null) {
+ this.lineList.sky = this.get_astronomical();
+ this.lineList.decay = this.decay;
+ this.lineList.timeSeries = this.timeSeries;
+ this.lineList.jNow = jNow;
+ this.lineList.drawLines(renderContext, opacity * this.get_opacity());
+ }
+ if (this.lineList2d != null) {
+ this.lineList2d.sky = this.get_astronomical();
+ this.lineList2d.decay = this.decay;
+ this.lineList2d.timeSeries = this.timeSeries;
+ this.lineList2d.showFarSide = this.get_showFarSide();
+ this.lineList2d.jNow = jNow;
+ this.lineList2d.drawLines(renderContext, opacity * this.get_opacity());
+ }
+ return true;
+ },
+
+ initFromXml: function (node) {
+ Layer.prototype.initFromXml.call(this, node);
+ },
+
+ cleanUp: function () {
+ if (this.lineList != null) {
+ this.lineList.clear();
+ }
+ if (this.lineList2d != null) {
+ this.lineList2d.clear();
+ }
+ if (this.triangleList2d != null) {
+ this.triangleList2d.clear();
+ }
+ if (this.pointList != null) {
+ this.pointList.clear();
+ }
+ if (this.triangleList != null) {
+ this.triangleList.clear();
+ }
+ },
+
+ dynamicUpdate: function () {
+ return false;
+ }
+};
+
+registerType("TimeSeriesLayer", [TimeSeriesLayer, TimeSeriesLayer$, Layer]);
diff --git a/engine/esm/layers/vo_table.js b/engine/esm/layers/vo_table.js
new file mode 100644
index 00000000..c1fd0448
--- /dev/null
+++ b/engine/esm/layers/vo_table.js
@@ -0,0 +1,393 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// The Virtual Observatory table (VOTable) format.
+
+import { ss } from "../ss.js";
+import { registerType, registerEnum } from "../typesystem.js";
+import { Util } from "../baseutil.js";
+import { URLHelpers } from "../url_helpers.js";
+import { WebFile } from "../web_file.js";
+
+
+// wwtlib.Primitives
+
+export var Primitives = {
+ voBoolean: 1,
+ voBit: 2,
+ voUnsignedByte: 3,
+ voShort: 4,
+ voInt: 5,
+ voLong: 6,
+ voChar: 7,
+ voUnicodeChar: 8,
+ voFloat: 9,
+ voDouble: 10,
+ voFloatComplex: 11,
+ voDoubleComplex: 12,
+ voUndefined: 13
+};
+
+registerType("Primitives", Primitives);
+registerEnum("Primitives", Primitives);
+
+
+// wwtlib.VoTable
+
+export function VoTable() {
+ this.columns = {};
+ this.column = [];
+ this.rows = [];
+ this.loadFilename = '';
+ this.sampId = '';
+ this.selectedRow = null;
+ this.error = false;
+ this.errorText = '';
+}
+
+VoTable.loadFromUrl = function (url, complete) {
+ var temp = new VoTable();
+ temp._onComplete = complete;
+ temp._webFile = new WebFile(URLHelpers.singleton.rewrite(url, 1));
+ temp._webFile.onStateChange = ss.bind('_loadData', temp);
+ temp._webFile.send();
+ return temp;
+};
+
+VoTable.loadFromString = function (data) {
+ var xParser = new DOMParser();
+ var doc = xParser.parseFromString(data, 'text/xml');
+ var table = new VoTable();
+ table.loadFromXML(doc);
+ return table;
+};
+
+var VoTable$ = {
+ _loadData: function () {
+ if (this._webFile.get_state() === 2) {
+ alert(this._webFile.get_message());
+ } else if (this._webFile.get_state() === 1) {
+ this.loadFromXML(this._webFile.getXml());
+ if (this._onComplete != null) {
+ this._onComplete();
+ }
+ }
+ },
+
+ loadFromXML: function (xml) {
+ var voTable = Util.selectSingleNode(xml, 'VOTABLE');
+ if (voTable == null) {
+ return;
+ }
+ var index = 0;
+ try {
+ var table = Util.selectSingleNode(Util.selectSingleNode(voTable, 'RESOURCE'), 'TABLE');
+ if (table != null) {
+ var $enum1 = ss.enumerate(table.childNodes);
+ while ($enum1.moveNext()) {
+ var node = $enum1.current;
+ if (node.nodeName === 'FIELD') {
+ var col = new VoColumn(node, index++);
+ this.columns[col.name] = col;
+ this.column.push(col);
+ }
+ }
+ }
+ }
+ catch ($e2) {
+ this.error = true;
+ this.errorText = Util.selectSingleNode(voTable, 'DESCRIPTION').text;
+ }
+ try {
+ var tableData = Util.selectSingleNode(Util.selectSingleNode(Util.selectSingleNode(Util.selectSingleNode(voTable, 'RESOURCE'), 'TABLE'), 'DATA'), 'TABLEDATA');
+ if (tableData != null) {
+ var $enum3 = ss.enumerate(tableData.childNodes);
+ while ($enum3.moveNext()) {
+ var node = $enum3.current;
+ if (node.nodeName === 'TR') {
+ var row = new VoRow(this);
+ row.columnData = new Array(ss.keyCount(this.columns));
+ index = 0;
+ var $enum4 = ss.enumerate(node.childNodes);
+ while ($enum4.moveNext()) {
+ var child = $enum4.current;
+ if (child.nodeName === 'TD') {
+ row.columnData[index++] = ss.trim(Util.getInnerText(child));
+ }
+ }
+ this.rows.push(row);
+ }
+ }
+ }
+ }
+ catch ($e5) {
+ }
+ },
+
+ save: function (filename) {
+ return true;
+ },
+
+ getColumnByUcd: function (ucd) {
+ var $enum1 = ss.enumerate(ss.keys(this.columns));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var col = this.columns[key];
+ if (ss.replaceString(col.ucd, '_', '.').toLocaleLowerCase().indexOf(ucd.toLocaleLowerCase()) > -1) {
+ return col;
+ }
+ }
+ return null;
+ },
+
+ getRAColumn: function () {
+ var $enum1 = ss.enumerate(ss.keys(this.columns));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var col = this.columns[key];
+ if (col.ucd.toLocaleLowerCase().indexOf('pos.eq.ra') > -1 || col.ucd.toLocaleLowerCase().indexOf('pos_eq_ra') > -1) {
+ return col;
+ }
+ }
+ var $enum2 = ss.enumerate(ss.keys(this.columns));
+ while ($enum2.moveNext()) {
+ var key = $enum2.current;
+ var col = this.columns[key];
+ if (col.name.toLocaleLowerCase().indexOf('ra') > -1) {
+ return col;
+ }
+ }
+ return null;
+ },
+
+ getDecColumn: function () {
+ var $enum1 = ss.enumerate(ss.keys(this.columns));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var col = this.columns[key];
+ if (col.ucd.toLowerCase().indexOf('pos.eq.dec') > -1 || col.ucd.toLowerCase().indexOf('pos_eq_dec') > -1) {
+ return col;
+ }
+ }
+ var $enum2 = ss.enumerate(ss.keys(this.columns));
+ while ($enum2.moveNext()) {
+ var key = $enum2.current;
+ var col = this.columns[key];
+ if (col.name.toLowerCase().indexOf('dec') > -1) {
+ return col;
+ }
+ }
+ return null;
+ },
+
+ getMagColumn: function () {
+ var $enum1 = ss.enumerate(ss.keys(this.columns));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var col = this.columns[key];
+ if (col.ucd.toLowerCase().indexOf('phot.mag') > -1 || col.ucd.toLowerCase().indexOf('phot_mag') > -1) {
+ return col;
+ }
+ }
+ return null;
+ },
+
+ getDistanceColumn: function () {
+ var $enum1 = ss.enumerate(ss.keys(this.columns));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var col = this.columns[key];
+ if (col.ucd.toLowerCase().indexOf('pos.distance') > -1 || col.ucd.toLowerCase().indexOf('pos_distance') > -1) {
+ return col;
+ }
+ }
+ return null;
+ },
+
+ toString: function () {
+ var sb = new ss.StringBuilder();
+ var first = true;
+
+ // Copy header
+
+ var $enum1 = ss.enumerate(ss.keys(this.columns));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var col = this.columns[key];
+ if (first) {
+ first = false;
+ }
+ else {
+ sb.append('\t');
+ }
+ sb.append(col.name);
+ }
+ sb.appendLine('');
+
+ // copy rows
+
+ var $enum2 = ss.enumerate(this.rows);
+ while ($enum2.moveNext()) {
+ var row = $enum2.current;
+ first = true;
+ var $enum3 = ss.enumerate(row.columnData);
+ while ($enum3.moveNext()) {
+ var col = $enum3.current;
+ if (first) {
+ first = false;
+ }
+ else {
+ sb.append('\t');
+ }
+ sb.append(col.toString());
+ }
+ sb.appendLine('');
+ }
+ return sb.toString();
+ }
+};
+
+registerType("VoTable", [VoTable, VoTable$, null]);
+
+
+// wwtlib.VoRow
+
+export function VoRow(owner) {
+ this.selected = false;
+ this.owner = owner;
+}
+
+var VoRow$ = {
+ getColumnData: function (key) {
+ if (this.owner.columns[key] != null) {
+ return this.columnData[this.owner.columns[key].index];
+ }
+ return null;
+ },
+
+ get_item: function (index) {
+ if (index < 0 || index >= this.columnData.length) {
+ return null;
+ }
+ return this.columnData[index];
+ }
+};
+
+registerType("VoRow", [VoRow, VoRow$, null]);
+
+
+// wwtlib.VoColumn
+
+export function VoColumn(node, index) {
+ this.id = '';
+ this.type = 0;
+ this.precision = 0;
+ this.dimentions = 0;
+ this.sizes = null;
+ this.ucd = '';
+ this.unit = '';
+ this.name = '';
+ this.index = 0;
+ this.index = index;
+ if (node.attributes.getNamedItem('datatype') != null) {
+ this.type = VoColumn.getType(node.attributes.getNamedItem('datatype').nodeValue);
+ }
+ if (node.attributes.getNamedItem('ucd') != null) {
+ this.ucd = node.attributes.getNamedItem('ucd').nodeValue;
+ }
+ if (node.attributes.getNamedItem('precision') != null) {
+ try {
+ this.precision = parseInt(node.attributes.getNamedItem('precision').nodeValue);
+ }
+ catch ($e1) {
+ }
+ }
+ if (node.attributes.getNamedItem('ID') != null) {
+ this.id = node.attributes.getNamedItem('ID').nodeValue;
+ }
+ if (node.attributes.getNamedItem('name') != null) {
+ this.name = node.attributes.getNamedItem('name').nodeValue;
+ }
+ else {
+ this.name = this.id;
+ }
+ if (node.attributes.getNamedItem('unit') != null) {
+ this.unit = node.attributes.getNamedItem('unit').nodeValue;
+ }
+ if (node.attributes.getNamedItem('arraysize') != null) {
+ var split = node.attributes.getNamedItem('arraysize').nodeValue.split('x');
+ this.dimentions = split.length;
+ this.sizes = new Array(split.length);
+ var indexer = 0;
+ var $enum2 = ss.enumerate(split);
+ while ($enum2.moveNext()) {
+ var dim = $enum2.current;
+ if (!(dim.indexOf('*') > -1)) {
+ this.sizes[indexer++] = parseInt(dim);
+ }
+ else {
+ var len = 9999;
+ var lenString = ss.replaceString(dim, '*', '');
+ if (lenString.length > 0) {
+ len = parseInt(lenString);
+ }
+ this.sizes[indexer++] = len;
+ }
+ }
+ }
+}
+
+VoColumn.getType = function (type) {
+ var Type = 13;
+ switch (type) {
+ case 'boolean':
+ Type = 1;
+ break;
+ case 'bit':
+ Type = 2;
+ break;
+ case 'unsignedByte':
+ Type = 3;
+ break;
+ case 'short':
+ Type = 4;
+ break;
+ case 'int':
+ Type = 5;
+ break;
+ case 'long':
+ Type = 6;
+ break;
+ case 'char':
+ Type = 7;
+ break;
+ case 'unicodeChar':
+ Type = 8;
+ break;
+ case 'float':
+ Type = 9;
+ break;
+ case 'double':
+ Type = 10;
+ break;
+ case 'floatComplex':
+ Type = 11;
+ break;
+ case 'doubleComplex':
+ Type = 12;
+ break;
+ default:
+ Type = 13;
+ break;
+ }
+ return Type;
+};
+
+var VoColumn$ = {
+ toString: function () {
+ return this.name;
+ }
+};
+
+registerType("VoColumn", [VoColumn, VoColumn$, null]);
+
diff --git a/engine/esm/layers/vo_table_layer.js b/engine/esm/layers/vo_table_layer.js
new file mode 100644
index 00000000..bdcfce45
--- /dev/null
+++ b/engine/esm/layers/vo_table_layer.js
@@ -0,0 +1,1117 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A layer that renders a VO data table.
+//
+// This has massive redundancy with SpreadSheetLayer, which I think was
+// necessitated by limitations in ScriptSharp. It would be nice to streamline
+// things.
+
+import { ss } from "../ss.js";
+import { registerType, Enums } from "../typesystem.js";
+import { Vector3d } from "../double3d.js";
+import { Dates, LineList, PointList, TimeSeriesPointVertex } from "../graphics/primitives3d.js";
+import { Texture } from "../graphics/texture.js";
+import { Color, Colors } from "../color.js";
+import { Coordinates } from "../coordinates.js";
+import { Place } from "../place.js";
+import { SpaceTimeController } from "../space_time_controller.js";
+import { URLHelpers } from "../url_helpers.js";
+import { Layer } from "./layer.js";
+import { VoTable } from "./vo_table.js";
+import { SpreadSheetLayer, PushPin } from "./spreadsheet_layer.js";
+
+
+// wwtlib.VoTableLayer
+
+export function VoTableLayer() {
+ this.isLongIndex = false;
+ this.shapeVertexCount = 0;
+ this.lines = false;
+ this.latColumn = -1;
+ this.fixedSize = 1;
+ this.decay = 0;
+ this.timeSeries = false;
+ this._dynamicData$1 = false;
+ this._autoUpdate$1 = false;
+ this._dataSourceUrl$1 = '';
+ this._beginRange$1 = new Date('1/1/2100');
+ this._endRange$1 = new Date('01/01/1800');
+ this.markerDomainValues = {};
+ this.colorDomainValues = {};
+ this._coordinatesType$1 = 0;
+ this.lngColumn = -1;
+ this.geometryColumn = -1;
+ this._xAxisColumn$1 = -1;
+ this._yAxisColumn$1 = -1;
+ this._zAxisColumn$1 = -1;
+ this._xAxisReverse$1 = false;
+ this._yAxisReverse$1 = false;
+ this._zAxisReverse$1 = false;
+ this._altType$1 = 3;
+ this._markerMix$1 = 0;
+ this._raUnits$1 = 0;
+ this._colorMap$1 = 3;
+ this._markerColumn$1 = -1;
+ this._colorMapColumn$1 = -1;
+ this._plotType$1 = 0;
+ this._markerIndex$1 = 0;
+ this._showFarSide$1 = false;
+ this._markerScale$1 = 1;
+ this._altUnit$1 = 1;
+ this._cartesianScale$1 = 1;
+ this._cartesianCustomScale$1 = 1;
+ this.altColumn = -1;
+ this.startDateColumn = -1;
+ this.endDateColumn = -1;
+ this.sizeColumn = -1;
+ this.nameColumn = 0;
+ this._hyperlinkFormat$1 = '';
+ this._hyperlinkColumn$1 = -1;
+ this.scaleFactor = 1;
+ this.pointScaleType = 1;
+ this.positions = [];
+ this.bufferIsFlat = false;
+ this.baseDate = new Date(2010, 0, 1, 12, 0, 0);
+ this.dirty = true;
+ this._filename$1 = '';
+ Layer.call(this);
+ this._table$1 = null;
+ this._filename$1 = '';
+ this.set_plotType(2);
+}
+
+VoTableLayer._circleTexture$1 = null;
+
+VoTableLayer.get__circleTexture$1 = function () {
+ if (VoTableLayer._circleTexture$1 == null) {
+ var url = URLHelpers.singleton.engineAssetUrl('circle.png');
+ VoTableLayer._circleTexture$1 = Texture.fromUrl(url);
+ }
+ return VoTableLayer._circleTexture$1;
+};
+
+VoTableLayer.create = function (table, plotType) {
+ var layer = new VoTableLayer();
+ layer._table$1 = table;
+ layer._filename$1 = table.loadFilename;
+ layer.set_lngColumn(table.getRAColumn().index);
+ layer.set_latColumn(table.getDecColumn().index);
+ layer.sizeColumn = table.getColumnByUcd('phot.mag').index;
+ layer.set_plotType(plotType);
+ return layer;
+};
+
+var VoTableLayer$ = {
+ get_dynamicData: function () {
+ return this._dynamicData$1;
+ },
+
+ set_dynamicData: function (value) {
+ this._dynamicData$1 = value;
+ return value;
+ },
+
+ get_autoUpdate: function () {
+ return this._autoUpdate$1;
+ },
+
+ set_autoUpdate: function (value) {
+ this._autoUpdate$1 = value;
+ return value;
+ },
+
+ get_dataSourceUrl: function () {
+ return this._dataSourceUrl$1;
+ },
+
+ set_dataSourceUrl: function (value) {
+ this._dataSourceUrl$1 = value;
+ return value;
+ },
+
+ get_timeSeries: function () {
+ return this.timeSeries;
+ },
+
+ set_timeSeries: function (value) {
+ if (this.timeSeries !== value) {
+ this.version++;
+ this.timeSeries = value;
+ }
+ return value;
+ },
+
+ get_beginRange: function () {
+ return this._beginRange$1;
+ },
+
+ set_beginRange: function (value) {
+ if (!ss.compareDates(this._beginRange$1, value)) {
+ this.version++;
+ this._beginRange$1 = value;
+ }
+ return value;
+ },
+
+ get_endRange: function () {
+ return this._endRange$1;
+ },
+
+ set_endRange: function (value) {
+ if (!ss.compareDates(this._endRange$1, value)) {
+ this.version++;
+ this._endRange$1 = value;
+ }
+ return value;
+ },
+
+ initializeFromXml: function (node) {
+ this.set_timeSeries(ss.boolean(node.attributes.getNamedItem('TimeSeries').nodeValue));
+ this.set_beginRange(new Date(node.attributes.getNamedItem('BeginRange').nodeValue));
+ this.set_endRange(new Date(node.attributes.getNamedItem('EndRange').nodeValue));
+ this.set_decay(parseFloat(node.attributes.getNamedItem('Decay').nodeValue));
+ this.set_coordinatesType(Enums.parse('CoordinatesTypes', node.attributes.getNamedItem('CoordinatesType').nodeValue));
+ if (this.get_coordinatesType() < 0) {
+ this.set_coordinatesType(0);
+ }
+ this.set_latColumn(parseInt(node.attributes.getNamedItem('LatColumn').nodeValue));
+ this.set_lngColumn(parseInt(node.attributes.getNamedItem('LngColumn').nodeValue));
+ if (node.attributes.getNamedItem('GeometryColumn') != null) {
+ this.set_geometryColumn(parseInt(node.attributes.getNamedItem('GeometryColumn').nodeValue));
+ }
+ switch (node.attributes.getNamedItem('AltType').nodeValue) {
+ case 'Depth':
+ this.set_altType(0);
+ break;
+ case 'Altitude':
+ this.set_altType(1);
+ break;
+ case 'Distance':
+ this.set_altType(2);
+ break;
+ case 'SeaLevel':
+ this.set_altType(3);
+ break;
+ case 'Terrain':
+ this.set_altType(4);
+ break;
+ default:
+ break;
+ }
+ this.set_markerMix(0);
+ switch (node.attributes.getNamedItem('ColorMap').nodeValue) {
+ case 'Same_For_All':
+ this.set__colorMap(0);
+ break;
+ case 'Group_by_Values':
+ this.set__colorMap(2);
+ break;
+ case 'Per_Column_Literal':
+ this.set__colorMap(3);
+ break;
+ default:
+ break;
+ }
+ this.set_markerColumn(parseInt(node.attributes.getNamedItem('MarkerColumn').nodeValue));
+ this.set_colorMapColumn(parseInt(node.attributes.getNamedItem('ColorMapColumn').nodeValue));
+ switch (node.attributes.getNamedItem('PlotType').nodeValue) {
+ case 'Gaussian':
+ this.set_plotType(0);
+ break;
+ case 'Point':
+ this.set_plotType(1);
+ break;
+ case 'Circle':
+ this.set_plotType(2);
+ break;
+ case 'PushPin':
+ this.set_plotType(4);
+ break;
+ default:
+ break;
+ }
+ this.set_markerIndex(parseInt(node.attributes.getNamedItem('MarkerIndex').nodeValue));
+ switch (node.attributes.getNamedItem('MarkerScale').nodeValue) {
+ case 'Screen':
+ this.set_markerScale(0);
+ break;
+ case 'World':
+ this.set_markerScale(1);
+ break;
+ default:
+ break;
+ }
+ switch (node.attributes.getNamedItem('AltUnit').nodeValue) {
+ case 'Meters':
+ this.set_altUnit(1);
+ break;
+ case 'Feet':
+ this.set_altUnit(2);
+ break;
+ case 'Inches':
+ this.set_altUnit(3);
+ break;
+ case 'Miles':
+ this.set_altUnit(4);
+ break;
+ case 'Kilometers':
+ this.set_altUnit(5);
+ break;
+ case 'AstronomicalUnits':
+ this.set_altUnit(6);
+ break;
+ case 'LightYears':
+ this.set_altUnit(7);
+ break;
+ case 'Parsecs':
+ this.set_altUnit(8);
+ break;
+ case 'MegaParsecs':
+ this.set_altUnit(9);
+ break;
+ case 'Custom':
+ this.set_altUnit(10);
+ break;
+ default:
+ break;
+ }
+ this.set_altColumn(parseInt(node.attributes.getNamedItem('AltColumn').nodeValue));
+ this.set_startDateColumn(parseInt(node.attributes.getNamedItem('StartDateColumn').nodeValue));
+ this.set_endDateColumn(parseInt(node.attributes.getNamedItem('EndDateColumn').nodeValue));
+ this.set_sizeColumn(parseInt(node.attributes.getNamedItem('SizeColumn').nodeValue));
+ this.set_hyperlinkFormat(node.attributes.getNamedItem('HyperlinkFormat').nodeValue);
+ this.set_hyperlinkColumn(parseInt(node.attributes.getNamedItem('HyperlinkColumn').nodeValue));
+ this.set_scaleFactor(parseFloat(node.attributes.getNamedItem('ScaleFactor').nodeValue));
+ switch (node.attributes.getNamedItem('PointScaleType').nodeValue) {
+ case 'Linear':
+ this.set_pointScaleType(0);
+ break;
+ case 'Power':
+ this.set_pointScaleType(1);
+ break;
+ case 'Log':
+ this.set_pointScaleType(2);
+ break;
+ case 'Constant':
+ this.set_pointScaleType(3);
+ break;
+ case 'StellarMagnitude':
+ this.set_pointScaleType(4);
+ break;
+ default:
+ break;
+ }
+ if (node.attributes.getNamedItem('ShowFarSide') != null) {
+ this.set_showFarSide(ss.boolean(node.attributes.getNamedItem('ShowFarSide').nodeValue));
+ }
+ if (node.attributes.getNamedItem('RaUnits') != null) {
+ switch (node.attributes.getNamedItem('RaUnits').nodeValue) {
+ case 'Hours':
+ this.set_raUnits(0);
+ break;
+ case 'Degrees':
+ this.set_raUnits(1);
+ break;
+ }
+ }
+ if (node.attributes.getNamedItem('HoverTextColumn') != null) {
+ this.set_nameColumn(parseInt(node.attributes.getNamedItem('HoverTextColumn').nodeValue));
+ }
+ if (node.attributes.getNamedItem('XAxisColumn') != null) {
+ this.set_xAxisColumn(parseInt(node.attributes.getNamedItem('XAxisColumn').nodeValue));
+ this.set_xAxisReverse(ss.boolean(node.attributes.getNamedItem('XAxisReverse').nodeValue));
+ this.set_yAxisColumn(parseInt(node.attributes.getNamedItem('YAxisColumn').nodeValue));
+ this.set_yAxisReverse(ss.boolean(node.attributes.getNamedItem('YAxisReverse').nodeValue));
+ this.set_zAxisColumn(parseInt(node.attributes.getNamedItem('ZAxisColumn').nodeValue));
+ this.set_zAxisReverse(ss.boolean(node.attributes.getNamedItem('ZAxisReverse').nodeValue));
+ switch (node.attributes.getNamedItem('CartesianScale').nodeValue) {
+ case 'Meters':
+ this.set_cartesianScale(1);
+ break;
+ case 'Feet':
+ this.set_cartesianScale(2);
+ break;
+ case 'Inches':
+ this.set_cartesianScale(3);
+ break;
+ case 'Miles':
+ this.set_cartesianScale(4);
+ break;
+ case 'Kilometers':
+ this.set_cartesianScale(5);
+ break;
+ case 'AstronomicalUnits':
+ this.set_cartesianScale(6);
+ break;
+ case 'LightYears':
+ this.set_cartesianScale(7);
+ break;
+ case 'Parsecs':
+ this.set_cartesianScale(8);
+ break;
+ case 'MegaParsecs':
+ this.set_cartesianScale(9);
+ break;
+ case 'Custom':
+ this.set_cartesianScale(10);
+ break;
+ default:
+ break;
+ }
+ this.set_cartesianCustomScale(parseFloat(node.attributes.getNamedItem('CartesianCustomScale').nodeValue));
+ }
+ if (node.attributes.getNamedItem('DynamicData') != null) {
+ this.set_dynamicData(ss.boolean(node.attributes.getNamedItem('DynamicData').nodeValue));
+ this.set_autoUpdate(ss.boolean(node.attributes.getNamedItem('AutoUpdate').nodeValue));
+ this.set_dataSourceUrl(node.attributes.getNamedItem('DataSourceUrl').nodeValue);
+ }
+ },
+
+ get_decay: function () {
+ return this.decay;
+ },
+
+ set_decay: function (value) {
+ if (this.decay !== value) {
+ this.version++;
+ this.decay = value;
+ }
+ return value;
+ },
+
+ get_coordinatesType: function () {
+ return this._coordinatesType$1;
+ },
+
+ set_coordinatesType: function (value) {
+ if (this._coordinatesType$1 !== value) {
+ this.version++;
+ this._coordinatesType$1 = value;
+ }
+ return value;
+ },
+
+ get_latColumn: function () {
+ return this.latColumn;
+ },
+
+ set_latColumn: function (value) {
+ if (this.latColumn !== value) {
+ this.version++;
+ this.latColumn = value;
+ }
+ return value;
+ },
+
+ get_lngColumn: function () {
+ return this.lngColumn;
+ },
+
+ set_lngColumn: function (value) {
+ if (this.lngColumn !== value) {
+ this.version++;
+ this.lngColumn = value;
+ }
+ return value;
+ },
+
+ get_geometryColumn: function () {
+ return this.geometryColumn;
+ },
+
+ set_geometryColumn: function (value) {
+ if (this.geometryColumn !== value) {
+ this.version++;
+ this.geometryColumn = value;
+ }
+ return value;
+ },
+
+ get_xAxisColumn: function () {
+ return this._xAxisColumn$1;
+ },
+
+ set_xAxisColumn: function (value) {
+ if (this._xAxisColumn$1 !== value) {
+ this.version++;
+ this._xAxisColumn$1 = value;
+ }
+ return value;
+ },
+
+ get_yAxisColumn: function () {
+ return this._yAxisColumn$1;
+ },
+
+ set_yAxisColumn: function (value) {
+ if (this._yAxisColumn$1 !== value) {
+ this.version++;
+ this._yAxisColumn$1 = value;
+ }
+ return value;
+ },
+
+ get_zAxisColumn: function () {
+ return this._zAxisColumn$1;
+ },
+
+ set_zAxisColumn: function (value) {
+ if (this._zAxisColumn$1 !== value) {
+ this.version++;
+ this._zAxisColumn$1 = value;
+ }
+ return value;
+ },
+
+ get_xAxisReverse: function () {
+ return this._xAxisReverse$1;
+ },
+
+ set_xAxisReverse: function (value) {
+ if (this._xAxisReverse$1 !== value) {
+ this.version++;
+ this._xAxisReverse$1 = value;
+ }
+ return value;
+ },
+
+ get_yAxisReverse: function () {
+ return this._yAxisReverse$1;
+ },
+
+ set_yAxisReverse: function (value) {
+ if (this._yAxisReverse$1 !== value) {
+ this.version++;
+ this._yAxisReverse$1 = value;
+ }
+ return value;
+ },
+
+ get_zAxisReverse: function () {
+ return this._zAxisReverse$1;
+ },
+
+ set_zAxisReverse: function (value) {
+ if (this._zAxisReverse$1 !== value) {
+ this.version++;
+ this._zAxisReverse$1 = value;
+ }
+ return value;
+ },
+
+ get_altType: function () {
+ return this._altType$1;
+ },
+
+ set_altType: function (value) {
+ if (this._altType$1 !== value) {
+ this.version++;
+ this._altType$1 = value;
+ }
+ return value;
+ },
+
+ get_markerMix: function () {
+ return this._markerMix$1;
+ },
+
+ set_markerMix: function (value) {
+ if (this._markerMix$1 !== value) {
+ this.version++;
+ this._markerMix$1 = value;
+ }
+ return value;
+ },
+
+ get_raUnits: function () {
+ return this._raUnits$1;
+ },
+
+ set_raUnits: function (value) {
+ if (this._raUnits$1 !== value) {
+ this.version++;
+ this._raUnits$1 = value;
+ }
+ return value;
+ },
+
+ get__colorMap: function () {
+ return this._colorMap$1;
+ },
+
+ set__colorMap: function (value) {
+ if (this._colorMap$1 !== value) {
+ this.version++;
+ this._colorMap$1 = value;
+ }
+ return value;
+ },
+
+ get_markerColumn: function () {
+ return this._markerColumn$1;
+ },
+
+ set_markerColumn: function (value) {
+ if (this._markerColumn$1 !== value) {
+ this.version++;
+ this._markerColumn$1 = value;
+ }
+ return value;
+ },
+
+ get_colorMapColumn: function () {
+ return this._colorMapColumn$1;
+ },
+
+ set_colorMapColumn: function (value) {
+ if (this._colorMapColumn$1 !== value) {
+ this.version++;
+ this._colorMapColumn$1 = value;
+ }
+ return value;
+ },
+
+ get_plotType: function () {
+ return this._plotType$1;
+ },
+
+ set_plotType: function (value) {
+ if (this._plotType$1 !== value) {
+ this.version++;
+ this._plotType$1 = value;
+ }
+ return value;
+ },
+
+ get_markerIndex: function () {
+ return this._markerIndex$1;
+ },
+
+ set_markerIndex: function (value) {
+ if (this._markerIndex$1 !== value) {
+ this.version++;
+ this._markerIndex$1 = value;
+ }
+ return value;
+ },
+
+ get_showFarSide: function () {
+ return this._showFarSide$1;
+ },
+
+ set_showFarSide: function (value) {
+ if (this._showFarSide$1 !== value) {
+ this.version++;
+ this._showFarSide$1 = value;
+ }
+ return value;
+ },
+
+ get_markerScale: function () {
+ return this._markerScale$1;
+ },
+
+ set_markerScale: function (value) {
+ if (this._markerScale$1 !== value) {
+ this.version++;
+ this._markerScale$1 = value;
+ }
+ return value;
+ },
+
+ get_altUnit: function () {
+ return this._altUnit$1;
+ },
+
+ set_altUnit: function (value) {
+ if (this._altUnit$1 !== value) {
+ this.version++;
+ this._altUnit$1 = value;
+ }
+ return value;
+ },
+
+ get_cartesianScale: function () {
+ return this._cartesianScale$1;
+ },
+
+ set_cartesianScale: function (value) {
+ if (this._cartesianScale$1 !== value) {
+ this.version++;
+ this._cartesianScale$1 = value;
+ }
+ return value;
+ },
+
+ get_cartesianCustomScale: function () {
+ return this._cartesianCustomScale$1;
+ },
+
+ set_cartesianCustomScale: function (value) {
+ if (this._cartesianCustomScale$1 !== value) {
+ this.version++;
+ this._cartesianCustomScale$1 = value;
+ }
+ return value;
+ },
+
+ get_altColumn: function () {
+ return this.altColumn;
+ },
+
+ set_altColumn: function (value) {
+ if (this.altColumn !== value) {
+ this.version++;
+ this.altColumn = value;
+ }
+ return value;
+ },
+
+ get_startDateColumn: function () {
+ return this.startDateColumn;
+ },
+
+ set_startDateColumn: function (value) {
+ if (this.startDateColumn !== value) {
+ this.version++;
+ this.startDateColumn = value;
+ }
+ return value;
+ },
+
+ get_endDateColumn: function () {
+ return this.endDateColumn;
+ },
+
+ set_endDateColumn: function (value) {
+ if (this.endDateColumn !== value) {
+ this.version++;
+ this.endDateColumn = value;
+ }
+ return value;
+ },
+
+ get_sizeColumn: function () {
+ return this.sizeColumn;
+ },
+
+ set_sizeColumn: function (value) {
+ if (this.sizeColumn !== value) {
+ this.version++;
+ this.sizeColumn = value;
+ }
+ return value;
+ },
+
+ get_nameColumn: function () {
+ return this.nameColumn;
+ },
+
+ set_nameColumn: function (value) {
+ if (this.nameColumn !== value) {
+ this.version++;
+ this.nameColumn = value;
+ }
+ return value;
+ },
+
+ get_hyperlinkFormat: function () {
+ return this._hyperlinkFormat$1;
+ },
+
+ set_hyperlinkFormat: function (value) {
+ if (this._hyperlinkFormat$1 !== value) {
+ this.version++;
+ this._hyperlinkFormat$1 = value;
+ }
+ return value;
+ },
+
+ get_hyperlinkColumn: function () {
+ return this._hyperlinkColumn$1;
+ },
+
+ set_hyperlinkColumn: function (value) {
+ if (this._hyperlinkColumn$1 !== value) {
+ this.version++;
+ this._hyperlinkColumn$1 = value;
+ }
+ return value;
+ },
+
+ get_scaleFactor: function () {
+ return this.scaleFactor;
+ },
+
+ set_scaleFactor: function (value) {
+ if (this.scaleFactor !== value) {
+ this.version++;
+ this.scaleFactor = value;
+ }
+ return value;
+ },
+
+ get_pointScaleType: function () {
+ return this.pointScaleType;
+ },
+
+ set_pointScaleType: function (value) {
+ if (this.pointScaleType !== value) {
+ this.version++;
+ this.pointScaleType = value;
+ }
+ return value;
+ },
+
+ draw: function (renderContext, opacity, flat) {
+ var device = renderContext;
+ if (this.bufferIsFlat !== flat) {
+ this.cleanUp();
+ this.bufferIsFlat = flat;
+ }
+ if (this.dirty) {
+ this.prepVertexBuffer(renderContext, opacity);
+ this.dirty = false;
+ }
+ var jNow = SpaceTimeController.get_jNow() - SpaceTimeController.utcToJulian(this.baseDate);
+ var adjustedScale = this.scaleFactor;
+ if (flat && this.astronomical && (this._markerScale$1 === 1)) {
+ adjustedScale = (this.scaleFactor / (renderContext.viewCamera.zoom / 360));
+ }
+ if (this.triangleList2d != null) {
+ this.triangleList2d.decay = this.decay;
+ this.triangleList2d.sky = this.get_astronomical();
+ this.triangleList2d.timeSeries = this.timeSeries;
+ this.triangleList2d.jNow = jNow;
+ this.triangleList2d.draw(renderContext, opacity * this.get_opacity(), 1);
+ }
+ if (this.triangleList != null) {
+ this.triangleList.decay = this.decay;
+ this.triangleList.sky = this.get_astronomical();
+ this.triangleList.timeSeries = this.timeSeries;
+ this.triangleList.jNow = jNow;
+ this.triangleList.draw(renderContext, opacity * this.get_opacity(), 1);
+ }
+ if (this.pointList != null) {
+ this.pointList.depthBuffered = false;
+ this.pointList.showFarSide = this.get_showFarSide();
+ this.pointList.decay = (this.timeSeries) ? this.decay : 0;
+ this.pointList.sky = this.get_astronomical();
+ this.pointList.timeSeries = this.timeSeries;
+ this.pointList.jNow = jNow;
+ this.pointList.scale = (this._markerScale$1 === 1) ? adjustedScale : -adjustedScale;
+ switch (this._plotType$1) {
+ case 0:
+ this.pointList.draw(renderContext, opacity * this.get_opacity(), false);
+ break;
+ case 2:
+ this.pointList.drawTextured(renderContext, VoTableLayer.get__circleTexture$1().texture2d, opacity * this.get_opacity());
+ break;
+ case 1:
+ this.pointList.drawTextured(renderContext, PushPin.getPushPinTexture(19), opacity * this.get_opacity());
+ break;
+ case 3:
+ this.pointList.drawTextured(renderContext, PushPin.getPushPinTexture(35), opacity * this.get_opacity());
+ break;
+ case 5:
+ case 4:
+ this.pointList.drawTextured(renderContext, PushPin.getPushPinTexture(this._markerIndex$1), opacity * this.get_opacity());
+ break;
+ default:
+ break;
+ }
+ }
+ if (this.lineList != null) {
+ this.lineList.sky = this.get_astronomical();
+ this.lineList.decay = this.decay;
+ this.lineList.timeSeries = this.timeSeries;
+ this.lineList.jNow = jNow;
+ this.lineList.drawLines(renderContext, opacity * this.get_opacity());
+ }
+ if (this.lineList2d != null) {
+ this.lineList2d.sky = this.get_astronomical();
+ this.lineList2d.decay = this.decay;
+ this.lineList2d.timeSeries = this.timeSeries;
+ this.lineList2d.showFarSide = this.get_showFarSide();
+ this.lineList2d.jNow = jNow;
+ this.lineList2d.drawLines(renderContext, opacity * this.get_opacity());
+ }
+ return true;
+ },
+
+ initFromXml: function (node) {
+ Layer.prototype.initFromXml.call(this, node);
+ },
+
+ cleanUp: function () {
+ this.dirty = true;
+ if (this.lineList != null) {
+ this.lineList.clear();
+ }
+ if (this.lineList2d != null) {
+ this.lineList2d.clear();
+ }
+ if (this.triangleList2d != null) {
+ this.triangleList2d.clear();
+ }
+ if (this.pointList != null) {
+ this.pointList.clear();
+ }
+ if (this.triangleList != null) {
+ this.triangleList.clear();
+ }
+ },
+
+ dynamicUpdate: function () {
+ return false;
+ },
+
+ addFilesToCabinet: function (fc) {
+ var fName = this._filename$1;
+ var fileName = fc.tempDirectory + ss.format('{0}\\{1}.txt', fc.get_packageID(), this.id.toString());
+ var path = fName.substring(0, fName.lastIndexOf('\\') + 1);
+ var path2 = fileName.substring(0, fileName.lastIndexOf('\\') + 1);
+ },
+
+ loadData: function (tourDoc, filename) {
+ var $this = this;
+
+ var blob = tourDoc.getFileBlob(filename);
+ var doc = new FileReader();
+ doc.onloadend = function (ee) {
+ var data = ss.safeCast(doc.result, String);
+ $this._table$1 = VoTable.loadFromString(data);
+ $this.set_lngColumn($this._table$1.getRAColumn().index);
+ $this.set_latColumn($this._table$1.getDecColumn().index);
+ };
+ doc.readAsText(blob);
+ },
+
+ canCopyToClipboard: function () {
+ return true;
+ },
+
+ copyToClipboard: function () { },
+
+ findClosest: function (target, distance, defaultPlace, astronomical) {
+ var searchPoint = Coordinates.geoTo3dDouble(target.get_lat(), target.get_lng());
+ var dist;
+ if (defaultPlace != null) {
+ var testPoint = Coordinates.raDecTo3dAu(defaultPlace.get_RA(), -defaultPlace.get_dec(), -1);
+ dist = Vector3d.subtractVectors(searchPoint, testPoint);
+ distance = dist.length();
+ }
+ var closestItem = -1;
+ var index = 0;
+ var $enum1 = ss.enumerate(this.positions);
+ while ($enum1.moveNext()) {
+ var point = $enum1.current;
+ dist = Vector3d.subtractVectors(searchPoint, point);
+ if (dist.length() < distance) {
+ distance = dist.length();
+ closestItem = index;
+ }
+ index++;
+ }
+ if (closestItem === -1) {
+ return defaultPlace;
+ }
+ var pnt = Coordinates.cartesianToSpherical2(this.positions[closestItem]);
+ var name = this._table$1.rows[closestItem].columnData[this.nameColumn].toString();
+ if (this.nameColumn === this.startDateColumn || this.nameColumn === this.endDateColumn) {
+ name = SpreadSheetLayer.parseDate(name).toString();
+ }
+ if (ss.emptyString(name)) {
+ name = ss.format('RA={0}, Dec={1}', Coordinates.formatHMS(pnt.get_RA()), Coordinates.formatDMS(pnt.get_dec()));
+ }
+ var place = Place.create(name, pnt.get_lat(), pnt.get_RA(), 268435456, '', 2, -1);
+ var rowData = {};
+ for (var i = 0; i < ss.keyCount(this._table$1.columns); i++) {
+ var colValue = this._table$1.rows[closestItem].get_item(i).toString();
+ if (i === this.startDateColumn || i === this.endDateColumn) {
+ colValue = SpreadSheetLayer.parseDate(colValue).toString();
+ }
+ if (!ss.keyExists(rowData, this._table$1.column[i].name) && !ss.emptyString(this._table$1.column[i].name)) {
+ rowData[this._table$1.column[i].name] = colValue;
+ }
+ else {
+ rowData['Column' + i.toString()] = colValue;
+ }
+ }
+ place.set_tag(rowData);
+ return place;
+ },
+
+ prepVertexBuffer: function (renderContext, opacity) {
+ var col = this._table$1.getColumnByUcd('meta.id');
+ if (col == null) {
+ col = this._table$1.column[0];
+ }
+ var siapSet = this.isSiapResultSet();
+ if (this.pointList == null) {
+ this.pointList = new PointList(renderContext);
+ }
+ if (this.lineList2d == null) {
+ this.lineList2d = new LineList();
+ }
+ this.lineList2d.clear();
+ var stcsCol = this._table$1.getColumnByUcd('phys.area;obs.field');
+ if (stcsCol == null && ss.keyExists(this._table$1.columns, 'regionSTCS')) {
+ stcsCol = this._table$1.columns['regionSTCS'];
+ }
+ if (!this.get_plotType()) {
+ this.set_markerScale(1);
+ } else {
+ this.set_markerScale(0);
+ }
+ var vertList = [];
+ var indexList = [];
+ var lastItem = new TimeSeriesPointVertex();
+ this.positions.length = 0;
+ var currentIndex = 0;
+ var color = Color.fromArgb(ss.truncate((opacity * this.get_color().a)), this.get_color().r, this.get_color().g, this.get_color().b);
+ this.pointScaleType = 4;
+ var $enum1 = ss.enumerate(this._table$1.rows);
+ while ($enum1.moveNext()) {
+ var row = $enum1.current;
+ try {
+ if (this.lngColumn > -1 && this.latColumn > -1) {
+ var ra = parseFloat(row.get_item(this.get_lngColumn()).toString());
+ var dec = parseFloat(row.get_item(this.get_latColumn()).toString());
+ var position = Coordinates.geoTo3dDouble(dec, ra);
+ lastItem.position = position;
+ this.positions.push(lastItem.position);
+ lastItem.set_color(color);
+ if (this.sizeColumn > -1) {
+ try {
+ if (!this.get_markerScale()) {
+ lastItem.pointSize = 20;
+ }
+ else {
+ switch (this.pointScaleType) {
+ case 0:
+ lastItem.pointSize = parseFloat(row.get_item(this.sizeColumn).toString());
+ break;
+ case 2:
+ lastItem.pointSize = Math.log(parseFloat(row.get_item(this.sizeColumn).toString()));
+ break;
+ case 1:
+ lastItem.pointSize = Math.pow(2, parseFloat(row.get_item(this.sizeColumn).toString()));
+ break;
+ case 4:
+ var size = parseFloat(row.get_item(this.sizeColumn).toString());
+ lastItem.pointSize = (40 / Math.pow(1.6, size)) * 10;
+ break;
+ case 3:
+ lastItem.pointSize = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ catch ($e2) {
+ lastItem.pointSize = 0.01;
+ }
+ }
+ else {
+ if (!this.get_markerScale()) {
+ lastItem.pointSize = 20;
+ }
+ else {
+ lastItem.pointSize = Math.pow(2, 1) * 100;
+ }
+ }
+ if (this.startDateColumn > -1) {
+ var dateTime = ss.date(row.get_item(this.startDateColumn).toString());
+ lastItem.tu = SpaceTimeController.utcToJulian(dateTime);
+ lastItem.tv = 0;
+ }
+ vertList.push(lastItem);
+ this.pointList.addPoint(lastItem.position, lastItem.color, new Dates(lastItem.tu, lastItem.tv), lastItem.pointSize);
+ currentIndex++;
+ }
+ if (siapSet && stcsCol != null) {
+ this._addSiapStcRow$1(stcsCol.name, row, row === this._table$1.selectedRow);
+ }
+ }
+ catch ($e3) {
+ }
+ this.lines = false;
+ }
+ if (siapSet && stcsCol != null) {
+ this._addSiapStcRow$1(stcsCol.name, this._table$1.selectedRow, true);
+ }
+ return true;
+ },
+ _addSiapStcRow$1: function (stcsColName, row, selected) {
+ var stcs = ss.replaceString(row.getColumnData(stcsColName).toString(), ' ', ' ');
+ var col = Color.fromArgb(120, 255, 255, 255);
+ if (selected) {
+ col = Colors.get_yellow();
+ }
+ if (ss.startsWith(stcs, 'Polygon J2000')) {
+ var parts = stcs.split(' ');
+ var len = parts.length;
+ var index = 0;
+ while (index < len) {
+ if (parts[index] === 'Polygon') {
+ index += 2;
+ var lastPoint = new Vector3d();
+ var firstPoint = new Vector3d();
+ var start = true;
+ for (var i = index; i < len; i += 2) {
+ if (parts[i] === 'Polygon') {
+ start = true;
+ break;
+ }
+ else {
+ var Xcoord = Coordinates.parseRA(parts[i], true) * 15 + 180;
+ var Ycoord = Coordinates.parseDec(parts[i + 1]);
+ var pnt = Coordinates.geoTo3dDouble(Ycoord, Xcoord);
+ if (!start) {
+ this.lineList2d.addLine(lastPoint, pnt, col, new Dates(0, 0));
+ }
+ else {
+ firstPoint = pnt;
+ start = false;
+ }
+ lastPoint = pnt;
+ }
+ index += 2;
+ }
+ if (len > 4) {
+ this.lineList2d.addLine(firstPoint, lastPoint, col, new Dates(0, 0));
+ }
+ }
+ }
+ }
+ },
+
+ isSiapResultSet: function () {
+ return this._table$1.getColumnByUcd('vox:image.title') != null && this._table$1.getColumnByUcd('VOX:Image.AccessReference') != null;
+ },
+
+ get_header: function () {
+ var header = new Array(ss.keyCount(this._table$1.columns));
+ var index = 0;
+ var $enum1 = ss.enumerate(this._table$1.column);
+ while ($enum1.moveNext()) {
+ var col = $enum1.current;
+ header[index++] = col.name;
+ }
+ return header;
+ },
+
+ get_table: function () {
+ return this._table$1;
+ },
+
+ set_table: function (value) {
+ this._table$1 = value;
+ return value;
+ }
+};
+
+registerType("VoTableLayer", [VoTableLayer, VoTableLayer$, Layer]);
diff --git a/engine/esm/layers/wcs_image.js b/engine/esm/layers/wcs_image.js
new file mode 100644
index 00000000..64a94f43
--- /dev/null
+++ b/engine/esm/layers/wcs_image.js
@@ -0,0 +1,261 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Information about an image with a World Coordinate System registration.
+
+import { registerType } from "../typesystem.js";
+
+
+// wwtlib.WcsImage
+
+export function WcsImage() {
+ this.copyright = '';
+ this.creditsUrl = '';
+ this._validWcs = false;
+ this.keywords = [];
+ this.description = '';
+ this.scaleX = 0;
+ this.scaleY = 0;
+ this.centerX = 0;
+ this.centerY = 0;
+ this.rotation = 0;
+ this.referenceX = 0;
+ this.referenceY = 0;
+ this.sizeX = 0;
+ this.sizeY = 0;
+ this.cd1_1 = 0;
+ this.cd1_2 = 0;
+ this.cd2_1 = 0;
+ this.cd2_2 = 0;
+ this.hasRotation = false;
+ this.hasSize = false;
+ this.hasScale = false;
+ this.hasLocation = false;
+ this.hasPixel = false;
+ this.filename = '';
+ this._colorCombine = false;
+}
+
+var WcsImage$ = {
+ get_copyright: function () {
+ return this.copyright;
+ },
+
+ set_copyright: function (value) {
+ this.copyright = value;
+ return value;
+ },
+
+ get_creditsUrl: function () {
+ return this.creditsUrl;
+ },
+
+ set_creditsUrl: function (value) {
+ this.creditsUrl = value;
+ return value;
+ },
+
+ get_validWcs: function () {
+ return this._validWcs;
+ },
+
+ set_validWcs: function (value) {
+ this._validWcs = value;
+ return value;
+ },
+
+ get_keywords: function () {
+ if (!this.keywords.length) {
+ this.keywords.push('Image File');
+ }
+ return this.keywords;
+ },
+
+ set_keywords: function (value) {
+ this.keywords = value;
+ return value;
+ },
+
+ get_description: function () {
+ return this.description;
+ },
+
+ set_description: function (value) {
+ this.description = value;
+ return value;
+ },
+
+ get_scaleX: function () {
+ return this.scaleX;
+ },
+
+ set_scaleX: function (value) {
+ this.scaleX = value;
+ return value;
+ },
+
+ get_scaleY: function () {
+ return this.scaleY;
+ },
+
+ set_scaleY: function (value) {
+ this.scaleY = value;
+ return value;
+ },
+
+ get_centerX: function () {
+ return this.centerX;
+ },
+
+ set_centerX: function (value) {
+ this.centerX = value;
+ return value;
+ },
+
+ get_viewCenterX: function () {
+ return this.centerX + (this.get_sizeX() / 2 - this.get_referenceX()) * this.get_scaleX();
+ },
+
+ get_centerY: function () {
+ return this.centerY;
+ },
+
+ set_centerY: function (value) {
+ this.centerY = value;
+ return value;
+ },
+
+ get_viewCenterY: function () {
+ return this.centerY + (this.get_sizeY() / 2 - this.get_referenceY()) * this.get_scaleY();
+ },
+
+ get_rotation: function () {
+ return this.rotation;
+ },
+
+ set_rotation: function (value) {
+ this.rotation = value;
+ return value;
+ },
+
+ get_referenceX: function () {
+ return this.referenceX;
+ },
+
+ set_referenceX: function (value) {
+ this.referenceX = value;
+ return value;
+ },
+
+ get_referenceY: function () {
+ return this.referenceY;
+ },
+
+ set_referenceY: function (value) {
+ this.referenceY = value;
+ return value;
+ },
+
+ get_sizeX: function () {
+ return this.sizeX;
+ },
+
+ set_sizeX: function (value) {
+ this.sizeX = value;
+ return value;
+ },
+
+ get_sizeY: function () {
+ return this.sizeY;
+ },
+
+ set_sizeY: function (value) {
+ this.sizeY = value;
+ return value;
+ },
+
+ get_cd1_1: function () {
+ return this.cd1_1;
+ },
+
+ set_cd1_1: function (value) {
+ this.cd1_1 = value;
+ return value;
+ },
+
+ get_cd1_2: function () {
+ return this.cd1_2;
+ },
+
+ set_cd1_2: function (value) {
+ this.cd1_2 = value;
+ return value;
+ },
+
+ get_cd2_1: function () {
+ return this.cd2_1;
+ },
+
+ set_cd2_1: function (value) {
+ this.cd2_1 = value;
+ return value;
+ },
+
+ get_cd2_2: function () {
+ return this.cd2_2;
+ },
+
+ set_cd2_2: function (value) {
+ this.cd2_2 = value;
+ return value;
+ },
+
+ adjustScale: function (width, height) {
+ //adjusts the actual height vs the reported height.
+ if (width !== this.sizeX) {
+ this.scaleX *= (this.sizeX / width);
+ this.referenceX /= (this.sizeX / width);
+ this.sizeX = width;
+ }
+ if (height !== this.sizeY) {
+ this.scaleY *= (this.sizeY / height);
+ this.referenceY /= (this.sizeY / height);
+ this.sizeY = height;
+ }
+ },
+
+ calculateScaleFromCD: function () {
+ this.scaleX = (Math.sqrt(this.cd1_1 * this.cd1_1 + this.cd2_1 * this.cd2_1) * (this.cd1_1 * this.cd2_2 - this.cd1_2 * this.cd2_1) < 0) ? -1 : 1;
+ this.scaleY = Math.sqrt(this.cd1_2 * this.cd1_2 + this.cd2_2 * this.cd2_2);
+ },
+
+ calculateRotationFromCD: function () {
+ var sign = ((this.cd1_1 * this.cd2_2 - this.cd1_2 * this.cd2_1) < 0) ? -1 : 1;
+ var rot2 = Math.atan2((-sign * this.cd1_2), this.cd2_2);
+ this.rotation = rot2 / Math.PI * 180;
+ },
+
+ get_filename: function () {
+ return this.filename;
+ },
+
+ set_filename: function (value) {
+ this.filename = value;
+ return value;
+ },
+
+ get_colorCombine: function () {
+ return this._colorCombine;
+ },
+
+ set_colorCombine: function (value) {
+ this._colorCombine = value;
+ return value;
+ },
+
+ getBitmap: function () {
+ return null;
+ }
+};
+
+registerType("WcsImage", [WcsImage, WcsImage$, null]);
diff --git a/engine/esm/mercator_tile.js b/engine/esm/mercator_tile.js
new file mode 100644
index 00000000..20748d8e
--- /dev/null
+++ b/engine/esm/mercator_tile.js
@@ -0,0 +1,404 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A tile in a pyramid that uses a Mercator projection.
+
+import { ss } from "./ss.js";
+import { registerType } from "./typesystem.js";
+import { tilePrepDevice, tileUvMultiple } from "./render_globals.js";
+import { Vector2d, Vector3d, PositionTexture } from "./double3d.js";
+import { WEBGL } from "./graphics/webgl_constants.js";
+import { RenderTriangle } from "./render_triangle.js";
+import { Tile } from "./tile.js";
+
+
+// wwtlib.MercatorTile
+
+export function MercatorTile() {
+ this._tileDegrees$1 = 0;
+ this._latMin$1 = 0;
+ this._latMax$1 = 0;
+ this._lngMin$1 = 0;
+ this._lngMax$1 = 0;
+ this._subDivisionLevel$1 = 32;
+ Tile.call(this);
+}
+
+MercatorTile.create = function (level, X, Y, dataset, parent) {
+ var temp = new MercatorTile();
+ temp.parent = parent;
+ temp.level = level;
+ temp.tileX = X;
+ temp.tileY = Y;
+ temp.dataset = dataset;
+ temp.computeBoundingSphere();
+ return temp;
+};
+
+MercatorTile.getCentrePointOffsetAsTileRatio = function (lat, lon, zoom) {
+ var metersX = MercatorTile.absoluteLonToMetersAtZoom(lon, zoom);
+ var relativeXIntoCell = (metersX / 256) - Math.floor(metersX / 256);
+ var metersY = MercatorTile.absoluteLatToMetersAtZoom(lat, zoom);
+ var relativeYIntoCell = (metersY / 256) - Math.floor(metersY / 256);
+ return Vector2d.create(relativeXIntoCell, relativeYIntoCell);
+};
+
+MercatorTile.relativeMetersToLatAtZoom = function (Y, zoom) {
+ var metersPerPixel = MercatorTile.metersPerPixel2(zoom);
+ var metersY = Y * metersPerPixel;
+ return MercatorTile._radToDeg$1(Math.PI / 2 - 2 * Math.atan(Math.exp(0 - metersY / 6378137)));
+};
+
+MercatorTile.relativeMetersToLonAtZoom = function (X, zoom) {
+ var metersPerPixel = MercatorTile.metersPerPixel2(zoom);
+ var metersX = X * metersPerPixel;
+ return MercatorTile._radToDeg$1(metersX / 6378137);
+};
+
+MercatorTile.absoluteLatToMetersAtZoom = function (latitude, zoom) {
+ var sinLat = Math.sin(MercatorTile._degToRad$1(latitude));
+ var metersY = 6378137 / 2 * Math.log((1 + sinLat) / (1 - sinLat));
+ var metersPerPixel = MercatorTile.metersPerPixel2(zoom);
+ return ss.truncate((Math.round(20037508 - metersY) / metersPerPixel));
+};
+
+MercatorTile.absoluteMetersToLatAtZoom = function (Y, zoom) {
+ var metersPerPixel = MercatorTile.metersPerPixel2(zoom);
+ var metersY = 20037508 - Y * metersPerPixel;
+ return MercatorTile._radToDeg$1(Math.PI / 2 - 2 * Math.atan(Math.exp(0 - metersY / 6378137)));
+};
+
+MercatorTile.absoluteLonToMetersAtZoom = function (longitude, zoom) {
+ var metersX = 6378137 * MercatorTile._degToRad$1(longitude);
+ var metersPerPixel = MercatorTile.metersPerPixel2(zoom);
+ return ss.truncate(((metersX + 20037508) / metersPerPixel));
+};
+
+MercatorTile.absoluteMetersToLonAtZoom = function (X, zoom) {
+ var metersPerPixel = MercatorTile.metersPerPixel2(zoom);
+ var metersX = X * metersPerPixel - 20037508;
+ return MercatorTile._radToDeg$1(metersX / 6378137);
+};
+
+MercatorTile.absoluteLonToMetersAtZoomTile = function (longitude, zoom, tileX) {
+ var metersX = 6378137 * MercatorTile._degToRad$1(longitude);
+ var metersPerPixel = MercatorTile.metersPerPixel2(zoom);
+ return ss.truncate(((metersX + 20037508) / metersPerPixel));
+};
+
+MercatorTile.absoluteLatToMetersAtZoomTile = function (latitude, zoom, tileX) {
+ var sinLat = Math.sin(MercatorTile._degToRad$1(latitude));
+ var metersY = 6378137 / 2 * Math.log((1 + sinLat) / (1 - sinLat));
+ var metersPerPixel = MercatorTile.metersPerPixel2(zoom);
+ return ss.truncate((Math.round(20037508 - metersY) / metersPerPixel));
+};
+
+MercatorTile.absoluteMetersToLonAtZoomByTileY = function (X, zoom, tileY) {
+ var metersPerPixel = MercatorTile.metersPerPixel2(zoom);
+ var metersX = X * metersPerPixel - 20037508;
+ return MercatorTile._radToDeg$1(metersX / 6378137);
+};
+
+MercatorTile._degToRad$1 = function (deg) {
+ return (deg * Math.PI / 180);
+};
+
+MercatorTile.metersPerPixel2 = function (zoom) {
+ return (156543 / (1 << zoom));
+};
+
+MercatorTile._radToDeg$1 = function (rad) {
+ return (rad * 180 / Math.PI);
+};
+
+var MercatorTile$ = {
+ computeBoundingSphere: function () {
+ this._tileDegrees$1 = 360 / Math.pow(2, this.level);
+ this._latMin$1 = MercatorTile.absoluteMetersToLatAtZoom(this.tileY * 256, this.level);
+ this._latMax$1 = MercatorTile.absoluteMetersToLatAtZoom((this.tileY + 1) * 256, this.level);
+ this._lngMin$1 = ((this.tileX * this._tileDegrees$1) - 180);
+ this._lngMax$1 = ((((this.tileX + 1)) * this._tileDegrees$1) - 180);
+ var latCenter = (this._latMin$1 + this._latMax$1) / 2;
+ var lngCenter = (this._lngMin$1 + this._lngMax$1) / 2;
+ this.sphereCenter = this.geoTo3d(latCenter, lngCenter, false);
+ this.topLeft = this.geoTo3d(this._latMin$1, this._lngMin$1, false);
+ this.bottomRight = this.geoTo3d(this._latMax$1, this._lngMax$1, false);
+ this.topRight = this.geoTo3d(this._latMin$1, this._lngMax$1, false);
+ this.bottomLeft = this.geoTo3d(this._latMax$1, this._lngMin$1, false);
+ if (!this.tileY) {
+ this.topLeft = Vector3d.create(0, 1, 0);
+ this.topRight = Vector3d.create(0, 1, 0);
+ }
+ if (this.tileY === Math.pow(2, this.level) - 1) {
+ this.bottomRight = Vector3d.create(0, -1, 0);
+ this.bottomLeft = Vector3d.create(0, -1, 0);
+ }
+ var distVect = this.topLeft;
+ distVect.subtract(this.sphereCenter);
+ this.sphereRadius = distVect.length();
+ distVect = this.bottomRight;
+ distVect.subtract(this.sphereCenter);
+ var len = distVect.length();
+ if (this.sphereRadius < len) {
+ this.sphereRadius = len;
+ }
+ this._tileDegrees$1 = Math.abs(this._latMax$1 - this._latMin$1);
+ },
+
+ isPointInTile: function (lat, lng) {
+ if (!this.demReady || this.demData == null || lat < Math.min(this._latMin$1, this._latMax$1) || lat > Math.max(this._latMax$1, this._latMin$1) || lng < Math.min(this._lngMin$1, this._lngMax$1) || lng > Math.max(this._lngMin$1, this._lngMax$1)) {
+ return false;
+ }
+ return true;
+ },
+
+ getSurfacePointAltitude: function (lat, lng, meters) {
+ if (this.level < Tile.lastDeepestLevel) {
+ var $enum1 = ss.enumerate(this.children);
+ while ($enum1.moveNext()) {
+ var child = $enum1.current;
+ if (child != null) {
+ if (child.isPointInTile(lat, lng)) {
+ var retVal = child.getSurfacePointAltitude(lat, lng, meters);
+ if (!!retVal) {
+ return retVal;
+ }
+ else {
+ break;
+ }
+ }
+ }
+ }
+ }
+ var alt = this._getAltitudeAtLatLng$1(lat, lng, (meters) ? 1 : this.get__demScaleFactor());
+ return alt;
+ },
+
+ _getAltitudeAtLatLng$1: function (lat, lng, scaleFactor) {
+ var height = Math.abs(this._latMax$1 - this._latMin$1);
+ var width = Math.abs(this._lngMax$1 - this._lngMin$1);
+ var yy = ((lat - Math.min(this._latMax$1, this._latMin$1)) / height * 32);
+ var xx = ((lng - Math.min(this._lngMax$1, this._lngMin$1)) / width * 32);
+ var indexY = Math.min(31, ss.truncate(yy));
+ var indexX = Math.min(31, ss.truncate(xx));
+ var ha = xx - indexX;
+ var va = yy - indexY;
+ var ul = this.demData[indexY * 33 + indexX];
+ var ur = this.demData[indexY * 33 + (indexX + 1)];
+ var ll = this.demData[(indexY + 1) * 33 + indexX];
+ var lr = this.demData[(indexY + 1) * 33 + (indexX + 1)];
+ var top = ul * (1 - ha) + ha * ur;
+ var bottom = ll * (1 - ha) + ha * lr;
+ var val = top * (1 - va) + va * bottom;
+ return val / scaleFactor;
+ },
+
+ createGeometry: function (renderContext) {
+ Tile.prototype.createGeometry.call(this, renderContext);
+ if (this.geometryCreated) {
+ return true;
+ }
+ this.geometryCreated = true;
+ if (tileUvMultiple == 256) {
+ if (!this.dataset.get_dataSetType() || this.dataset.get_dataSetType() === 1) {
+ this._subDivisionLevel$1 = Math.max(2, (6 - this.level) * 2);
+ }
+ }
+ for (var i = 0; i < 4; i++) {
+ this._renderTriangleLists[i] = [];
+ }
+ var lat, lng;
+ var index = 0;
+ var tileDegrees = 360 / Math.pow(2, this.level);
+ this._latMin$1 = MercatorTile.absoluteMetersToLatAtZoom(this.tileY * 256, this.level);
+ this._latMax$1 = MercatorTile.absoluteMetersToLatAtZoom((this.tileY + 1) * 256, this.level);
+ this._lngMin$1 = ((this.tileX * tileDegrees) - 180);
+ this._lngMax$1 = ((((this.tileX + 1)) * tileDegrees) - 180);
+ var latCenter = MercatorTile.absoluteMetersToLatAtZoom(((this.tileY * 2) + 1) * 256, this.level + 1);
+ this.topLeft = this.geoTo3d(this._latMin$1, this._lngMin$1, false);
+ this.bottomRight = this.geoTo3d(this._latMax$1, this._lngMax$1, false);
+ this.topRight = this.geoTo3d(this._latMin$1, this._lngMax$1, false);
+ this.bottomLeft = this.geoTo3d(this._latMax$1, this._lngMin$1, false);
+ var verts = new Array((this._subDivisionLevel$1 + 1) * (this._subDivisionLevel$1 + 1));
+ tileDegrees = this._lngMax$1 - this._lngMin$1;
+ var dGrid = (tileDegrees / this._subDivisionLevel$1);
+ var x1, y1;
+ var textureStep = 1 / this._subDivisionLevel$1;
+ var latDegrees = this._latMax$1 - latCenter;
+ for (y1 = 0; y1 < this._subDivisionLevel$1 / 2; y1++) {
+ if (y1 !== this._subDivisionLevel$1 / 2) {
+ lat = this._latMax$1 - (2 * textureStep * latDegrees * y1);
+ }
+ else {
+ lat = latCenter;
+ }
+ for (x1 = 0; x1 <= this._subDivisionLevel$1; x1++) {
+ if (x1 !== this._subDivisionLevel$1) {
+ lng = this._lngMin$1 + (textureStep * tileDegrees * x1);
+ }
+ else {
+ lng = this._lngMax$1;
+ }
+ index = y1 * (this._subDivisionLevel$1 + 1) + x1;
+ verts[index] = new PositionTexture();
+ verts[index].position = this.geoTo3dWithAlt(lat, lng, false, true);
+ verts[index].tu = (x1 * textureStep) * tileUvMultiple;
+ verts[index].tv = ((MercatorTile.absoluteLatToMetersAtZoom(lat, this.level) - (this.tileY * 256)) / 256) * tileUvMultiple;
+ this.demIndex++;
+ }
+ }
+ latDegrees = this._latMin$1 - latCenter;
+ for (y1 = this._subDivisionLevel$1 / 2; y1 <= this._subDivisionLevel$1; y1++) {
+ if (y1 !== this._subDivisionLevel$1) {
+ lat = latCenter + (2 * textureStep * latDegrees * (y1 - (this._subDivisionLevel$1 / 2)));
+ }
+ else {
+ lat = this._latMin$1;
+ }
+ for (x1 = 0; x1 <= this._subDivisionLevel$1; x1++) {
+ if (x1 !== this._subDivisionLevel$1) {
+ lng = this._lngMin$1 + (textureStep * tileDegrees * x1);
+ }
+ else {
+ lng = this._lngMax$1;
+ }
+ index = y1 * (this._subDivisionLevel$1 + 1) + x1;
+ verts[index] = new PositionTexture();
+ verts[index].position = this.geoTo3dWithAlt(lat, lng, false, true);
+ verts[index].tu = (x1 * textureStep) * tileUvMultiple;
+ verts[index].tv = ((MercatorTile.absoluteLatToMetersAtZoom(lat, this.level) - (this.tileY * 256)) / 256) * tileUvMultiple;
+ this.demIndex++;
+ }
+ }
+ if (!this.tileY) {
+ // Send the tops to the pole to fill in the Bing Hole
+ y1 = this._subDivisionLevel$1;
+ for (x1 = 0; x1 <= this._subDivisionLevel$1; x1++) {
+ index = y1 * (this._subDivisionLevel$1 + 1) + x1;
+ verts[index].position = Vector3d.create(0, 1, 0);
+ }
+ }
+ if (this.tileY === Math.pow(2, this.level) - 1) {
+ // Send the tops to the pole to fill in the Bing Hole
+ y1 = 0;
+ for (x1 = 0; x1 <= this._subDivisionLevel$1; x1++) {
+ index = y1 * (this._subDivisionLevel$1 + 1) + x1;
+ verts[index].position = Vector3d.create(0, -1, 0);
+ }
+ }
+ this.triangleCount = this._subDivisionLevel$1 * this._subDivisionLevel$1 * 2;
+ var quarterDivisions = this._subDivisionLevel$1 / 2;
+ var part = 0;
+ if (renderContext.gl == null) {
+ for (var y2 = 0; y2 < 2; y2++) {
+ for (var x2 = 0; x2 < 2; x2++) {
+ index = 0;
+ for (y1 = (quarterDivisions * y2); y1 < (quarterDivisions * (y2 + 1)); y1++) {
+ for (x1 = (quarterDivisions * x2); x1 < (quarterDivisions * (x2 + 1)); x1++) {
+ var p1;
+ var p2;
+ var p3;
+
+ // First triangle in quad
+ p1 = verts[(y1 * (this._subDivisionLevel$1 + 1) + x1)];
+ p2 = verts[((y1 + 1) * (this._subDivisionLevel$1 + 1) + x1)];
+ p3 = verts[(y1 * (this._subDivisionLevel$1 + 1) + (x1 + 1))];
+ var tri = RenderTriangle.create(p1, p2, p3, this.texture, this.level);
+ this._renderTriangleLists[part].push(tri);
+
+ // Second triangle in quad
+ p1 = verts[(y1 * (this._subDivisionLevel$1 + 1) + (x1 + 1))];
+ p2 = verts[((y1 + 1) * (this._subDivisionLevel$1 + 1) + x1)];
+ p3 = verts[((y1 + 1) * (this._subDivisionLevel$1 + 1) + (x1 + 1))];
+ tri = RenderTriangle.create(p1, p2, p3, this.texture, this.level);
+ this._renderTriangleLists[part].push(tri);
+ }
+ }
+ part++;
+ }
+ }
+ } else {
+ this._vertexBuffer = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ARRAY_BUFFER, this._vertexBuffer);
+ var f32array = new Float32Array(verts.length * 5);
+ var buffer = f32array;
+ index = 0;
+ var $enum1 = ss.enumerate(verts);
+ while ($enum1.moveNext()) {
+ var pt = $enum1.current;
+ index = this.addVertex(buffer, index, pt);
+ }
+ tilePrepDevice.bufferData(WEBGL.ARRAY_BUFFER, f32array, WEBGL.STATIC_DRAW);
+ for (var y2 = 0; y2 < 2; y2++) {
+ for (var x2 = 0; x2 < 2; x2++) {
+ var ui16array = new Uint16Array(this.triangleCount * 3);
+ var indexArray = ui16array;
+ index = 0;
+ for (y1 = (quarterDivisions * y2); y1 < (quarterDivisions * (y2 + 1)); y1++) {
+ for (x1 = (quarterDivisions * x2); x1 < (quarterDivisions * (x2 + 1)); x1++) {
+ // First triangle in quad
+ indexArray[index++] = (y1 * (this._subDivisionLevel$1 + 1) + x1);
+ indexArray[index++] = ((y1 + 1) * (this._subDivisionLevel$1 + 1) + x1);
+ indexArray[index++] = (y1 * (this._subDivisionLevel$1 + 1) + (x1 + 1));
+
+ // Second triangle in quad
+ indexArray[index++] = (y1 * (this._subDivisionLevel$1 + 1) + (x1 + 1));
+ indexArray[index++] = ((y1 + 1) * (this._subDivisionLevel$1 + 1) + x1);
+ indexArray[index++] = ((y1 + 1) * (this._subDivisionLevel$1 + 1) + (x1 + 1));
+ }
+ }
+ this._indexBuffers[part] = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, this._indexBuffers[part]);
+ tilePrepDevice.bufferData(WEBGL.ELEMENT_ARRAY_BUFFER, ui16array, WEBGL.STATIC_DRAW);
+ part++;
+ }
+ }
+ }
+ return true;
+ },
+
+ _getDemSample$1: function (x, y) {
+ return this.demData[(32 - y) * 33 + x];
+ },
+
+ createDemFromParent: function () {
+ var parent = ss.safeCast(this.parent, MercatorTile);
+ if (parent == null || parent.demData == null) {
+ return false;
+ }
+ var offsetX = (((this.tileX % 2) === 1) ? 16 : 0);
+ var offsetY = (((this.tileY % 2) === 1) ? 16 : 0);
+ this.demData = new Array(this.demSize);
+
+ // Interpolate across
+ for (var y = 0; y < 33; y += 2) {
+ var copy = true;
+ for (var x = 0; x < 33; x++) {
+ if (copy) {
+ this.demData[(32 - y) * 33 + x] = parent._getDemSample$1((x / 2) + offsetX, (y / 2) + offsetY);
+ }
+ else {
+ this.demData[(32 - y) * 33 + x] = ((parent._getDemSample$1((x / 2) + offsetX, (y / 2) + offsetY) + parent._getDemSample$1(((x / 2) + offsetX) + 1, (y / 2) + offsetY)) / 2);
+ }
+ copy = !copy;
+ }
+ }
+
+ // Interpolate down
+ for (var y = 1; y < 33; y += 2) {
+ for (var x = 0; x < 33; x++) {
+ this.demData[(32 - y) * 33 + x] = ((this._getDemSample$1(x, y - 1) + this._getDemSample$1(x, y + 1)) / 2);
+ }
+ }
+ var $enum1 = ss.enumerate(this.demData);
+ while ($enum1.moveNext()) {
+ var sample = $enum1.current;
+ this.demAverage += sample;
+ }
+ this.demAverage /= this.demData.length;
+ this.demReady = true;
+ return true;
+ }
+};
+
+registerType("MercatorTile", [MercatorTile, MercatorTile$, Tile]);
diff --git a/engine/esm/minor_planets.js b/engine/esm/minor_planets.js
new file mode 100644
index 00000000..135d36ad
--- /dev/null
+++ b/engine/esm/minor_planets.js
@@ -0,0 +1,162 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Rendering the minor planet database
+
+import { ss } from "./ss.js";
+import { registerType } from "./typesystem.js";
+import { Vector3d, Matrix3d } from "./double3d.js";
+import { EOE } from "./astrocalc/elliptical.js";
+import { Texture } from "./graphics/texture.js";
+import { WEBGL } from "./graphics/webgl_constants.js";
+import { KeplerVertexBuffer } from "./graphics/gl_buffers.js"
+import { KeplerPointSpriteShader } from "./graphics/shaders.js";
+import { BlendState } from "./blend_state.js";
+import { Colors } from "./color.js";
+import { freestandingMode } from "./data_globals.js";
+import { KeplerVertex } from "./kepler_vertex.js";
+import { SpaceTimeController } from "./space_time_controller.js";
+import { URLHelpers } from "./url_helpers.js";
+import { BinaryReader } from "./utilities/binary_reader.js";
+import { WebFile } from "./web_file.js";
+
+
+// wwtlib.MinorPlanets
+
+export function MinorPlanets() { }
+
+MinorPlanets.mpcList = [];
+MinorPlanets._initBegun = false;
+MinorPlanets._mpcBlendStates = new Array(7);
+MinorPlanets.starTexture = null;
+MinorPlanets._mpcVertexBuffer = null;
+MinorPlanets._mpcCount = 0;
+
+MinorPlanets.getMpcFile = function (url) {
+ MinorPlanets._webMpcFile = new WebFile(url);
+ MinorPlanets._webMpcFile.responseType = 'blob';
+ MinorPlanets._webMpcFile.onStateChange = MinorPlanets.starFileStateChange;
+ MinorPlanets._webMpcFile.send();
+};
+
+MinorPlanets.starFileStateChange = function () {
+ if (MinorPlanets._webMpcFile.get_state() === 2) {
+ alert(MinorPlanets._webMpcFile.get_message());
+ }
+ else if (MinorPlanets._webMpcFile.get_state() === 1) {
+ var mainBlob = MinorPlanets._webMpcFile.getBlob();
+ var chunck = new FileReader();
+ chunck.onloadend = function (e) {
+ MinorPlanets._readFromBin(new BinaryReader(new Uint8Array(chunck.result)));
+ MinorPlanets.initMPCVertexBuffer();
+ };
+ chunck.readAsArrayBuffer(mainBlob);
+ }
+};
+
+MinorPlanets._readFromBin = function (br) {
+ MinorPlanets.mpcList = [];
+ var len = br.get_length();
+ var ee;
+ try {
+ while (br.get_position() < len) {
+ ee = EOE._create(br);
+ MinorPlanets.mpcList.push(ee);
+ }
+ }
+ catch ($e1) { }
+ br.close();
+};
+
+MinorPlanets.drawMPC3D = function (renderContext, opacity, centerPoint) {
+ var zoom = renderContext.viewCamera.zoom;
+ var distAlpha = ((Math.log(Math.max(1, zoom)) / Math.log(4)) - 15.5) * 90;
+ var alpha = Math.min(255, Math.max(0, ss.truncate(distAlpha)));
+ if (alpha > 254) {
+ return;
+ }
+ if (MinorPlanets._mpcVertexBuffer == null) {
+ if (MinorPlanets.starTexture == null) {
+ MinorPlanets.starTexture = Texture.fromUrl(URLHelpers.singleton.engineAssetUrl('StarProfileAlpha.png'));
+ }
+ for (var i = 0; i < 7; i++) {
+ MinorPlanets._mpcBlendStates[i] = BlendState.create(false, 1000);
+ }
+ if (!MinorPlanets._initBegun) {
+ MinorPlanets._startInit();
+ MinorPlanets._initBegun = true;
+ }
+ return;
+ }
+ var offset = Matrix3d.translation(Vector3d.negate(centerPoint));
+ var world = Matrix3d.multiplyMatrix(renderContext.get_world(), offset);
+ var matrixWV = Matrix3d.multiplyMatrix(world, renderContext.get_view());
+ var cam = Vector3d._transformCoordinate(renderContext.cameraPosition, Matrix3d.invertMatrix(renderContext.get_world()));
+ if (MinorPlanets._mpcVertexBuffer != null) {
+ for (var i = 0; i < 7; i++) {
+ MinorPlanets._mpcBlendStates[i].set_targetState(true);
+ if (MinorPlanets._mpcBlendStates[i].get_state()) {
+ KeplerPointSpriteShader.use(renderContext, matrixWV, MinorPlanets._mpcVertexBuffer[i].vertexBuffer, MinorPlanets.starTexture.texture2d, Colors.get_white(), opacity * MinorPlanets._mpcBlendStates[i].get_opacity(), false, (SpaceTimeController.get_jNow() - KeplerVertex.baseDate), 0, renderContext.cameraPosition, 200, 0.1);
+ renderContext.gl.drawArrays(WEBGL.POINTS, 0, MinorPlanets._mpcVertexBuffer[i].count);
+ }
+ }
+ }
+};
+
+MinorPlanets._startInit = function () {
+ if (!freestandingMode) {
+ MinorPlanets.getMpcFile(URLHelpers.singleton.coreStaticUrl('wwtweb/catalog.aspx?Q=mpcbin'));
+ }
+};
+
+MinorPlanets.initMPCVertexBuffer = function () {
+ try {
+ if (MinorPlanets._mpcVertexBuffer == null) {
+ var mpcVertexBufferTemp = new Array(7);
+ MinorPlanets._mpcCount = MinorPlanets.mpcList.length;
+ var lists = new Array(7);
+ for (var i = 0; i < 7; i++) {
+ lists[i] = [];
+ }
+ var $enum1 = ss.enumerate(MinorPlanets.mpcList);
+ while ($enum1.moveNext()) {
+ var ee = $enum1.current;
+ var listID = 0;
+ if (ee.a < 2.5) {
+ listID = 0;
+ }
+ else if (ee.a < 2.83) {
+ listID = 1;
+ }
+ else if (ee.a < 2.96) {
+ listID = 2;
+ }
+ else if (ee.a < 3.3) {
+ listID = 3;
+ }
+ else if (ee.a < 5) {
+ listID = 4;
+ }
+ else if (ee.a < 10) {
+ listID = 5;
+ }
+ else {
+ listID = 6;
+ }
+ var vert = new KeplerVertex();
+ vert.fill(ee);
+ lists[listID].push(vert);
+ }
+ for (var i = 0; i < 7; i++) {
+ mpcVertexBufferTemp[i] = KeplerVertexBuffer.create(lists[i]);
+ mpcVertexBufferTemp[i].unlock();
+ }
+ MinorPlanets._mpcVertexBuffer = mpcVertexBufferTemp;
+ }
+ }
+ finally { }
+};
+
+var MinorPlanets$ = {};
+
+registerType("MinorPlanets", [MinorPlanets, MinorPlanets$, null]);
diff --git a/engine/esm/place.js b/engine/esm/place.js
new file mode 100644
index 00000000..59e3fe0a
--- /dev/null
+++ b/engine/esm/place.js
@@ -0,0 +1,538 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A place to look at, potentially with associated imagesets.
+
+import { ss } from "./ss.js";
+import { registerType, registerEnum, Enums } from "./typesystem.js";
+import { Vector3d } from "./double3d.js";
+import { freestandingMode, set_createPlace } from "./data_globals.js";
+import { Util } from "./baseutil.js";
+import { CameraParameters } from "./camera_parameters.js";
+import { IPlace, IThumbnail } from "./interfaces.js";
+import { UiTools } from "./ui_tools.js";
+import { URLHelpers } from "./url_helpers.js";
+import { Coordinates } from "./coordinates.js";
+import { Imageset } from "./imageset.js";
+import { Planets } from "./planets.js";
+
+
+// wwtlib.Classification
+//
+// This was defined in `IPlace.cs`, which we've folded into `interfaces.js`.
+
+export var Classification = {
+ star: 1,
+ supernova: 2,
+ blackHole: 4,
+ neutronStar: 8,
+ doubleStar: 16,
+ multipleStars: 32,
+ asterism: 64,
+ constellation: 128,
+ openCluster: 256,
+ globularCluster: 512,
+ nebulousCluster: 1024,
+ nebula: 2048,
+ emissionNebula: 4096,
+ planetaryNebula: 8192,
+ reflectionNebula: 16384,
+ darkNebula: 32768,
+ giantMolecularCloud: 65536,
+ supernovaRemnant: 131072,
+ interstellarDust: 262144,
+ quasar: 524288,
+ galaxy: 1048576,
+ spiralGalaxy: 2097152,
+ irregularGalaxy: 4194304,
+ ellipticalGalaxy: 8388608,
+ knot: 16777216,
+ plateDefect: 33554432,
+ clusterOfGalaxies: 67108864,
+ otherNGC: 134217728,
+ unidentified: 268435456,
+ solarSystem: 536870912,
+ unfiltered: 1073741823,
+ stellar: 63,
+ stellarGroupings: 2032,
+ nebulae: 523264,
+ galactic: 133693440,
+ other: 436207616
+};
+
+registerType("Classification", Classification);
+registerEnum("Classification", Classification);
+
+
+// wwtlib.Place
+
+export function Place() {
+ this._camParams = CameraParameters.create(0, 0, -1, 0, 0, 100);
+ this._location3d = Vector3d.create(0, 0, 0);
+ this.htmlDescription = '';
+ this._constellation = '';
+ this._classification = 1048576;
+ this._type = 2;
+ this._magnitude = 0;
+ this._distnace = 0;
+ this.angularSize = 60; // Angular size in arcseconds
+ this.annotation = '';
+ this._thumbNail = null;
+ this._studyImageset = null;
+ this._backgroundImageSet = null;
+ this._searchDistance = 0;
+ this._elevation = 50;
+}
+
+Place.create = function (name, lat, lng, classification, constellation, type, zoomFactor) {
+ var temp = new Place();
+ temp.set_zoomLevel(zoomFactor);
+ temp._constellation = constellation;
+ temp._name = name;
+ if (type === 2 || type === 4) {
+ temp._camParams.set_RA(lng);
+ }
+ else {
+ temp.set_lng(lng);
+ }
+ temp.set_lat(lat);
+ temp.set_classification(classification);
+ temp.set_type(type);
+ return temp;
+};
+
+Place.createCameraParams = function (name, camParams, classification, constellation, type, target) {
+ var temp = new Place();
+ temp._constellation = constellation;
+ temp._name = name;
+ temp.set_classification(classification);
+ temp._camParams = camParams;
+ temp.set_type(type);
+ temp.set_target(target);
+ return temp;
+};
+
+Place._fromXml = function (place) {
+ var newPlace = new Place();
+ newPlace._name = place.attributes.getNamedItem('Name').nodeValue;
+ if (place.attributes.getNamedItem('MSRComponentId') != null && place.attributes.getNamedItem('Permission') != null && place.attributes.getNamedItem('Url') != null) {
+ //communities item
+ newPlace.set_url(place.attributes.getNamedItem('Url').nodeValue);
+ newPlace.set_thumbnailUrl(place.attributes.getNamedItem('Thumbnail').nodeValue);
+ return newPlace;
+ }
+ if (place.attributes.getNamedItem('DataSetType') != null) {
+ newPlace._type = Enums.parse('ImageSetType', place.attributes.getNamedItem('DataSetType').nodeValue);
+ }
+ if (newPlace.get_type() === 2) {
+ newPlace._camParams.set_RA(parseFloat(place.attributes.getNamedItem('RA').nodeValue));
+ newPlace._camParams.set_dec(parseFloat(place.attributes.getNamedItem('Dec').nodeValue));
+ }
+ else {
+ newPlace.set_lat(parseFloat(place.attributes.getNamedItem('Lat').nodeValue));
+ newPlace.set_lng(parseFloat(place.attributes.getNamedItem('Lng').nodeValue));
+ }
+ if (place.attributes.getNamedItem('Constellation') != null) {
+ newPlace._constellation = place.attributes.getNamedItem('Constellation').nodeValue;
+ }
+ if (place.attributes.getNamedItem('Classification') != null) {
+ newPlace._classification = Enums.parse('Classification', place.attributes.getNamedItem('Classification').nodeValue);
+ }
+ if (place.attributes.getNamedItem('Magnitude') != null) {
+ newPlace._magnitude = parseFloat(place.attributes.getNamedItem('Magnitude').nodeValue);
+ }
+ if (place.attributes.getNamedItem('AngularSize') != null) {
+ newPlace.angularSize = parseFloat(place.attributes.getNamedItem('AngularSize').nodeValue);
+ }
+ if (place.attributes.getNamedItem('ZoomLevel') != null) {
+ newPlace.set_zoomLevel(parseFloat(place.attributes.getNamedItem('ZoomLevel').nodeValue));
+ }
+ if (place.attributes.getNamedItem('Rotation') != null) {
+ newPlace._camParams.rotation = parseFloat(place.attributes.getNamedItem('Rotation').nodeValue);
+ }
+ if (place.attributes.getNamedItem('Annotation') != null) {
+ newPlace.annotation = place.attributes.getNamedItem('Annotation').nodeValue;
+ }
+ if (place.attributes.getNamedItem('Angle') != null) {
+ newPlace._camParams.angle = parseFloat(place.attributes.getNamedItem('Angle').nodeValue);
+ }
+ if (place.attributes.getNamedItem('Opacity') != null) {
+ newPlace._camParams.opacity = parseFloat(place.attributes.getNamedItem('Opacity').nodeValue);
+ }
+ else {
+ newPlace._camParams.opacity = 100;
+ }
+ newPlace.set_target(65536);
+ if (place.attributes.getNamedItem('Target') != null) {
+ newPlace.set_target(Enums.parse('SolarSystemObjects', place.attributes.getNamedItem('Target').nodeValue));
+ }
+ if (place.attributes.getNamedItem('ViewTarget') != null) {
+ newPlace._camParams.viewTarget = Vector3d.parse(place.attributes.getNamedItem('ViewTarget').nodeValue);
+ }
+ if (place.attributes.getNamedItem('TargetReferenceFrame') != null) {
+ newPlace._camParams.targetReferenceFrame = place.attributes.getNamedItem('TargetReferenceFrame').nodeValue;
+ }
+ var descriptionNode = Util.selectSingleNode(place, 'Description');
+ if (descriptionNode != null) {
+ newPlace.htmlDescription = Util.getInnerText(descriptionNode);
+ }
+ var backgroundImageSet = Util.selectSingleNode(place, 'BackgroundImageSet');
+ if (backgroundImageSet != null) {
+ var imageSet = Util.selectSingleNode(backgroundImageSet, 'ImageSet');
+ newPlace._backgroundImageSet = Imageset.fromXMLNode(imageSet);
+ }
+ var study = Util.selectSingleNode(place, 'ForegroundImageSet');
+ if (study != null) {
+ var imageSet = Util.selectSingleNode(study, 'ImageSet');
+ newPlace._studyImageset = Imageset.fromXMLNode(imageSet);
+ }
+ study = Util.selectSingleNode(place, 'ImageSet');
+ if (study != null) {
+ newPlace._studyImageset = Imageset.fromXMLNode(study);
+ }
+ return newPlace;
+};
+
+Place._properCaps = function (name) {
+ var list = name.split(' ');
+ var ProperName = '';
+ var $enum1 = ss.enumerate(list);
+ while ($enum1.moveNext()) {
+ var part = $enum1.current;
+ ProperName = ProperName + part.substr(0, 1).toUpperCase() + ((part.length > 1) ? part.substr(1).toLowerCase() : '') + ' ';
+ }
+ return ss.trim(ProperName);
+};
+
+var Place$ = {
+ get_tag: function () {
+ return this._tag;
+ },
+
+ set_tag: function (value) {
+ this._tag = value;
+ return value;
+ },
+
+ get_url: function () {
+ return this._url;
+ },
+
+ set_url: function (value) {
+ this._url = value;
+ return value;
+ },
+
+ get_thumbnail: function () {
+ return this._thumbnail;
+ },
+
+ set_thumbnail: function (value) {
+ this._thumbnail = value;
+ return value;
+ },
+
+ get_name: function () {
+ return this.get_names()[0];
+ },
+
+ get_names: function () {
+ if (ss.emptyString(this._name)) {
+ return ''.split(';');
+ }
+ return this._name.split(';');
+ },
+
+ set_names: function (value) {
+ this._name = UiTools.getNamesStringFromArray(value);
+ return value;
+ },
+
+ get_camParams: function () {
+ if (this.get_classification() === 536870912 && this._camParams.target !== 20) {
+ var raDec = Planets.getPlanetLocation(this.get_name());
+ this._camParams.set_RA(raDec.RA);
+ this._camParams.set_dec(raDec.dec);
+ this._distnace = raDec.distance;
+ }
+ return this._camParams;
+ },
+
+ set_camParams: function (value) {
+ this._camParams = value;
+ return value;
+ },
+
+ updatePlanetLocation: function (jNow) {
+ this._camParams.viewTarget = Planets.getPlanet3dLocationJD(this.get_target(), jNow);
+ if (this.get_target() !== 65536 && this.get_target() !== 20) {
+ this._camParams.viewTarget = Planets.getPlanetTargetPoint(this.get_target(), this.get_lat(), this.get_lng(), jNow);
+ }
+ },
+
+ get_location3d: function () {
+ if (this.get_classification() === 536870912 || (!this._location3d.x && !this._location3d.y && !this._location3d.z)) {
+ this._location3d = Coordinates.raDecTo3d(this.get_RA(), this.get_dec());
+ }
+ return this._location3d;
+ },
+
+ get_lat: function () {
+ return this.get_camParams().lat;
+ },
+
+ set_lat: function (value) {
+ this._camParams.lat = value;
+ return value;
+ },
+
+ get_lng: function () {
+ return this.get_camParams().lng;
+ },
+
+ set_lng: function (value) {
+ this._camParams.lng = value;
+ return value;
+ },
+
+ get_opacity: function () {
+ return this.get_camParams().opacity;
+ },
+
+ set_opacity: function (value) {
+ this._camParams.opacity = value;
+ return value;
+ },
+
+ get_constellation: function () {
+ return this._constellation;
+ },
+
+ set_constellation: function (value) {
+ this._constellation = value;
+ return value;
+ },
+
+ get_classification: function () {
+ return this._classification;
+ },
+
+ set_classification: function (value) {
+ this._classification = value;
+ return value;
+ },
+
+ get_type: function () {
+ return this._type;
+ },
+
+ set_type: function (value) {
+ this._type = value;
+ return value;
+ },
+
+ get_magnitude: function () {
+ return this._magnitude;
+ },
+
+ set_magnitude: function (value) {
+ this._magnitude = value;
+ return value;
+ },
+
+ get_distance: function () {
+ return this._distnace;
+ },
+
+ set_distance: function (value) {
+ this._distnace = value;
+ return value;
+ },
+
+ get_zoomLevel: function () {
+ return this.get_camParams().zoom;
+ },
+
+ set_zoomLevel: function (value) {
+ this._camParams.zoom = value;
+ return value;
+ },
+
+ get_annotation: function () {
+ return this.annotation;
+ },
+
+ set_annotation: function (value) {
+ this.annotation = value;
+ return value;
+ },
+
+ get_studyImageset: function () {
+ return this._studyImageset;
+ },
+
+ set_studyImageset: function (value) {
+ this._studyImageset = value;
+ return value;
+ },
+
+ get_backgroundImageset: function () {
+ return this._backgroundImageSet;
+ },
+
+ set_backgroundImageset: function (value) {
+ if (value != null) {
+ this.set_type(value.get_dataSetType());
+ }
+ this._backgroundImageSet = value;
+ return value;
+ },
+
+ get_searchDistance: function () {
+ return this._searchDistance;
+ },
+
+ set_searchDistance: function (value) {
+ this._searchDistance = value;
+ return value;
+ },
+
+ get_elevation: function () {
+ return this._elevation;
+ },
+
+ set_elevation: function (value) {
+ this._elevation = value;
+ return value;
+ },
+
+ get_thumbnailUrl: function () {
+ if (ss.emptyString(this._thumbnailField)) {
+ if (this._studyImageset != null && !ss.emptyString(this._studyImageset.get_thumbnailUrl())) {
+ return this._studyImageset.get_thumbnailUrl();
+ }
+ if (this._backgroundImageSet != null && !ss.emptyString(this._backgroundImageSet.get_thumbnailUrl())) {
+ return this._backgroundImageSet.get_thumbnailUrl();
+ }
+ var name = this.get_name();
+ if (name.indexOf(';') > -1) {
+ name = name.substr(0, name.indexOf(';'));
+ }
+ if (this.get_classification() === 1 || freestandingMode) {
+ return URLHelpers.singleton.engineAssetUrl('thumb_star.jpg');
+ }
+ return URLHelpers.singleton.coreStaticUrl('wwtweb/thumbnail.aspx?name=' + name.toLowerCase());
+ }
+ return this._thumbnailField;
+ },
+
+ set_thumbnailUrl: function (value) {
+ this._thumbnailField = value;
+ return value;
+ },
+
+ get_RA: function () {
+ return this.get_camParams().get_RA();
+ },
+
+ set_RA: function (value) {
+ this._camParams.set_RA(value);
+ return value;
+ },
+
+ get_dec: function () {
+ return this.get_camParams().get_dec();
+ },
+
+ set_dec: function (value) {
+ this._camParams.set_dec(value);
+ return value;
+ },
+
+ toString: function () {
+ return this._name;
+ },
+
+ _saveToXml: function (xmlWriter, elementName) {
+ xmlWriter._writeStartElement(elementName);
+ xmlWriter._writeAttributeString('Name', this._name);
+ xmlWriter._writeAttributeString('DataSetType', Enums.toXml('ImageSetType', this._type));
+ if (this.get_type() === 2) {
+ xmlWriter._writeAttributeString('RA', this._camParams.get_RA().toString());
+ xmlWriter._writeAttributeString('Dec', this._camParams.get_dec().toString());
+ } else {
+ xmlWriter._writeAttributeString('Lat', this.get_lat().toString());
+ xmlWriter._writeAttributeString('Lng', this.get_lng().toString());
+ }
+ xmlWriter._writeAttributeString('Constellation', this._constellation);
+ xmlWriter._writeAttributeString('Classification', Enums.toXml('Classification', this._classification));
+ xmlWriter._writeAttributeString('Magnitude', this._magnitude.toString());
+ xmlWriter._writeAttributeString('Distance', this._distnace.toString());
+ xmlWriter._writeAttributeString('AngularSize', this.angularSize.toString());
+ xmlWriter._writeAttributeString('ZoomLevel', this.get_zoomLevel().toString());
+ xmlWriter._writeAttributeString('Rotation', this._camParams.rotation.toString());
+ xmlWriter._writeAttributeString('Angle', this._camParams.angle.toString());
+ xmlWriter._writeAttributeString('Opacity', this._camParams.opacity.toString());
+ xmlWriter._writeAttributeString('Target', Enums.toXml('SolarSystemObjects', this.get_target()));
+ xmlWriter._writeAttributeString('ViewTarget', this._camParams.viewTarget.toString());
+ xmlWriter._writeAttributeString('TargetReferenceFrame', this._camParams.targetReferenceFrame);
+ xmlWriter._writeStartElement('Description');
+ xmlWriter._writeCData(this.htmlDescription);
+ xmlWriter._writeEndElement();
+ if (this._backgroundImageSet != null) {
+ xmlWriter._writeStartElement('BackgroundImageSet');
+ Imageset.saveToXml(xmlWriter, this._backgroundImageSet, '');
+ xmlWriter._writeEndElement();
+ }
+ if (this._studyImageset != null) {
+ Imageset.saveToXml(xmlWriter, this._studyImageset, '');
+ }
+ xmlWriter._writeEndElement();
+ },
+
+ get_bounds: function () {
+ return this._bounds;
+ },
+
+ set_bounds: function (value) {
+ this._bounds = value;
+ return value;
+ },
+
+ get_isImage: function () {
+ return this._studyImageset != null || this._backgroundImageSet != null;
+ },
+
+ get_isTour: function () {
+ return false;
+ },
+
+ get_isFolder: function () {
+ return false;
+ },
+
+ get_children: function () {
+ return [];
+ },
+
+ get_readOnly: function () {
+ return true;
+ },
+
+ get_target: function () {
+ return this._camParams.target;
+ },
+
+ set_target: function (value) {
+ this._camParams.target = value;
+ return value;
+ },
+
+ get_isCloudCommunityItem: function () {
+ return false;
+ }
+};
+
+registerType("Place", [Place, Place$, null, IThumbnail, IPlace]);
+
+set_createPlace(Place.create);
diff --git a/engine/esm/planets.js b/engine/esm/planets.js
new file mode 100644
index 00000000..099b08b2
--- /dev/null
+++ b/engine/esm/planets.js
@@ -0,0 +1,1033 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// The main planet-related code.
+//
+// This does not include the 3D planet-rendering code, which has been separated
+// into `planets_3d.js`.
+
+import { ss } from "./ss.js";
+import { registerType } from "./typesystem.js";
+import { Vector3d, Matrix3d, PositionColoredTextured } from "./double3d.js";
+import { CAAEarth } from "./astrocalc/earth.js";
+import { CAAMercury } from "./astrocalc/mercury.js";
+import { CAAVenus } from "./astrocalc/venus.js";
+import { CAAMars } from "./astrocalc/mars.js";
+import { CAAJupiter } from "./astrocalc/jupiter.js";
+import { CAASaturn } from "./astrocalc/saturn.js";
+import { CAAUranus } from "./astrocalc/uranus.js";
+import { CAANeptune } from "./astrocalc/neptune.js";
+import { CAAPluto } from "./astrocalc/pluto.js";
+import { GM } from "./astrocalc/galilean_moons.js";
+import { CAAMoon } from "./astrocalc/moon.js";
+import { AstroCalc } from "./astrocalc.js";
+import { Texture } from "./graphics/texture.js";
+import { Sprite2d } from "./graphics/sprite2d.js";
+import { BasePlanets } from "./baseplanets.js";
+import { SolarSystemObjects } from "./camera_parameters.js";
+import { Color, Colors } from "./color.js";
+import { Coordinates } from "./coordinates.js";
+import { Settings } from "./settings.js";
+import { SpaceTimeController } from "./space_time_controller.js";
+import { URLHelpers } from "./url_helpers.js";
+
+
+// wwtlib.KeplerianElements
+//
+// Keplerian elements defined here use eccentric anomaly instead of mean anomaly
+// and have all orbital plane angles converted to a rotation matrix.
+export function KeplerianElements() {
+ this.a = 0;
+ this.e = 0;
+ this.ea = 0;
+}
+
+var KeplerianElements$ = {};
+
+registerType("KeplerianElements", [KeplerianElements, KeplerianElements$, null]);
+
+
+// wwtlib.BodyAngles
+
+export function BodyAngles(poleRa, poleDec, primeMeridian, rotationRate) {
+ this.poleDec = 0;
+ this.poleRa = 0;
+ this.primeMeridian = 0;
+ this.rotationRate = 0;
+ this.poleDec = poleDec;
+ this.poleRa = poleRa;
+ this.primeMeridian = primeMeridian;
+ this.rotationRate = rotationRate;
+}
+
+var BodyAngles$ = {};
+
+registerType("BodyAngles", [BodyAngles, BodyAngles$, null]);
+
+
+// wwtlib.Planets
+
+export function Planets() { }
+
+Planets.RC = (Math.PI / 180);
+Planets._jNow = 0;
+
+// Values taken from version 10 of the SPICE planetary constants file, updated
+// October 21, 2011: ftp://naif.jpl.nasa.gov/pub/naif/generic_kernels/pck/pck00010.tpc
+//
+// Precession rates for rotation angles are currently not stored.
+//
+// All angles are in degrees.
+Planets._planetAngles = [
+ new BodyAngles(286.13, 63.87, 84.176, 14.1844),
+ new BodyAngles(281.0097, 61.4143, 329.548, 6.1385025),
+ new BodyAngles(272.76, 67.16, 160.2, -1.4813688),
+ new BodyAngles(317.68143, 52.8865, 176.63, 350.89198226),
+ new BodyAngles(268.056595, 64.495303, 284.95, 870.536),
+ new BodyAngles(40.589, 83.537, 38.9, 810.7939024),
+ new BodyAngles(257.311, -15.175, 203.81, 501.1600928),
+ new BodyAngles(299.36, 43.46, 253.18, 536.3128492),
+ new BodyAngles(132.993, -6.163, 302.695, 56.3625225),
+ new BodyAngles(269.9949, 66.5392, 38.3213, 13.17635815),
+ new BodyAngles(268.05, 64.5, 200.39, 203.4889538),
+ new BodyAngles(268.08, 64.51, 36.022, 101.3747235),
+ new BodyAngles(268.2, 64.57, 44.064, 50.3176081),
+ new BodyAngles(268.72, 64.83, 259.51, 21.5710715),
+ new BodyAngles(0, 0, 0, 0),
+ new BodyAngles(0, 0, 0, 0),
+ new BodyAngles(0, 0, 0, 0),
+ new BodyAngles(0, 0, 0, 0),
+ new BodyAngles(0, 0, 0, 0),
+ new BodyAngles(0, 90, 190.147, 360.9856235)
+];
+Planets._lastPlanetCenterID = -2;
+Planets._orbitalSampleRate = 256;
+Planets._obliquity = 23.5 * Planets.RC;
+Planets._drawOrder = {};
+Planets.earthMatrix = new Matrix3d();
+Planets.earthMatrixInv = new Matrix3d();
+Planets._lastUpdate = new Date();
+Planets._planetSprite = new Sprite2d();
+Planets._planetPoints = null;
+Planets._planet3dLocations = null;
+
+// This function is equivalent to `Texture.from_url` and not specific to the
+// Planets infrastructure at all. It should go away. But at the moment, we
+// preserve it so as not to break API.
+Planets.loadPlanetTexture = function (url) {
+ var texture = new Texture();
+ texture.load(url);
+ return texture;
+};
+
+Planets.getPlanet3dLocation = function (target) {
+ try {
+ if (target < 21) {
+ return Planets._planet3dLocations[target].copy();
+ }
+ }
+ catch ($e1) { }
+ return Vector3d.create(0, 0, 0);
+};
+
+Planets.getPlanet3dSufaceAltitude = function (target) {
+ try {
+ if (target < 21) {
+ return Planets.getAdjustedPlanetRadius(target);
+ }
+ }
+ catch ($e1) { }
+ return 0;
+};
+
+Planets.getPlanetTargetPoint = function (target, lat, lng, jNow) {
+ var temp;
+ if (!jNow) {
+ temp = Planets.getPlanet3dLocation(target);
+ }
+ else {
+ temp = Planets.getPlanet3dLocationJD(target, jNow);
+ }
+ temp.add(Coordinates.raDecTo3dAu((lng / 15) + 6, lat, Planets.getPlanet3dSufaceAltitude(target)));
+ return temp;
+};
+
+Planets.getPlanet3dLocationJD = function (target, jNow) {
+ try {
+ var result = new Vector3d();
+ var centerRaDec = AstroCalc.getPlanet(jNow, 0, 0, 0, -6378149);
+ var center = Coordinates.raDecTo3dAu(centerRaDec.RA, centerRaDec.dec, centerRaDec.distance);
+ if (target === SolarSystemObjects.earth) {
+ result = Vector3d.create(-center.x, -center.y, -center.z);
+ } else {
+ var planet = AstroCalc.getPlanet(jNow, target, 0, 0, -6378149);
+ result = Coordinates.raDecTo3dAu(planet.RA, planet.dec, planet.distance);
+ result.subtract(center);
+ }
+ result.rotateX(Coordinates.meanObliquityOfEcliptic(jNow) * Planets.RC);
+ if (Settings.get_active().get_solarSystemScale() !== 1) {
+ switch (target) {
+ case SolarSystemObjects.moon:
+ var parent = Planets.getPlanet3dLocationJD(SolarSystemObjects.earth, jNow);
+ result.subtract(parent);
+ result.multiply(Settings.get_active().get_solarSystemScale() / 2);
+ result.add(parent);
+ break;
+ case SolarSystemObjects.io:
+ case SolarSystemObjects.europa:
+ case SolarSystemObjects.ganymede:
+ case SolarSystemObjects.callisto:
+ var parent = Planets.getPlanet3dLocationJD(SolarSystemObjects.jupiter, jNow);
+ result.subtract(parent);
+ result.multiply(Settings.get_active().get_solarSystemScale());
+ result.add(parent);
+ break;
+ default:
+ break;
+ }
+ }
+ return result;
+ }
+ catch ($e1) {
+ return Vector3d.create(0, 0, 0);
+ }
+};
+
+Planets.getPlanetLocation = function (name) {
+ var id = Planets.getPlanetIDFromName(name);
+ if (Planets._planetLocations != null) {
+ return Planets._planetLocations[id];
+ }
+ else {
+ return AstroCalc.getPlanet(SpaceTimeController.get_jNow(), id, SpaceTimeController.get_location().get_lat(), SpaceTimeController.get_location().get_lng(), SpaceTimeController.get_altitude());
+ }
+};
+
+Planets.getPlanetLocationJD = function (name, jNow) {
+ var id = Planets.getPlanetIDFromName(name);
+ return AstroCalc.getPlanet(jNow, id, SpaceTimeController.get_location().get_lat(), SpaceTimeController.get_location().get_lng(), SpaceTimeController.get_altitude());
+};
+
+Planets.getPlanetIDFromName = function (planetName) {
+ switch (planetName) {
+ case 'Sun':
+ return SolarSystemObjects.sun;
+ case 'Mercury':
+ return SolarSystemObjects.mercury;
+ case 'Venus':
+ return SolarSystemObjects.venus;
+ case 'Mars':
+ return SolarSystemObjects.mars;
+ case 'Jupiter':
+ return SolarSystemObjects.jupiter;
+ case 'Saturn':
+ return SolarSystemObjects.saturn;
+ case 'Uranus':
+ return SolarSystemObjects.uranus;
+ case 'Neptune':
+ return SolarSystemObjects.neptune;
+ case 'Pluto':
+ return SolarSystemObjects.pluto;
+ case 'Moon':
+ return SolarSystemObjects.moon;
+ case 'Io':
+ return SolarSystemObjects.io;
+ case 'Europa':
+ return SolarSystemObjects.europa;
+ case 'Ganymede':
+ return SolarSystemObjects.ganymede;
+ case 'Callisto':
+ return SolarSystemObjects.callisto;
+ case 'Earth':
+ return SolarSystemObjects.earth;
+ case 'IoShadow':
+ return SolarSystemObjects.ioShadow;
+ case 'EuropaShadow':
+ return SolarSystemObjects.europaShadow;
+ case 'GanymedeShadow':
+ return SolarSystemObjects.ganymedeShadow;
+ case 'CallistoShadow':
+ return SolarSystemObjects.callistoShadow;
+ case 'SunEclipsed':
+ return SolarSystemObjects.sunEclipsed;
+ case 'Custom':
+ return SolarSystemObjects.custom;
+ case 'Undefined':
+ return SolarSystemObjects.undefined;
+ default:
+ return -1;
+ }
+};
+
+Planets.getNameFrom3dId = function (id) {
+ switch (id) {
+ case SolarSystemObjects.sun:
+ return 'Sun';
+ case SolarSystemObjects.mercury:
+ return 'Mercury';
+ case SolarSystemObjects.venus:
+ return 'Venus';
+ case SolarSystemObjects.mars:
+ return 'Mars';
+ case SolarSystemObjects.jupiter:
+ return 'Jupiter';
+ case SolarSystemObjects.saturn:
+ return 'Saturn';
+ case SolarSystemObjects.uranus:
+ return 'Uranus';
+ case SolarSystemObjects.neptune:
+ return 'Neptune';
+ case SolarSystemObjects.pluto:
+ return 'Pluto';
+ case SolarSystemObjects.moon:
+ return 'Moon';
+ case SolarSystemObjects.io:
+ return 'Io';
+ case SolarSystemObjects.europa:
+ return 'Europa';
+ case SolarSystemObjects.ganymede:
+ return 'Ganymede';
+ case SolarSystemObjects.callisto:
+ return 'Callisto';
+ case SolarSystemObjects.earth:
+ return 'Earth';
+ default:
+ return '';
+ }
+};
+
+Planets.updatePlanetLocations = function (threeDee) {
+ Planets._jNow = SpaceTimeController.get_jNow();
+ if (threeDee) {
+ Planets.updateOrbits(0);
+ }
+ if (Planets._planetDiameters == null) {
+ Planets._planetDiameters = new Array(20);
+ Planets._planetDiameters[0] = 0.009291568;
+ Planets._planetDiameters[1] = 3.25794793734425E-05;
+ Planets._planetDiameters[2] = 8.08669220531394E-05;
+ Planets._planetDiameters[3] = 4.53785605596396E-05;
+ Planets._planetDiameters[4] = 0.000954501;
+ Planets._planetDiameters[5] = 0.000802173;
+ Planets._planetDiameters[6] = 0.000339564;
+ Planets._planetDiameters[7] = 0.000324825;
+ Planets._planetDiameters[8] = 1.52007379777805E-05;
+ Planets._planetDiameters[9] = 2.32084653538149E-05;
+ Planets._planetDiameters[10] = 2.43519298386342E-05;
+ Planets._planetDiameters[11] = 2.08692629580609E-05;
+ Planets._planetDiameters[12] = 3.51742670356556E-05;
+ Planets._planetDiameters[13] = 3.22263666626559E-05;
+ Planets._planetDiameters[14] = 2.43519298386342E-05;
+ Planets._planetDiameters[15] = 2.08692629580609E-05;
+ Planets._planetDiameters[16] = 3.51742670356556E-05;
+ Planets._planetDiameters[17] = 3.22263666626559E-05;
+ Planets._planetDiameters[18] = 0.009291568 * 2;
+ Planets._planetDiameters[SolarSystemObjects.earth] = 8.55626412117809E-05;
+ }
+ if (Planets.planetColors == null) {
+ var lightYellow = Color.fromArgb(255, 255, 255, 221);
+ var orangeRed = Color.fromArgb(255, 255, 68, 0);
+ Planets.planetColors = new Array(20);
+ Planets.planetColors[0] = Colors.get_yellow();
+ Planets.planetColors[1] = Colors.get_white();
+ Planets.planetColors[2] = lightYellow;
+ Planets.planetColors[3] = orangeRed;
+ Planets.planetColors[4] = Color.fromArgb(255, 255, 165, 0);
+ Planets.planetColors[5] = Color.fromArgb(255, 184, 134, 11);
+ Planets.planetColors[6] = Color.fromArgb(255, 173, 216, 230);
+ Planets.planetColors[7] = Colors.get_blue();
+ Planets.planetColors[8] = Colors.get_white();
+ Planets.planetColors[9] = Colors.get_white();
+ Planets.planetColors[10] = Colors.get_white();
+ Planets.planetColors[11] = Colors.get_white();
+ Planets.planetColors[12] = Colors.get_white();
+ Planets.planetColors[13] = Colors.get_white();
+ Planets.planetColors[14] = Colors.get_black();
+ Planets.planetColors[15] = Colors.get_black();
+ Planets.planetColors[16] = Colors.get_black();
+ Planets.planetColors[17] = Colors.get_black();
+ Planets.planetColors[18] = Colors.get_white();
+ Planets.planetColors[SolarSystemObjects.earth] = Color.fromArgb(255, 173, 216, 230);
+ }
+ if (Planets._planetTilts == null) {
+ Planets._planetTilts = new Array(20);
+ Planets._planetTilts[0] = 0;
+ Planets._planetTilts[1] = 0.01;
+ Planets._planetTilts[2] = 177.4;
+ Planets._planetTilts[3] = 25.19;
+ Planets._planetTilts[4] = 3.13;
+ Planets._planetTilts[5] = 26.73;
+ Planets._planetTilts[6] = 97.77;
+ Planets._planetTilts[7] = 28.32;
+ Planets._planetTilts[8] = 119.61;
+ Planets._planetTilts[9] = 23.439;
+ Planets._planetTilts[10] = 2.21;
+ Planets._planetTilts[11] = 0;
+ Planets._planetTilts[12] = -0.33;
+ Planets._planetTilts[13] = 0;
+ Planets._planetTilts[14] = 0;
+ Planets._planetTilts[15] = 0;
+ Planets._planetTilts[16] = 0;
+ Planets._planetTilts[17] = 0;
+ Planets._planetTilts[18] = 0;
+ Planets._planetTilts[SolarSystemObjects.earth] = 23.5;
+ }
+ Planets._planetTilts[SolarSystemObjects.earth] = Planets._obliquity / Planets.RC;
+ if (Planets.planetRotationPeriod == null) {
+ Planets.planetRotationPeriod = new Array(20);
+ Planets.planetRotationPeriod[0] = 25.37995;
+ Planets.planetRotationPeriod[1] = 58.6462;
+ Planets.planetRotationPeriod[2] = -243.0187;
+ Planets.planetRotationPeriod[3] = 1.02595675;
+ Planets.planetRotationPeriod[4] = 0.41007;
+ Planets.planetRotationPeriod[5] = 0.426;
+ Planets.planetRotationPeriod[6] = -0.71833;
+ Planets.planetRotationPeriod[7] = 0.67125;
+ Planets.planetRotationPeriod[8] = -6.38718;
+ Planets.planetRotationPeriod[9] = 27.3;
+ Planets.planetRotationPeriod[10] = 1.769137786;
+ Planets.planetRotationPeriod[11] = 3.551;
+ Planets.planetRotationPeriod[12] = 7.155;
+ Planets.planetRotationPeriod[13] = 16.69;
+ Planets.planetRotationPeriod[14] = 0;
+ Planets.planetRotationPeriod[15] = 0;
+ Planets.planetRotationPeriod[16] = 0;
+ Planets.planetRotationPeriod[17] = 0;
+ Planets.planetRotationPeriod[18] = 0;
+ Planets.planetRotationPeriod[SolarSystemObjects.earth] = 0.99726968;
+ }
+ if (Planets._planetScales == null) {
+ Planets._planetScales = new Array(20);
+ }
+ if (Planets._planet3dLocations == null) {
+ Planets._planet3dLocations = new Array(20);
+ }
+ if (Settings.get_active().get_actualPlanetScale()) {
+ Planets._planetScales[0] = 0.5;
+ Planets._planetScales[1] = 0.25;
+ Planets._planetScales[2] = 0.25;
+ Planets._planetScales[3] = 0.25;
+ Planets._planetScales[4] = 0.25;
+ Planets._planetScales[5] = 0.5;
+ Planets._planetScales[6] = 0.25;
+ Planets._planetScales[7] = 0.25;
+ Planets._planetScales[8] = 0.25;
+ Planets._planetScales[9] = 0.25;
+ Planets._planetScales[10] = 0.25;
+ Planets._planetScales[11] = 0.25;
+ Planets._planetScales[12] = 0.25;
+ Planets._planetScales[13] = 0.25;
+ Planets._planetScales[14] = 0.25;
+ Planets._planetScales[15] = 0.25;
+ Planets._planetScales[16] = 0.25;
+ Planets._planetScales[17] = 0.25;
+ Planets._planetScales[18] = 0.5;
+ Planets._planetScales[SolarSystemObjects.earth] = 0.25;
+ }
+ else {
+ for (var i = 0; i < 20; i++) {
+ if (i < 10) {
+ Planets._planetScales[i] = 0.25;
+ }
+ else {
+ Planets._planetScales[i] = 0.1;
+ }
+ }
+
+ // Make Sun and Saturn bigger
+ Planets._planetScales[SolarSystemObjects.sun] = 0.5;
+ Planets._planetScales[SolarSystemObjects.saturn] = 0.5;
+ Planets._planetScales[SolarSystemObjects.sunEclipsed] = 0.5;
+ }
+ Planets._planetDrawOrder = {};
+ Planets._planetLocations = new Array(20);
+ var center = new Vector3d();
+ var planetCenter = 0;
+ if (planetCenter > -1) {
+ var centerRaDec = AstroCalc.getPlanet(Planets._jNow, planetCenter, (threeDee) ? 0 : SpaceTimeController.get_location().get_lat(), (threeDee) ? 0 : SpaceTimeController.get_location().get_lng(), (threeDee) ? -6378149 : SpaceTimeController.get_altitude());
+ center = Coordinates.raDecTo3dAu(centerRaDec.RA, centerRaDec.dec, centerRaDec.distance);
+ }
+ Planets._planet3dLocations[SolarSystemObjects.earth] = Vector3d.create(-center.x, -center.y, -center.z);
+ Planets._planet3dLocations[SolarSystemObjects.earth].rotateX(Planets._obliquity);
+ for (var i = 0; i < 18; i++) {
+ Planets._planetLocations[i] = AstroCalc.getPlanet(Planets._jNow, i, (threeDee) ? 0 : SpaceTimeController.get_location().get_lat(), (threeDee) ? 0 : SpaceTimeController.get_location().get_lng(), (threeDee) ? -6378149 : SpaceTimeController.get_altitude());
+ Planets._planet3dLocations[i] = Coordinates.raDecTo3dAu(Planets._planetLocations[i].RA, Planets._planetLocations[i].dec, Planets._planetLocations[i].distance);
+ Planets._planet3dLocations[i].subtract(center);
+ Planets._planet3dLocations[i].rotateX(Planets._obliquity);
+ if (Settings.get_active().get_actualPlanetScale()) {
+ Planets._planetScales[i] = (2 * Math.atan(0.5 * (Planets._planetDiameters[i] / Planets._planetLocations[i].distance))) / Math.PI * 180;
+ }
+ if (Settings.get_active().get_solarSystemScale() !== 1) {
+ var id = i;
+ switch (id) {
+ case SolarSystemObjects.moon:
+ var parent = Planets._planet3dLocations[SolarSystemObjects.earth];
+ Planets._planet3dLocations[i].subtract(parent);
+ Planets._planet3dLocations[i].multiply(Settings.get_active().get_solarSystemScale() / 2);
+ Planets._planet3dLocations[i].add(parent);
+ break;
+ case SolarSystemObjects.io:
+ case SolarSystemObjects.europa:
+ case SolarSystemObjects.ganymede:
+ case SolarSystemObjects.callisto:
+ var parent = Planets._planet3dLocations[SolarSystemObjects.jupiter];
+ Planets._planet3dLocations[i].subtract(parent);
+ Planets._planet3dLocations[i].multiply(Settings.get_active().get_solarSystemScale());
+ Planets._planet3dLocations[i].add(parent);
+ break;
+ default:
+ break;
+ }
+ }
+ var finalDistance = -Planets._planetLocations[i].distance;
+ while (ss.keyExists(Planets._planetDrawOrder, finalDistance)) {
+ finalDistance += 1E-10;
+ }
+ Planets._planetDrawOrder[finalDistance] = i;
+ }
+ Planets._planetLocations[SolarSystemObjects.sunEclipsed] = Planets._planetLocations[SolarSystemObjects.sun];
+ Planets._planetScales[SolarSystemObjects.sun] *= 2;
+ Planets._planetScales[SolarSystemObjects.sunEclipsed] = Planets._planetScales[SolarSystemObjects.sun];
+ Planets._planetScales[SolarSystemObjects.saturn] = Planets._planetScales[SolarSystemObjects.saturn] * 2;
+ Planets._lastUpdate = SpaceTimeController.get_now();
+};
+
+Planets.planetsReady = function () { };
+
+Planets.updateOrbits = function (planetCenter) {
+ try {
+ Planets._obliquity = Coordinates.meanObliquityOfEcliptic(SpaceTimeController.get_jNow()) * Planets.RC;
+ if (planetCenter !== Planets._lastPlanetCenterID) {
+ Planets._orbits = null;
+ }
+ Planets._lastPlanetCenterID = planetCenter;
+ if (Planets._orbits == null) {
+ if (planetCenter < 0) {
+ Planets._eclipticTilt = Matrix3d.get_identity();
+ }
+ else {
+ Planets._eclipticTilt = Matrix3d.get_identity();
+ Planets._eclipticTilt = Matrix3d._rotationX(Planets._obliquity);
+ }
+ if (Planets.planetOrbitalYears == null) {
+ Planets.planetOrbitalYears = new Array(20);
+ Planets.planetOrbitalYears[0] = 1;
+ Planets.planetOrbitalYears[1] = 0.241;
+ Planets.planetOrbitalYears[2] = 0.615;
+ Planets.planetOrbitalYears[3] = 1.881;
+ Planets.planetOrbitalYears[4] = 11.87;
+ Planets.planetOrbitalYears[5] = 29.45;
+ Planets.planetOrbitalYears[6] = 84.07;
+ Planets.planetOrbitalYears[7] = 164.9;
+ Planets.planetOrbitalYears[8] = 248.1;
+ Planets.planetOrbitalYears[9] = 27.3 / 365.25;
+ Planets.planetOrbitalYears[10] = 16.6890184 / 365.25;
+ Planets.planetOrbitalYears[11] = 3.551181 / 365.25;
+ Planets.planetOrbitalYears[12] = 7.15455296 / 365.25;
+ Planets.planetOrbitalYears[13] = 16.6890184 / 365.25;
+ Planets.planetOrbitalYears[SolarSystemObjects.earth] = 1;
+ }
+ if (!Planets.readOrbits()) {
+ Planets._orbits = new Array(20);
+ for (var i = 1; i < 20; i++) {
+ Planets._orbits[i] = new Array(Planets._orbitalSampleRate);
+ if (i < 9 || i === SolarSystemObjects.earth) {
+ for (var j = 0; j < Planets._orbitalSampleRate; j++) {
+ var centerId = planetCenter;
+ var now = Planets._jNow + ((Planets.planetOrbitalYears[i] * 365.25 / Planets._orbitalSampleRate) * (j - (Planets._orbitalSampleRate / 2)));
+ var center = new Vector3d();
+ if (i === SolarSystemObjects.moone) {
+ centerId = -1;
+ }
+ else if (i > 9 && i < 14) {
+ centerId = 4;
+ }
+ if (centerId > -1) {
+ var centerRaDec = AstroCalc.getPlanet(now, centerId, 0, 0, -6378149);
+ center = Coordinates.raDecTo3dAu(centerRaDec.RA, centerRaDec.dec, centerRaDec.distance);
+ }
+ if (i !== SolarSystemObjects.earth) {
+ var planetRaDec = AstroCalc.getPlanet(now, i, 0, 0, -6378149);
+ Planets._orbits[i][j] = Coordinates.raDecTo3dAu(planetRaDec.RA, planetRaDec.dec, planetRaDec.distance);
+ Planets._orbits[i][j].subtract(center);
+ }
+ else {
+ Planets._orbits[i][j] = Vector3d.create(-center.x, -center.y, -center.z);
+ }
+ Planets._orbits[i][j].rotateX(Planets._obliquity);
+ }
+ Planets._orbits[i][Planets._orbitalSampleRate - 1] = Planets._orbits[i][0];
+ }
+ }
+ Planets.dumpOrbitsFile();
+ }
+ }
+ }
+ finally { }
+};
+
+Planets.readOrbits = function () {
+ // This function ought to fetch wwtweb/catalog.aspx?Q=orbitsbin and set
+ // `orbits`, see Windows client code.
+ return false;
+};
+
+Planets.dumpOrbitsFile = function () { };
+
+Planets.drawPlanets = function (renderContext, opacity) {
+ if (Planets._planetTextures == null) {
+ Planets._loadPlanetTextures();
+ }
+
+ // Get Moon Phase
+
+ var elong = Planets._geocentricElongation(Planets._planetLocations[9].RA, Planets._planetLocations[9].dec, Planets._planetLocations[0].RA, Planets._planetLocations[0].dec);
+ var raDif = Planets._planetLocations[9].RA - Planets._planetLocations[0].RA;
+ if (Planets._planetLocations[9].RA < Planets._planetLocations[0].RA) {
+ raDif += 24;
+ }
+ var phaseAngle = Planets._phaseAngle(elong, Planets._planetLocations[9].distance, Planets._planetLocations[0].distance);
+ var limbAngle = Planets._positionAngle(Planets._planetLocations[9].RA, Planets._planetLocations[9].dec, Planets._planetLocations[0].RA, Planets._planetLocations[0].dec);
+ if (raDif < 12) {
+ phaseAngle += 180;
+ }
+
+ // Check for solar eclipse
+
+ var dista = (Math.abs(Planets._planetLocations[9].RA - Planets._planetLocations[0].RA) * 15) * Math.cos(Coordinates.degreesToRadians(Planets._planetLocations[0].dec));
+ var distb = Math.abs(Planets._planetLocations[9].dec - Planets._planetLocations[0].dec);
+ var sunMoonDist = Math.sqrt(dista * dista + distb * distb);
+ var eclipse = false;
+ var coronaOpacity = 0;
+ var moonEffect = (Planets._planetScales[9] / 2 - sunMoonDist);
+ var darkLimb = Math.min(32, ss.truncate((sunMoonDist * 32)));
+ if (moonEffect > (Planets._planetScales[0] / 4)) {
+ eclipse = true;
+ coronaOpacity = Math.min(1, (moonEffect - (Planets._planetScales[0] / 2)) / 0.001);
+ Planets._drawPlanet(renderContext, 18, coronaOpacity);
+ }
+ var $enum1 = ss.enumerate(ss.keys(Planets._planetDrawOrder));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var planetId = Planets._planetDrawOrder[key];
+ Planets._drawPlanet(renderContext, planetId, 1);
+ }
+ return true;
+};
+
+Planets._loadPlanetTextures = function () {
+ // Note: these PNG files are fairly large and are loaded at
+ // startup of the web client, adding nontrivially to the needed
+ // network traffic. JPGs are a lot smaller, but unfortunately the
+ // transparency support is important here since we don't want
+ // black boxes surrounding all of our planets when they're viewed
+ // in the sky.
+
+ var baseUrl = URLHelpers.singleton.engineAssetUrl('');
+
+ Planets._planetTextures = new Array(20);
+ Planets._planetTextures[0] = Texture.fromUrl(baseUrl + 'sun.png');
+ Planets._planetTextures[1] = Texture.fromUrl(baseUrl + 'mercury.png');
+ Planets._planetTextures[2] = Texture.fromUrl(baseUrl + 'venus.png');
+ Planets._planetTextures[3] = Texture.fromUrl(baseUrl + 'mars.png');
+ Planets._planetTextures[4] = Texture.fromUrl(baseUrl + 'jupiter.png');
+ Planets._planetTextures[5] = Texture.fromUrl(baseUrl + 'saturn.png');
+ Planets._planetTextures[6] = Texture.fromUrl(baseUrl + 'uranus.png');
+ Planets._planetTextures[7] = Texture.fromUrl(baseUrl + 'neptune.png');
+ Planets._planetTextures[8] = Texture.fromUrl(baseUrl + 'pluto.png');
+ Planets._planetTextures[9] = Texture.fromUrl(baseUrl + 'moon.png');
+ Planets._planetTextures[10] = Texture.fromUrl(baseUrl + 'io.png');
+ Planets._planetTextures[11] = Texture.fromUrl(baseUrl + 'europa.png');
+ Planets._planetTextures[12] = Texture.fromUrl(baseUrl + 'ganymede.png');
+ Planets._planetTextures[13] = Texture.fromUrl(baseUrl + 'callisto.png');
+ Planets._planetTextures[14] = Texture.fromUrl(baseUrl + 'moonshadow.png');
+ Planets._planetTextures[15] = Texture.fromUrl(baseUrl + 'moonshadow.png');
+ Planets._planetTextures[16] = Texture.fromUrl(baseUrl + 'moonshadow.png');
+ Planets._planetTextures[17] = Texture.fromUrl(baseUrl + 'moonshadow.png');
+ Planets._planetTextures[18] = Texture.fromUrl(baseUrl + 'sunCorona.png');
+ Planets._planetTextures[SolarSystemObjects.earth] = Texture.fromUrl(baseUrl + 'earth.png');
+};
+
+// Compute the rotation of a planet at the J2000 epoch.
+//
+// The rotation at some instant in can be computed by multiplying the
+// the returned matrix by Y(W * t)
+Planets.getPlanetOrientationAtEpoch = function (planetID) {
+ var m = Matrix3d.get_identity();
+
+ // Rotational elements for the planets are in the form used by the
+ // IAU Working Group on Cartographic Coordinates and Rotational Elements:
+ //
+ // a : Right ascension of north pole
+ // d : Declination of north pole
+ // W0 : Prime meridian angle at epoch J2000.0
+ //
+ // The canonical Euler angle sequence is: Z(a - 90) * X(90 - d) * Z(W0)
+ //
+ // The following transformations are required to convert it to a rotation for WWT:
+ // * WWT uses a coordinate system with +Y = ecliptic north, +X = equinox of J2000
+ // This system is rotated 90 degrees about the X axis from the standard ecliptic
+ // system based on the Earth Mean Equinox of J2000 (EMEJ2000)
+ // * WWT uses row vectors instead of column vectors, so the order of transformations
+ // is reversed
+ // * WWT has planet maps with longitude 0 at the edge rather than the middle. This
+ // requires an extra 180 degrees to be added to W0
+ var obliquityOfEcliptic = 23.4392794;
+
+ if (planetID === SolarSystemObjects.earth) {
+ // Different calculation for Earth, since the meridian offset
+ // is already included in the Mean Sidereal Time function.
+ //
+ // equatorial to ecliptic transformation
+ m._multiply(Matrix3d._rotationX(obliquityOfEcliptic * Planets.RC));
+ } else {
+ // 90 degree rotation from WWT coord sys
+ m._multiply(Matrix3d._rotationX(-90 * Planets.RC));
+
+ m._multiply(Matrix3d._rotationZ((180 + Planets._planetAngles[planetID].primeMeridian) * Planets.RC));
+ m._multiply(Matrix3d._rotationX((90 - Planets._planetAngles[planetID].poleDec) * Planets.RC));
+ m._multiply(Matrix3d._rotationZ((Planets._planetAngles[planetID].poleRa - 90) * Planets.RC));
+ m._multiply(Matrix3d._rotationX(obliquityOfEcliptic * Planets.RC)); // equatorial to ecliptic transformation
+
+ // 90 degree rotation back to WWT coord sys
+ m._multiply(Matrix3d._rotationX(90 * Planets.RC));
+ }
+ return m;
+};
+
+Planets.setupPlanetMatrix = function (renderContext, planetID, centerPoint, makeFrustum) {
+ var matNonRotating = renderContext.get_world().clone();
+ Planets._setupMatrixForPlanetGeometry(renderContext, planetID, centerPoint, makeFrustum);
+
+ if (planetID === SolarSystemObjects.sun) {
+ // Don't apply the Sun's orientation to its non-rotating frame; this means that
+ // the Sun's reference frame will be the ecliptic frame.
+ var radius = Planets.getAdjustedPlanetRadius(planetID);
+ matNonRotating.scale(Vector3d.create(radius, radius, radius));
+ var translation = Vector3d.subtractVectors(Planets._planet3dLocations[planetID], centerPoint);
+ matNonRotating._multiply(Matrix3d.translation(translation));
+ renderContext.set_worldBaseNonRotating(matNonRotating);
+ }
+};
+
+Planets._setupMatrixForPlanetGeometry = function (renderContext, planetID, centerPoint, makeFrustum) {
+ var radius = Planets.getAdjustedPlanetRadius(planetID);
+ var rotationCurrent = 0;
+ if (planetID === SolarSystemObjects.earth) {
+ rotationCurrent = Math.PI + Coordinates.mstFromUTC2(SpaceTimeController.get_now(), 0) / 180 * Math.PI;
+ }
+ else {
+ rotationCurrent = Math.PI + (((Planets._jNow - 2451545) / Planets.planetRotationPeriod[planetID]) * Math.PI * 2) % (Math.PI * 2);
+ }
+ if (planetID === 9) {
+ rotationCurrent -= Math.PI / 2;
+ }
+ var matLocal = renderContext.get_world().clone();
+ var matNonRotating = renderContext.get_world().clone();
+ var translation = Vector3d.subtractVectors(Planets._planet3dLocations[planetID], centerPoint);
+ var orientationAtEpoch = Planets.getPlanetOrientationAtEpoch(planetID);
+ matLocal.scale(Vector3d.create(radius, radius, radius));
+ matLocal._multiply(Matrix3d._rotationY(-rotationCurrent));
+ matLocal._multiply(orientationAtEpoch);
+ if (planetID === renderContext.viewCamera.target) {
+ Planets.earthMatrix = Matrix3d.get_identity();
+ Planets.earthMatrix._multiply(Matrix3d._rotationY(-rotationCurrent));
+ Planets.earthMatrix._multiply(orientationAtEpoch);
+ Planets.earthMatrixInv = Planets.earthMatrix.clone();
+ Planets.earthMatrixInv.invert();
+ }
+ matLocal._multiply(Matrix3d.translation(translation));
+ renderContext.set_world(matLocal);
+ renderContext.set_worldBase(renderContext.get_world().clone());
+ renderContext.set_nominalRadius(Planets.getPlanetRadiusInMeters(planetID));
+ if (makeFrustum) {
+ renderContext.makeFrustum();
+ }
+ matNonRotating.scale(Vector3d.create(radius, radius, radius));
+ matNonRotating._multiply(orientationAtEpoch);
+ matNonRotating._multiply(Matrix3d.translation(translation));
+ renderContext.set_worldBaseNonRotating(matNonRotating);
+ return rotationCurrent;
+};
+
+// Get the position of a Solar System object using a 'direct' calculation that
+// avoids including an aberration correction.
+//
+// The returned position is in ecliptic coordinate system with the origin at the center
+// of the parent body (i.e. the Sun for planets, a planet for moons). The position of moons
+// is _not_ modified by the SolarSystemScale, making it possible to use function to
+// a calculate valid Keplerian elements.
+Planets.getPlanetPositionDirect = function (id, jd) {
+ var L = 0;
+ var B = 0;
+ var R = 0;
+ switch (id) {
+ case 1:
+ L = CAAMercury.eclipticLongitude(jd);
+ B = CAAMercury.eclipticLatitude(jd);
+ R = CAAMercury.radiusVector(jd);
+ break;
+ case 2:
+ L = CAAVenus.eclipticLongitude(jd);
+ B = CAAVenus.eclipticLatitude(jd);
+ R = CAAVenus.radiusVector(jd);
+ break;
+ case SolarSystemObjects.earth:
+ L = CAAEarth.eclipticLongitude(jd);
+ B = CAAEarth.eclipticLatitude(jd);
+ R = CAAEarth.radiusVector(jd);
+ break;
+ case 3:
+ L = CAAMars.eclipticLongitude(jd);
+ B = CAAMars.eclipticLatitude(jd);
+ R = CAAMars.radiusVector(jd);
+ break;
+ case 4:
+ L = CAAJupiter.eclipticLongitude(jd);
+ B = CAAJupiter.eclipticLatitude(jd);
+ R = CAAJupiter.radiusVector(jd);
+ break;
+ case 5:
+ L = CAASaturn.eclipticLongitude(jd);
+ B = CAASaturn.eclipticLatitude(jd);
+ R = CAASaturn.radiusVector(jd);
+ break;
+ case 6:
+ L = CAAUranus.eclipticLongitude(jd);
+ B = CAAUranus.eclipticLatitude(jd);
+ R = CAAUranus.radiusVector(jd);
+ break;
+ case 7:
+ L = CAANeptune.eclipticLongitude(jd);
+ B = CAANeptune.eclipticLatitude(jd);
+ R = CAANeptune.radiusVector(jd);
+ break;
+ case 8:
+ L = CAAPluto.eclipticLongitude(jd);
+ B = CAAPluto.eclipticLatitude(jd);
+ R = CAAPluto.radiusVector(jd);
+ break;
+ case 9:
+ L = CAAMoon.eclipticLongitude(jd);
+ B = CAAMoon.eclipticLatitude(jd);
+ R = CAAMoon.radiusVector(jd) / 149598000;
+ break;
+ case 10:
+ var galileanInfo = GM.calculate(jd);
+ var position = galileanInfo.satellite1.eclipticRectangularCoordinates;
+ return Vector3d.create(position.x, position.z, position.y);
+ case 11:
+ var galileanInfo = GM.calculate(jd);
+ var position = galileanInfo.satellite2.eclipticRectangularCoordinates;
+ return Vector3d.create(position.x, position.z, position.y);
+ case 12:
+ var galileanInfo = GM.calculate(jd);
+ var position = galileanInfo.satellite3.eclipticRectangularCoordinates;
+ return Vector3d.create(position.x, position.z, position.y);
+ case 13:
+ var galileanInfo = GM.calculate(jd);
+ var position = galileanInfo.satellite4.eclipticRectangularCoordinates;
+ return Vector3d.create(position.x, position.z, position.y);
+ }
+
+ // Enabling this code transforms planet positions from the mean ecliptic/equinox of
+ // date to the J2000 ecliptic. It is necessary because the VSOP87D series used
+ // for planet positions is in the mean-of-date frame. The transformation is currently
+ // disabled in order to better match planet positions calculated elsewhere in the code.
+ //CAA2DCoordinate prec = CAAPrecession.PrecessEcliptic(L, B, jd, 2451545.0);
+ //L = prec.X;
+ //B = prec.Y;
+
+ L = Coordinates.degreesToRadians(L);
+ B = Coordinates.degreesToRadians(B);
+ var eclPos = Vector3d.create(Math.cos(L) * Math.cos(B) * R, Math.sin(L) * Math.cos(B) * R, Math.sin(B) * R);
+
+
+ // Transform from the ecliptic of date to the J2000 ecliptic; this transformation should be deleted
+ // once the precession is turned on.
+ var eclipticOfDateRotation = (Coordinates.meanObliquityOfEcliptic(jd) - Coordinates.meanObliquityOfEcliptic(2451545)) * Planets.RC;
+ eclPos.rotateX(eclipticOfDateRotation);
+ return Vector3d.create(eclPos.x, eclPos.z, eclPos.y);
+};
+
+Planets._stateVectorToKeplerian = function (position, velocity, mu) {
+ // Work in units of km and seconds
+ var r = Vector3d.scale(position, 149598000);
+ var v = Vector3d.scale(Vector3d.scale(velocity, 1 / 86400), 149598000);
+ var rmag = r.length();
+ var vmag = v.length();
+ var sma = 1 / (2 / rmag - vmag * vmag / mu);
+
+ // h is the orbital angular momentum vector
+ var h = Vector3d.cross(r, v);
+
+ // ecc is the eccentricity vector, which points from the
+ // planet at periapsis to the center point.
+ var ecc = Vector3d.subtractVectors(Vector3d.scale(Vector3d.cross(v, h), 1 / mu), Vector3d.scale(r, 1 / rmag));
+ var e = ecc.length();
+
+ h.normalize();
+ ecc.normalize();
+
+ // h, s, and ecc are orthogonal vectors that define a coordinate
+ // system. h is normal to the orbital plane.
+ var s = Vector3d.cross(h, ecc);
+
+ // Calculate the sine and cosine of the true anomaly
+ r.normalize();
+ var cosNu = Vector3d.dot(ecc, r);
+ var sinNu = Vector3d.dot(s, r);
+
+ // Compute the eccentric anomaly
+ var E = Math.atan2(Math.sqrt(1 - e * e) * sinNu, e + cosNu);
+ var elements = new KeplerianElements();
+
+ // Create a rotation matrix given the three orthogonal vectors:
+ // ecc - eccentricity vector
+ // s - in the orbital plane, perpendicular to ecc
+ // h - angular momentum vector, normal to orbital plane
+ elements.orientation = Matrix3d.create(ecc.x, ecc.y, ecc.z, 0, s.x, s.y, s.z, 0, h.x, h.y, h.z, 0, 0, 0, 0, 1);
+ elements.a = sma;
+ elements.e = e;
+ elements.ea = E;
+ return elements;
+};
+
+Planets.getAdjustedPlanetRadius = function (planetID) {
+ if (planetID > Planets._planetDiameters.length - 1) {
+ planetID = SolarSystemObjects.earth;
+ }
+ var diameter = Planets._planetDiameters[planetID];
+ var radius = (diameter / 2);
+ if (!!planetID) {
+ radius = radius * (1 + (3 * (Settings.get_active().get_solarSystemScale() - 1)));
+ }
+ else {
+ radius = radius * (1 + (0.3 * (Settings.get_active().get_solarSystemScale() - 1)));
+ }
+ return radius;
+};
+
+Planets.getPlanetRadiusInMeters = function (planetID) {
+ if (planetID > Planets._planetDiameters.length - 1) {
+ planetID = SolarSystemObjects.earth;
+ }
+ var diameter = Planets._planetDiameters[planetID];
+ return (diameter / 2) * 149598000 * 1000;
+};
+
+Planets._drawPlanet = function (renderContext, planetID, opacity) {
+ var planetPosition = Planets._planetLocations[planetID];
+ if (((planetID < 14) && Planets._planetScales[planetID] < (renderContext.viewCamera.zoom / 6) / 400)) {
+ if (planetID < 10 || ((planetID < 14) && Planets._planetScales[planetID] > (renderContext.viewCamera.zoom / 6) / 6400)) {
+ var point = Coordinates.raDecTo3d(planetPosition.RA, planetPosition.dec);
+ BasePlanets.drawPointPlanet(renderContext, point, 3, Planets.planetColors[planetID], false);
+ }
+ return;
+ }
+ var brush = null;
+ if (planetID < 10 || planetID === 18) {
+ brush = Planets._planetTextures[planetID];
+ }
+ else if (planetID < 14) {
+ if (Planets._planetLocations[planetID].eclipsed) {
+ brush = Planets._planetTextures[15];
+ } else {
+ if (Settings.get_active().get_showMoonsAsPointSource()) {
+ brush = Planets._planetTextures[14];
+ }
+ else {
+ brush = Planets._planetTextures[planetID];
+ }
+ }
+ }
+ else {
+ if (!Planets._planetLocations[planetID].shadow) {
+ return;
+ }
+
+ //Shadows of moons
+ brush = Planets._planetTextures[15];
+ }
+ if (renderContext.gl != null) {
+ if (Planets._planetPoints == null) {
+ Planets._planetPoints = new Array(4);
+ for (var i = 0; i < 4; i++) {
+ Planets._planetPoints[i] = new PositionColoredTextured();
+ }
+ }
+ var radius = (Planets._planetScales[planetID] / 2);
+ var raRadius = (radius / Math.cos(planetPosition.dec / 180 * Math.PI));
+ Planets._planetPoints[0].position = Coordinates.raDecTo3dAu((planetPosition.RA - (raRadius / 15)), planetPosition.dec + radius, 1);
+ Planets._planetPoints[0].tu = 0;
+ Planets._planetPoints[0].tv = 1;
+ Planets._planetPoints[0].color = Colors.get_white();
+ Planets._planetPoints[1].position = Coordinates.raDecTo3dAu((planetPosition.RA - (raRadius / 15)), planetPosition.dec - radius, 1);
+ Planets._planetPoints[1].tu = 0;
+ Planets._planetPoints[1].tv = 0;
+ Planets._planetPoints[1].color = Colors.get_white();
+ Planets._planetPoints[2].position = Coordinates.raDecTo3dAu((planetPosition.RA + (raRadius / 15)), planetPosition.dec + radius, 1);
+ Planets._planetPoints[2].tu = 1;
+ Planets._planetPoints[2].tv = 1;
+ Planets._planetPoints[2].color = Colors.get_white();
+ Planets._planetPoints[3].position = Coordinates.raDecTo3dAu((planetPosition.RA + (raRadius / 15)), planetPosition.dec - radius, 1);
+ Planets._planetPoints[3].tu = 1;
+ Planets._planetPoints[3].tv = 0;
+ Planets._planetPoints[3].color = Colors.get_white();
+ Planets._planetSprite.draw(renderContext, Planets._planetPoints, 4, brush, true, 1);
+ }
+ else {
+ var center = Coordinates.raDecTo3d(planetPosition.RA, planetPosition.dec);
+ var rad = Planets._planetScales[planetID] / (renderContext.get_fovScale() / 3600) / 2;
+ var screenSpacePnt = renderContext.WVP.transform(center);
+ if (screenSpacePnt.z < 0) {
+ return;
+ }
+ if (Vector3d.dot(renderContext.get_viewPoint(), center) < 0.55) {
+ return;
+ }
+ var ctx = renderContext.device;
+ ctx.save();
+ ctx.globalAlpha = opacity;
+ ctx.beginPath();
+ ctx.arc(screenSpacePnt.x, screenSpacePnt.y, rad, 0, Math.PI * 2, true);
+ ctx.lineWidth = 0;
+ ctx.closePath();
+ ctx.clip();
+ ctx.drawImage(brush.imageElement, screenSpacePnt.x - rad, screenSpacePnt.y - rad, rad * 2, rad * 2);
+ ctx.globalAlpha = 1;
+ ctx.restore();
+ }
+};
+
+Planets._drawPlanetPhase = function (renderContext, planetID, phase, angle, dark) { };
+
+Planets._geocentricElongation = function (ObjectAlpha, ObjectDelta, SunAlpha, SunDelta) {
+ //Convert the RA's to radians
+ ObjectAlpha = Coordinates.degreesToRadians(ObjectAlpha * 15);
+ SunAlpha = Coordinates.degreesToRadians(SunAlpha * 15);
+
+ //Convert the declinations to radians
+ ObjectDelta = Coordinates.degreesToRadians(ObjectDelta);
+ SunDelta = Coordinates.degreesToRadians(SunDelta);
+ return Coordinates.radiansToDegrees(Math.acos(Math.sin(SunDelta) * Math.sin(ObjectDelta) + Math.cos(SunDelta) * Math.cos(ObjectDelta) * Math.cos(SunAlpha - ObjectAlpha)));
+};
+
+Planets._phaseAngle = function (GeocentricElongation, EarthObjectDistance, EarthSunDistance) {
+ //Convert from degrees to radians
+ GeocentricElongation = Coordinates.degreesToRadians(GeocentricElongation);
+
+ return Coordinates.mapTo0To360Range(Coordinates.radiansToDegrees(Math.atan2(EarthSunDistance * Math.sin(GeocentricElongation), EarthObjectDistance - EarthSunDistance * Math.cos(GeocentricElongation))));
+};
+
+Planets._positionAngle = function (Alpha0, Delta0, Alpha, Delta) {
+ Alpha0 = Coordinates.hoursToRadians(Alpha0);
+ Alpha = Coordinates.hoursToRadians(Alpha);
+ Delta0 = Coordinates.degreesToRadians(Delta0);
+ Delta = Coordinates.degreesToRadians(Delta);
+ return Coordinates.mapTo0To360Range(Coordinates.radiansToDegrees(Math.atan2(Math.cos(Delta0) * Math.sin(Alpha0 - Alpha), Math.sin(Delta0) * Math.cos(Delta) - Math.cos(Delta0) * Math.sin(Delta) * Math.cos(Alpha0 - Alpha))));
+};
+
+var Planets$ = {};
+
+registerType("Planets", [Planets, Planets$, null]);
diff --git a/engine/esm/planets_3d.js b/engine/esm/planets_3d.js
new file mode 100644
index 00000000..891602b9
--- /dev/null
+++ b/engine/esm/planets_3d.js
@@ -0,0 +1,540 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// The 3D planet-related code.
+//
+// This does not include the 3D planet-rendering code, which has been separated
+// into `planets_3d.js`.
+
+import { ss } from "./ss.js";
+import { registerType } from "./typesystem.js";
+import { Vector3d, Vector4d, Matrix3d, PositionTexture } from "./double3d.js";
+import { WEBGL } from "./graphics/webgl_constants.js";
+import { PositionTextureVertexBuffer } from "./graphics/gl_buffers.js";
+import { OrbitLineList } from "./graphics/primitives3d.js";
+import { Texture } from "./graphics/texture.js";
+import { TileShader } from "./graphics/shaders.js";
+import { Util } from "./baseutil.js";
+import { BasePlanets } from "./baseplanets.js";
+import { globalWWTControl } from "./data_globals.js";
+import { Color, Colors } from "./color.js";
+import { Planets } from "./planets.js";
+import { RenderTriangle } from "./render_triangle.js";
+import { Settings } from "./settings.js";
+import { Triangle } from "./triangle.js";
+import { UiTools } from "./ui_tools.js";
+import { URLHelpers } from "./url_helpers.js";
+import { EllipseRenderer } from "./layers/orbit.js";
+import { LayerManager } from "./layers/layer_manager.js";
+
+
+// 3D planet code. This used to live in `Planets.cs` with the 2D planet.
+
+export function Planets3d() { }
+
+Planets3d._ringsTriangleLists = new Array(2);
+Planets3d._ringImage = null;
+Planets3d._triangleCountRings = 192 + 1 * 2;
+Planets3d._ringsVertexBuffer = null;
+
+Planets3d.getImageSetNameNameFrom3dId = function (id) {
+ switch (id) {
+ case 0:
+ return 'Sun';
+ case 1:
+ return 'Mercury';
+ case 2:
+ return 'Venus';
+ case 3:
+ return 'Visible Imagery';
+ case 4:
+ return 'Jupiter';
+ case 5:
+ return 'Saturn';
+ case 6:
+ return 'Uranus';
+ case 7:
+ return 'Neptune';
+ case 8:
+ return 'Pluto';
+ case 9:
+ return 'Moon';
+ case 10:
+ return 'Io (Jupiter)';
+ case 11:
+ return 'Europa (Jupiter)';
+ case 12:
+ return 'Ganymede (Jupiter)';
+ case 13:
+ return 'Callisto (Jupiter)';
+ case 19:
+ return 'Bing Maps Aerial';
+ default:
+ return '';
+ }
+};
+
+Planets3d.initPlanetResources = function (renderContext) { };
+
+Planets3d.drawPlanets3D = function (renderContext, opacity, centerPoint) {
+ Planets3d.initPlanetResources(renderContext);
+ var distss = UiTools.solarSystemToMeters(renderContext.get_solarSystemCameraDistance());
+ var moonFade = Math.min(1, Math.max(Util.log10(distss) - 7.3, 0));
+ var fade = Math.min(1, Math.max(Util.log10(distss) - 8.6, 0));
+ if (Settings.get_active().get_solarSystemOrbits() && fade > 0) {
+ for (var ii = 1; ii < 10; ii++) {
+ var id = ii;
+ if (ii === 9) {
+ id = 19;
+ }
+ var angle = Math.atan2(Planets._planet3dLocations[id].z, Planets._planet3dLocations[id].x);
+ Planets3d._drawSingleOrbit(renderContext, Planets.planetColors[id], id, centerPoint, angle, Planets._planet3dLocations[id], fade);
+ }
+ var mid = 9;
+ Planets3d._drawSingleOrbit(renderContext, Planets.planetColors[mid], mid, centerPoint, 0, Planets._planet3dLocations[mid], fade);
+ }
+ ss.clearKeys(Planets._drawOrder);
+ var camera = renderContext.cameraPosition.copy();
+ for (var planetId = 0; planetId < 14; planetId++) {
+ // If we're using realistic lighting and this is an eclipsed
+ // moon, don't draw it at all. This is slightly suboptimal
+ // since, if you're looking at the moon, you'll suddenly be able
+ // to see the stars through it. In principle we should do
+ // something like keep on drawing it, but as an all-black
+ // sphere.
+ if (!(Settings.get_active().get_solarSystemLighting() && Planets._planetLocations[planetId].eclipsed)) {
+ var distVector = Vector3d.subtractVectors(camera, Vector3d.subtractVectors(Planets._planet3dLocations[planetId], centerPoint));
+ if (!ss.keyExists(Planets._drawOrder, distVector.length())) {
+ Planets._drawOrder[distVector.length()] = planetId;
+ }
+ }
+ }
+ var distVectorEarth = Vector3d.subtractVectors(camera, Vector3d.subtractVectors(Planets._planet3dLocations[19], centerPoint));
+ if (!ss.keyExists(Planets._drawOrder, distVectorEarth.length())) {
+ Planets._drawOrder[distVectorEarth.length()] = 19;
+ }
+ var $enum1 = ss.enumerate(ss.keys(Planets._drawOrder));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var planetId = Planets._drawOrder[key];
+ Planets3d._drawPlanet3d(renderContext, planetId, centerPoint);
+ }
+ return true;
+};
+
+Planets3d._drawSingleOrbit = function (renderContext, eclipticColor, id, centerPoint, startAngle, planetNow, opacity) {
+ // mu is the standard gravitational parameter GM, where G
+ // is the gravitational constant and M is the mass of the
+ // central body.
+ const muSun = 1.327124400188e11; // km^3/s^2
+ const muEarth = 3.9860044189e5;
+ const muMoon = 4.9027779e3;
+ const muJupiter = 1.26686534e8;
+
+ if (opacity < 0.01) {
+ return;
+ }
+ if (renderContext.gl == null) {
+ var count = Planets._orbitalSampleRate;
+ var planetDropped = false;
+ var viewPoint = renderContext.get_viewPoint();
+ var ctx = renderContext.device;
+ ctx.save();
+ ctx.strokeStyle = eclipticColor.toString();
+ ctx.lineWidth = 2;
+ ctx.globalAlpha = 1;
+ var point = new Vector3d();
+ var pointTest = new Vector3d();
+ var lastPoint = new Vector3d();
+ var firstPoint = true;
+ var translate = Matrix3d.translation(Vector3d.negate(centerPoint));
+ var mat = Matrix3d.multiplyMatrix(translate, renderContext.WVP);
+ var matWV = Matrix3d.multiplyMatrix(translate, renderContext.WV);
+ for (var i = 0; i < count; i++) {
+ var pnt = Planets._orbits[id][i];
+ var angle = (Math.atan2(Planets._orbits[id][i].z, Planets._orbits[id][i].x) + Math.PI * 2 - startAngle) % (Math.PI * 2);
+ var alpha = ss.truncate((angle / (Math.PI * 2) * 255));
+ var alphaD = alpha / 255;
+ if (alpha < 2 && !planetDropped) {
+ pnt = planetNow;
+ alphaD = 1;
+ }
+ pointTest = matWV.transform(pnt);
+ point = mat.transform(pnt);
+ if (pointTest.z > 0) {
+ if (firstPoint) {
+ firstPoint = false;
+ }
+ else {
+ ctx.beginPath();
+ ctx.globalAlpha = alphaD * opacity;
+ ctx.moveTo(lastPoint.x, lastPoint.y);
+ ctx.lineTo(point.x, point.y);
+ ctx.stroke();
+ }
+ }
+ lastPoint = point;
+ }
+ ctx.restore();
+ }
+ else {
+ if (id !== 9) {
+ var count = Planets._orbitalSampleRate;
+ var planetDropped = false;
+ var viewPoint = renderContext.get_viewPoint();
+ var point = new Vector3d();
+ var pointTest = new Vector3d();
+ var lastPoint = new Vector3d();
+ var lastColor = new Color();
+ var firstPoint = true;
+ var list = new OrbitLineList();
+ for (var i = 0; i < count; i++) {
+ var pnt = Planets._orbits[id][i].copy();
+ var angle = (Math.atan2(pnt.z, pnt.x) + Math.PI * 2 - startAngle) % (Math.PI * 2);
+ var alpha = ss.truncate((angle / (Math.PI * 2) * 255));
+ var alphaD = alpha / 255;
+ var color = Color.fromArgb(alpha, eclipticColor.r, eclipticColor.g, eclipticColor.b);
+ if (alpha < 2 && !planetDropped && !firstPoint) {
+ pnt = Vector3d.subtractVectors(planetNow, centerPoint);
+ alphaD = 1;
+ alpha = 255;
+ color.a = 255;
+ lastColor.a = 255;
+ list.addLine(lastPoint, pnt.copy(), lastColor._clone(), color._clone());
+ lastColor.a = 0;
+ color.a = 0;
+ pnt = Planets._orbits[id][i].copy();
+ planetDropped = true;
+ }
+ pnt = Vector3d.subtractVectors(pnt, centerPoint);
+ if (firstPoint) {
+ firstPoint = false;
+ }
+ else {
+ list.addLine(lastPoint, pnt, lastColor, color);
+ }
+ lastPoint = pnt;
+ lastColor = color._clone();
+ }
+ list.drawLines(renderContext, 1, Colors.get_white());
+ list.clear();
+ } else {
+ var mu = 0;
+ switch (id) {
+ case 9:
+ mu = muEarth + muMoon;
+ break;
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ mu = muJupiter;
+ break;
+ default:
+ mu = muSun;
+ break;
+ }
+ var deltaT = 1 / 1440 * 0.1;
+ var r0 = Planets.getPlanetPositionDirect(id, Planets._jNow);
+ var r1 = Planets.getPlanetPositionDirect(id, Planets._jNow - deltaT);
+ var v = Vector3d.scale(Vector3d.subtractVectors(r0, r1), 1 / deltaT);
+ var elements = Planets._stateVectorToKeplerian(r0, v, mu);
+ Planets3d._drawSingleOrbitElements(renderContext, eclipticColor, id, centerPoint, startAngle, planetNow, elements);
+ }
+ }
+};
+
+Planets3d._drawSingleOrbitElements = function (renderContext, eclipticColor, id, centerPoint, xstartAngle, planetNow, el) {
+ var scaleFactor;
+ switch (id) {
+ case 9:
+ if (Settings.get_active().get_solarSystemScale() > 1) {
+ scaleFactor = Settings.get_active().get_solarSystemScale() / 2;
+ }
+ else {
+ scaleFactor = 1;
+ }
+ break;
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ scaleFactor = Settings.get_active().get_solarSystemScale();
+ break;
+ default:
+ scaleFactor = 1;
+ break;
+ }
+ var translation = Vector3d.negate(centerPoint);
+ if (id === 9) {
+ translation.add(Planets._planet3dLocations[19]);
+ }
+ else if (id === 10 || id === 11 || id === 12 || id === 13) {
+ translation.add(Planets._planet3dLocations[4]);
+ }
+ var currentPosition = Vector3d.subtractVectors(planetNow, centerPoint);
+ var worldMatrix = Matrix3d.multiplyMatrix(Matrix3d.multiplyMatrix(el.orientation, Matrix3d.translation(translation)), renderContext.get_world());
+ EllipseRenderer.drawEllipseWithPosition(renderContext, el.a / 149598000 * scaleFactor, el.e, el.ea, eclipticColor, worldMatrix, currentPosition);
+};
+
+Planets3d.isPlanetInFrustum = function (renderContext, rad) {
+ var frustum = renderContext.get_frustum();
+ var center = Vector3d.create(0, 0, 0);
+ var centerV4 = new Vector4d(0, 0, 0, 1);
+ for (var i = 0; i < 6; i++) {
+ if (frustum[i].dot(centerV4) + rad < 0) {
+ return false;
+ }
+ }
+ return true;
+};
+
+Planets3d._drawPlanet3d = function (renderContext, planetID, centerPoint) {
+ if (planetID === 0) {
+ TileShader.minLightingBrightness = 1;
+ }
+ else {
+ TileShader.minLightingBrightness = 0.025;
+ if (planetID === 19) {
+ TileShader.atmosphereColor = Color.fromArgb(255, 65, 157, 217);
+ } else {
+ TileShader.atmosphereColor = Color.fromArgb(0, 0, 0, 0);
+ }
+ }
+ var matOld = renderContext.get_world();
+ var matOldBase = renderContext.get_worldBase();
+ var matOldNonRotating = renderContext.get_worldBaseNonRotating();
+ var radius = Planets.getAdjustedPlanetRadius(planetID);
+ Planets.setupPlanetMatrix(renderContext, planetID, centerPoint, true);
+ var planetWidth = 1;
+ if (planetID === 5) {
+ planetWidth = 3;
+ }
+ if (Planets3d.isPlanetInFrustum(renderContext, planetWidth)) {
+ // Save all matrices modified by SetupMatrix...
+ var matOld2 = renderContext.get_world();
+ var matOldBase2 = renderContext.get_worldBase();
+ var matOldNonRotating2 = renderContext.get_worldBaseNonRotating();
+ var sun = Planets._planet3dLocations[0].copy();
+ var planet = Planets._planet3dLocations[planetID].copy();
+ sun = matOld.transform(sun);
+ planet = matOld.transform(planet);
+ renderContext.set_world(matOld);
+ renderContext.set_worldBase(matOldBase);
+ renderContext.set_worldBaseNonRotating(matOldNonRotating);
+ Planets._setupMatrixForPlanetGeometry(renderContext, planetID, centerPoint, true);
+ var sunPosition = Vector3d.subtractVectors(sun, planet);
+ sunPosition.normalize();
+ renderContext.set_sunPosition(sunPosition);
+ TileShader.sunPosition = Vector3d.subtractVectors(Planets._planet3dLocations[0], planet);
+ var loc = Vector3d.subtractVectors(Planets._planet3dLocations[planetID], centerPoint);
+ loc.subtract(renderContext.cameraPosition);
+ var dist = loc.length();
+ var sizeIndexParam = (2 * Math.atan(0.5 * (radius / dist))) / Math.PI * 180;
+ var sizeIndex = 0;
+ if (sizeIndexParam > 10.5) {
+ sizeIndex = 0;
+ } else if (sizeIndexParam > 3.9) {
+ sizeIndex = 1;
+ } else if (sizeIndexParam > 0.72) {
+ sizeIndex = 2;
+ } else if (sizeIndexParam > 0.05) {
+ sizeIndex = 3;
+ } else {
+ sizeIndex = 4;
+ }
+ if (planetID === 19 && sizeIndex < 2) {
+ var width = Settings.get_active().get_solarSystemScale() * 1E-05;
+ }
+ if (sizeIndex < 4) {
+ var oldLighting = renderContext.lighting;
+ if (planetID === 5) {
+ if (renderContext.gl == null) {
+ renderContext.lighting = false;
+ // DRAW BACK HALF OF RINGS
+ Planets3d.drawSaturnsRings(renderContext, false, dist);
+ renderContext.lighting = oldLighting;
+ }
+ }
+ if (!planetID) {
+ renderContext.lighting = false;
+ }
+ Planets3d._drawSphere(renderContext, planetID);
+ if (planetID === 5) {
+ if (renderContext.gl == null) {
+ renderContext.lighting = false;
+ // DRAW FRONT HALF OF RINGS
+ Planets3d.drawSaturnsRings(renderContext, true, dist);
+ }
+ else {
+ renderContext.lighting = false;
+ Planets3d._drawRings(renderContext);
+ renderContext.lighting = oldLighting;
+ }
+ }
+ renderContext.lighting = oldLighting;
+ } else {
+ if (!planetID) {
+ BasePlanets.drawPointPlanet(renderContext, new Vector3d(), (10 * Planets._planetDiameters[planetID]), Planets.planetColors[planetID], true);
+ }
+ else if (planetID < 9 || planetID === 19) {
+ var size = (800 * Planets._planetDiameters[planetID]);
+ BasePlanets.drawPointPlanet(renderContext, new Vector3d(), Math.max(0.05, Math.min(0.1, size)), Planets.planetColors[planetID], true);
+ }
+ else if (sizeIndexParam > 0.002) {
+ var size = (800 * Planets._planetDiameters[planetID]);
+ BasePlanets.drawPointPlanet(renderContext, new Vector3d(), Math.max(0.05, Math.min(0.1, size)), Planets.planetColors[planetID], true);
+ }
+ }
+ }
+ LayerManager._draw(renderContext, 1, false, Planets.getNameFrom3dId(planetID), true, false);
+ renderContext.set_world(matOld);
+ renderContext.set_worldBase(matOldBase);
+ renderContext.set_worldBaseNonRotating(matOldNonRotating);
+};
+
+Planets3d.drawSaturnsRings = function (renderContext, front, distance) {
+ if (Planets3d._ringsTriangleLists[0] == null) {
+ Planets3d._ringImage = document.createElement('img');
+ var xdomimg = Planets3d._ringImage;
+ xdomimg.crossOrigin = 'anonymous';
+ Planets3d._ringImage.src = URLHelpers.singleton.engineAssetUrl('saturnringsshadow.png');
+ Planets3d._ringsTriangleLists[0] = [];
+ Planets3d._ringsTriangleLists[1] = [];
+ var ringSize = 2.25;
+ var TopLeft = Vector3d.create(-ringSize, 0, -ringSize);
+ var TopRight = Vector3d.create(ringSize, 0, -ringSize);
+ var BottomLeft = Vector3d.create(-ringSize, 0, ringSize);
+ var BottomRight = Vector3d.create(ringSize, 0, ringSize);
+ var center = Vector3d.create(0, 0, 0);
+ var leftCenter = Vector3d.create(-ringSize, 0, 0);
+ var topCenter = Vector3d.create(0, 0, -ringSize);
+ var bottomCenter = Vector3d.create(0, 0, ringSize);
+ var rightCenter = Vector3d.create(ringSize, 0, 0);
+ var level = 6;
+ var vertexList;
+ vertexList = [];
+ var Width = 1024;
+ var Height = 1024;
+ vertexList.push(PositionTexture.createPosSize(TopLeft, 0, 0, Width, Height));
+ vertexList.push(PositionTexture.createPosSize(TopRight, 1, 0, Width, Height));
+ vertexList.push(PositionTexture.createPosSize(BottomLeft, 0, 1, Width, Height));
+ vertexList.push(PositionTexture.createPosSize(BottomRight, 1, 1, Width, Height));
+ var childTriangleList = [];
+ childTriangleList.push(Triangle.create(0, 2, 1));
+ childTriangleList.push(Triangle.create(2, 3, 1));
+ var count = 5;
+ while (count-- > 1) {
+ var newList = [];
+ var $enum1 = ss.enumerate(childTriangleList);
+ while ($enum1.moveNext()) {
+ var tri = $enum1.current;
+ tri.subDivideNoNormalize(newList, vertexList);
+ }
+ childTriangleList = newList;
+ }
+ var miter = 0.6 / (Width / 256);
+ var $enum2 = ss.enumerate(childTriangleList);
+ while ($enum2.moveNext()) {
+ var tri = $enum2.current;
+ var p1 = vertexList[tri.a];
+ var p2 = vertexList[tri.b];
+ var p3 = vertexList[tri.c];
+ Planets3d._ringsTriangleLists[0].push(RenderTriangle.createWithMiter(p1, p2, p3, Planets3d._ringImage, level, miter));
+ }
+ }
+ if (renderContext.gl == null) {
+ var cam = renderContext.cameraPosition;
+ var test = new Vector3d();
+ var worldLocal = Matrix3d.multiplyMatrix(Matrix3d._rotationY(Math.atan2(renderContext.get_sunPosition().x, renderContext.get_sunPosition().z)), renderContext.get_worldBaseNonRotating());
+ var wv = Matrix3d.multiplyMatrix(worldLocal, renderContext.get_view());
+ var wvp = Matrix3d.multiplyMatrix(wv, renderContext.get_projection());
+ var Width = renderContext.width;
+ var Height = renderContext.height;
+ wvp.scale(Vector3d.create(Width / 2, -Height / 2, 1));
+ wvp.translate(Vector3d.create(Width / 2, Height / 2, 0));
+ var td = 0;
+ for (var i = 0; i < 2; i++) {
+ var $enum3 = ss.enumerate(Planets3d._ringsTriangleLists[0]);
+ while ($enum3.moveNext()) {
+ var tri = $enum3.current;
+ test = wv.transform(tri.a.position);
+ td = test.length();
+ var draw = td > distance;
+ if (front) {
+ draw = !draw;
+ }
+ if (draw) {
+ tri.opacity = 1;
+ tri.draw(renderContext.device, wvp);
+ }
+ }
+ RenderTriangle.cullInside = !RenderTriangle.cullInside;
+ }
+ }
+ else { }
+};
+
+// Various input layouts used in 3D solar system mode
+// TODO Replace with an input layout cache
+
+Planets3d._drawRings = function (renderContext) {
+ Planets3d._initRings();
+ TileShader.use(renderContext, Planets3d._ringsVertexBuffer.vertexBuffer, null, Planets._ringsTexture.texture2d, 1, false, Vector3d.zero);
+ renderContext.gl.drawArrays(WEBGL.TRIANGLE_STRIP, 0, Planets3d._triangleCountRings);
+};
+
+Planets3d._initRings = function () {
+ if (Planets3d._ringsVertexBuffer != null) {
+ return;
+ }
+ Planets._ringsTexture = Texture.fromUrl(URLHelpers.singleton.engineAssetUrl('saturnringsstrip.png'));
+ var inner = 1.113;
+ var outer = 2.25;
+ Planets3d._ringsVertexBuffer = new PositionTextureVertexBuffer(((192 + 1) * 2));
+ Planets3d._triangleCountRings = (192 + 1) * 2;
+ var verts = Planets3d._ringsVertexBuffer.lock();
+ var radStep = Math.PI * 2 / 192;
+ var index = 0;
+ for (var x = 0; x <= 192; x += 2) {
+ var rads1 = x * radStep;
+ var rads2 = (x + 1) * radStep;
+ verts[index] = new PositionTexture();
+ verts[index].position = Vector3d.create((Math.cos(rads1) * inner), 0, (Math.sin(rads1) * inner));
+ verts[index].tu = 1;
+ verts[index].tv = 0;
+ index++;
+ verts[index] = new PositionTexture();
+ verts[index].position = Vector3d.create((Math.cos(rads1) * outer), 0, (Math.sin(rads1) * outer));
+ verts[index].tu = 0;
+ verts[index].tv = 0;
+ index++;
+ verts[index] = new PositionTexture();
+ verts[index].position = Vector3d.create((Math.cos(rads2) * inner), 0, (Math.sin(rads2) * inner));
+ verts[index].tu = 1;
+ verts[index].tv = 1;
+ index++;
+ verts[index] = new PositionTexture();
+ verts[index].position = Vector3d.create((Math.cos(rads2) * outer), 0, (Math.sin(rads2) * outer));
+ verts[index].tu = 0;
+ verts[index].tv = 1;
+ index++;
+ }
+ Planets3d._ringsVertexBuffer.unlock();
+};
+
+Planets3d._drawSphere = function (renderContext, planetID) {
+ var planetName = Planets3d.getImageSetNameNameFrom3dId(planetID);
+ var planet = globalWWTControl.getImagesetByName(planetName);
+ if (planet == null) {
+ planet = globalWWTControl.getImagesetByName('Bing Maps Aerial');
+ }
+ if (planet != null) {
+ renderContext.drawImageSet(planet, 100);
+ if (planetID === 19) {
+ }
+ return;
+ }
+};
+
+registerType("Planets3d", [Planets3d, {}, null]);
diff --git a/engine/esm/plot_tile.js b/engine/esm/plot_tile.js
new file mode 100644
index 00000000..c8aecf09
--- /dev/null
+++ b/engine/esm/plot_tile.js
@@ -0,0 +1,266 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A tile that plots tabular data.
+//
+// This tile class is not implemented for the WebGL rendering backend!
+
+import { ss } from "./ss.js";
+import { registerType } from "./typesystem.js";
+import { tileCacheRemoveFromQueue, tileCacheGetTile, tileUvMultiple } from "./render_globals.js";
+import { Vector2d, Vector3d, PositionTexture } from "./double3d.js";
+import { BasePlanets } from "./baseplanets.js";
+import { Coordinates } from "./coordinates.js";
+import { Star } from "./star.js";
+import { URLHelpers } from "./url_helpers.js";
+import { WebFile } from "./web_file.js";
+import { Tile } from "./tile.js";
+
+
+// wwtlib.PlotTile
+
+export function PlotTile() {
+ this._topDown$1 = true;
+ this.backslash = false;
+ this._vertexList$1 = null;
+ this._childTriangleList$1 = null;
+ this._stars$1 = [];
+ this._subDivisionLevel$1 = 4;
+ this._subDivided$1 = false;
+ Tile.call(this);
+}
+
+PlotTile.create = function (level, xc, yc, dataset, parent) {
+ var temp = new PlotTile();
+ temp.parent = parent;
+ temp.level = level;
+ temp.tileX = xc;
+ temp.tileY = yc;
+ temp.dataset = dataset;
+ temp._topDown$1 = !dataset.get_bottomsUp();
+ if (temp.tileX !== xc) {
+ alert('bad');
+ }
+ if (!!dataset.get_meanRadius()) {
+ temp.set__demScaleFactor(dataset.get_meanRadius());
+ }
+ else {
+ if (!dataset.get_dataSetType()) {
+ temp.set__demScaleFactor(6371000);
+ } else {
+ temp.set__demScaleFactor(3396010);
+ }
+ }
+ temp.computeBoundingSphere();
+ return temp;
+};
+
+var PlotTile$ = {
+ computeBoundingSphere: function () {
+ this._initializeGrids$1();
+ this.topLeft = this.bounds[0 + 3 * 0].position.copy();
+ this.bottomRight = this.bounds[2 + 3 * 2].position.copy();
+ this.topRight = this.bounds[2 + 3 * 0].position.copy();
+ this.bottomLeft = this.bounds[0 + 3 * 2].position.copy();
+ this.calcSphere();
+ },
+
+ renderPart: function (renderContext, part, opacity, combine) {
+ if (renderContext.gl != null) {
+ //todo draw in WebGL
+ } else {
+ if (!part) {
+ var $enum1 = ss.enumerate(this._stars$1);
+ while ($enum1.moveNext()) {
+ var star = $enum1.current;
+ var radDec = 25 / Math.pow(1.6, star.magnitude);
+ BasePlanets.drawPointPlanet(renderContext, star.position, radDec, star.col, false);
+ }
+ }
+ }
+ },
+
+ requestImage: function () {
+ if (!this.downloading && !this.readyToRender) {
+ this.downloading = true;
+ this._webFile$1 = new WebFile(URLHelpers.singleton.rewrite(this.get_URL(), 0));
+ this._webFile$1.onStateChange = ss.bind('fileStateChange', this);
+ this._webFile$1.send();
+ }
+ },
+
+ fileStateChange: function () {
+ if (this._webFile$1.get_state() === 2) {
+ this.downloading = false;
+ this.readyToRender = false;
+ this.errored = true;
+ this.requestPending = false;
+ tileCacheRemoveFromQueue(this.get_key(), true);
+ } else if (this._webFile$1.get_state() === 1) {
+ this.texReady = true;
+ this.downloading = false;
+ this.errored = false;
+ this.readyToRender = this.texReady && (this.demReady || !this.demTile);
+ this.requestPending = false;
+ tileCacheRemoveFromQueue(this.get_key(), true);
+ this._loadData$1(this._webFile$1.getText());
+ }
+ },
+
+ _loadData$1: function (data) {
+ var rows = ss.replaceString(data, '\r\n', '\n').split('\n');
+ var firstRow = true;
+ var type = 0;
+ var star = null;
+ var $enum1 = ss.enumerate(rows);
+ while ($enum1.moveNext()) {
+ var row = $enum1.current;
+ if (firstRow) {
+ firstRow = false;
+ continue;
+ }
+ if (ss.trim(row).length > 5) {
+ star = new Star(row);
+ star.position = Coordinates.raDecTo3dAu(star.RA, star.dec, 1);
+ this._stars$1.push(star);
+ }
+ }
+ },
+
+ isPointInTile: function (lat, lng) {
+ if (!this.level) {
+ return true;
+ }
+ if (this.level === 1) {
+ if ((lng >= 0 && lng <= 90) && (!this.tileX && this.tileY === 1)) {
+ return true;
+ }
+ if ((lng > 90 && lng <= 180) && (this.tileX === 1 && this.tileY === 1)) {
+ return true;
+ }
+ if ((lng < 0 && lng >= -90) && (!this.tileX && !this.tileY)) {
+ return true;
+ }
+ if ((lng < -90 && lng >= -180) && (this.tileX === 1 && !this.tileY)) {
+ return true;
+ }
+ return false;
+ }
+ if (!this.demReady || this.demData == null) {
+ return false;
+ }
+ var testPoint = Coordinates.geoTo3dDouble(-lat, lng);
+ var top = this._isLeftOfHalfSpace$1(this.topLeft.copy(), this.topRight.copy(), testPoint);
+ var right = this._isLeftOfHalfSpace$1(this.topRight.copy(), this.bottomRight.copy(), testPoint);
+ var bottom = this._isLeftOfHalfSpace$1(this.bottomRight.copy(), this.bottomLeft.copy(), testPoint);
+ var left = this._isLeftOfHalfSpace$1(this.bottomLeft.copy(), this.topLeft.copy(), testPoint);
+ if (top && right && bottom && left) {
+ return true;
+ }
+ return false;
+ },
+
+ _isLeftOfHalfSpace$1: function (pntA, pntB, pntTest) {
+ pntA.normalize();
+ pntB.normalize();
+ var cross = Vector3d.cross(pntA, pntB);
+ var dot = Vector3d.dot(cross, pntTest);
+ return dot < 0;
+ },
+
+ _initializeGrids$1: function () {
+ this._vertexList$1 = [];
+ this._childTriangleList$1 = new Array(4);
+ this._childTriangleList$1[0] = [];
+ this._childTriangleList$1[1] = [];
+ this._childTriangleList$1[2] = [];
+ this._childTriangleList$1[3] = [];
+ this.bounds = new Array(9);
+ if (this.level > 0) {
+ if (this.parent == null) {
+ this.parent = tileCacheGetTile(this.level - 1, this.tileX / 2, this.tileY / 2, this.dataset, null);
+ }
+ var parent = this.parent;
+ var xIndex = this.tileX % 2;
+ var yIndex = this.tileY % 2;
+ if (this.level > 1) {
+ this.backslash = parent.backslash;
+ }
+ else {
+ this.backslash = (xIndex === 1 ^ yIndex === 1) === 1;
+ }
+ this.bounds[0 + 3 * 0] = parent.bounds[xIndex + 3 * yIndex].copy();
+ this.bounds[1 + 3 * 0] = this._midpoint$1(parent.bounds[xIndex + 3 * yIndex], parent.bounds[xIndex + 1 + 3 * yIndex]);
+ this.bounds[2 + 3 * 0] = parent.bounds[xIndex + 1 + 3 * yIndex].copy();
+ this.bounds[0 + 3 * 1] = this._midpoint$1(parent.bounds[xIndex + 3 * yIndex], parent.bounds[xIndex + 3 * (yIndex + 1)]);
+ if (this.backslash) {
+ this.bounds[1 + 3 * 1] = this._midpoint$1(parent.bounds[xIndex + 3 * yIndex], parent.bounds[xIndex + 1 + 3 * (yIndex + 1)]);
+ }
+ else {
+ this.bounds[1 + 3 * 1] = this._midpoint$1(parent.bounds[xIndex + 1 + 3 * yIndex], parent.bounds[xIndex + 3 * (yIndex + 1)]);
+ }
+ this.bounds[2 + 3 * 1] = this._midpoint$1(parent.bounds[xIndex + 1 + 3 * yIndex], parent.bounds[xIndex + 1 + 3 * (yIndex + 1)]);
+ this.bounds[0 + 3 * 2] = parent.bounds[xIndex + 3 * (yIndex + 1)].copy();
+ this.bounds[1 + 3 * 2] = this._midpoint$1(parent.bounds[xIndex + 3 * (yIndex + 1)], parent.bounds[xIndex + 1 + 3 * (yIndex + 1)]);
+ this.bounds[2 + 3 * 2] = parent.bounds[xIndex + 1 + 3 * (yIndex + 1)].copy();
+ this.bounds[0 + 3 * 0].tu = 0 * tileUvMultiple;
+ this.bounds[0 + 3 * 0].tv = 0 * tileUvMultiple;
+ this.bounds[1 + 3 * 0].tu = 0.5 * tileUvMultiple;
+ this.bounds[1 + 3 * 0].tv = 0 * tileUvMultiple;
+ this.bounds[2 + 3 * 0].tu = 1 * tileUvMultiple;
+ this.bounds[2 + 3 * 0].tv = 0 * tileUvMultiple;
+ this.bounds[0 + 3 * 1].tu = 0 * tileUvMultiple;
+ this.bounds[0 + 3 * 1].tv = 0.5 * tileUvMultiple;
+ this.bounds[1 + 3 * 1].tu = 0.5 * tileUvMultiple;
+ this.bounds[1 + 3 * 1].tv = 0.5 * tileUvMultiple;
+ this.bounds[2 + 3 * 1].tu = 1 * tileUvMultiple;
+ this.bounds[2 + 3 * 1].tv = 0.5 * tileUvMultiple;
+ this.bounds[0 + 3 * 2].tu = 0 * tileUvMultiple;
+ this.bounds[0 + 3 * 2].tv = 1 * tileUvMultiple;
+ this.bounds[1 + 3 * 2].tu = 0.5 * tileUvMultiple;
+ this.bounds[1 + 3 * 2].tv = 1 * tileUvMultiple;
+ this.bounds[2 + 3 * 2].tu = 1 * tileUvMultiple;
+ this.bounds[2 + 3 * 2].tv = 1 * tileUvMultiple;
+ } else {
+ this.bounds[0 + 3 * 0] = PositionTexture.create(0, -1, 0, 0, 0);
+ this.bounds[1 + 3 * 0] = PositionTexture.create(0, 0, 1, 0.5, 0);
+ this.bounds[2 + 3 * 0] = PositionTexture.create(0, -1, 0, 1, 0);
+ this.bounds[0 + 3 * 1] = PositionTexture.create(-1, 0, 0, 0, 0.5);
+ this.bounds[1 + 3 * 1] = PositionTexture.create(0, 1, 0, 0.5, 0.5);
+ this.bounds[2 + 3 * 1] = PositionTexture.create(1, 0, 0, 1, 0.5);
+ this.bounds[0 + 3 * 2] = PositionTexture.create(0, -1, 0, 0, 1);
+ this.bounds[1 + 3 * 2] = PositionTexture.create(0, 0, -1, 0.5, 1);
+ this.bounds[2 + 3 * 2] = PositionTexture.create(0, -1, 0, 1, 1);
+ }
+ },
+
+ _midpoint$1: function (positionNormalTextured, positionNormalTextured_2) {
+ var a1 = Vector3d.lerp(positionNormalTextured.position, positionNormalTextured_2.position, 0.5);
+ var a1uv = Vector2d.lerp(Vector2d.create(positionNormalTextured.tu, positionNormalTextured.tv), Vector2d.create(positionNormalTextured_2.tu, positionNormalTextured_2.tv), 0.5);
+ a1.normalize();
+ return PositionTexture.createPos(a1, a1uv.x, a1uv.y);
+ },
+
+ createGeometry: function (renderContext) {
+ if (this.geometryCreated) {
+ return true;
+ }
+ this.geometryCreated = true;
+ Tile.prototype.createGeometry.call(this, renderContext);
+ return true;
+ },
+
+ cleanUp: function (removeFromParent) {
+ Tile.prototype.cleanUp.call(this, removeFromParent);
+ if (this._vertexList$1 != null) {
+ this._vertexList$1 = null;
+ }
+ if (this._childTriangleList$1 != null) {
+ this._childTriangleList$1 = null;
+ }
+ this._subDivided$1 = false;
+ this.demArray = null;
+ }
+};
+
+registerType("PlotTile", [PlotTile, PlotTile$, Tile]);
diff --git a/engine/esm/pointing.js b/engine/esm/pointing.js
new file mode 100644
index 00000000..29900896
--- /dev/null
+++ b/engine/esm/pointing.js
@@ -0,0 +1,54 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A lat/lon datatype. This is unused in the engine, but preserved for API
+// compatibility.
+
+import { ss } from "./ss.js";
+import { registerType } from "./typesystem.js";
+import { HealpixUtils } from "./healpix_utils.js";
+
+
+// wwtlib.Pointing
+
+export function Pointing() {
+ // Colatitude in radians (0 is North Pole; Pi is South Pole)
+ this.theta = 0;
+
+ // Longitude in radians
+ this.phi = 0;
+}
+
+Pointing.create = function (theta, phi) {
+ var temp = new Pointing();
+ temp.theta = theta;
+ temp.phi = phi;
+ return temp;
+};
+
+var Pointing$ = {
+ normalizeTheta: function () {
+ this.theta = HealpixUtils.fmodulo(this.theta, 2 * Math.PI);
+ if (this.theta > Math.PI) {
+ this.phi += Math.PI;
+ this.theta = 2 * Math.PI - this.theta;
+ }
+ },
+
+ normalize: function () {
+ this.normalizeTheta();
+ this.phi = HealpixUtils.fmodulo(this.phi, 2 * Math.PI);
+ },
+
+ toString: function () {
+ var s = new ss.StringBuilder();
+ s.append('ptg(');
+ s.append(this.theta);
+ s.append(',');
+ s.append(this.phi);
+ s.append(')');
+ return s.toString();
+ }
+};
+
+registerType("Pointing", [Pointing, Pointing$, null]);
diff --git a/engine/esm/render_context.js b/engine/esm/render_context.js
new file mode 100644
index 00000000..f8cdedaa
--- /dev/null
+++ b/engine/esm/render_context.js
@@ -0,0 +1,978 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// The main engine renderer implementation.
+
+import { ss } from "./ss.js";
+import { registerType } from "./typesystem.js";
+import { Vector3d, Matrix3d, PlaneD } from "./double3d.js";
+import { globalWWTControl, makeNewHipsProperties } from "./data_globals.js";
+import { set_tileDemEnabled, set_tileUvMultiple, tileCacheGetTile } from "./render_globals.js";
+import { Util } from "./baseutil.js";
+import { WEBGL } from "./graphics/webgl_constants.js";
+import { TileShader } from "./graphics/shaders.js";
+import { CameraParameters } from "./camera_parameters.js";
+import { Colors } from "./color.js";
+import { Coordinates } from "./coordinates.js";
+import { ProjectionType, ImageSetType } from "./imageset.js";
+import { Planets } from "./planets.js";
+import { RenderTriangle } from "./render_triangle.js";
+import { Settings } from "./settings.js";
+import { SpaceTimeController } from "./space_time_controller.js";
+import { CatalogSpreadSheetLayer } from "./layers/spreadsheet_layer.js";
+import { LayerManager } from "./layers/layer_manager.js";
+
+
+// wwtlib.InViewReturnMessage
+
+export function InViewReturnMessage() {
+ this.aborted = false;
+}
+
+var InViewReturnMessage$ = {};
+
+registerType("InViewReturnMessage", [InViewReturnMessage, InViewReturnMessage$, null]);
+
+
+// wwtlib.RenderContext
+
+export function RenderContext() {
+ this.height = 0;
+ this.width = 0;
+ this.lighting = false;
+ this._viewPoint = new Vector3d();
+ this.space = false;
+ this._fovAngle = 0;
+ this._fovScale = 0;
+ this._nominalRadius = 6378137;
+ this._mainTexture = null;
+ this.viewMover = null;
+ this.viewCamera = new CameraParameters();
+ this.targetCamera = new CameraParameters();
+ this.alt = 0;
+ this.az = 0;
+ this.targetAlt = 0;
+ this.targetAz = 0;
+ this._backgroundImageset = null;
+ this._foregroundImageset = null;
+ this._activeCatalogHipsImagesets = [];
+ this._targetHeight = 1;
+ this.targetAltitude = 0;
+ this._galactic = true;
+ this._galacticMatrix = Matrix3d.create(-0.4838350155, -0.0548755604, -0.8734370902, 0, 0.7469822445, 0.4941094279, -0.44482963, 0, 0.4559837762, -0.867666149, -0.1980763734, 0, 0, 0, 0, 1);
+ this._firstTimeInit = false;
+ this._useSolarSystemTilt = true;
+ this.customTrackingParams = new CameraParameters();
+ this._cameraOffset = new Vector3d();
+ this._fovLocal = (Math.PI / 4);
+ this.perspectiveFov = Math.PI / 4;
+ this.nearPlane = 0;
+ this._frustumDirty = true;
+ this._frustum = new Array(6);
+ this._ambientLightColor = Colors.get_black();
+ this._hemiLightColor = Colors.get_black();
+ this._hemiLightUp = new Vector3d();
+ this._sunlightColor = Colors.get_white();
+ this._sunPosition = new Vector3d();
+ this._reflectedLightColor = Colors.get_black();
+ this._reflectedLightPosition = new Vector3d();
+ this._occludingPlanetRadius = 0;
+ this._occludingPlanetPosition = new Vector3d();
+ this._lightingStateDirty = true;
+ this._twoSidedLighting = false;
+ this.cameraPosition = new Vector3d();
+ this._skyColor = 'Blue';
+ for (var i = 0; i < 6; i++) {
+ this._frustum[i] = new PlaneD(0, 0, 0, 0);
+ }
+}
+
+RenderContext.back = 0;
+
+RenderContext.create = function (device) {
+ var temp = new RenderContext();
+ temp.device = device;
+ temp.viewCamera.zoom = 700;
+ temp.viewCamera.target = 65536;
+ return temp;
+};
+
+RenderContext.getTilesYForLevel = function (layer, level) {
+ var maxY = 1;
+ switch (layer.get_projection()) {
+ case ProjectionType.mercator:
+ maxY = Math.pow(2, level);
+ break;
+ case ProjectionType.equirectangular:
+ maxY = (Math.pow(2, level) * (180 / layer.get_baseTileDegrees()));
+ break;
+ case ProjectionType.tangent:
+ maxY = Math.pow(2, level);
+ break;
+ case ProjectionType.spherical:
+ maxY = 1;
+ break;
+ case ProjectionType.healpix:
+ maxY = 4 * Math.pow(2, level);
+ break;
+ default:
+ maxY = Math.pow(2, level);
+ break;
+ }
+ if (maxY === Number.POSITIVE_INFINITY) {
+ maxY = 1;
+ }
+ return maxY;
+};
+
+RenderContext.getTilesXForLevel = function (layer, level) {
+ var maxX = 1;
+ switch (layer.get_projection()) {
+ case ProjectionType.plotted:
+ case ProjectionType.toast:
+ maxX = Math.pow(2, level);
+ break;
+ case ProjectionType.mercator:
+ maxX = Math.pow(2, level) * ss.truncate((layer.get_baseTileDegrees() / 360));
+ break;
+ case ProjectionType.equirectangular:
+ maxX = Math.pow(2, level) * ss.truncate((360 / layer.get_baseTileDegrees()));
+ break;
+ case ProjectionType.tangent:
+ if (layer.get_widthFactor() === 1) {
+ maxX = Math.pow(2, level) * 2;
+ }
+ else {
+ maxX = Math.pow(2, level);
+ }
+ break;
+ case ProjectionType.skyImage:
+ maxX = 1;
+ break;
+ case ProjectionType.spherical:
+ maxX = 1;
+ break;
+ case ProjectionType.healpix:
+ maxX = Math.pow(2, level) * 3;
+ break;
+ default:
+ maxX = Math.pow(2, level) * 2;
+ break;
+ }
+ return maxX;
+};
+
+var RenderContext$ = {
+ save: function () {
+ if (this.gl != null) {
+ } else {
+ this.device.save();
+ }
+ },
+
+ restore: function () {
+ if (this.gl != null) {
+ } else {
+ this.device.restore();
+ }
+ },
+
+ clear: function () {
+ if (this.gl != null) {
+ this.gl.viewport(0, 0, ss.truncate(this.width), ss.truncate(this.height));
+ this.gl.clear(WEBGL.COLOR_BUFFER_BIT | WEBGL.DEPTH_BUFFER_BIT);
+ } else {
+ this.device.save();
+ this.device.fillStyle = 'black';
+ this.device.fillRect(0, 0, this.width, this.height);
+ this.device.restore();
+ }
+ },
+
+ get_viewPoint: function () {
+ return this._viewPoint;
+ },
+
+ get_RA: function () {
+ return ((((180 - (this.viewCamera.lng - 180)) / 15) % 24) + 48) % 24;
+ },
+
+ rAtoViewLng: function (ra) {
+ return 180 - (ra / 24 * 360) - 180;
+ },
+
+ get_dec: function () {
+ return this.viewCamera.lat;
+ },
+
+ get_fovAngle: function () {
+ return this._fovAngle;
+ },
+
+ get_fovScale: function () {
+ return this._fovScale;
+ },
+
+ set_fovScale: function (value) {
+ this._fovScale = value;
+ return value;
+ },
+
+ get_view: function () {
+ return this._view;
+ },
+
+ set_view: function (value) {
+ this._view = value;
+ this._frustumDirty = true;
+ return value;
+ },
+
+ get_viewBase: function () {
+ return this._viewBase;
+ },
+
+ set_viewBase: function (value) {
+ this._viewBase = value;
+ return value;
+ },
+
+ get_projection: function () {
+ return this._projection;
+ },
+
+ set_projection: function (value) {
+ this._projection = value;
+ this._frustumDirty = true;
+ return value;
+ },
+
+ get_world: function () {
+ return this._world;
+ },
+
+ set_world: function (value) {
+ this._world = value;
+ this._frustumDirty = true;
+ return value;
+ },
+
+ _getScreenTexture: function () {
+ //todo add code to capture screen
+ var tex = null;
+ return tex;
+ },
+
+ get_worldBase: function () {
+ return this._worldBase;
+ },
+
+ set_worldBase: function (value) {
+ this._worldBase = value;
+ return value;
+ },
+
+ get_worldBaseNonRotating: function () {
+ return this._worldBaseNonRotating;
+ },
+
+ set_worldBaseNonRotating: function (value) {
+ this._worldBaseNonRotating = value;
+ return value;
+ },
+
+ get_nominalRadius: function () {
+ return this._nominalRadius;
+ },
+
+ set_nominalRadius: function (value) {
+ this._nominalRadius = value;
+ return value;
+ },
+
+ get_mainTexture: function () {
+ return this._mainTexture;
+ },
+
+ set_mainTexture: function (value) {
+ if (value != null) {
+ this._mainTexture = value;
+ this.gl.bindTexture(WEBGL.TEXTURE_2D, this._mainTexture.texture2d);
+ }
+ return value;
+ },
+
+ onTarget: function (place) {
+ return ((Math.abs(this.viewCamera.lat - this.targetCamera.lat) < 1E-12 && Math.abs(this.viewCamera.lng - this.targetCamera.lng) < 1E-12 && Math.abs(this.viewCamera.zoom - this.targetCamera.zoom) < 1E-12) && this.viewMover == null);
+ },
+
+ setTexture: function (texture) { },
+
+ get_backgroundImageset: function () {
+ return this._backgroundImageset;
+ },
+
+ set_backgroundImageset: function (value) {
+ var viewModeChanged = this._backgroundImageset != null && value != null && (this._backgroundImageset.get_dataSetType() !== value.get_dataSetType());
+ this._backgroundImageset = value;
+
+ if (viewModeChanged) {
+ //Prevent potential artifacts when going from 3D to Sky/Pan
+ globalWWTControl._freezeView();
+ globalWWTControl.clampZooms(this);
+ }
+ return value;
+ },
+
+ get_foregroundImageset: function () {
+ return this._foregroundImageset;
+ },
+
+ set_foregroundImageset: function (value) {
+ this._foregroundImageset = value;
+ return value;
+ },
+
+ get_catalogHipsImagesets: function () {
+ return this._activeCatalogHipsImagesets;
+ },
+
+ getCatalogHipsDataInView: function (imageset, limit, onComplete) {
+ var $this = this;
+
+ var layer = new CatalogSpreadSheetLayer();
+ var onHeaderInfoLoad = function () {
+ layer.useHeadersFromVoTable(imageset.get_hipsProperties().get_catalogColumnInfo());
+ $this._tryGetAllDataInView(imageset, limit, layer, onComplete, 0);
+ };
+ if (imageset.get_hipsProperties() == null) {
+ imageset.set_hipsProperties(makeNewHipsProperties(imageset));
+ imageset.get_hipsProperties().setDownloadCompleteListener(onHeaderInfoLoad);
+ } else if (imageset.get_hipsProperties() != null && imageset.get_hipsProperties().get_downloadComplete()) {
+ onHeaderInfoLoad();
+ } else {
+ imageset.get_hipsProperties().setDownloadCompleteListener(onHeaderInfoLoad);
+ }
+ },
+
+ _tryGetAllDataInView: function (imageset, limit, catalogSpreadSheetLayer, onComplete, i) {
+ var $this = this;
+
+ var maxX = RenderContext.getTilesXForLevel(imageset, imageset.get_baseLevel());
+ var maxY = RenderContext.getTilesYForLevel(imageset, imageset.get_baseLevel());
+ var anyTileStillDownloading = false;
+ for (var x = 0; x < maxX; x++) {
+ for (var y = 0; y < maxY; y++) {
+ var tile = tileCacheGetTile(imageset.get_baseLevel(), x, y, imageset, null);
+ if (tile != null) {
+ var tileAndChildrenReady = (tile).getDataInView(this, limit, catalogSpreadSheetLayer);
+ anyTileStillDownloading = anyTileStillDownloading || !tileAndChildrenReady;
+ }
+ else {
+ anyTileStillDownloading = true;
+ }
+ }
+ }
+ if (anyTileStillDownloading) {
+ var count = catalogSpreadSheetLayer.get__table().rows.length;
+ if ((count > 10000 || i > 100 * 60 * 5) && limit) {
+ console.log('Too Many results - Aborting');
+ console.log(count);
+ var returnMessage = new InViewReturnMessage();
+ returnMessage.aborted = true;
+ returnMessage.table = catalogSpreadSheetLayer.getTableDataInView();
+ onComplete(returnMessage);
+ catalogSpreadSheetLayer.cleanUp();
+ }
+ else {
+ setTimeout(function () {
+ $this._tryGetAllDataInView(imageset, limit, catalogSpreadSheetLayer, onComplete, i);
+ }, 10);
+ if (!(i % 200)) {
+ console.log('Waiting for more tiles to load');
+ console.log(count);
+ }
+ i++;
+ }
+ } else {
+ var count = catalogSpreadSheetLayer.get__table().rows.length;
+ console.log('Done!');
+ console.log(count);
+ var returnMessage = new InViewReturnMessage();
+ returnMessage.aborted = false;
+ returnMessage.table = catalogSpreadSheetLayer.getTableDataInView();
+ onComplete(returnMessage);
+ catalogSpreadSheetLayer.cleanUp();
+ }
+ },
+
+ addCatalogHips: function (imageset, onLoad) {
+ if (!(this._activeCatalogHipsImagesets.indexOf(imageset) >= 0)) {
+ this._activeCatalogHipsImagesets.push(imageset);
+ }
+ if (imageset.get_hipsProperties() == null) {
+ imageset.set_hipsProperties(makeNewHipsProperties(imageset));
+ imageset.get_hipsProperties().setDownloadCompleteListener(onLoad);
+ } else if (imageset.get_hipsProperties() != null && imageset.get_hipsProperties().get_downloadComplete()) {
+ LayerManager.addSpreadsheetLayer(imageset.get_hipsProperties().get_catalogSpreadSheetLayer(), 'Sky');
+ if (onLoad != null) {
+ onLoad();
+ }
+ }
+ },
+
+ removeCatalogHips: function (imageset) {
+ ss.remove(this._activeCatalogHipsImagesets, imageset);
+ if (imageset.get_hipsProperties() != null) {
+ LayerManager.deleteLayerByID(imageset.get_hipsProperties().get_catalogSpreadSheetLayer().id, true, true);
+ }
+ },
+
+ getCatalogHipsByName: function (name) {
+ var $enum1 = ss.enumerate(this._activeCatalogHipsImagesets);
+ while ($enum1.moveNext()) {
+ var imageset = $enum1.current;
+ if (imageset.get_name() === name) {
+ return imageset;
+ }
+ }
+ return null;
+ },
+
+ getAltitudeForLatLongForPlanet: function (planetID, viewLat, viewLong) {
+ var layer = globalWWTControl.getImagesetByName(Planets.getNameFrom3dId(planetID));
+ if (layer == null) {
+ return 0;
+ }
+ var maxX = RenderContext.getTilesXForLevel(layer, layer.get_baseLevel());
+ var maxY = RenderContext.getTilesYForLevel(layer, layer.get_baseLevel());
+ for (var x = 0; x < maxX; x++) {
+ for (var y = 0; y < maxY; y++) {
+ var tile = tileCacheGetTile(layer.get_baseLevel(), x, y, layer, null);
+ if (tile != null) {
+ if (tile.isPointInTile(viewLat, viewLong)) {
+ return tile.getSurfacePointAltitude(viewLat, viewLong, true);
+ }
+ }
+ }
+ }
+ return 0;
+ },
+
+ getEarthAltitude: function (ViewLat, ViewLong, meters) {
+ if (globalWWTControl.get_solarSystemMode()) {
+ var pnt = Coordinates.geoTo3dDouble(ViewLat, ViewLong + 90);
+ var EarthMat = Planets.earthMatrixInv;
+ pnt = Vector3d._transformCoordinate(pnt, EarthMat);
+ pnt.normalize();
+ var point = Coordinates.cartesianToLatLng(pnt);
+ return this.getAltitudeForLatLongForPlanet(this.viewCamera.target, point.y, point.x);
+ } else if (this.get_backgroundImageset().get_dataSetType() != ImageSetType.earth) {
+ return (meters) ? this.getMetersAltitudeForLatLong(ViewLat, ViewLong) : this.getScaledAltitudeForLatLong(ViewLat, ViewLong);
+ } else {
+ return 0;
+ }
+ },
+
+ drawImageSet: function (imageset, opacity) {
+ var maxX = RenderContext.getTilesXForLevel(imageset, imageset.get_baseLevel());
+ var maxY = RenderContext.getTilesYForLevel(imageset, imageset.get_baseLevel());
+ for (var x = 0; x < maxX; x++) {
+ for (var y = 0; y < maxY; y++) {
+ var tile = tileCacheGetTile(imageset.get_baseLevel(), x, y, imageset, null);
+ if (tile != null) {
+ tile.draw3D(this, opacity);
+ }
+ }
+ }
+ },
+
+ _getTileAtLatLong: function (viewLat, viewLong) {
+ var layer = this.get_backgroundImageset();
+ if (layer == null) {
+ return null;
+ }
+ var maxX = RenderContext.getTilesXForLevel(layer, layer.get_baseLevel());
+ var maxY = RenderContext.getTilesYForLevel(layer, layer.get_baseLevel());
+ for (var x = 0; x < maxX; x++) {
+ for (var y = 0; y < maxY; y++) {
+ var tile = tileCacheGetTile(layer.get_baseLevel(), x, y, layer, null);
+ if (tile != null) {
+ if (tile.isPointInTile(viewLat, viewLong)) {
+ return tile;
+ }
+ }
+ }
+ }
+ return null;
+ },
+
+ getScaledAltitudeForLatLong: function (viewLat, viewLong) {
+ var tile = this._getTileAtLatLong(viewLat, viewLong);
+ if (tile != null) {
+ return tile.getSurfacePointAltitude(viewLat, viewLong, false);
+ }
+ return 0;
+ },
+
+ getMetersAltitudeForLatLong: function (viewLat, viewLong) {
+ var tile = this._getTileAtLatLong(viewLat, viewLong);
+ if (tile != null) {
+ return tile.getSurfacePointAltitude(viewLat, viewLong, true);
+ }
+ return 0;
+ },
+
+ _setupMatricesLand3d: function () {
+ this.lighting = false;
+ this.space = false;
+ RenderTriangle.cullInside = false;
+
+ // For our world matrix, we will just rotate the Earth and Clouds about the y-axis.
+ var WorldMatrix = Matrix3d._rotationY(((this.viewCamera.lng - 90) / 180 * Math.PI));
+ WorldMatrix._multiply(Matrix3d._rotationX(((-this.viewCamera.lat) / 180 * Math.PI)));
+ this.set_world(WorldMatrix);
+ this.set_worldBase(WorldMatrix.clone());
+ this._viewPoint = Coordinates.geoTo3d(this.viewCamera.lat, this.viewCamera.lng);
+ var distance = 0;
+ if (this._backgroundImageset.get_isMandelbrot()) {
+ distance = (4 * (this.viewCamera.zoom / 180)) + 1E-41;
+ } else {
+ distance = (4 * (this.viewCamera.zoom / 180)) + 1E-06;
+ }
+ this._fovAngle = (this.viewCamera.zoom / 343.774) / Math.PI * 180;
+ this._fovScale = (this._fovAngle / this.height) * 3600;
+ if (this.gl != null) {
+ this.targetAltitude = this.getScaledAltitudeForLatLong(this.viewCamera.lat, this.viewCamera.lng);
+ var heightNow = 1 + this.targetAltitude;
+ this.targetAltitude *= this.get_nominalRadius();
+ if (this._targetHeight < heightNow) {
+ this._targetHeight = (((this._targetHeight * 2) + heightNow) / 3);
+ }
+ else {
+ this._targetHeight = (((this._targetHeight * 9) + heightNow) / 10);
+ }
+ } else {
+ this.targetAltitude = 0;
+ this._targetHeight = 1;
+ }
+ var rotLocal = this.viewCamera.rotation;
+ this.cameraPosition = Vector3d.create((Math.sin(rotLocal) * Math.sin(this.viewCamera.angle) * distance), (Math.cos(rotLocal) * Math.sin(this.viewCamera.angle) * distance), (-this._targetHeight - (Math.cos(this.viewCamera.angle) * distance)));
+ var cameraTarget = Vector3d.create(0, 0, -this._targetHeight);
+ var camHeight = this.cameraPosition.length();
+ var lookUp = Vector3d.create(Math.sin(rotLocal) * Math.cos(this.viewCamera.angle), Math.cos(rotLocal) * Math.cos(this.viewCamera.angle), Math.sin(this.viewCamera.angle));
+ this.set_view(Matrix3d.lookAtLH(this.cameraPosition, cameraTarget, lookUp));
+ this.set_viewBase(this.get_view());
+ var back = Math.sqrt((distance + 1) * (distance + 1) - 1);
+ back = Math.max(0.5, back);
+ var m_nearPlane = distance * 0.05;
+ m_nearPlane = distance * 0.05;
+ this.set_projection(Matrix3d.perspectiveFovLH((Math.PI / 4), this.width / this.height, m_nearPlane, back));
+ this._setMatrixes();
+ this.makeFrustum();
+ },
+
+ setupMatricesSpace3d: function (canvasWidth, canvasHeight) {
+ this.lighting = false;
+ if (!this._firstTimeInit) {
+ this._galacticMatrix = Matrix3d.get_identity();
+ this._galacticMatrix._multiply(Matrix3d._rotationY(-(270 - (17.7603329867975 * 15)) / 180 * Math.PI));
+ this._galacticMatrix._multiply(Matrix3d._rotationX(-(-28.9361739586894) / 180 * Math.PI));
+ this._galacticMatrix._multiply(Matrix3d._rotationZ(((31.422052860102) - 90) / 180 * Math.PI));
+ this._firstTimeInit = true;
+ }
+ this.space = true;
+ RenderTriangle.cullInside = true;
+ var WorldMatrix = Matrix3d.get_identity();
+ if (Settings.get_active().get_galacticMode()) {
+ WorldMatrix._multiply(this._galacticMatrix);
+ WorldMatrix._multiply(Matrix3d._rotationY(this.az / 180 * Math.PI));
+ WorldMatrix._multiply(Matrix3d._rotationX(-this.alt / 180 * Math.PI));
+ var gPoint = Coordinates.galactictoJ2000(this.az, this.alt);
+ this._viewPoint = Coordinates.raDecTo3dAu(gPoint[0] / 15, gPoint[1], 1);
+ this.targetCamera.lng = this.rAtoViewLng(gPoint[0] / 15);
+ this.targetCamera.lat = gPoint[1];
+ this.viewCamera.lat = this.targetCamera.lat;
+ this.viewCamera.lng = this.targetCamera.lng;
+ } else {
+ WorldMatrix._multiply(Matrix3d._rotationY(-(this.viewCamera.lng - 90) / 180 * Math.PI));
+ WorldMatrix._multiply(Matrix3d._rotationX(-this.viewCamera.lat / 180 * Math.PI));
+ this._viewPoint = Coordinates.raDecTo3dAu(this.get_RA(), this.get_dec(), 1);
+ }
+ var camLocal = this.viewCamera.rotation;
+ this._fovAngle = (this.viewCamera.zoom / 343.774) / Math.PI * 180;
+ this._fovScale = (this._fovAngle / canvasHeight) * 3600;
+
+ // altaz
+ if (Settings.get_active().get_localHorizonMode() && this._backgroundImageset.get_dataSetType() == ImageSetType.sky) {
+ var zenithAltAz = new Coordinates(0, 0);
+ zenithAltAz.set_az(0);
+ zenithAltAz.set_alt(0);
+ var zenith = Coordinates.horizonToEquitorial(zenithAltAz, SpaceTimeController.get_location(), SpaceTimeController.get_now());
+ var raPart = -((zenith.get_RA() - 6) / 24 * (Math.PI * 2));
+ var decPart = -(zenith.get_dec() / 360 * (Math.PI * 2));
+ var raText = Coordinates.formatDMS(zenith.get_RA());
+ WorldMatrix = Matrix3d._rotationY(-raPart - Math.PI);
+ WorldMatrix._multiply(Matrix3d._rotationX(decPart));
+ if (SpaceTimeController.get_location().get_lat() < 0) {
+ WorldMatrix._multiply(Matrix3d._rotationY((this.az / 180 * Math.PI)));
+ WorldMatrix._multiply(Matrix3d._rotationX((this.alt / 180 * Math.PI)));
+ camLocal += Math.PI;
+ }
+ else {
+ WorldMatrix._multiply(Matrix3d._rotationY(((-this.az) / 180 * Math.PI)));
+ WorldMatrix._multiply(Matrix3d._rotationX(((-this.alt) / 180 * Math.PI)));
+ }
+ var currentRaDec = Coordinates.horizonToEquitorial(Coordinates.fromLatLng(this.alt, this.az), SpaceTimeController.get_location(), SpaceTimeController.get_now());
+ this.viewCamera.lat = this.targetCamera.lat = currentRaDec.get_dec();
+ this.viewCamera.lng = this.targetCamera.lng = this.rAtoViewLng(currentRaDec.get_RA());
+ }
+ this.set_world(WorldMatrix);
+ this.set_worldBase(WorldMatrix.clone());
+ var localZoomFactor = this.viewCamera.zoom;
+ var FovAngle = (localZoomFactor / 343.774) / Math.PI * 180;
+ this.cameraPosition = Vector3d.create(0, 0, 0);
+
+ // This is for distance Calculation. For space everything is the same distance, so camera target is key.
+ this.set_view(Matrix3d.lookAtLH(this.cameraPosition, Vector3d.create(0, 0, -1), Vector3d.create(Math.sin(camLocal), Math.cos(camLocal), 0)));
+ this.set_viewBase(this.get_view().clone());
+ var m_nearPlane = 0.1;
+ this.nearPlane = 0.1;
+ this.set_projection(Matrix3d.perspectiveFovLH(localZoomFactor / 343.774, canvasWidth / canvasHeight, 0.1, -2));
+ this._setMatrixes();
+ this.makeFrustum();
+ },
+
+ get_solarSystemTrack: function () {
+ return this.viewCamera.target;
+ },
+
+ set_solarSystemTrack: function (value) {
+ this.viewCamera.target = value;
+ return value;
+ },
+
+ get_solarSystemCameraDistance: function () {
+ return (4 * (this.viewCamera.zoom / 9)) + 1E-06;
+ },
+
+ get_sandboxMode: function () {
+ if (this._backgroundImageset == null) {
+ return false;
+ }
+ return this._backgroundImageset.get_dataSetType() === ImageSetType.sandbox;
+ },
+
+ get_trackingFrame: function () {
+ return this.viewCamera.targetReferenceFrame;
+ },
+
+ set_trackingFrame: function (value) {
+ this.viewCamera.targetReferenceFrame = value;
+ return value;
+ },
+
+ get_fovLocal: function () {
+ return this._fovLocal;
+ },
+
+ set_fovLocal: function (value) {
+ this._fovLocal = value;
+ return value;
+ },
+
+ setupMatricesOverlays: function () {
+ this.set_world(Matrix3d.get_identity());
+ var lookAtAdjust = Matrix3d.get_identity();
+ var lookFrom = Vector3d.create(0, 0, 0);
+ var lookAt = Vector3d.create(0, 0, 1);
+ var lookUp = Vector3d.create(0, 1, 0);
+ var view;
+ view = Matrix3d.lookAtLH(lookFrom, lookAt, lookUp);
+ view._multiply(Matrix3d._scaling(1, -1, 1));
+ this.set_view(view);
+ var back = 10000;
+ this.nearPlane = 0.1;
+ this.set_projection(Matrix3d.perspectiveFovLH(this._fovLocal, this.width / this.height, this.nearPlane, back));
+ },
+
+ setupMatricesSolarSystem: function (forStars) {
+ this.lighting = Settings.get_active().get_solarSystemLighting();
+ this.space = false;
+ if (this.get_solarSystemTrack() !== 20 && this.get_solarSystemTrack() !== 65536) {
+ this.viewCamera.viewTarget = Planets.getPlanetTargetPoint(this.get_solarSystemTrack(), this.viewCamera.lat, this.viewCamera.lng, 0);
+ }
+ RenderTriangle.cullInside = false;
+ var cameraDistance = this.get_solarSystemCameraDistance();
+ var trackingMatrix = Matrix3d.get_identity();
+ cameraDistance -= 1E-06;
+ var activeTrackingFrame = false;
+ if (this.get_solarSystemTrack() === 20 && !ss.emptyString(this.get_trackingFrame())) {
+ activeTrackingFrame = true;
+ var target = LayerManager._getFrameTarget(this, this.get_trackingFrame());
+ this.viewCamera.viewTarget = target.target;
+ trackingMatrix = target.matrix;
+ } else if (!ss.emptyString(this.get_trackingFrame())) {
+ this.set_trackingFrame('');
+ }
+ var center = this.viewCamera.viewTarget;
+ var localZoom = this.viewCamera.zoom * 20;
+ var lookAt = new Vector3d();
+ var viewAdjust = Matrix3d.get_identity();
+ viewAdjust._multiply(Matrix3d._rotationX(((-this.viewCamera.lat) / 180 * Math.PI)));
+ viewAdjust._multiply(Matrix3d._rotationY(((-this.viewCamera.lng) / 180 * Math.PI)));
+ var lookAtAdjust = Matrix3d.get_identity();
+ var dome = false;
+ var lookUp;
+ if (this._useSolarSystemTilt && !this.get_sandboxMode()) {
+ var angle = this.viewCamera.angle;
+ if (cameraDistance > 0.0008) {
+ angle = 0;
+ }
+ else if (cameraDistance > 1E-05) {
+ var val = Math.min(1.903089987, Util.log10(cameraDistance) + 5) / 1.903089987;
+ angle = angle * Math.max(0, 1 - val);
+ }
+ this.cameraPosition = Vector3d.create((Math.sin(-this.viewCamera.rotation) * Math.sin(angle) * cameraDistance), (Math.cos(-this.viewCamera.rotation) * Math.sin(angle) * cameraDistance), (Math.cos(angle) * cameraDistance));
+ lookUp = Vector3d.create(Math.sin(-this.viewCamera.rotation), Math.cos(-this.viewCamera.rotation), 1E-05);
+ } else {
+ this.cameraPosition = Vector3d.create(0, 0, cameraDistance);
+ lookUp = Vector3d.create(Math.sin(-this.viewCamera.rotation), Math.cos(-this.viewCamera.rotation), 0.0001);
+ }
+ this.cameraPosition = viewAdjust.transform(this.cameraPosition);
+ this._cameraOffset = this.cameraPosition.copy();
+ var tmp = trackingMatrix.clone();
+ tmp.invert();
+ this._cameraOffset = Vector3d._transformCoordinate(this._cameraOffset, tmp);
+ lookUp = viewAdjust.transform(lookUp);
+ this.set_world(Matrix3d.get_identity());
+ this.set_worldBase(Matrix3d.get_identity());
+ this.set_worldBaseNonRotating(Matrix3d.get_identity());
+ this.set_view(Matrix3d.multiplyMatrix(Matrix3d.multiplyMatrix(trackingMatrix, Matrix3d.lookAtLH(this.cameraPosition, lookAt, lookUp)), lookAtAdjust));
+ this.set_viewBase(this.get_view().clone());
+ var temp = Vector3d.subtractVectors(lookAt, this.cameraPosition);
+ temp.normalize();
+ temp = Vector3d._transformCoordinate(temp, trackingMatrix);
+ temp.normalize();
+ this._viewPoint = temp;
+ var radius = Planets.getAdjustedPlanetRadius(this.get_solarSystemTrack());
+ if (cameraDistance < radius * 2 && !forStars) {
+ this.nearPlane = cameraDistance * 0.03;
+ this.nearPlane = Math.max(this.nearPlane, 1E-11);
+ RenderContext.back = 1900;
+ } else {
+ if (forStars) {
+ RenderContext.back = 900056;
+ RenderContext.back = (cameraDistance > 900056) ? cameraDistance * 3 : 900056;
+ this.nearPlane = 3E-05;
+ }
+ else {
+ RenderContext.back = (cameraDistance > 1900) ? cameraDistance + 200 : 1900;
+ if (Settings.get_active().get_solarSystemScale() < 13) {
+ this.nearPlane = Math.min(cameraDistance * 0.03, 0.01);
+ }
+ else {
+ this.nearPlane = 0.001;
+ }
+ }
+ }
+ this.set_projection(Matrix3d.perspectiveFovLH(this._fovLocal, this.width / this.height, this.nearPlane, RenderContext.back));
+ this.perspectiveFov = this._fovLocal;
+ this._fovAngle = (this.viewCamera.zoom / 343.774) / Math.PI * 180;
+ this._fovScale = (this._fovAngle / this.height) * 3600;
+ this._setMatrixes();
+ this.makeFrustum();
+ },
+
+ _setMatrixes: function () { },
+
+ get_frustum: function () {
+ return this._frustum;
+ },
+
+ get_ambientLightColor: function () {
+ return this._ambientLightColor;
+ },
+
+ set_ambientLightColor: function (value) {
+ this._ambientLightColor = value;
+ this._lightingStateDirty = true;
+ return value;
+ },
+
+ get_hemisphereLightColor: function () {
+ return this._hemiLightColor;
+ },
+
+ set_hemisphereLightColor: function (value) {
+ this._hemiLightColor = value;
+ this._lightingStateDirty = true;
+ return value;
+ },
+
+ get_hemisphereLightUp: function () {
+ return this._hemiLightUp;
+ },
+
+ set_hemisphereLightUp: function (value) {
+ this._hemiLightUp = value;
+ this._lightingStateDirty = true;
+ return value;
+ },
+
+ get_sunlightColor: function () {
+ return this._sunlightColor;
+ },
+
+ set_sunlightColor: function (value) {
+ this._sunlightColor = value;
+ this._lightingStateDirty = true;
+ return value;
+ },
+
+ get_sunPosition: function () {
+ return this._sunPosition;
+ },
+
+ set_sunPosition: function (value) {
+ this._sunPosition = value;
+ this._lightingStateDirty = true;
+ return value;
+ },
+
+ get_reflectedLightColor: function () {
+ return this._reflectedLightColor;
+ },
+
+ set_reflectedLightColor: function (value) {
+ if (this._reflectedLightColor !== value) {
+ this._reflectedLightColor = value;
+ this._lightingStateDirty = true;
+ }
+ return value;
+ },
+
+ get_reflectedLightPosition: function () {
+ return this._reflectedLightPosition;
+ },
+
+ set_reflectedLightPosition: function (value) {
+ this._reflectedLightPosition = value;
+ this._lightingStateDirty = true;
+ return value;
+ },
+
+ // Radius of a planet casting a shadow; zero when there's no shadow
+ get_occludingPlanetRadius: function () {
+ return this._occludingPlanetRadius;
+ },
+
+ set_occludingPlanetRadius: function (value) {
+ this._occludingPlanetRadius = value;
+ return value;
+ },
+
+ get_occludingPlanetPosition: function () {
+ return this._occludingPlanetPosition;
+ },
+
+ set_occludingPlanetPosition: function (value) {
+ this._occludingPlanetPosition = value;
+ return value;
+ },
+
+ get_twoSidedLighting: function () {
+ return this._twoSidedLighting;
+ },
+
+ set_twoSidedLighting: function (value) {
+ if (value !== this._twoSidedLighting) {
+ this._twoSidedLighting = value;
+ this._lightingStateDirty = true;
+ }
+ return value;
+ },
+
+ makeFrustum: function () {
+ this.WV = Matrix3d.multiplyMatrix(this.get_world(), this.get_view());
+ var viewProjection = Matrix3d.multiplyMatrix(this.WV, this.get_projection());
+ this.WVP = viewProjection.clone();
+ var inverseWorld = this.get_world().clone();
+ inverseWorld.invert();
+
+ // Left plane
+ this._frustum[0].a = viewProjection.get_m14() + viewProjection.get_m11();
+ this._frustum[0].b = viewProjection.get_m24() + viewProjection.get_m21();
+ this._frustum[0].c = viewProjection.get_m34() + viewProjection.get_m31();
+ this._frustum[0].d = viewProjection.get_m44() + viewProjection.get_m41();
+
+ // Right plane
+ this._frustum[1].a = viewProjection.get_m14() - viewProjection.get_m11();
+ this._frustum[1].b = viewProjection.get_m24() - viewProjection.get_m21();
+ this._frustum[1].c = viewProjection.get_m34() - viewProjection.get_m31();
+ this._frustum[1].d = viewProjection.get_m44() - viewProjection.get_m41();
+
+ // Top plane
+ this._frustum[2].a = viewProjection.get_m14() - viewProjection.get_m12();
+ this._frustum[2].b = viewProjection.get_m24() - viewProjection.get_m22();
+ this._frustum[2].c = viewProjection.get_m34() - viewProjection.get_m32();
+ this._frustum[2].d = viewProjection.get_m44() - viewProjection.get_m42();
+
+ // Bottom plane
+ this._frustum[3].a = viewProjection.get_m14() + viewProjection.get_m12();
+ this._frustum[3].b = viewProjection.get_m24() + viewProjection.get_m22();
+ this._frustum[3].c = viewProjection.get_m34() + viewProjection.get_m32();
+ this._frustum[3].d = viewProjection.get_m44() + viewProjection.get_m42();
+
+ // Near plane
+ this._frustum[4].a = viewProjection.get_m13();
+ this._frustum[4].b = viewProjection.get_m23();
+ this._frustum[4].c = viewProjection.get_m33();
+ this._frustum[4].d = viewProjection.get_m43();
+
+ // Far plane
+ this._frustum[5].a = viewProjection.get_m14() - viewProjection.get_m13();
+ this._frustum[5].b = viewProjection.get_m24() - viewProjection.get_m23();
+ this._frustum[5].c = viewProjection.get_m34() - viewProjection.get_m33();
+ this._frustum[5].d = viewProjection.get_m44() - viewProjection.get_m43();
+
+ // Normalize planes
+ for (var i = 0; i < 6; i++) {
+ this._frustum[i].normalize();
+ }
+ this._frustumDirty = false;
+ this.WVP.scale(Vector3d.create(this.width / 2, -this.height / 2, 1));
+ this.WVP.translate(Vector3d.create(this.width / 2, this.height / 2, 0));
+ this._setMatrixes();
+ },
+
+ _initGL: function () {
+ if (this.gl == null) {
+ return;
+ }
+ var uints_for_indices = this.gl.getExtension('OES_element_index_uint');
+ set_tileUvMultiple(1);
+ set_tileDemEnabled(true);
+ TileShader.init(this);
+ },
+
+ freezeView: function () {
+ this.targetAlt = this.alt;
+ this.targetAz = this.az;
+ this.targetCamera = this.viewCamera.copy();
+ },
+
+ _setVertexBuffer: function (vertexBuffer) { },
+
+ _setIndexBuffer: function (indexBuffer) { },
+
+ // Set up a shader for the specified material properties and the
+ // current lighting environment.
+ setMaterial: function (material, diffuseTex, specularTex, normalMap, opacity) {
+ this.set_mainTexture(diffuseTex);
+ },
+
+ preDraw: function () { }
+};
+
+registerType("RenderContext", [RenderContext, RenderContext$, null]);
diff --git a/engine/esm/render_globals.js b/engine/esm/render_globals.js
new file mode 100644
index 00000000..dfae59a2
--- /dev/null
+++ b/engine/esm/render_globals.js
@@ -0,0 +1,95 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Various global variables associated with the rendering engine.
+//
+// In the original C# code these were generally static values associated with
+// various classes, but since we want to avoid circular dependencies in our
+// module structure, we gather some of those values in modules that contain
+// minimal amounts of code (like this one) so that they can go early in the
+// dependency graph.
+
+// This used to be Tile.prepDevice. It's the global WebGL rendering context.
+export var tilePrepDevice = null;
+
+export function set_tilePrepDevice(value) {
+ tilePrepDevice = value;
+}
+
+// This used to be Tile.uvMultiple. It's some GL rendering state variable.
+export var tileUvMultiple = 256;
+
+export function set_tileUvMultiple(value) {
+ tileUvMultiple = value;
+}
+
+// This used to be Tile.demEnabled. It controls whether DEM rendering is
+// enabled, hopefully?
+export var tileDemEnabled = false;
+
+export function set_tileDemEnabled(value) {
+ tileDemEnabled = !!value;
+}
+
+// This used to be `RenderContext.useGl`. It sets whether we're using WebGL.
+//
+// Older versions of the engine used to support HTML Canvas rendering, but that
+// mode is now deprecated. Uses where `useGl` is false may break at any time.
+export var useGl = false;
+
+export function set_useGl(value) {
+ useGl = !!value;
+}
+
+// This used to be `RenderContext.useGlVersion2`. It sets whether we're
+// using WebGL >= 2.
+export var useGlVersion2 = false;
+
+export function set_useGlVersion2(value) {
+ useGlVersion2 = !!value;
+}
+
+// This used to be `TileCache.addTileToQueue()`. It's a function that
+// adds a tile to the fetch queue.
+export var tileCacheAddTileToQueue = null;
+
+export function set_tileCacheAddTileToQueue(value) {
+ tileCacheAddTileToQueue = value;
+}
+
+// This used to be `TileCache.removeFromQueue()`. It's a function that
+// removes a tile from the fetch queue.
+export var tileCacheRemoveFromQueue = null;
+
+export function set_tileCacheRemoveFromQueue(value) {
+ tileCacheRemoveFromQueue = value;
+}
+
+// This used to be `TileCache.accessID`.
+var tileCacheAccessID = 0;
+
+export function inc_tileCacheAccessID() {
+ return tileCacheAccessID++;
+}
+
+// This used to be `TileCache.getTile()`. It gets a tile from the cache, unconditionally.
+export var tileCacheGetTile = null;
+
+export function set_tileCacheGetTile(value) {
+ tileCacheGetTile = value;
+}
+
+// This used to be `TileCache.getCachedTile()`. It gets a tile from the cache.
+export var tileCacheGetCachedTile = null;
+
+export function set_tileCacheGetCachedTile(value) {
+ tileCacheGetCachedTile = value;
+}
+
+// This is another way to access `WWTControl.singleton.renderContext`. It's the
+// global singleton RenderContext instance.
+export var globalRenderContext = null;
+
+export function set_globalRenderContext(value) {
+ globalRenderContext = value;
+}
diff --git a/engine/esm/render_triangle.js b/engine/esm/render_triangle.js
new file mode 100644
index 00000000..536592c5
--- /dev/null
+++ b/engine/esm/render_triangle.js
@@ -0,0 +1,296 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A triangle that is part of a tile pyramid render.
+
+import { registerType } from "./typesystem.js";
+import { Vector2d, Vector3d, PositionTexture } from "./double3d.js";
+
+
+// wwtlib.RenderTriangle
+
+export function RenderTriangle() {
+ this.a = new PositionTexture();
+ this.b = new PositionTexture();
+ this.c = new PositionTexture();
+ this.normal = new Vector3d();
+ this.opacity = 1;
+ this.expansionInPixels = 0.6;
+ this.tileLevel = 0;
+ this._ta = new Vector3d();
+ this._tb = new Vector3d();
+ this._tc = new Vector3d();
+ this._expandedS0 = new Vector2d();
+ this._expandedS1 = new Vector2d();
+ this._expandedS2 = new Vector2d();
+ this.lighting = 1;
+}
+
+RenderTriangle.width = 1024;
+RenderTriangle.height = 768;
+RenderTriangle._contractionInPixels = -0.5;
+RenderTriangle.trianglesRendered = 0;
+RenderTriangle.trianglesCulled = 0;
+RenderTriangle.renderingOn = true;
+RenderTriangle._factor = 1;
+RenderTriangle.cullInside = true;
+RenderTriangle._hw = 0;
+RenderTriangle._qw = 0;
+RenderTriangle._hh = 0;
+RenderTriangle._qh = 0;
+
+RenderTriangle.create = function (a, b, c, img, level) {
+ var temp = new RenderTriangle();
+ temp.a = a.copy();
+ temp.b = b.copy();
+ temp.c = c.copy();
+ temp._texture = img;
+ temp.tileLevel = level;
+ temp.makeNormal();
+ return temp;
+};
+
+RenderTriangle.createWithMiter = function (a, b, c, img, level, expansion) {
+ var temp = new RenderTriangle();
+ temp.expansionInPixels = expansion;
+ temp.a = a.copy();
+ temp.b = b.copy();
+ temp.c = c.copy();
+ temp._texture = img;
+ temp.tileLevel = level;
+ temp.makeNormal();
+ return temp;
+};
+
+RenderTriangle._getMiterPoint = function (p1, p2, p3, edgeOffset) {
+ var edge1 = Vector2d.subtract(p2, p1);
+ var edge2 = Vector2d.subtract(p3, p1);
+ edge1.normalize();
+ edge2.normalize();
+ var dir = Vector2d.create(edge1.x + edge2.x, edge1.y + edge2.y);
+ dir.normalize();
+ var delta = Vector2d.create(edge1.x - edge2.x, edge1.y - edge2.y);
+ var sineHalfAngle = delta.get_length() / 2;
+ var net = Math.min(2, edgeOffset / sineHalfAngle);
+ dir.extend(net);
+ return Vector2d.create(p1.x - dir.x, p1.y - dir.y);
+};
+
+RenderTriangle._miterPoint = function (p1x, p1y, p2x, p2y, p3x, p3y, ExpansionInPixels) {
+ var e1x = p2x - p1x;
+ var e1y = p2y - p1y;
+ var e2x = p3x - p1x;
+ var e2y = p3y - p1y;
+ var length = Math.sqrt(e1x * e1x + e1y * e1y);
+ if (!!length) {
+ e1x /= length;
+ e1y /= length;
+ }
+ length = Math.sqrt(e2x * e2x + e2y * e2y);
+ if (!!length) {
+ e2x /= length;
+ e2y /= length;
+ }
+ var dx = e1x + e2x;
+ var dy = e1y + e2y;
+ length = Math.sqrt(dx * dx + dy * dy);
+ if (!!length) {
+ dx /= length;
+ dy /= length;
+ }
+ var deltax = e1x - e2x;
+ var deltay = e1y - e2y;
+ length = Math.sqrt(deltax * deltax + deltay * deltay);
+ var sineHalfAngle = length / 2;
+ var net = Math.min(2, ExpansionInPixels / sineHalfAngle);
+ dx *= net;
+ dy *= net;
+ return Vector2d.create(p1x - dx, p1y - dy);
+};
+
+RenderTriangle._miterPointOut = function (pntOut, p1x, p1y, p2x, p2y, p3x, p3y, ExpansionInPixels) {
+ var e1x = p2x - p1x;
+ var e1y = p2y - p1y;
+ var e2x = p3x - p1x;
+ var e2y = p3y - p1y;
+ var length = Math.sqrt(e1x * e1x + e1y * e1y);
+ if (!!length) {
+ e1x /= length;
+ e1y /= length;
+ }
+ length = Math.sqrt(e2x * e2x + e2y * e2y);
+ if (!!length) {
+ e2x /= length;
+ e2y /= length;
+ }
+ var dx = e1x + e2x;
+ var dy = e1y + e2y;
+ length = Math.sqrt(dx * dx + dy * dy);
+ if (!!length) {
+ dx /= length;
+ dy /= length;
+ }
+ var deltax = e1x - e2x;
+ var deltay = e1y - e2y;
+ length = Math.sqrt(deltax * deltax + deltay * deltay);
+ var sineHalfAngle = length / 2;
+ var net = Math.min(2, ExpansionInPixels / sineHalfAngle);
+ dx *= net;
+ dy *= net;
+ pntOut.x = p1x - dx;
+ pntOut.y = p1y - dy;
+};
+
+var RenderTriangle$ = {
+ makeNormal: function () {
+ var a = this.a.position.copy();
+ var b = this.b.position.copy();
+ var c = this.c.position.copy();
+ a.normalize();
+ b.normalize();
+ c.normalize();
+ var x = a.x + b.x + c.x;
+ var y = a.y + b.y + c.y;
+ var z = a.z + b.z + c.z;
+ this.normal = Vector3d.create(x / 3, y / 3, z / 3);
+ this.normal.normalize();
+ },
+
+ _checkBackface: function () {
+ var ab = Vector3d.subtractVectors(this._ta, this._tb);
+ var ac = Vector3d.subtractVectors(this._ta, this._tc);
+ var cp = Vector3d.cross(ab, ac);
+ cp.normalize();
+ return cp.z >= 0;
+ },
+
+ draw: function (ctx, wvp) {
+ if (ctx == null) {
+ return;
+ }
+ wvp._transformTo(this.a.position, this._ta);
+ wvp._transformTo(this.b.position, this._tb);
+ wvp._transformTo(this.c.position, this._tc);
+ if (this._checkBackface() === RenderTriangle.cullInside) {
+ RenderTriangle.trianglesCulled++;
+ return;
+ }
+ this._drawTriangle(ctx, this._texture, this._ta.x, this._ta.y, this._tb.x, this._tb.y, this._tc.x, this._tc.y, this.a.tu, this.a.tv, this.b.tu, this.b.tv, this.c.tu, this.c.tv);
+ },
+
+ _drawTriangle: function (ctx, im, x0, y0, x1, y1, x2, y2, sx0, sy0, sx1, sy1, sx2, sy2) {
+ if (!this.intersects(0, RenderTriangle.width, 0, RenderTriangle.height, x0, y0, x1, y1, x2, y2)) {
+ return false;
+ }
+ RenderTriangle._miterPointOut(this._expandedS0, x0, y0, x1, y1, x2, y2, this.expansionInPixels);
+ RenderTriangle._miterPointOut(this._expandedS1, x1, y1, x0, y0, x2, y2, this.expansionInPixels);
+ RenderTriangle._miterPointOut(this._expandedS2, x2, y2, x1, y1, x0, y0, this.expansionInPixels);
+ x0 = this._expandedS0.x;
+ y0 = this._expandedS0.y;
+ x1 = this._expandedS1.x;
+ y1 = this._expandedS1.y;
+ x2 = this._expandedS2.x;
+ y2 = this._expandedS2.y;
+ ctx.save();
+ if (RenderTriangle.renderingOn) {
+ ctx.beginPath();
+ ctx.moveTo(x0, y0);
+ ctx.lineTo(x1, y1);
+ ctx.lineTo(x2, y2);
+ ctx.closePath();
+ ctx.clip();
+ }
+ var denom = sx0 * (sy2 - sy1) - sx1 * sy2 + sx2 * sy1 + (sx1 - sx2) * sy0;
+ //if (denom == 0)
+ //{
+ // ctx.Restore();
+ // return false;
+ //}
+
+ var m11 = -(sy0 * (x2 - x1) - sy1 * x2 + sy2 * x1 + (sy1 - sy2) * x0) / denom;
+ var m12 = (sy1 * y2 + sy0 * (y1 - y2) - sy2 * y1 + (sy2 - sy1) * y0) / denom;
+ var m21 = (sx0 * (x2 - x1) - sx1 * x2 + sx2 * x1 + (sx1 - sx2) * x0) / denom;
+ var m22 = -(sx1 * y2 + sx0 * (y1 - y2) - sx2 * y1 + (sx2 - sx1) * y0) / denom;
+ var dx = (sx0 * (sy2 * x1 - sy1 * x2) + sy0 * (sx1 * x2 - sx2 * x1) + (sx2 * sy1 - sx1 * sy2) * x0) / denom;
+ var dy = (sx0 * (sy2 * y1 - sy1 * y2) + sy0 * (sx1 * y2 - sx2 * y1) + (sx2 * sy1 - sx1 * sy2) * y0) / denom;
+ ctx.transform(m11, m12, m21, m22, dx, dy);
+ if (RenderTriangle.renderingOn) {
+ ctx.globalAlpha = this.opacity;
+ if (this.lighting < 1) {
+ ctx.globalAlpha = 1;
+ ctx.fillStyle = 'Black';
+ ctx.fillRect(0, 0, RenderTriangle.width, RenderTriangle.height);
+ ctx.globalAlpha = this.lighting * this.opacity;
+ }
+ ctx.drawImage(im, 0, 0);
+ }
+ ctx.restore();
+ return true;
+ },
+
+ intersects: function (l, r, t, b, x0, y0, x1, y1, x2, y2) {
+ if (x0 > l && x0 < r && y0 > t && y0 < b) {
+ return true;
+ }
+ if (x1 > l && x1 < r && y1 > t && y1 < b) {
+ return true;
+ }
+ if (x2 > l && x2 < r && y2 > t && y2 < b) {
+ return true;
+ }
+ var h4 = RenderTriangle.height * 4;
+ if (this.tileLevel < 4 && ((Math.abs(x0 - x1) > h4) || (Math.abs(y0 - y1) > h4) || (Math.abs(x2 - x1) > h4) || (Math.abs(y2 - y1) > h4) || (Math.abs(x0 - x2) > h4) || (Math.abs(y0 - y2) > h4))) {
+ return false;
+ }
+ return this.lineRectangleIntersect(l, r, t, b, x0, y0, x1, y1) || this.lineRectangleIntersect(l, r, t, b, x1, y1, x2, y2) || this.lineRectangleIntersect(l, r, t, b, x2, y2, x0, y0);
+ },
+
+ lineRectangleIntersect: function (l, r, t, b, x0, y0, x1, y1) {
+ var top_intersection;
+ var bottom_intersection;
+ var toptrianglepoint;
+ var bottomtrianglepoint;
+ var m;
+ var c;
+
+ // Calculate m and c for the equation for the line (y = mx+c)
+ m = (y1 - y0) / (x1 - x0);
+ c = y0 - (m * x0);
+
+ // if the line is going up from right to left then the top intersect point is on the left
+ if (m > 0) {
+ top_intersection = (m * l + c);
+ bottom_intersection = (m * r + c);
+ } else {
+ // otherwise it's on the right
+ top_intersection = (m * r + c);
+ bottom_intersection = (m * l + c);
+ }
+
+ // work out the top and bottom extents for the triangle
+ if (y0 < y1) {
+ toptrianglepoint = y0;
+ bottomtrianglepoint = y1;
+ } else {
+ toptrianglepoint = y1;
+ bottomtrianglepoint = y0;
+ }
+
+ // and calculate the overlap between those two bounds
+ var topoverlap;
+ var botoverlap;
+ topoverlap = (top_intersection > toptrianglepoint) ? top_intersection : toptrianglepoint;
+ botoverlap = (bottom_intersection < bottomtrianglepoint) ? bottom_intersection : bottomtrianglepoint;
+
+ // (topoverlapb)) :
+ // If the bottom overlap is higher than the top of the rectangle or the top overlap is
+ // lower than the bottom of the rectangle we don't have intersection. So return the negative
+ // of that. Much faster than checking each of the points is within the bounds of the rectangle.
+ return (topoverlap < botoverlap) && (!((botoverlap < t) || (topoverlap > b)));
+ }
+};
+
+registerType("RenderTriangle", [RenderTriangle, RenderTriangle$, null]);
diff --git a/engine/esm/script_interface.js b/engine/esm/script_interface.js
new file mode 100644
index 00000000..3a093be5
--- /dev/null
+++ b/engine/esm/script_interface.js
@@ -0,0 +1,716 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// The quasi-legacy ScriptInterface control interface.
+//
+// I believe that this new class was created in the very early days of the WWT
+// web control and was used as the interface point with the browser. In the
+// modern WebGL engine, there's not need to put all this functionality in this
+// separate module. But, as always, to preserve API compatibility, we maintain
+// all of the interfaces that were added here.
+
+import { ss } from "./ss.js";
+import { registerType } from "./typesystem.js";
+import { Util } from "./util.js";
+import { globalRenderContext, useGlVersion2 } from "./render_globals.js";
+import { globalWWTControl, layerManagerGetAllMaps, loadWtmlFile } from "./data_globals.js";
+import { Annotation, Circle, Poly, PolyLine } from "./annotation.js";
+import { FitsImage } from "./layers/fits_image.js";
+import { FitsImageJs } from "./layers/fits_image_js.js";
+import { Imageset } from "./imageset.js";
+import { ImageSetLayer } from "./layers/imageset_layer.js";
+import { LayerManager } from "./layers/layer_manager.js";
+import { Folder } from "./folder.js";
+
+
+// wwtlib.SlideChangedEventArgs
+
+export function SlideChangedEventArgs(caption) {
+ ss.EventArgs.call(this);
+ this.set_caption(caption);
+}
+
+var SlideChangedEventArgs$ = {
+ get_caption: function () {
+ return this._caption$2;
+ },
+
+ set_caption: function (value) {
+ this._caption$2 = value;
+ return value;
+ }
+};
+
+registerType("SlideChangedEventArgs", [SlideChangedEventArgs, SlideChangedEventArgs$, ss.EventArgs]);
+
+
+// wwtlib.ArrivedEventArgs
+
+export function ArrivedEventArgs(ra, dec, zoom) {
+ this._ra$2 = 0;
+ this._dec$2 = 0;
+ this._zoom$2 = 0;
+ ss.EventArgs.call(this);
+ this.set_RA(ra * 15);
+ this.set_dec(dec);
+ this.set_zoom(zoom / 6);
+}
+
+var ArrivedEventArgs$ = {
+ get_RA: function () {
+ return this._ra$2;
+ },
+
+ set_RA: function (value) {
+ this._ra$2 = value;
+ return value;
+ },
+
+ get_dec: function () {
+ return this._dec$2;
+ },
+
+ set_dec: function (value) {
+ this._dec$2 = value;
+ return value;
+ },
+
+ get_zoom: function () {
+ return this._zoom$2;
+ },
+
+ set_zoom: function (value) {
+ this._zoom$2 = value;
+ return value;
+ }
+};
+
+registerType("ArrivedEventArgs", [ArrivedEventArgs, ArrivedEventArgs$, ss.EventArgs]);
+
+
+// wwtlib.AnnotationClickEventArgs
+
+export function AnnotationClickEventArgs(ra, dec, id) {
+ this._ra$2 = 0;
+ this._dec$2 = 0;
+ ss.EventArgs.call(this);
+ this.set_RA(ra * 15);
+ this.set_dec(dec);
+ this.set_id(id);
+}
+
+var AnnotationClickEventArgs$ = {
+ get_RA: function () {
+ return this._ra$2;
+ },
+
+ set_RA: function (value) {
+ this._ra$2 = value;
+ return value;
+ },
+
+ get_dec: function () {
+ return this._dec$2;
+ },
+
+ set_dec: function (value) {
+ this._dec$2 = value;
+ return value;
+ },
+
+ get_id: function () {
+ return this._id$2;
+ },
+
+ set_id: function (value) {
+ this._id$2 = value;
+ return value;
+ }
+};
+
+registerType("AnnotationClickEventArgs", [AnnotationClickEventArgs, AnnotationClickEventArgs$, ss.EventArgs]);
+
+
+// wwtlib.CollectionLoadedEventArgs
+
+export function CollectionLoadedEventArgs(url) {
+ ss.EventArgs.call(this);
+ this._url$2 = url;
+}
+
+var CollectionLoadedEventArgs$ = {
+ get_url: function () {
+ return this._url$2;
+ },
+
+ set_url: function (value) {
+ this._url$2 = value;
+ return value;
+ }
+};
+
+registerType("CollectionLoadedEventArgs", [CollectionLoadedEventArgs, CollectionLoadedEventArgs$, ss.EventArgs]);
+
+
+// wwtlib.ScriptInterface
+
+export function ScriptInterface() {
+ this._missedReady = false;
+ this.hideTourFeedback = false;
+ this._smoothAnimation = false;
+ this._showCaptions = true;
+}
+
+ScriptInterface._containsFitsLikeExtentsion = function (url) {
+ var lowerCaseUrl = url.toLowerCase();
+ return (ss.endsWith(lowerCaseUrl, 'fits') || ss.endsWith(lowerCaseUrl, 'ftz') || ss.endsWith(lowerCaseUrl, 'fit') || ss.endsWith(lowerCaseUrl, 'fts'));
+};
+
+ScriptInterface._addImageSet = function (name, gotoTarget, loaded, imageset) {
+ if (ss.whitespace(name)) {
+ name = LayerManager.getNextImageSetName();
+ }
+ var imagesetLayer = LayerManager.addImageSetLayerCallback(imageset, name, loaded);
+ if (gotoTarget) {
+ var zoom = imageset._guessZoomSetting(globalRenderContext.viewCamera.zoom);
+ globalWWTControl.gotoRADecZoom(imageset.get_viewCenterX() / 15, imageset.get_viewCenterY(), zoom, false, null);
+ }
+ return imagesetLayer;
+};
+
+ScriptInterface._addFitsLayer = function (url, name, gotoTarget, loaded) {
+ if (ss.whitespace(name)) {
+ name = LayerManager.getNextFitsName();
+ }
+ var imagesetLayer = new ImageSetLayer();
+ var imageset = new Imageset();
+ var wcsLoaded = function (wcsImage) {
+ if ((wcsImage).errored) {
+ return;
+ }
+ var width = ss.truncate(wcsImage.get_sizeX());
+ var height = ss.truncate(wcsImage.get_sizeY());
+ imageset.setInitialParameters(wcsImage.get_description(), wcsImage.get_filename(), 2, 3, 5, Util.getHashCode(wcsImage.get_filename()), 0, 0, wcsImage.get_scaleY(), '.fits', wcsImage.get_scaleX() > 0, '', wcsImage.get_centerX(), wcsImage.get_centerY(), wcsImage.get_rotation(), false, '', false, false, 1, wcsImage.get_referenceX(), wcsImage.get_referenceY(), wcsImage.get_copyright(), wcsImage.get_creditsUrl(), '', '', 0, '');
+ imageset.set_wcsImage(wcsImage);
+ imagesetLayer.set_imageSet(imageset);
+ LayerManager.addFitsImageSetLayer(imagesetLayer, name);
+ if (gotoTarget) {
+ var zoom = imageset._guessZoomSetting(globalRenderContext.viewCamera.zoom);
+ globalWWTControl.gotoRADecZoom(wcsImage.get_viewCenterX() / 15, wcsImage.get_viewCenterY(), zoom, false, null);
+ }
+ if (loaded != null) {
+ loaded(imagesetLayer);
+ }
+ };
+ if (ss.whitespace(name)) {
+ name = LayerManager.getNextFitsName();
+ }
+ if (useGlVersion2) {
+ new FitsImage(imageset, url, null, wcsLoaded);
+ }
+ else {
+ new FitsImageJs(imageset, url, null, wcsLoaded);
+ }
+ return imagesetLayer;
+};
+
+var ScriptInterface$ = {
+ add_ready: function (value) {
+ this.__ready = ss.bindAdd(this.__ready, value);
+ },
+
+ remove_ready: function (value) {
+ this.__ready = ss.bindSub(this.__ready, value);
+ },
+
+ _fireReady: function () {
+ if (this.__ready != null) {
+ this.__ready(this, new ss.EventArgs());
+ } else {
+ this._missedReady = true;
+ }
+ },
+
+ add_collectionLoaded: function (value) {
+ this.__collectionLoaded = ss.bindAdd(this.__collectionLoaded, value);
+ },
+
+ remove_collectionLoaded: function (value) {
+ this.__collectionLoaded = ss.bindSub(this.__collectionLoaded, value);
+ },
+
+ _fireCollectionLoaded: function (url) {
+ if (this.__collectionLoaded != null) {
+ this.__collectionLoaded(this, new CollectionLoadedEventArgs(url));
+ }
+ },
+
+ add_colorPickerDisplay: function (value) {
+ this.__colorPickerDisplay = ss.bindAdd(this.__colorPickerDisplay, value);
+ },
+
+ remove_colorPickerDisplay: function (value) {
+ this.__colorPickerDisplay = ss.bindSub(this.__colorPickerDisplay, value);
+ },
+
+ add_voTableDisplay: function (value) {
+ this.__voTableDisplay = ss.bindAdd(this.__voTableDisplay, value);
+ },
+
+ remove_voTableDisplay: function (value) {
+ this.__voTableDisplay = ss.bindSub(this.__voTableDisplay, value);
+ },
+
+ add_refreshLayerManager: function (value) {
+ this.__refreshLayerManager = ss.bindAdd(this.__refreshLayerManager, value);
+ },
+
+ remove_refreshLayerManager: function (value) {
+ this.__refreshLayerManager = ss.bindSub(this.__refreshLayerManager, value);
+ },
+
+ add_arrived: function (value) {
+ this.__arrived = ss.bindAdd(this.__arrived, value);
+ },
+
+ remove_arrived: function (value) {
+ this.__arrived = ss.bindSub(this.__arrived, value);
+ },
+
+ add_clicked: function (value) {
+ this.__clicked = ss.bindAdd(this.__clicked, value);
+ },
+
+ remove_clicked: function (value) {
+ this.__clicked = ss.bindSub(this.__clicked, value);
+ },
+
+ add_annotationClicked: function (value) {
+ this.__annotationClicked = ss.bindAdd(this.__annotationClicked, value);
+ },
+
+ remove_annotationClicked: function (value) {
+ this.__annotationClicked = ss.bindSub(this.__annotationClicked, value);
+ },
+
+ add_imageryLoaded: function (value) {
+ this.__imageryLoaded = ss.bindAdd(this.__imageryLoaded, value);
+ },
+
+ remove_imageryLoaded: function (value) {
+ this.__imageryLoaded = ss.bindSub(this.__imageryLoaded, value);
+ },
+
+ add_tourReady: function (value) {
+ this.__tourReady = ss.bindAdd(this.__tourReady, value);
+ },
+
+ remove_tourReady: function (value) {
+ this.__tourReady = ss.bindSub(this.__tourReady, value);
+ },
+
+ add_tourError: function (value) {
+ this.__tourError = ss.bindAdd(this.__tourError, value);
+ },
+
+ remove_tourError: function (value) {
+ this.__tourError = ss.bindSub(this.__tourError, value);
+ },
+
+ add_tourPaused: function (value) {
+ this.__tourPaused = ss.bindAdd(this.__tourPaused, value);
+ },
+
+ remove_tourPaused: function (value) {
+ this.__tourPaused = ss.bindSub(this.__tourPaused, value);
+ },
+
+ add_tourResumed: function (value) {
+ this.__tourResumed = ss.bindAdd(this.__tourResumed, value);
+ },
+
+ remove_tourResumed: function (value) {
+ this.__tourResumed = ss.bindSub(this.__tourResumed, value);
+ },
+
+ add_tourEnded: function (value) {
+ this.__tourEnded = ss.bindAdd(this.__tourEnded, value);
+ },
+
+ remove_tourEnded: function (value) {
+ this.__tourEnded = ss.bindSub(this.__tourEnded, value);
+ },
+
+ add_slideChanged: function (value) {
+ this.__slideChanged = ss.bindAdd(this.__slideChanged, value);
+ },
+
+ remove_slideChanged: function (value) {
+ this.__slideChanged = ss.bindSub(this.__slideChanged, value);
+ },
+
+ //UI will set this to a function that takes 2 string properties (prop,val)
+ //("title", "left", or "right" for the labels, "pos" for the slider pos)
+ //Pass a 0-1 float to set the slider position (stringify it if you need to for strong typing)
+
+ add_timeScrubberHook: function (value) {
+ this.__timeScrubberHook = ss.bindAdd(this.__timeScrubberHook, value);
+ },
+
+ remove_timeScrubberHook: function (value) {
+ this.__timeScrubberHook = ss.bindSub(this.__timeScrubberHook, value);
+ },
+
+ setTimeScrubberPosition: function (posLeft) {
+ LayerManager.setTimeSliderValue(posLeft);
+ },
+
+ setTimeSlider: function (name, value) {
+ this.__timeScrubberHook(name, value);
+ },
+
+ showColorPicker: function (pickerInstance, e) {
+ if (this.__colorPickerDisplay != null) {
+ this.__colorPickerDisplay(pickerInstance, e);
+ }
+ },
+
+ displayVoTableLayer: function (layer) {
+ if (this.__voTableDisplay != null) {
+ this.__voTableDisplay(layer, new ss.EventArgs());
+ }
+ },
+
+ refreshLayerManagerNow: function () {
+ if (this.__refreshLayerManager != null) {
+ this.__refreshLayerManager(null, new ss.EventArgs());
+ }
+ },
+
+ _fireTourReady: function () {
+ if (this.__tourReady != null) {
+ this.__tourReady(this, new ss.EventArgs());
+ }
+ },
+
+ _fireTourError: function (ex) {
+ if (this.__tourError != null) {
+ this.__tourError(ex, new ss.EventArgs());
+ }
+ },
+
+ _fireTourPaused: function () {
+ if (this.__tourPaused != null) {
+ this.__tourPaused(this, new ss.EventArgs());
+ }
+ },
+
+ _fireTourResume: function () {
+ if (this.__tourResumed != null) {
+ this.__tourResumed(this, new ss.EventArgs());
+ }
+ },
+
+ _fireTourEnded: function () {
+ if (this.__tourEnded != null) {
+ this.__tourEnded(this, new ss.EventArgs());
+ }
+ },
+
+ _fireImageryLoaded: function () {
+ if (this.__imageryLoaded != null) {
+ this.__imageryLoaded(this, new ss.EventArgs());
+ }
+ },
+
+ _fireClick: function (ra, dec) {
+ if (this.__clicked != null) {
+ this.__clicked(this, new ArrivedEventArgs(ra, dec, globalRenderContext.viewCamera.zoom));
+ }
+ },
+
+ _fireArrived: function (ra, dec, zoom) {
+ if (this.__arrived != null) {
+ this.__arrived(this, new ArrivedEventArgs(ra, dec, zoom));
+ }
+ },
+
+ _fireAnnotationclicked: function (RA, Dec, id) {
+ try {
+ if (this.__annotationClicked != null) {
+ this.__annotationClicked(this, new AnnotationClickEventArgs(RA, Dec, id));
+ }
+ }
+ catch ($e1) {
+ }
+ },
+
+ _fireSlideChanged: function (caption) {
+ try {
+ if (this.__slideChanged != null) {
+ this.__slideChanged(this, new SlideChangedEventArgs(caption));
+ }
+ }
+ catch ($e1) {
+ }
+ },
+
+ endInit: function () {
+ if (this._missedReady) {
+ this._fireReady();
+ }
+ },
+
+ gotoRaDecZoom: function (ra, dec, zoom, instant, roll) {
+ if (globalWWTControl != null) {
+ globalWWTControl.gotoRADecZoom(ra / 15, dec, zoom * 6, instant, roll);
+ }
+ },
+
+ setBackgroundImageByName: function (name) {
+ if (globalWWTControl != null) {
+ globalWWTControl.setBackgroundImageByName(name);
+ }
+ },
+
+ // Call this to add a VOTable to layers
+ addVoTableLayer: function (table) {
+ return LayerManager.addVoTableLayer(table, 'Vo Table');
+ },
+
+ getLayers: function () {
+ return LayerManager.get_layerList();
+ },
+
+ setForegroundImageByName: function (name) {
+ if (globalWWTControl != null) {
+ globalWWTControl.setForegroundImageByName(name);
+ globalRenderContext.viewCamera.opacity = 100;
+ }
+ },
+
+ setForegroundOpacity: function (opacity) {
+ if (globalWWTControl != null) {
+ globalRenderContext.viewCamera.opacity = opacity;
+ }
+ },
+
+ addCatalogHipsByName: function (name) {
+ if (globalWWTControl != null) {
+ globalWWTControl.addCatalogHipsByName(name);
+ }
+ },
+
+ addCatalogHipsByNameWithCallback: function (name, onLoad) {
+ if (globalWWTControl != null) {
+ globalWWTControl.addCatalogHipsByNameWithCallback(name, onLoad);
+ }
+ },
+
+ removeCatalogHipsByName: function (name) {
+ if (globalWWTControl != null) {
+ globalWWTControl.removeCatalogHipsByName(name);
+ }
+ },
+
+ getCatalogHipsDataInView: function (name, limit, onComplete) {
+ if (globalWWTControl != null) {
+ globalWWTControl.getCatalogHipsDataInView(name, limit, onComplete);
+ }
+ },
+
+ setCutsForFits: function (imagesetName, min, max) {
+ if (globalWWTControl != null) {
+ globalWWTControl.setCutsForFits(imagesetName, min, max);
+ }
+ },
+
+ setColorMapForFits: function (imagesetName, colorMapName) {
+ if (globalWWTControl != null) {
+ globalWWTControl.setColorMapForFits(imagesetName, colorMapName);
+ }
+ },
+
+ setScaleTypeForFits: function (imagesetName, scaleType) {
+ if (globalWWTControl != null) {
+ globalWWTControl.setScaleTypeForFits(imagesetName, scaleType);
+ }
+ },
+
+ hideUI: function (hide) { },
+
+ loadTour: function (url) {
+ if (globalWWTControl != null) {
+ globalWWTControl.playTour(url);
+ }
+ },
+
+ loadFits: function (url) {
+ return this.loadFitsLayer(url, '', true, null);
+ },
+
+ loadFitsLayer: function (url, name, gotoTarget, loaded) {
+ return this.addImageSetLayer(url, 'fits', name, gotoTarget, loaded);
+ },
+
+ addImageSetLayer: function (url, mode, name, gotoTarget, loaded) {
+ if (mode != null && mode.toLowerCase() === 'fits') {
+ return ScriptInterface._addFitsLayer(url, name, gotoTarget, loaded);
+ } else if (mode != null && mode.toLowerCase() === 'preloaded') {
+ var imageset = globalWWTControl.getImageSetByUrl(url);
+ if (imageset != null) {
+ return ScriptInterface._addImageSet(name, gotoTarget, loaded, imageset);
+ }
+ } else {
+ var imageset = globalWWTControl.getImageSetByUrl(url);
+ if (imageset != null) {
+ return ScriptInterface._addImageSet(name, gotoTarget, loaded, imageset);
+ }
+ else if (ScriptInterface._containsFitsLikeExtentsion(url)) {
+ return ScriptInterface._addFitsLayer(url, name, gotoTarget, loaded);
+ }
+ }
+ return null;
+ },
+
+ setImageSetLayerOrder: function (id, order) {
+ var layer = LayerManager.get_layerList()[id];
+ if (ss.canCast(layer, ImageSetLayer) && order >= 0) {
+ ss.remove(layerManagerGetAllMaps()[layer.get_referenceFrame()].layers, layer);
+
+ //In case of order > Layers.length, the layer is properly put at the end of the list
+ layerManagerGetAllMaps()[layer.get_referenceFrame()].layers.splice(order, 0, layer);
+ }
+ },
+
+ isUsingWebGl2: function () {
+ return useGlVersion2;
+ },
+
+ get_hideTourFeedback: function () {
+ return this.hideTourFeedback;
+ },
+
+ set_hideTourFeedback: function (value) {
+ this.hideTourFeedback = value;
+ return value;
+ },
+
+ playTour: function () {
+ if (globalWWTControl != null) {
+ globalWWTControl.playCurrentTour();
+ }
+ },
+
+ stopTour: function () {
+ if (globalWWTControl != null) {
+ globalWWTControl.stopCurrentTour();
+ }
+ },
+
+ loadImageCollection: function (url, loadChildFolders) {
+ var $this = this;
+
+ this._imageUrl = url;
+ loadWtmlFile(url, function () {
+ $this._fireCollectionLoaded(url);
+ }, loadChildFolders);
+ },
+
+ _imageFileLoaded: function () {
+ this._fireCollectionLoaded(this._imageUrl);
+ },
+
+ zoom: function (factor) {
+ if (globalWWTControl != null) {
+ globalWWTControl.zoom(factor);
+ }
+ return;
+ },
+
+ getRA: function () {
+ if (globalWWTControl != null) {
+ return globalRenderContext.get_RA();
+ }
+ return 0;
+ },
+
+ getDec: function () {
+ if (globalWWTControl != null) {
+ return globalRenderContext.get_dec();
+ }
+ return 0;
+ },
+
+ createFolder: function () {
+ var folder = new Folder();
+ return folder;
+ },
+
+ createPolygon: function (fill) {
+ var p = new Poly();
+ p.set_fill(fill);
+ return p;
+ },
+
+ createPolyLine: function (fill) {
+ return new PolyLine();
+ },
+
+ createCircle: function (fill) {
+ var c = new Circle();
+ c.set_fill(fill);
+ return c;
+ },
+
+ addAnnotation: function (annotation) {
+ if (annotation != null && ss.canCast(annotation, Annotation)) {
+ if (globalWWTControl != null) {
+ globalWWTControl._addAnnotation(annotation);
+ }
+ }
+ },
+
+ removeAnnotation: function (annotation) {
+ if (annotation != null) {
+ if (globalWWTControl != null) {
+ globalWWTControl._removeAnnotation(annotation);
+ }
+ }
+ },
+
+ clearAnnotations: function () {
+ if (globalWWTControl != null) {
+ globalWWTControl._clearAnnotations();
+ }
+ },
+
+ get_smoothAnimation: function () {
+ return this._smoothAnimation;
+ },
+
+ set_smoothAnimation: function (value) {
+ this._smoothAnimation = value;
+ return value;
+ },
+
+ get_showCaptions: function () {
+ return this._showCaptions;
+ },
+
+ set_showCaptions: function (value) {
+ this._showCaptions = value;
+ return value;
+ },
+
+ loadVOTable: function (url, useCurrentView) { },
+
+ get_fov: function () {
+ if (globalWWTControl != null) {
+ return globalRenderContext.viewCamera.zoom / 6;
+ }
+ return 60;
+ }
+};
+
+registerType("ScriptInterface", [ScriptInterface, ScriptInterface$, null]);
diff --git a/engine/esm/settings.js b/engine/esm/settings.js
new file mode 100644
index 00000000..96e298ae
--- /dev/null
+++ b/engine/esm/settings.js
@@ -0,0 +1,840 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Planet-related code that can come lower in the dependency graph.
+
+import { registerType, registerEnum } from "./typesystem.js";
+import { Colors } from "./color.js";
+import { ConstellationFilter } from "./constellation_filter.js";
+import { ISettings } from "./interfaces.js";
+
+
+// wwtlib.StockSkyOverlayTypes
+//
+// This was defined in `Tours/ISettings.cs`, which we've folded into `interfaces.js`.
+
+export var StockSkyOverlayTypes = {
+ empty: 0,
+ equatorialGrid: 1,
+ equatorialGridText: 2,
+ galacticGrid: 3,
+ galacticGridText: 4,
+ eclipticGrid: 5,
+ eclipticGridText: 6,
+ eclipticOverview: 7,
+ eclipticOverviewText: 8,
+ precessionChart: 9,
+ altAzGrid: 10,
+ altAzGridText: 11,
+ constellationFigures: 12,
+ constellationBoundaries: 13,
+ constellationFocusedOnly: 14,
+ constellationNames: 15,
+ constellationPictures: 16,
+ fadeToBlack: 17,
+ fadeToLogo: 18,
+ fadeToGradient: 19,
+ screenBroadcast: 20,
+ fadeRemoteOnly: 21,
+ skyGrids: 22,
+ constellations: 23,
+ solarSystemStars: 24,
+ solarSystemMilkyWay: 25,
+ solarSystemCosmos: 26,
+ solarSystemOrbits: 27,
+ solarSystemPlanets: 28,
+ solarSystemAsteroids: 29,
+ solarSystemLighting: 30,
+ solarSystemMinorOrbits: 31,
+ showEarthCloudLayer: 32,
+ showElevationModel: 33,
+ showAtmosphere: 34,
+ multiResSolarSystemBodies: 35,
+ auroraBorialis: 36,
+ earthCutAway: 37,
+ showSolarSystem: 38,
+ clouds8k: 39,
+ filedOfView: 40,
+ showISSModel: 41,
+ solarSystemCMB: 42,
+ mpcZone1: 43,
+ mpcZone2: 44,
+ mpcZone3: 45,
+ mpcZone4: 46,
+ mpcZone5: 47,
+ mpcZone6: 48,
+ mpcZone7: 49,
+ orbitFilters: 50
+};
+
+registerType("StockSkyOverlayTypes", StockSkyOverlayTypes);
+registerEnum("StockSkyOverlayTypes", StockSkyOverlayTypes);
+
+
+// wwtlib.SettingParameter
+//
+// This was defined in `Tours/ISettings.cs`, which we've folded into `interfaces.js`.
+
+export function SettingParameter(edgeTrigger, opacity, targetState, filter) {
+ this.targetState = false;
+ this.edgeTrigger = false;
+ this.opacity = 0;
+ this.edgeTrigger = edgeTrigger;
+ this.opacity = opacity;
+ this.targetState = targetState;
+ this.filter = filter;
+}
+
+var SettingParameter$ = {};
+
+registerType("SettingParameter", [SettingParameter, SettingParameter$, null]);
+
+
+// wwtlib.Settings
+
+export function Settings() {
+ this.autoRepeatTour = false;
+ this._localHorizonMode = false;
+ this._galacticMode = false;
+ this._constellationBoundryColor = 'blue';
+ this._constellationSelectionColor = 'yellow';
+ this._constellationFigureColor = 'red';
+ this._showConstellationFigures = true;
+ this._showConstellationBoundries = true;
+ this._showConstellationSelection = true;
+ this._showCrosshairs = true;
+ this._crosshairsColor = 'white';
+ this._showEcliptic = false;
+ this._locationLat = 47.717;
+ this._locationLng = -122.0858;
+ this._locationAltitude = 100;
+ this._showFiledOfView = false;
+ this._actualPlanetScale = true;
+ this._fovCamera = 0;
+ this._fovEyepiece = 0;
+ this._fovTelescope = 0;
+ this._showClouds = false;
+ this._showGrid = false;
+ this._showHorizon = true;
+ this._showHorizonPanorama = false;
+ this._showMoonsAsPointSource = true;
+ this._showSolarSystem = true;
+ this._solarSystemStars = true;
+ this._solarSystemMilkyWay = true;
+ this._solarSystemCosmos = true;
+ this._solarSystemOrbits = true;
+ this._solarSystemOverlays = true;
+ this._solarSystemLighting = true;
+ this._solarSystemMultiRes = true;
+ this._solarSystemScale = 1;
+ this._smoothPan = true;
+ this._showElevationModel = true;
+ this._showEquatorialGridText = false;
+ this._showGalacticGrid = false;
+ this._showGalacticGridText = false;
+ this._showEclipticGrid = false;
+ this._showEclipticGridText = false;
+ this._showEclipticOverviewText = false;
+ this._showAltAzGrid = false;
+ this._eclipticGridColor = Colors.get_green();
+ this._galacticGridColor = Colors.get_cyan();
+ this._altAzGridColor = Colors.get_magenta();
+ this._precessionChartColor = Colors.get_orange();
+ this._eclipticColor = Colors.get_blue();
+ this._equatorialGridColor = Colors.get_white();
+ this._showAltAzGridText = false;
+ this._showPrecessionChart = false;
+ this._showConstellationPictures = false;
+ this._showConstellationLabels = false;
+ this._constellationLabelsHeight = 80;
+ this._solarSystemCMB = true;
+ this._solarSystemMinorPlanets = false;
+ this._solarSystemPlanets = true;
+ this._showEarthSky = true;
+ this._solarSystemMinorOrbits = false;
+ this._constellationsEnabled = '';
+ this._constellationFiguresFilter = new ConstellationFilter();
+ this._constellationBoundariesFilter = new ConstellationFilter();
+ this._constellationNamesFilter = new ConstellationFilter();
+ this._constellationArtFilter = new ConstellationFilter();
+ this._showSkyOverlays = true;
+ this._showConstellations = true;
+ this._showSkyNode = true;
+ this._showSkyGrids = true;
+ this._showSkyOverlaysIn3d = true;
+ this._earthCutawayView = false;
+ this._showISSModel = false;
+ this._milkyWayModel = false;
+ this._minorPlanetsFilter = 255;
+ this._planetOrbitsFilter = 2147483647;
+ this._constellations = true;
+}
+
+Settings._active = null;
+Settings.tourSettings = null;
+
+Settings.get_current = function () {
+ if (Settings._active == null) {
+ Settings._active = new Settings();
+ }
+ return Settings._active;
+};
+
+Settings.get_globalSettings = function () {
+ if (Settings._active == null) {
+ Settings._active = new Settings();
+ }
+ return Settings._active;
+};
+
+Settings.get_active = function () {
+ if (Settings._active == null) {
+ Settings._active = new Settings();
+ }
+ if (Settings.tourSettings != null) {
+ return Settings.tourSettings;
+ }
+ return Settings._active;
+};
+
+var Settings$ = {
+ get_constellationFigureColor: function () {
+ return this._constellationFigureColor;
+ },
+
+ set_constellationFigureColor: function (value) {
+ this._constellationFigureColor = value;
+ return value;
+ },
+
+ get_constellationBoundryColor: function () {
+ return this._constellationBoundryColor;
+ },
+
+ set_constellationBoundryColor: function (value) {
+ this._constellationBoundryColor = value;
+ return value;
+ },
+
+ get_constellationSelectionColor: function () {
+ return this._constellationSelectionColor;
+ },
+
+ set_constellationSelectionColor: function (value) {
+ this._constellationSelectionColor = value;
+ return value;
+ },
+
+ get_showCrosshairs: function () {
+ return this._showCrosshairs;
+ },
+
+ set_showCrosshairs: function (value) {
+ this._showCrosshairs = value;
+ return value;
+ },
+
+ get_smoothPan: function () {
+ return this._smoothPan;
+ },
+
+ set_smoothPan: function (value) {
+ this._smoothPan = value;
+ return value;
+ },
+
+ get_crosshairsColor: function () {
+ return this._crosshairsColor;
+ },
+
+ set_crosshairsColor: function (value) {
+ this._crosshairsColor = value;
+ return value;
+ },
+
+ get_actualPlanetScale: function () {
+ return this._actualPlanetScale;
+ },
+
+ set_actualPlanetScale: function (value) {
+ this._actualPlanetScale = value;
+ return value;
+ },
+
+ get_fovCamera: function () {
+ return this._fovCamera;
+ },
+
+ get_fovEyepiece: function () {
+ return this._fovEyepiece;
+ },
+
+ get_fovTelescope: function () {
+ return this._fovTelescope;
+ },
+
+ get_locationAltitude: function () {
+ return this._locationAltitude;
+ },
+
+ set_locationAltitude: function (value) {
+ this._locationAltitude = value;
+ return value;
+ },
+
+ get_locationLat: function () {
+ return this._locationLat;
+ },
+
+ set_locationLat: function (value) {
+ this._locationLat = value;
+ return value;
+ },
+
+ get_locationLng: function () {
+ return this._locationLng;
+ },
+
+ set_locationLng: function (value) {
+ this._locationLng = value;
+ return value;
+ },
+
+ get_showClouds: function () {
+ return this._showClouds;
+ },
+
+ get_showConstellationBoundries: function () {
+ return this._showConstellationBoundries;
+ },
+
+ set_showConstellationBoundries: function (value) {
+ this._showConstellationBoundries = value;
+ return value;
+ },
+
+ get_showConstellationFigures: function () {
+ return this._showConstellationFigures;
+ },
+
+ set_showConstellationFigures: function (value) {
+ this._showConstellationFigures = value;
+ return value;
+ },
+
+ get_showConstellationSelection: function () {
+ return this._showConstellationSelection;
+ },
+
+ set_showConstellationSelection: function (value) {
+ this._showConstellationSelection = value;
+ return value;
+ },
+
+ get_showEcliptic: function () {
+ return this._showEcliptic;
+ },
+
+ set_showEcliptic: function (value) {
+ this._showEcliptic = value;
+ return value;
+ },
+
+ get_showElevationModel: function () {
+ return this._showElevationModel;
+ },
+
+ set_showElevationModel: function (value) {
+ this._showElevationModel = value;
+ return value;
+ },
+
+ get_showFieldOfView: function () {
+ return this._showFiledOfView;
+ },
+
+ get_showGrid: function () {
+ return this._showGrid;
+ },
+
+ set_showGrid: function (value) {
+ this._showGrid = value;
+ return value;
+ },
+
+ get_showHorizon: function () {
+ return this._showHorizon;
+ },
+
+ set_showHorizon: function (value) {
+ this._showHorizon = value;
+ return value;
+ },
+
+ get_showHorizonPanorama: function () {
+ return this._showHorizonPanorama;
+ },
+
+ get_showMoonsAsPointSource: function () {
+ return this._showMoonsAsPointSource;
+ },
+
+ get_showSolarSystem: function () {
+ return this._showSolarSystem;
+ },
+
+ set_showSolarSystem: function (value) {
+ this._showSolarSystem = value;
+ return value;
+ },
+
+ get_localHorizonMode: function () {
+ return this._localHorizonMode;
+ },
+
+ set_localHorizonMode: function (value) {
+ this._localHorizonMode = value;
+ return value;
+ },
+
+ get_galacticMode: function () {
+ return this._galacticMode;
+ },
+
+ set_galacticMode: function (value) {
+ this._galacticMode = value;
+ return value;
+ },
+
+ get_solarSystemStars: function () {
+ return this._solarSystemStars;
+ },
+
+ set_solarSystemStars: function (value) {
+ this._solarSystemStars = value;
+ return value;
+ },
+
+ get_solarSystemMilkyWay: function () {
+ return this._solarSystemMilkyWay;
+ },
+
+ set_solarSystemMilkyWay: function (value) {
+ this._solarSystemMilkyWay = value;
+ return value;
+ },
+
+ get_solarSystemCosmos: function () {
+ return this._solarSystemCosmos;
+ },
+
+ set_solarSystemCosmos: function (value) {
+ this._solarSystemCosmos = value;
+ return value;
+ },
+
+ get_solarSystemOrbits: function () {
+ return this._solarSystemOrbits;
+ },
+
+ set_solarSystemOrbits: function (value) {
+ this._solarSystemOrbits = value;
+ return value;
+ },
+
+ get_solarSystemOverlays: function () {
+ return this._solarSystemOverlays;
+ },
+
+ set_solarSystemOverlays: function (value) {
+ this._solarSystemOverlays = value;
+ return value;
+ },
+
+ get_solarSystemLighting: function () {
+ return this._solarSystemLighting;
+ },
+
+ set_solarSystemLighting: function (value) {
+ this._solarSystemLighting = value;
+ return value;
+ },
+
+ get_solarSystemMultiRes: function () {
+ return true;
+ },
+
+ set_solarSystemMultiRes: function (value) {
+ this._solarSystemMultiRes = value;
+ return value;
+ },
+
+ get_solarSystemScale: function () {
+ return this._solarSystemScale;
+ },
+
+ set_solarSystemScale: function (value) {
+ this._solarSystemScale = value;
+ return value;
+ },
+
+ get_showEquatorialGridText: function () {
+ return this._showEquatorialGridText;
+ },
+
+ set_showEquatorialGridText: function (value) {
+ this._showEquatorialGridText = value;
+ return value;
+ },
+
+ get_showGalacticGrid: function () {
+ return this._showGalacticGrid;
+ },
+
+ set_showGalacticGrid: function (value) {
+ this._showGalacticGrid = value;
+ return value;
+ },
+
+ get_showGalacticGridText: function () {
+ return this._showGalacticGridText;
+ },
+
+ set_showGalacticGridText: function (value) {
+ this._showGalacticGridText = value;
+ return value;
+ },
+
+ get_showEclipticGrid: function () {
+ return this._showEclipticGrid;
+ },
+
+ set_showEclipticGrid: function (value) {
+ this._showEclipticGrid = value;
+ return value;
+ },
+
+ get_showEclipticGridText: function () {
+ return this._showEclipticGridText;
+ },
+
+ set_showEclipticGridText: function (value) {
+ this._showEclipticGridText = value;
+ return value;
+ },
+
+ get_showEclipticOverviewText: function () {
+ return this._showEclipticOverviewText;
+ },
+
+ set_showEclipticOverviewText: function (value) {
+ this._showEclipticOverviewText = value;
+ return value;
+ },
+
+ get_showAltAzGrid: function () {
+ return this._showAltAzGrid;
+ },
+
+ set_showAltAzGrid: function (value) {
+ this._showAltAzGrid = value;
+ return value;
+ },
+
+ get_eclipticGridColor: function () {
+ return this._eclipticGridColor;
+ },
+
+ set_eclipticGridColor: function (value) {
+ this._eclipticGridColor = value;
+ return value;
+ },
+
+ get_galacticGridColor: function () {
+ return this._galacticGridColor;
+ },
+
+ set_galacticGridColor: function (value) {
+ this._galacticGridColor = value;
+ return value;
+ },
+
+ get_altAzGridColor: function () {
+ return this._altAzGridColor;
+ },
+
+ set_altAzGridColor: function (value) {
+ this._altAzGridColor = value;
+ return value;
+ },
+
+ get_precessionChartColor: function () {
+ return this._precessionChartColor;
+ },
+
+ set_precessionChartColor: function (value) {
+ this._precessionChartColor = value;
+ return value;
+ },
+
+ get_eclipticColor: function () {
+ return this._eclipticColor;
+ },
+
+ set_eclipticColor: function (value) {
+ this._eclipticColor = value;
+ return value;
+ },
+
+ get_equatorialGridColor: function () {
+ return this._equatorialGridColor;
+ },
+
+ set_equatorialGridColor: function (value) {
+ this._equatorialGridColor = value;
+ return value;
+ },
+
+ get_showAltAzGridText: function () {
+ return this._showAltAzGridText;
+ },
+
+ set_showAltAzGridText: function (value) {
+ this._showAltAzGridText = value;
+ return value;
+ },
+
+ get_showPrecessionChart: function () {
+ return this._showPrecessionChart;
+ },
+
+ set_showPrecessionChart: function (value) {
+ this._showPrecessionChart = value;
+ return value;
+ },
+
+ get_showConstellationPictures: function () {
+ return this._showConstellationPictures;
+ },
+
+ set_showConstellationPictures: function (value) {
+ this._showConstellationPictures = value;
+ return value;
+ },
+
+ get_showConstellationLabels: function () {
+ return this._showConstellationLabels;
+ },
+
+ set_showConstellationLabels: function (value) {
+ this._showConstellationLabels = value;
+ return value;
+ },
+
+ get_constellationLabelsHeight: function () {
+ return this._constellationLabelsHeight;
+ },
+
+ set_constellationLabelsHeight: function (value) {
+ this._constellationLabelsHeight = value;
+ return value;
+ },
+
+ get_solarSystemCMB: function () {
+ return this._solarSystemCMB;
+ },
+
+ set_solarSystemCMB: function (value) {
+ this._solarSystemCMB = value;
+ return value;
+ },
+
+ get_solarSystemMinorPlanets: function () {
+ return this._solarSystemMinorPlanets;
+ },
+
+ set_solarSystemMinorPlanets: function (value) {
+ this._solarSystemMinorPlanets = value;
+ return value;
+ },
+
+ get_solarSystemPlanets: function () {
+ return this._solarSystemPlanets;
+ },
+
+ set_solarSystemPlanets: function (value) {
+ this._solarSystemPlanets = value;
+ return value;
+ },
+
+ get_showEarthSky: function () {
+ return this._showEarthSky;
+ },
+
+ set_showEarthSky: function (value) {
+ this._showEarthSky = value;
+ return value;
+ },
+
+ get_solarSystemMinorOrbits: function () {
+ return this._solarSystemMinorOrbits;
+ },
+
+ set_solarSystemMinorOrbits: function (value) {
+ this._solarSystemMinorOrbits = value;
+ return value;
+ },
+
+ get_constellationsEnabled: function () {
+ return this._constellationsEnabled;
+ },
+
+ set_constellationsEnabled: function (value) {
+ this._constellationsEnabled = value;
+ return value;
+ },
+
+ get_constellationFiguresFilter: function () {
+ return this._constellationFiguresFilter;
+ },
+
+ set_constellationFiguresFilter: function (value) {
+ this._constellationFiguresFilter = value;
+ return value;
+ },
+
+ get_constellationBoundariesFilter: function () {
+ return this._constellationBoundariesFilter;
+ },
+
+ set_constellationBoundariesFilter: function (value) {
+ this._constellationBoundariesFilter = value;
+ return value;
+ },
+
+ get_constellationNamesFilter: function () {
+ return this._constellationNamesFilter;
+ },
+
+ set_constellationNamesFilter: function (value) {
+ this._constellationNamesFilter = value;
+ return value;
+ },
+
+ get_constellationArtFilter: function () {
+ return this._constellationArtFilter;
+ },
+
+ set_constellationArtFilter: function (value) {
+ this._constellationArtFilter = value;
+ return value;
+ },
+
+ get_showSkyOverlays: function () {
+ return this._showSkyOverlays;
+ },
+
+ set_showSkyOverlays: function (value) {
+ this._showSkyOverlays = value;
+ return value;
+ },
+
+ get_showConstellations: function () {
+ return this._showConstellations;
+ },
+
+ set_showConstellations: function (value) {
+ this._showConstellations = value;
+ return value;
+ },
+
+ get_showSkyNode: function () {
+ return this._showSkyNode;
+ },
+
+ set_showSkyNode: function (value) {
+ this._showSkyNode = value;
+ return value;
+ },
+
+ get_showSkyGrids: function () {
+ return this._showSkyGrids;
+ },
+
+ set_showSkyGrids: function (value) {
+ this._showSkyGrids = value;
+ return value;
+ },
+
+ get_showSkyOverlaysIn3d: function () {
+ return this._showSkyOverlaysIn3d;
+ },
+
+ set_showSkyOverlaysIn3d: function (value) {
+ this._showSkyOverlaysIn3d = value;
+ return value;
+ },
+
+ get_earthCutawayView: function () {
+ return this._earthCutawayView;
+ },
+
+ set_earthCutawayView: function (value) {
+ this._earthCutawayView = value;
+ return value;
+ },
+
+ get_showISSModel: function () {
+ return this._showISSModel;
+ },
+
+ set_showISSModel: function (value) {
+ this._showISSModel = value;
+ return value;
+ },
+
+ get_milkyWayModel: function () {
+ return this._milkyWayModel;
+ },
+
+ set_milkyWayModel: function (value) {
+ this._milkyWayModel = value;
+ return value;
+ },
+
+ get_minorPlanetsFilter: function () {
+ return this._minorPlanetsFilter;
+ },
+
+ set_minorPlanetsFilter: function (value) {
+ this._minorPlanetsFilter = value;
+ return value;
+ },
+
+ get_planetOrbitsFilter: function () {
+ return this._planetOrbitsFilter;
+ },
+
+ set_planetOrbitsFilter: function (value) {
+ this._planetOrbitsFilter = value;
+ return value;
+ },
+
+ get_constellations: function () {
+ return this._constellations;
+ },
+
+ set_constellations: function (value) {
+ this._constellations = value;
+ return value;
+ },
+
+ getSetting: function (type) {
+ if (type === 17) {
+ return new SettingParameter(true, 0, !!0, null);
+ }
+ return new SettingParameter(false, 1, false, null);
+ }
+};
+
+registerType("Settings", [Settings, Settings$, null, ISettings]);
diff --git a/engine/esm/sky_image_tile.js b/engine/esm/sky_image_tile.js
new file mode 100644
index 00000000..06a35646
--- /dev/null
+++ b/engine/esm/sky_image_tile.js
@@ -0,0 +1,66 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A "tile" that is really a single image displayed using a tangential
+// projection.
+
+import { ss } from "./ss.js";
+import { registerType } from "./typesystem.js";
+import { useGl, useGlVersion2 } from "./render_globals.js";
+import { WcsImage } from "./layers/wcs_image.js";
+import { TangentTile, LatLngEdges } from "./tangent_tile.js";
+
+
+// wwtlib.SkyImageTile
+
+export function SkyImageTile(level, x, y, dataset, parent) {
+ this.pixelCenterX = 0;
+ this.pixelCenterY = 0;
+ this.scaleX = 0.01;
+ this.scaleY = 0.01;
+ this.height = 0;
+ this.width = 0;
+ TangentTile.call(this, level, x, y, dataset, parent);
+ this.pixelCenterX = dataset.get_offsetX();
+ this.pixelCenterY = dataset.get_offsetY();
+ this.scaleX = -(this.scaleY = dataset.get_baseTileDegrees());
+ if (dataset.get_bottomsUp()) {
+ this.scaleX = -this.scaleX;
+ }
+ this.sphereCenter = this.geoTo3dTan(0, 0);
+ this.radius = 1.25;
+ this.computeBoundingSphere();
+}
+
+var SkyImageTile$ = {
+ getLatLngEdges: function () {
+ var edges = new LatLngEdges();
+ var wcsImage = ss.safeCast(this.dataset.get_wcsImage(), WcsImage);
+ if (wcsImage != null && useGl) {
+ if (useGlVersion2) {
+ this.width = wcsImage.get_sizeX();
+ this.height = wcsImage.get_sizeY();
+ }
+ else {
+ this.height = this.bmp.height;
+ this.width = this.bmp.width;
+ if (this.bmp.height !== wcsImage.get_sizeY()) {
+ this.pixelCenterY += this.bmp.height - wcsImage.get_sizeY();
+ }
+ }
+ } else if (this.texture != null) {
+ this.height = this.texture.naturalHeight;
+ this.width = this.texture.naturalWidth;
+ } else {
+ this.height = 256;
+ this.width = 256;
+ }
+ edges.latMin = 0 + (this.scaleY * (this.height - this.pixelCenterY));
+ edges.latMax = 0 - (this.scaleY * this.pixelCenterY);
+ edges.lngMin = 0 + (this.scaleX * this.pixelCenterX);
+ edges.lngMax = 0 - (this.scaleX * (this.width - this.pixelCenterX));
+ return edges;
+ }
+};
+
+registerType("SkyImageTile", [SkyImageTile, SkyImageTile$, TangentTile]);
diff --git a/engine/esm/sky_text.js b/engine/esm/sky_text.js
new file mode 100644
index 00000000..afe41244
--- /dev/null
+++ b/engine/esm/sky_text.js
@@ -0,0 +1,429 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Text rendered on the sky.
+
+import { ss } from "./ss.js";
+import { registerType, registerEnum } from "./typesystem.js";
+import { Vector2d, Vector3d, Matrix3d, PositionTexture } from "./double3d.js";
+import { Util } from "./baseutil.js";
+import { Colors } from "./color.js";
+import { WEBGL } from "./graphics/webgl_constants.js";
+import { PositionTextureVertexBuffer } from "./graphics/gl_buffers.js";
+import { Texture } from "./graphics/texture.js";
+import { TextShader } from "./graphics/shaders.js";
+import { TextObject } from "./tours/text_object.js";
+import { URLHelpers } from "./url_helpers.js";
+import { Rectangle } from "./util.js";
+import { WebFile } from "./web_file.js";
+
+
+// wwtlib.Alignment
+
+export var Alignment = {
+ center: 0,
+ left: 1
+};
+
+registerType("Alignment", Alignment);
+registerEnum("Alignment", Alignment);
+
+
+// wwtlib.Text3dBatch
+
+export function Text3dBatch(height) {
+ this.height = 128;
+ this.items = [];
+ this._glyphVersion = -1;
+ this.viewTransform = Matrix3d.get_identity();
+ this._textObject = new TextObject();
+ this._vertCount = 0;
+ this.height = (height * 3);
+}
+
+var Text3dBatch$ = {
+ add: function (newItem) {
+ this.items.push(newItem);
+ },
+
+ draw: function (renderContext, opacity, color) {
+ if (renderContext.gl == null) {
+ var viewPoint = Vector3d._transformCoordinate(renderContext.get_viewPoint(), this.viewTransform);
+ var drawHeight = (this.height / renderContext.get_fovAngle()) * renderContext.height / 180;
+ var $enum1 = ss.enumerate(this.items);
+ while ($enum1.moveNext()) {
+ var t3d = $enum1.current;
+ var screenSpacePnt = renderContext.WVP.transform(t3d.center);
+ if (screenSpacePnt.z < 0) {
+ continue;
+ }
+ if (Vector3d.dot(viewPoint, t3d.center) < 0.55) {
+ continue;
+ }
+ var screenSpaceTop = renderContext.WVP.transform(t3d.top);
+ var rotation = Math.atan2(screenSpacePnt.x - screenSpaceTop.x, screenSpacePnt.y - screenSpaceTop.y);
+ var ctx = renderContext.device;
+ ctx.save();
+ ctx.translate(screenSpacePnt.x, screenSpacePnt.y);
+ ctx.rotate(-rotation); // todo update with up vector
+ ctx.globalAlpha = opacity;
+ ctx.fillStyle = color.toString();
+ ctx.font = 'normal' + ' ' + ((false) ? 'bold' : 'normal') + ' ' + Math.round(drawHeight * 1.2).toString() + 'px ' + 'Arial';
+ ctx.textBaseline = 'top';
+ var tm = ctx.measureText(t3d.text);
+ ctx.fillText(t3d.text, -tm.width / 2, -drawHeight / 2);
+ ctx.restore();
+ }
+ } else {
+ if (this._glyphCache == null || this._glyphCache.get_version() > this._glyphVersion) {
+ this.prepareBatch();
+ }
+ if (!this._glyphCache.ready) {
+ return;
+ }
+ TextShader.use(renderContext, this._vertexBuffer.vertexBuffer, this._glyphCache.get_texture().texture2d);
+ renderContext.gl.drawArrays(WEBGL.TRIANGLES, 0, this._vertexBuffer.count);
+ }
+ },
+
+ prepareBatch: function () {
+ if (this._glyphCache == null) {
+ this._glyphCache = GlyphCache.getCache(this.height);
+ }
+ if (!this._glyphCache.ready) {
+ return;
+ }
+ this._textObject.text = '';
+ this._textObject.fontSize = this.height * 0.5;
+ var verts = [];
+ var $enum1 = ss.enumerate(this.items);
+ while ($enum1.moveNext()) {
+ var t3d = $enum1.current;
+ var text = t3d.text;
+ var left = 0;
+ var top = 0;
+ var fntAdjust = this._textObject.fontSize / 128;
+ var factor = 0.6666;
+ var width = 0;
+ var height = 0;
+ for (var i = 0; i < text.length; i++) {
+ var item = this._glyphCache.getGlyphItem(text.substr(i, 1));
+ if (item != null) {
+ width += item.extents.x;
+ height = Math.max(item.extents.y, height);
+ }
+ }
+ var size = Vector2d.create(width, height);
+ t3d.width = size.x * t3d.scale * factor * fntAdjust;
+ t3d.height = size.y * t3d.scale * factor * fntAdjust;
+ var charsLeft = text.length;
+ for (var i = 0; i < charsLeft; i++) {
+ var item = this._glyphCache.getGlyphItem(text.substr(i, 1));
+ if (item != null) {
+ var position = Rectangle.create(left * t3d.scale * factor, 0 * t3d.scale * factor, item.extents.x * fntAdjust * t3d.scale * factor, item.extents.y * fntAdjust * t3d.scale * factor);
+ left += (item.extents.x * fntAdjust);
+ t3d.addGlyphPoints(verts, item.size, position, item.uvRect);
+ }
+ }
+ }
+ this._vertCount = verts.length;
+ this._vertexBuffer = new PositionTextureVertexBuffer(this._vertCount);
+ var vertBuf = this._vertexBuffer.lock();
+ for (var i = 0; i < this._vertCount; i++) {
+ vertBuf[i] = verts[i];
+ }
+ this._vertexBuffer.unlock();
+ this._glyphVersion = this._glyphCache.get_version();
+ },
+
+ cleanUp: function () {
+ if (this._vertexBuffer != null) {
+ this._vertexBuffer = null;
+ }
+ this.items.length = 0;
+ }
+};
+
+registerType("Text3dBatch", [Text3dBatch, Text3dBatch$, null]);
+
+// wwtlib.GlyphItem
+
+export function GlyphItem(glyph) {
+ this.referenceCount = 0;
+ this.glyph = glyph;
+ this.uvRect = new Rectangle();
+ this.size = new Vector2d();
+ this.referenceCount = 1;
+}
+
+GlyphItem.create = function (glyph, uv, size, extents) {
+ var temp = new GlyphItem(glyph);
+ temp.glyph = glyph;
+ temp.uvRect = uv;
+ temp.size = size;
+ temp.extents = extents;
+ temp.referenceCount = 1;
+ return temp;
+};
+
+GlyphItem._fromXML = function (node) {
+ var glyph = node.attributes.getNamedItem('Glyph').nodeValue;
+ var item = new GlyphItem(glyph);
+ item.uvRect = Rectangle.create(parseFloat(node.attributes.getNamedItem('UVLeft').nodeValue), parseFloat(node.attributes.getNamedItem('UVTop').nodeValue), parseFloat(node.attributes.getNamedItem('UVWidth').nodeValue), parseFloat(node.attributes.getNamedItem('UVHeight').nodeValue));
+ item.size = Vector2d.create(parseFloat(node.attributes.getNamedItem('SizeWidth').nodeValue), parseFloat(node.attributes.getNamedItem('SizeHeight').nodeValue));
+ item.extents = Vector2d.create(parseFloat(node.attributes.getNamedItem('ExtentsWidth').nodeValue), parseFloat(node.attributes.getNamedItem('ExtentsHeight').nodeValue));
+ return item;
+};
+
+var GlyphItem$ = {
+ addRef: function () {
+ this.referenceCount++;
+ },
+
+ release: function () {
+ this.referenceCount--;
+ }
+};
+
+registerType("GlyphItem", [GlyphItem, GlyphItem$, null]);
+
+// wwtlib.GlyphCache
+
+export function GlyphCache(height) {
+ this._cellHeight = 128;
+ this._gridSize = 8;
+ this.ready = false;
+ this._glyphItems = {};
+ this.textObject = new TextObject();
+ this._dirty = true;
+ this._textureDirty = true;
+ this._version = 0;
+ this._cellHeight = height;
+ this._texture = Texture.fromUrl(URLHelpers.singleton.engineAssetUrl('glyphs1.png'));
+ this._webFile = new WebFile(URLHelpers.singleton.engineAssetUrl('glyphs1.xml'));
+ this._webFile.onStateChange = ss.bind('_glyphXmlReady', this);
+ this._webFile.send();
+}
+
+GlyphCache._caches = {};
+GlyphCache._allGlyphs = '';
+
+GlyphCache.getCache = function (height) {
+ if (!ss.keyExists(GlyphCache._caches, height)) {
+ GlyphCache._caches[height] = new GlyphCache(height);
+ }
+ return GlyphCache._caches[height];
+};
+
+GlyphCache.cleanUpAll = function () {
+ ss.clearKeys(GlyphCache._caches);
+};
+
+var GlyphCache$ = {
+ get_height: function () {
+ return this._cellHeight;
+ },
+
+ _glyphXmlReady: function () {
+ if (this._webFile.get_state() === 2) {
+ alert(this._webFile.get_message());
+ } else if (this._webFile.get_state() === 1) {
+ this._loadXmlGlyph(this._webFile.getXml());
+ }
+ },
+
+ _loadXmlGlyph: function (xml) {
+ var nodes = Util.selectSingleNode(xml, 'GlyphItems');
+ var $enum1 = ss.enumerate(nodes.childNodes);
+ while ($enum1.moveNext()) {
+ var glyphItem = $enum1.current;
+ if (glyphItem.nodeName === 'GlyphItem') {
+ var item = GlyphItem._fromXML(glyphItem);
+ this._glyphItems[item.glyph] = item;
+ GlyphCache._allGlyphs = GlyphCache._allGlyphs + item.glyph;
+ }
+ }
+ this.ready = true;
+ },
+
+ get_texture: function () {
+ return this._texture;
+ },
+
+ _makeTexture: function () {
+ this._calcOrMake(true);
+ },
+
+ getGlyphItem: function (glyph) {
+ if (this._dirty) {
+ this._calculateGlyphDetails();
+ }
+ return this._glyphItems[glyph];
+ },
+
+ _calculateGlyphDetails: function () {
+ this._calcOrMake(false);
+ },
+
+ _calcOrMake: function (makeTexture) { },
+
+ get_version: function () {
+ return this._version;
+ },
+
+ set_version: function (value) {
+ this._version = value;
+ return value;
+ },
+
+ addGlyph: function (glyph) {
+ if (!ss.keyExists(this._glyphItems, glyph)) {
+ var item = new GlyphItem(glyph);
+ this._glyphItems[glyph] = item;
+ this._dirty = true;
+ this._textureDirty = true;
+ this._version++;
+ GlyphCache._allGlyphs = GlyphCache._allGlyphs + glyph;
+ } else {
+ this._glyphItems[glyph].addRef();
+ }
+ },
+
+ cleanUp: function () {
+ this._dirty = true;
+ this._texture = null;
+ },
+
+ dispose: function () {
+ this.cleanUp();
+ },
+
+ get_dirty: function () {
+ return this._dirty;
+ },
+
+ set_dirty: function (value) {
+ this._dirty = value;
+ return value;
+ }
+};
+
+registerType("GlyphCache", [GlyphCache, GlyphCache$, null, ss.IDisposable]);
+
+// wwtlib.Text3d
+
+export function Text3d(center, up, text, fontsize, scale) {
+ this.rotation = 0;
+ this.tilt = 0;
+ this.bank = 0;
+ this._matInit = false;
+ this.color = Colors.get_white();
+ this.sky = true;
+ this.scale = 0;
+ this.opacity = 1;
+ this.text = '';
+ this.width = 1;
+ this.height = 1;
+ this.alignment = 0;
+ this.text = text;
+ this.up = up;
+ this.center = center;
+ this.scale = scale;
+ this.top = Vector3d.addVectors(center, Vector3d.scale(up, scale));
+ if (fontsize < 0) {
+ this.sky = false;
+ }
+}
+
+var Text3d$ = {
+ addGlyphPoints: function (pointList, size, position, uv) {
+ var points = new Array(6);
+ for (var i = 0; i < 6; i++) {
+ points[i] = new PositionTexture();
+ }
+ var left = Vector3d.cross(this.center, this.up);
+ var right = Vector3d.cross(this.up, this.center);
+ left.normalize();
+ right.normalize();
+ this.up.normalize();
+ var upTan = Vector3d.cross(this.center, right);
+ upTan.normalize();
+ if (!this.alignment) {
+ left.multiply(this.width - position.get_left() * 2);
+ right.multiply(this.width - ((this.width * 2) - position.get_right() * 2));
+ } else if (this.alignment === 1) {
+ left.multiply(-position.get_left() * 2);
+ right.multiply(position.get_right() * 2);
+ }
+ var top = upTan.copy();
+ var bottom = Vector3d.subtractVectors(Vector3d.get_empty(), upTan);
+ top.multiply(this.height - position.get_top() * 2);
+ bottom.multiply(this.height - ((this.height * 2) - position.get_bottom() * 2));
+ var ul = this.center.copy();
+ ul.add(top);
+ if (this.sky) {
+ ul.add(left);
+ } else {
+ ul.subtract(left);
+ }
+ var ur = this.center.copy();
+ ur.add(top);
+ if (this.sky) {
+ ur.add(right);
+ } else {
+ ur.subtract(right);
+ }
+ var ll = this.center.copy();
+ if (this.sky) {
+ ll.add(left);
+ } else {
+ ll.subtract(left);
+ }
+ ll.add(bottom);
+ var lr = this.center.copy();
+ if (this.sky) {
+ lr.add(right);
+ } else {
+ lr.subtract(right);
+ }
+ lr.add(bottom);
+ points[0].position = ul.copy();
+ points[0].tu = uv.get_left();
+ points[0].tv = uv.get_top();
+ points[2].tu = uv.get_left();
+ points[2].tv = uv.get_bottom();
+ points[2].position = ll.copy();
+ points[1].tu = uv.get_right();
+ points[1].tv = uv.get_top();
+ points[1].position = ur.copy();
+ points[3].tu = uv.get_right();
+ points[3].tv = uv.get_bottom();
+ points[3].position = lr.copy();
+ points[5].tu = uv.get_right();
+ points[5].tv = uv.get_top();
+ points[5].position = ur.copy();
+ points[4].tu = uv.get_left();
+ points[4].tv = uv.get_bottom();
+ points[4].position = ll.copy();
+ if (!!this.rotation || !!this.tilt || !!this.bank) {
+ if (!this._matInit) {
+ var lookAt = Matrix3d.lookAtLH(this.center, new Vector3d(), this.up);
+ var lookAtInv = lookAt.clone();
+ lookAtInv.invert();
+ this._rtbMat = Matrix3d.multiplyMatrix(Matrix3d.multiplyMatrix(Matrix3d.multiplyMatrix(Matrix3d.multiplyMatrix(lookAt, Matrix3d._rotationZ(-this.rotation / 180 * Math.PI)), Matrix3d._rotationX(-this.tilt / 180 * Math.PI)), Matrix3d._rotationY(-this.bank / 180 * Math.PI)), lookAtInv);
+ // "todo make this true after debug"
+ this._matInit = true;
+ }
+ for (var i = 0; i < 6; i++) {
+ points[i].position = Vector3d._transformCoordinate(points[i].position, this._rtbMat);
+ }
+ }
+ var $enum1 = ss.enumerate(points);
+ while ($enum1.moveNext()) {
+ var pnt = $enum1.current;
+ pointList.push(pnt);
+ }
+ }
+};
+
+registerType("Text3d", [Text3d, Text3d$, null]);
diff --git a/engine/esm/space_time_controller.js b/engine/esm/space_time_controller.js
new file mode 100644
index 00000000..7451214e
--- /dev/null
+++ b/engine/esm/space_time_controller.js
@@ -0,0 +1,249 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// The WWT clock and related calculations.
+
+import { registerType } from "./typesystem.js";
+import { ss } from "./ss.js";
+import { DT } from "./astrocalc/date.js";
+import { AstroCalc } from "./astrocalc.js";
+import { Coordinates } from "./coordinates.js";
+import { Settings } from "./settings.js";
+
+
+// wwtlib.SpaceTimeController
+
+export function SpaceTimeController() { }
+
+SpaceTimeController.framesPerSecond = 30;
+SpaceTimeController.frameDumping = false;
+SpaceTimeController.cancelFrameDump = false;
+SpaceTimeController.currentFrameNumber = 0;
+SpaceTimeController.totalFrames = 0;
+SpaceTimeController._offset = 0;
+SpaceTimeController._syncToClock = true;
+SpaceTimeController._timeRate = 1;
+SpaceTimeController._altitude = 0;
+
+SpaceTimeController.updateClock = function () {
+ if (SpaceTimeController._syncToClock) {
+ var justNow = SpaceTimeController.get_metaNow();
+ if (SpaceTimeController._timeRate !== 1) {
+ var ts = justNow.getTime() - SpaceTimeController.last.getTime();
+ var ticks = (ts * SpaceTimeController._timeRate);
+ SpaceTimeController._offset += ticks;
+ }
+ SpaceTimeController.last = justNow;
+ try {
+ SpaceTimeController._now = new Date(justNow.getTime() + SpaceTimeController._offset);
+ }
+ catch ($e1) {
+ SpaceTimeController._now = new Date(1, 12, 25, 23, 59, 59);
+ SpaceTimeController._offset = SpaceTimeController._now - SpaceTimeController.get_metaNow();
+ }
+ if (SpaceTimeController._now.getFullYear() > 4000) {
+ SpaceTimeController._now = new Date(4000, 12, 31, 23, 59, 59);
+ SpaceTimeController._offset = SpaceTimeController._now - SpaceTimeController.get_metaNow();
+ }
+ if (SpaceTimeController._now.getFullYear() < 1) {
+ SpaceTimeController._now = new Date(0, 12, 25, 23, 59, 59);
+ SpaceTimeController._offset = SpaceTimeController._now - SpaceTimeController.get_metaNow();
+ }
+ }
+};
+
+SpaceTimeController.getTimeForFutureTime = function (delta) {
+ try {
+ if (SpaceTimeController._syncToClock) {
+ var future = new Date((SpaceTimeController.get_now().getTime() + (delta * 1000) * SpaceTimeController._timeRate));
+ return future;
+ } else {
+ return SpaceTimeController.get_now();
+ }
+ }
+ catch ($e1) {
+ return SpaceTimeController.get_now();
+ }
+};
+
+SpaceTimeController.getJNowForFutureTime = function (delta) {
+ try {
+ if (SpaceTimeController._syncToClock) {
+ var future = new Date(SpaceTimeController.get_now().getTime() + ss.truncate((delta * 1000 * SpaceTimeController._timeRate)));
+ return SpaceTimeController.utcToJulian(future);
+ } else {
+ return SpaceTimeController.utcToJulian(SpaceTimeController.get_now());
+ }
+ }
+ catch ($e1) {
+ return SpaceTimeController.utcToJulian(SpaceTimeController.get_now());
+ }
+};
+
+SpaceTimeController.get_now = function () {
+ return SpaceTimeController._now;
+};
+
+SpaceTimeController.set_now = function (value) {
+ SpaceTimeController._now = value;
+ SpaceTimeController._offset = SpaceTimeController._now - SpaceTimeController.get_metaNow();
+ SpaceTimeController.last = SpaceTimeController.get_metaNow();
+ return value;
+};
+
+SpaceTimeController.get_metaNow = function () {
+ return SpaceTimeController._metaNow;
+};
+
+SpaceTimeController.set_metaNow = function (value) {
+ if (!SpaceTimeController.frameDumping) {
+ SpaceTimeController._metaNow = value;
+ }
+ return value;
+};
+
+SpaceTimeController.nextFrame = function () {
+ SpaceTimeController._metaNow.setMilliseconds(SpaceTimeController._metaNow.getMilliseconds() + Math.round(1000 / SpaceTimeController.framesPerSecond));
+ SpaceTimeController.currentFrameNumber += 1;
+};
+
+SpaceTimeController.get_doneDumping = function () {
+ return !SpaceTimeController.frameDumping || SpaceTimeController.cancelFrameDump || (SpaceTimeController.currentFrameNumber >= SpaceTimeController.totalFrames);
+};
+
+SpaceTimeController.syncTime = function () {
+ SpaceTimeController._offset = 0;
+ SpaceTimeController._now = ss.now();
+ SpaceTimeController._syncToClock = true;
+};
+
+SpaceTimeController.get_jNow = function () {
+ return SpaceTimeController.utcToJulian(SpaceTimeController.get_now());
+};
+
+SpaceTimeController.get_syncToClock = function () {
+ return SpaceTimeController._syncToClock;
+};
+
+SpaceTimeController.set_syncToClock = function (value) {
+ if (SpaceTimeController._syncToClock !== value) {
+ SpaceTimeController._syncToClock = value;
+ if (value) {
+ SpaceTimeController.last = ss.now();
+ SpaceTimeController._offset = SpaceTimeController._now - ss.now();
+ } else {
+ SpaceTimeController._now = new Date(ss.now().getTime() + SpaceTimeController._offset);
+ }
+ }
+ return value;
+};
+
+SpaceTimeController.get_timeRate = function () {
+ return SpaceTimeController._timeRate;
+};
+
+SpaceTimeController.set_timeRate = function (value) {
+ SpaceTimeController._timeRate = value;
+ return value;
+};
+
+SpaceTimeController.get_altitude = function () {
+ return SpaceTimeController._altitude;
+};
+
+SpaceTimeController.set_altitude = function (value) {
+ SpaceTimeController._altitude = value;
+ return value;
+};
+
+SpaceTimeController.get_location = function () {
+ SpaceTimeController._location = Coordinates.fromLatLng(Settings.get_active().get_locationLat(), Settings.get_active().get_locationLng());
+ SpaceTimeController._altitude = Settings.get_active().get_locationAltitude();
+ return SpaceTimeController._location;
+};
+
+SpaceTimeController.set_location = function (value) {
+ if (Settings.get_globalSettings().get_locationLat() !== value.get_lat()) {
+ Settings.get_globalSettings().set_locationLat(value.get_lat());
+ }
+ if (Settings.get_globalSettings().get_locationLng() !== value.get_lng()) {
+ Settings.get_globalSettings().set_locationLng(value.get_lng());
+ }
+ SpaceTimeController._location = value;
+ return value;
+};
+
+SpaceTimeController.julianToUtc = function (jDate) {
+ var date = new DT();
+ date.setJD(jDate, true);
+ var ms = (date.second() - ss.truncate(date.second())) * 1000;
+ return new Date(date.year(), date.month() - 1, date.day(), date.hour(), date.minute(), ss.truncate(date.second()), ss.truncate(ms));
+};
+
+SpaceTimeController._twoLineDateToJulian = function (p) {
+ var pre1950 = parseInt(p.substring(0, 1)) < 6;
+ var year = parseInt(((pre1950) ? ' 20' : '19') + p.substring(0, 2));
+ var days = parseFloat(p.substring(2, 3));
+ var fraction = parseFloat(p.substr(5));
+ var date = new Date(year, 0, 1, 0, 0);
+ return SpaceTimeController.utcToJulian(date) + (days - 1 + fraction);
+};
+
+SpaceTimeController.julianToTwoLineDate = function (jDate) {
+ return SpaceTimeController.dateToTwoLineDate(SpaceTimeController.julianToUtc(jDate));
+};
+
+SpaceTimeController.dateToTwoLineDate = function (date) {
+ var sb = new ss.StringBuilder();
+ sb.append(date.getFullYear() % 100);
+ var fullYear = new Date(date.getFullYear(), 0, 1, 0, 0);
+ var dayofyear = Math.floor((date - fullYear) / (60 * 60 * 24 * 1000)) + 2;
+ var day = dayofyear + date.getHours() / 24 + date.getMinutes() / 60 / 24 + date.getSeconds() / 60 / 60 / 24 + date.getMilliseconds() / 1000 / 60 / 60 / 24;
+ var sDay = SpaceTimeController.tleDayString(day);
+ sb.append(sDay);
+ return sb.toString();
+};
+
+SpaceTimeController.tleDayString = function (day) {
+ var formated = day.toString();
+ var point = formated.indexOf('.');
+ if (point === -1) {
+ point = formated.length;
+ formated += '.0';
+ }
+ var len = formated.length - point - 1;
+ var fill = '00000000';
+ formated = fill.substr(0, 3 - point) + formated + fill.substr(0, 8 - len);
+ return formated;
+};
+
+SpaceTimeController.utcToJulian = function (utc) {
+ var year = utc.getUTCFullYear();
+ var month = utc.getUTCMonth() + 1;
+ var day = utc.getUTCDate();
+ var hour = utc.getUTCHours();
+ var minute = utc.getUTCMinutes();
+ var second = utc.getUTCSeconds() + utc.getUTCMilliseconds() / 1000;
+ var dblDay = day + (hour / 24) + (minute / 1440) + (second / 86400);
+ return AstroCalc.getJulianDay(year, month, dblDay);
+};
+
+SpaceTimeController.dateToJD = function (Year, Month, Day, bGregorianCalendar) {
+ var Y = Year;
+ var M = Month;
+ if (M < 3) {
+ Y = Y - 1;
+ M = M + 12;
+ }
+ var A = 0;
+ var B = 0;
+ if (bGregorianCalendar) {
+ A = ss.truncate((Y / 100));
+ B = 2 - A + ss.truncate((A / 4));
+ }
+ return ss.truncate((365.25 * (Y + 4716))) + ss.truncate((30.6001 * (M + 1))) + Day + B - 1524.5;
+};
+
+var SpaceTimeController$ = {};
+
+registerType("SpaceTimeController", [SpaceTimeController, SpaceTimeController$, null]);
diff --git a/engine/scriptsharp-0.8.0/ss.js b/engine/esm/ss.js
similarity index 98%
rename from engine/scriptsharp-0.8.0/ss.js
rename to engine/esm/ss.js
index 9309cfe7..947b3919 100644
--- a/engine/scriptsharp-0.8.0/ss.js
+++ b/engine/esm/ss.js
@@ -1,9 +1,14 @@
+// This file is part of WorldWide Telescope and derived from:
+
/*! Script# Runtime
* Designed and licensed for use and distribution with Script#-generated scripts.
* Copyright (c) 2012, Nikhil Kothari, and the Script# Project.
* More information at http://scriptsharp.com
*/
+// It has been customized to adapt to the particulars of the WWT JavaScript
+// build system.
+
function _ss() {
"use strict";
@@ -134,7 +139,7 @@ function _ss() {
function fail(message) {
console.assert(false, message);
- if (global.navigator) {
+ if (globalThis.navigator) {
eval('debugger;');
}
}
@@ -323,7 +328,7 @@ function _ss() {
return (s1 === s2) ? 0 : (s1 < s2) ? -1 : 1;
}
- var _formatPlaceHolderRE = /(\{[^\}^\{]+\})/g;
+ var _formatPlaceHolderRE = /(\{[^}^{]+\})/g;
var _formatters = {};
function format(cultureOrFormat) {
@@ -507,7 +512,7 @@ function _ss() {
// If unspecified, exported bindings go on the global object
// (so they are callable using a simple identifier).
- root = root || global;
+ root = root || globalThis;
var exp = {
name: name,
@@ -1329,7 +1334,7 @@ function _ss() {
function type(s) {
var nsIndex = s.indexOf('.');
- var ns = nsIndex > 0 ? _modules[s.substr(0, nsIndex)] : global;
+ var ns = nsIndex > 0 ? _modules[s.substr(0, nsIndex)] : globalThis;
var name = nsIndex > 0 ? s.substr(nsIndex + 1) : s;
return ns ? ns[name] : null;
@@ -1434,6 +1439,11 @@ function _ss() {
return api;
}
+ function createRegistry(name) {
+ var registry = _modules[name] = { $name: name };
+ return registry;
+ }
+
return extend(ss_module('ss', null, {
IDisposable: [IDisposable],
IEnumerable: [IEnumerable],
@@ -1497,6 +1507,8 @@ function _ss() {
module: ss_module,
modules: _modules,
+ createRegistry: createRegistry,
+ createType: createType,
isClass: isClass,
isInterface: isInterface,
@@ -1517,4 +1529,4 @@ function _ss() {
});
}
-var ss = _ss();
\ No newline at end of file
+export var ss = _ss();
\ No newline at end of file
diff --git a/engine/esm/star.js b/engine/esm/star.js
new file mode 100644
index 00000000..762d13ba
--- /dev/null
+++ b/engine/esm/star.js
@@ -0,0 +1,215 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Information about catalogued objects.
+
+import { ss } from "./ss.js";
+import { registerType } from "./typesystem.js";
+import { Util } from "./baseutil.js";
+import { Color } from "./color.js";
+import { Coordinates } from "./coordinates.js";
+
+
+// wwtlib.Star
+
+export function Star(input) {
+ this.magnitude = 0;
+ this.RA = 0;
+ this.dec = 0;
+ this.BMV = 0;
+ this.id = 0;
+ this.absoluteMagnitude = 0;
+ this.par = 0;
+ this.distance = 0;
+ var sa = input.split('\t');
+ this.id = parseInt(ss.replaceString(sa[0], 'HIP', ''));
+ this.dec = parseFloat(sa[3]);
+ this.RA = parseFloat(sa[2]) / 15;
+ if (sa.length > 4) {
+ try {
+ if (sa[4].toUpperCase() !== 'NULL' && !!sa[4]) {
+ this.magnitude = parseFloat(sa[4]);
+ }
+ }
+ catch ($e1) {
+ }
+ }
+ if (sa.length > 5) {
+ try {
+ this.BMV = parseFloat(sa[5]);
+ this._makeColor(this.BMV);
+ }
+ catch ($e2) {
+ }
+ }
+ if (sa.length > 6) {
+ this.par = parseFloat(sa[6]);
+ this._makeDistanceAndMagnitude();
+ }
+}
+
+var Star$ = {
+ get_name: function () {
+ return 'HIP' + this.id.toString();
+ },
+
+ get_coordinates: function () {
+ return Coordinates.fromRaDec(this.RA, this.dec);
+ },
+
+ stars: function (input, newish) {
+ var sa = input.split('\t');
+ this.id = parseInt(sa[0]);
+ this.RA = parseFloat(sa[1]) / 15;
+ this.dec = parseFloat(sa[2]);
+ if (sa.length > 3) {
+ try {
+ this.magnitude = parseFloat(sa[3]);
+ }
+ catch ($e1) {
+ }
+ }
+ if (sa.length > 4) {
+ try {
+ this.col = Color.load(sa[4]);
+ }
+ catch ($e2) {
+ }
+ }
+ },
+
+ _makeDistanceAndMagnitude: function () {
+ this.distance = 1 / (this.par / 1000);
+ this.absoluteMagnitude = this.magnitude - 5 * (Util.logN(this.distance, 10) - 1);
+ //Convert to AU
+ this.distance *= 206264.806;
+ },
+
+ _makeColor: function (bmv) {
+ var c = 0xFFFFFFFF;
+
+ if (bmv <= -0.32) {
+ c = 0xFFA2B8FF;
+ } else if (bmv <= -0.31) {
+ c = 0xFFA3B8FF;
+ } else if (bmv <= -0.3) {
+ c = 0xFFA4BAFF;
+ }
+ // mistake in original source. Should this be "<= -0.29" or something?
+ // else if (bmv <= -0.3) {
+ // c = 0xFFA5BAFF;
+ // }
+ else if (bmv <= -0.28) {
+ c = 0xFFA7BCFF;
+ } else if (bmv <= -0.26) {
+ c = 0xFFA9BDFF;
+ } else if (bmv <= -0.24) {
+ c = 0xFFABBFFF;
+ } else if (bmv <= -0.2) {
+ c = 0xFFAFC2FF;
+ } else if (bmv <= -0.16) {
+ c = 0xFFB4C6FF;
+ } else if (bmv <= -0.14) {
+ c = 0xFFB6C8FF;
+ } else if (bmv <= -0.12) {
+ c = 0xFFB9CAFF;
+ } else if (bmv <= -0.09) {
+ c = 0xFFBCCDFF;
+ } else if (bmv <= -0.06) {
+ c = 0xFFC1D0FF;
+ } else if (bmv <= 0) {
+ c = 0xFFCAD6FF;
+ } else if (bmv <= 0.06) {
+ c = 0xFFD2DCFF;
+ } else if (bmv <= 0.14) {
+ c = 0xFFDDE4FF;
+ } else if (bmv <= 0.19) {
+ c = 0xFFE3E8FF;
+ } else if (bmv <= 0.31) {
+ c = 0xFFF2F2FF;
+ } else if (bmv <= 0.36) {
+ c = 0xFFF9F6FF;
+ } else if (bmv <= 0.43) {
+ c = 0xFFFFF9FC;
+ } else if (bmv <= 0.54) {
+ c = 0xFFFFF6F3;
+ } else if (bmv <= 0.59) {
+ c = 0xFFFFF3EB;
+ } else if (bmv <= 0.63) {
+ c = 0xFFFFF1E7;
+ } else if (bmv <= 0.66) {
+ c = 0xFFFFEFE1;
+ } else if (bmv <= 0.74) {
+ c = 0xFFFFEEDD;
+ } else if (bmv <= 0.82) {
+ c = 0xFFFFEAD5;
+ } else if (bmv <= 0.92) {
+ c = 0xFFFFE4C4;
+ } else if (bmv <= 1.15) {
+ c = 0xFFFFFDFB8;
+ } else if (bmv <= 1.3) {
+ c = 0xFFFFDDB4;
+ } else if (bmv <= 1.41) {
+ c = 0xFFFFD39D;
+ } else if (bmv <= 1.48) {
+ c = 0xFFFFCD91;
+ } else if (bmv <= 1.52) {
+ c = 0xFFFFC987;
+ } else if (bmv <= 1.55) {
+ c = 0xFFFFC57F;
+ } else if (bmv <= 1.56) {
+ c = 0xFFFFC177;
+ } else if (bmv <= 1.61) {
+ c = 0xFFFFBD71;
+ } else if (bmv <= 1.72) {
+ c = 0xFFFFB866;
+ } else if (bmv <= 1.84) {
+ c = 0xFFFFB25B;
+ } else if (bmv <= 2) {
+ c = 0xFFFFAD51;
+ }
+
+ this.col = Color.fromInt(c);
+ }
+};
+
+registerType("Star", [Star, Star$, null]);
+
+
+// wwtlib.Galaxy
+
+export function Galaxy(br) {
+ this.RA = 0;
+ this.dec = 0;
+ this.distance = 0;
+ this.type = 0;
+ this.eTypeBucket = 0;
+ this.size = 5;
+ this.sdssID = 0;
+ this.sdssID = br.readInt64();
+ this.RA = br.readSingle();
+ this.dec = br.readSingle();
+ this.distance = br.readSingle();
+ this.eTypeBucket = br.readByte();
+ this.size = br.readSingle();
+}
+
+Galaxy._eTypeBuckets = [-3, -0.186, -0.168, -0.158, -0.15, -0.143, -0.137, -0.13, -0.123, -0.115, -0.104, -0.089, -0.068, -0.042, -0.011, 0.024, 0.064, 0.111, 0.169, 0.252, 3];
+
+Galaxy.getEType = function (value) {
+ var a = 0;
+ var b = Galaxy._eTypeBuckets.length - 1;
+ while (b - a > 1) {
+ var m = (a + b) / 2;
+ if (value > Galaxy._eTypeBuckets[m]) {
+ a = m;
+ } else {
+ b = m;
+ }
+ }
+ return a;
+};
+
+var Galaxy$ = {};
+
+registerType("Galaxy", [Galaxy, Galaxy$, null]);
diff --git a/engine/esm/tangent_tile.js b/engine/esm/tangent_tile.js
new file mode 100644
index 00000000..1ccdb68f
--- /dev/null
+++ b/engine/esm/tangent_tile.js
@@ -0,0 +1,216 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A tile in a pyramid that uses a tangential (gnomonic) projection.
+
+import { ss } from "./ss.js";
+import { registerType } from "./typesystem.js";
+import { tileCacheRemoveFromQueue, tilePrepDevice, useGlVersion2 } from "./render_globals.js";
+import { Vector3d, PositionTexture } from "./double3d.js";
+import { WEBGL } from "./graphics/webgl_constants.js";
+import { RenderTriangle } from "./render_triangle.js";
+import { FitsImage } from "./layers/fits_image.js";
+import { Tile } from "./tile.js";
+
+
+// wwtlib.LatLngEdges
+
+export function LatLngEdges() {
+ this.latMin = 0;
+ this.latMax = 0;
+ this.lngMin = 0;
+ this.lngMax = 0;
+}
+
+var LatLngEdges$ = {};
+
+registerType("LatLngEdges", [LatLngEdges, LatLngEdges$, null]);
+
+
+// wwtlib.TangentTile
+
+export function TangentTile(level, x, y, dataset, parent) {
+ this._topDown$1 = true;
+ Tile.call(this);
+ this.parent = parent;
+ this.level = level;
+ this.tileX = x;
+ this.tileY = y;
+ this.dataset = dataset;
+ this._topDown$1 = !dataset.get_bottomsUp();
+ this.computeBoundingSphere();
+}
+
+var TangentTile$ = {
+ computeBoundingSphere: function () {
+ if (!this._topDown$1) {
+ this.computeBoundingSphereBottomsUp();
+ return;
+ }
+ var tileDegrees = this.dataset.get_baseTileDegrees() / Math.pow(2, this.level);
+ var latMin = (this.dataset.get_baseTileDegrees() / 2 - (this.tileY) * tileDegrees) + this.dataset.get_offsetY();
+ var latMax = (this.dataset.get_baseTileDegrees() / 2 - ((this.tileY + 1)) * tileDegrees) + this.dataset.get_offsetY();
+ var lngMin = ((this.tileX) * tileDegrees - this.dataset.get_baseTileDegrees() / this.dataset.get_widthFactor()) + this.dataset.get_offsetX();
+ var lngMax = (((this.tileX + 1)) * tileDegrees - this.dataset.get_baseTileDegrees() / this.dataset.get_widthFactor()) + this.dataset.get_offsetX();
+ var latCenter = (latMin + latMax) / 2;
+ var lngCenter = (lngMin + lngMax) / 2;
+ this.sphereCenter = this.geoTo3dTan(latCenter, lngCenter);
+ this.topLeft = this.geoTo3dTan(latMin, lngMin);
+ this.bottomRight = this.geoTo3dTan(latMax, lngMax);
+ this.topRight = this.geoTo3dTan(latMin, lngMax);
+ this.bottomLeft = this.geoTo3dTan(latMax, lngMin);
+ var distVect = this.geoTo3dTan(latMin, lngMin);
+ distVect.subtract(this.sphereCenter);
+ this.sphereRadius = distVect.length();
+ },
+
+ computeBoundingSphereBottomsUp: function () {
+ var tileDegrees = this.dataset.get_baseTileDegrees() / Math.pow(2, this.level);
+ var latMin = (this.dataset.get_baseTileDegrees() / 2 + ((this.tileY + 1)) * tileDegrees) + this.dataset.get_offsetY();
+ var latMax = (this.dataset.get_baseTileDegrees() / 2 + (this.tileY) * tileDegrees) + this.dataset.get_offsetY();
+ var lngMin = ((this.tileX) * tileDegrees - this.dataset.get_baseTileDegrees() / this.dataset.get_widthFactor()) + this.dataset.get_offsetX();
+ var lngMax = (((this.tileX + 1)) * tileDegrees - this.dataset.get_baseTileDegrees() / this.dataset.get_widthFactor()) + this.dataset.get_offsetX();
+ this.topLeft = this.geoTo3dTan(latMin, lngMin);
+ this.bottomRight = this.geoTo3dTan(latMax, lngMax);
+ this.topRight = this.geoTo3dTan(latMin, lngMax);
+ this.bottomLeft = this.geoTo3dTan(latMax, lngMin);
+ },
+
+ getLatLngEdges: function () {
+ var tileDegrees = this.dataset.get_baseTileDegrees() / Math.pow(2, this.level);
+ var edges = new LatLngEdges();
+ edges.latMin = (this.dataset.get_baseTileDegrees() / 2 - (this.tileY) * tileDegrees) + this.dataset.get_offsetY();
+ edges.latMax = (this.dataset.get_baseTileDegrees() / 2 - ((this.tileY + 1)) * tileDegrees) + this.dataset.get_offsetY();
+ edges.lngMin = ((this.tileX) * tileDegrees - this.dataset.get_baseTileDegrees() / this.dataset.get_widthFactor()) + this.dataset.get_offsetX();
+ edges.lngMax = (((this.tileX + 1)) * tileDegrees - this.dataset.get_baseTileDegrees() / this.dataset.get_widthFactor()) + this.dataset.get_offsetX();
+ return edges;
+ },
+
+ geoTo3dTan: function (lat, lng) {
+ lng = -lng;
+ var fac1 = this.dataset.get_baseTileDegrees() / 2;
+ var factor = Math.tan(fac1 * Tile.RC);
+ return this.dataset.get_matrix().transform(Vector3d.create(1, (lat / fac1 * factor), (lng / fac1 * factor)));
+ },
+
+ requestImage: function () {
+ this.fitsImage = ss.safeCast(this.dataset.get_wcsImage(), FitsImage);
+ if (this.fitsImage != null) {
+ this.texReady = true;
+ this.downloading = false;
+ this.errored = this.fitsImage.errored;
+ this.requestPending = false;
+ tileCacheRemoveFromQueue(this.get_key(), true);
+ if (useGlVersion2) {
+ this.makeTexture();
+ this.readyToRender = true;
+ }
+ else {
+ //Cached bitmap for performance reasons
+ //Only used in legacy rendering of FITS (WebGL 1.0) inside SkyImageTile
+ this.bmp = this.fitsImage.getBitmap();
+ this.texture2d = this.bmp.getTexture();
+ this.readyToRender = true;
+ }
+ } else {
+ Tile.prototype.requestImage.call(this);
+ }
+ },
+
+ createGeometry: function (renderContext) {
+ if (this.geometryCreated) {
+ return true;
+ }
+ this.geometryCreated = true;
+ for (var i = 0; i < 4; i++) {
+ this._renderTriangleLists[i] = [];
+ }
+ this.globalCenter = this.geoTo3dTan(0, 0);
+ var edges = this.getLatLngEdges();
+ this.topLeft = this.geoTo3dTan(edges.latMin, edges.lngMin).subtract(this.globalCenter);
+ this.bottomRight = this.geoTo3dTan(edges.latMax, edges.lngMax).subtract(this.globalCenter);
+ this.topRight = this.geoTo3dTan(edges.latMin, edges.lngMax).subtract(this.globalCenter);
+ this.bottomLeft = this.geoTo3dTan(edges.latMax, edges.lngMin).subtract(this.globalCenter);
+ var center = Vector3d.midPoint(this.topLeft, this.bottomRight);
+ var leftCenter = Vector3d.midPoint(this.topLeft, this.bottomLeft);
+ var rightCenter = Vector3d.midPoint(this.topRight, this.bottomRight);
+ var topCenter = Vector3d.midPoint(this.topLeft, this.topRight);
+ var bottomCenter = Vector3d.midPoint(this.bottomLeft, this.bottomRight);
+ if (renderContext.gl == null) {
+ this._renderTriangleLists[0].push(RenderTriangle.create(PositionTexture.createPos(this.topLeft, 0, 0), PositionTexture.createPos(leftCenter, 0, 0.5), PositionTexture.createPos(topCenter, 0.5, 0), this.texture, this.level));
+ this._renderTriangleLists[0].push(RenderTriangle.create(PositionTexture.createPos(leftCenter, 0, 0.5), PositionTexture.createPos(center, 0.5, 0.5), PositionTexture.createPos(topCenter, 0.5, 0), this.texture, this.level));
+ this._renderTriangleLists[1].push(RenderTriangle.create(PositionTexture.createPos(topCenter, 0.5, 0), PositionTexture.createPos(rightCenter, 1, 0.5), PositionTexture.createPos(this.topRight, 1, 0), this.texture, this.level));
+ this._renderTriangleLists[1].push(RenderTriangle.create(PositionTexture.createPos(topCenter, 0.5, 0), PositionTexture.createPos(center, 0.5, 0.5), PositionTexture.createPos(rightCenter, 1, 0.5), this.texture, this.level));
+ this._renderTriangleLists[2].push(RenderTriangle.create(PositionTexture.createPos(leftCenter, 0, 0.5), PositionTexture.createPos(bottomCenter, 0.5, 1), PositionTexture.createPos(center, 0.5, 0.5), this.texture, this.level));
+ this._renderTriangleLists[2].push(RenderTriangle.create(PositionTexture.createPos(leftCenter, 0, 0.5), PositionTexture.createPos(this.bottomLeft, 0, 1), PositionTexture.createPos(bottomCenter, 0.5, 1), this.texture, this.level));
+ this._renderTriangleLists[3].push(RenderTriangle.create(PositionTexture.createPos(center, 0.5, 0.5), PositionTexture.createPos(this.bottomRight, 1, 1), PositionTexture.createPos(rightCenter, 1, 0.5), this.texture, this.level));
+ this._renderTriangleLists[3].push(RenderTriangle.create(PositionTexture.createPos(center, 0.5, 0.5), PositionTexture.createPos(bottomCenter, 0.5, 1), PositionTexture.createPos(this.bottomRight, 1, 1), this.texture, this.level));
+ this.readyToRender = true;
+ } else {
+ //process vertex list
+ this._vertexBuffer = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ARRAY_BUFFER, this._vertexBuffer);
+ var f32array = new Float32Array(9 * 5);
+ var buffer = f32array;
+ var index = 0;
+ index = this.addVertex(buffer, index, PositionTexture.createPos(bottomCenter, 0.5, 1));
+ index = this.addVertex(buffer, index, PositionTexture.createPos(this.bottomLeft, 0, 1));
+ index = this.addVertex(buffer, index, PositionTexture.createPos(this.bottomRight, 1, 1));
+ index = this.addVertex(buffer, index, PositionTexture.createPos(center, 0.5, 0.5));
+ index = this.addVertex(buffer, index, PositionTexture.createPos(leftCenter, 0, 0.5));
+ index = this.addVertex(buffer, index, PositionTexture.createPos(rightCenter, 1, 0.5));
+ index = this.addVertex(buffer, index, PositionTexture.createPos(topCenter, 0.5, 0));
+ index = this.addVertex(buffer, index, PositionTexture.createPos(this.topLeft, 0, 0));
+ index = this.addVertex(buffer, index, PositionTexture.createPos(this.topRight, 1, 0));
+ tilePrepDevice.bufferData(WEBGL.ARRAY_BUFFER, f32array, WEBGL.STATIC_DRAW);
+
+ // process index buffers
+ for (var i = 0; i < 4; i++) {
+ index = 0;
+ this.triangleCount = 2;
+ var ui16array = new Uint16Array(this.triangleCount * 3);
+ var indexArray = ui16array;
+ switch (i) {
+ case 0:
+ indexArray[index++] = 7;
+ indexArray[index++] = 4;
+ indexArray[index++] = 6;
+ indexArray[index++] = 4;
+ indexArray[index++] = 3;
+ indexArray[index++] = 6;
+ break;
+ case 1:
+ indexArray[index++] = 6;
+ indexArray[index++] = 5;
+ indexArray[index++] = 8;
+ indexArray[index++] = 6;
+ indexArray[index++] = 3;
+ indexArray[index++] = 5;
+ break;
+ case 2:
+ indexArray[index++] = 4;
+ indexArray[index++] = 0;
+ indexArray[index++] = 3;
+ indexArray[index++] = 4;
+ indexArray[index++] = 1;
+ indexArray[index++] = 0;
+ break;
+ case 3:
+ indexArray[index++] = 3;
+ indexArray[index++] = 2;
+ indexArray[index++] = 5;
+ indexArray[index++] = 3;
+ indexArray[index++] = 0;
+ indexArray[index++] = 2;
+ break;
+ }
+ this._indexBuffers[i] = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, this._indexBuffers[i]);
+ tilePrepDevice.bufferData(WEBGL.ELEMENT_ARRAY_BUFFER, ui16array, WEBGL.STATIC_DRAW);
+ }
+ }
+ return true;
+ }
+};
+
+registerType("TangentTile", [TangentTile, TangentTile$, Tile]);
diff --git a/engine/esm/tile.js b/engine/esm/tile.js
new file mode 100644
index 00000000..be8c8fc5
--- /dev/null
+++ b/engine/esm/tile.js
@@ -0,0 +1,841 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// The base class for tiles in image tile pyramids.
+
+import { ss } from "./ss.js";
+import { registerType } from "./typesystem.js";
+import { Vector3d, Vector4d, ConvexHull } from "./double3d.js";
+import {
+ tileCacheAddTileToQueue,
+ tileCacheGetCachedTile,
+ tileCacheGetTile,
+ tileCacheRemoveFromQueue,
+ tilePrepDevice,
+ tileDemEnabled,
+ useGlVersion2,
+ inc_tileCacheAccessID,
+ set_tileDemEnabled,
+ set_tileUvMultiple,
+} from "./render_globals.js";
+import { freestandingMode } from "./data_globals.js";
+import { WEBGL } from "./graphics/webgl_constants.js";
+import { Texture } from "./graphics/texture.js";
+import { FitsShader, TileShader } from "./graphics/shaders.js";
+import { getTileKey } from "./util.js";
+import { BlendState } from "./blend_state.js";
+import { URLHelpers } from "./url_helpers.js";
+import { ColorMapContainer } from "./layers/color_map_container.js";
+import { FitsImageJs } from "./layers/fits_image_js.js";
+import { FitsImageTile } from "./layers/fits_image_tile.js";
+
+
+// wwtlib.Tile
+
+export function Tile() {
+ this._renderTriangleLists = new Array(4);
+ this._indexBuffers = new Array(4);
+ this.level = 0;
+ this.tileX = 0;
+ this.tileY = 0;
+ this.texture = null;
+ this.texture2d = null;
+ this.isCatalogTile = false;
+ this.readyToRender = false;
+ this.inViewFrustum = true;
+ this.globalCenter = Vector3d.zero;
+ this.children = [null, null, null, null];
+ this.parent = null;
+ this.localCenter = new Vector3d();
+ this.renderedAtOrBelowGeneration = 0;
+ this._demScaleFactor = 6371000;
+ this.demIndex = 0;
+ this.demAverage = 0;
+ this.demReady = false;
+ this.texReady = false;
+ this.demTile = false;
+ this.demDownloading = false;
+ this.renderedGeneration = 0;
+ this.accomidation = 0;
+ this.accessCount = 0;
+ this.downloading = false;
+ this.geometryCreated = false;
+ this._isHdTile = false;
+ this.demSize = 33 * 33;
+ this._topLeftScreen = new Vector3d();
+ this._bottomRightScreen = new Vector3d();
+ this._topRightScreen = new Vector3d();
+ this._bottomLeftScreen = new Vector3d();
+ this.sphereRadius = 0;
+ this.sphereCenter = new Vector3d();
+ this.radius = 1;
+ this.triangleCount = 0;
+ this.requestHits = 0;
+ this.requestPending = false;
+ this.errored = false;
+ this._key = null;
+ this._tileId = null;
+ this._vertexCount = 0;
+ this.renderChildPart = null;
+ this.renderChildPart = new Array(4);
+ for (var i = 0; i < 4; i++) {
+ this.renderChildPart[i] = BlendState.create(false, 500);
+ }
+}
+
+Tile.currentRenderGeneration = 0;
+Tile.tileTargetX = -1;
+Tile.tileTargetY = -1;
+Tile.tileTargetLevel = -1;
+Tile.tilesInView = 0;
+Tile.trianglesRendered = 0;
+Tile.tilesTouched = 0;
+Tile.frustumList = null;
+set_tileUvMultiple(1);
+Tile.callCount = 0;
+Tile.useAccomidation = true;
+set_tileDemEnabled(true);
+Tile.maxLevel = 20;
+Tile.meshComplexity = 50;
+Tile.imageQuality = 50;
+Tile.lastDeepestLevel = 0;
+Tile.deepestLevel = 0;
+Tile.RC = (3.1415927 / 180);
+
+Tile.getFrustumList = function () {
+ try {
+ return Tile.frustumList;
+ }
+ catch ($e1) {
+ return null;
+ }
+};
+
+Tile.get_subDivisions = function () {
+ return 32;
+};
+
+var Tile$ = {
+ getIndexBuffer: function (index, accomidation) {
+ return this._indexBuffers[index];
+ },
+
+ isPointInTile: function (lat, lng) {
+ return false;
+ },
+
+ getSurfacePointAltitude: function (lat, lng, meters) {
+ return 0;
+ },
+
+ makeTexture: function () {
+ if (tilePrepDevice != null) {
+ try {
+ this.texture2d = tilePrepDevice.createTexture();
+ tilePrepDevice.bindTexture(WEBGL.TEXTURE_2D, this.texture2d);
+ tilePrepDevice.texParameteri(WEBGL.TEXTURE_2D, WEBGL.TEXTURE_WRAP_S, WEBGL.CLAMP_TO_EDGE);
+ tilePrepDevice.texParameteri(WEBGL.TEXTURE_2D, WEBGL.TEXTURE_WRAP_T, WEBGL.CLAMP_TO_EDGE);
+ if (this.dataset.get_extension().toLowerCase().indexOf('fits') > -1 && useGlVersion2) {
+ tilePrepDevice.texImage2D(WEBGL.TEXTURE_2D, 0, WEBGL.R32F, ss.truncate(this.fitsImage.get_sizeX()), ss.truncate(this.fitsImage.get_sizeY()), 0, WEBGL.RED, WEBGL.FLOAT, this.fitsImage.dataUnit);
+ tilePrepDevice.texParameteri(WEBGL.TEXTURE_2D, WEBGL.TEXTURE_MIN_FILTER, WEBGL.NEAREST);
+ tilePrepDevice.texParameteri(WEBGL.TEXTURE_2D, WEBGL.TEXTURE_MAG_FILTER, WEBGL.NEAREST);
+ }
+ else {
+ var image = this.texture;
+ // Before we bind resize to a power of two if nessesary so we can MIPMAP
+ if ((!Texture.isPowerOfTwo(this.texture.height) | !Texture.isPowerOfTwo(this.texture.width)) === 1) {
+ var temp = document.createElement('canvas');
+ temp.height = Texture.fitPowerOfTwo(image.height);
+ temp.width = Texture.fitPowerOfTwo(image.width);
+ var ctx = temp.getContext('2d');
+ ctx.drawImage(image, 0, 0, temp.width, temp.height);
+ //Substitute the resized image
+ image = temp;
+ }
+ tilePrepDevice.texImage2D(WEBGL.TEXTURE_2D, 0, WEBGL.RGBA, WEBGL.RGBA, WEBGL.UNSIGNED_BYTE, image);
+ tilePrepDevice.texParameteri(WEBGL.TEXTURE_2D, WEBGL.TEXTURE_MIN_FILTER, WEBGL.LINEAR_MIPMAP_NEAREST);
+ tilePrepDevice.generateMipmap(WEBGL.TEXTURE_2D);
+ }
+ tilePrepDevice.bindTexture(WEBGL.TEXTURE_2D, null);
+ }
+ catch ($e1) {
+ this.errored = true;
+ }
+ }
+ },
+
+ addVertex: function (buffer, index, p) {
+ buffer[index++] = p.position.x;
+ buffer[index++] = p.position.y;
+ buffer[index++] = p.position.z;
+ buffer[index++] = p.tu;
+ buffer[index++] = p.tv;
+ return index;
+ },
+
+ geoTo3dWithAlt: function (lat, lng, useLocalCenter, rev) {
+ lat = Math.max(Math.min(90, lat), -90);
+ lng = Math.max(Math.min(180, lng), -180);
+ if (!tileDemEnabled || this.demData == null) {
+ return this.geoTo3d(lat, lng, useLocalCenter);
+ }
+ if (rev) {
+ lng -= 180;
+ }
+ var altitude = this.demData[this.demIndex];
+ var retVal = this.geoTo3dWithAltitude(lat, lng, altitude, useLocalCenter);
+ return retVal;
+ },
+
+ geoTo3dWithAltitude: function (lat, lng, altitude, useLocalCenter) {
+ var radius = 1 + (altitude / this.get__demScaleFactor());
+ var retVal = Vector3d.create((Math.cos(lng * Tile.RC) * Math.cos(lat * Tile.RC) * radius), (Math.sin(lat * Tile.RC) * radius), (Math.sin(lng * Tile.RC) * Math.cos(lat * Tile.RC) * radius));
+ if (useLocalCenter) {
+ retVal.subtract(this.localCenter);
+ }
+ return retVal;
+ },
+
+ get__demScaleFactor: function () {
+ return this._demScaleFactor; // / Properties.Settings.Default.TerrainScaling;
+ },
+
+ set__demScaleFactor: function (value) {
+ this._demScaleFactor = value;
+ return value;
+ },
+
+ requestImage: function () {
+ var $this = this;
+
+ if (this.dataset.get_extension().toLowerCase().indexOf('fits') > -1) {
+ if (!this.downloading && !this.readyToRender) {
+ this.downloading = true;
+ if (useGlVersion2) {
+ this.fitsImage = new FitsImageTile(this.dataset, this.get_URL(), function (wcsImage) {
+ $this.downloading = false;
+ $this.errored = $this.fitsImage.errored;
+ tileCacheRemoveFromQueue($this.get_key(), true);
+ if (!$this.fitsImage.errored) {
+ if (!$this.level) {
+ // For a non-HiPS tiled FITS, this is our
+ // mechanism for notifying the layer creator
+ // that the initial FITS data have loaded and
+ // the FitsProperties can be trusted.
+ $this.dataset.get_fitsProperties()._fireMainImageLoaded($this.fitsImage);
+ $this.fitsImage.applyDisplaySettings();
+ }
+ $this.texReady = true;
+ $this.readyToRender = $this.texReady && ($this.demReady || !$this.demTile);
+ $this.requestPending = false;
+ $this.makeTexture();
+ }
+ });
+ }
+ else {
+ this.fitsImage = FitsImageJs.createTiledFits(this.dataset, this.get_URL(), function (wcsImage) {
+ if (!$this.level) {
+ $this.dataset.get_fitsProperties()._fireMainImageLoaded($this.fitsImage);
+ }
+ $this.texReady = true;
+ $this.downloading = false;
+ $this.errored = $this.fitsImage.errored;
+ $this.readyToRender = $this.texReady && ($this.demReady || !$this.demTile);
+ $this.requestPending = false;
+ tileCacheRemoveFromQueue($this.get_key(), true);
+ $this.texture2d = wcsImage.getBitmap().getTexture();
+ });
+ }
+ }
+ } else {
+ if (this.get_dataset().get_wcsImage() != null) {
+ this.texReady = true;
+ this.downloading = false;
+ this.errored = false;
+ this.readyToRender = true;
+ this.requestPending = false;
+ tileCacheRemoveFromQueue(this.get_key(), true);
+ return;
+ }
+ if (!this.downloading && !this.readyToRender) {
+ this.downloading = true;
+ this.texture = document.createElement('img');
+ var xdomimg = this.texture;
+ this.texture.addEventListener('load', function (e) {
+ $this.texReady = true;
+ $this.downloading = false;
+ $this.errored = false;
+ $this.readyToRender = $this.texReady && ($this.demReady || !$this.demTile);
+ $this.requestPending = false;
+ tileCacheRemoveFromQueue($this.get_key(), true);
+ $this.makeTexture();
+ }, false);
+ this.texture.addEventListener('error', function (e) {
+ if (!$this.texture.hasAttribute('proxyattempt')) {
+ $this.texture.setAttribute('proxyattempt', true);
+ // NOTE: `this.URL` is dynamically generated using
+ // URLHelpers.rewrite(). Say that we request tiles from
+ // example.com, which requires CORS proxying. Say also
+ // that this callback is called for a request to a tile
+ // that should in fact be available. If a different
+ // request fails before this callback is called,
+ // activateProxy() will be called on the example.com
+ // domain, making it so that `this.URL` in the following
+ // call goes through the proxy, making it so that
+ // `new_url` is null, making it so that this tile is
+ // erroneously marked as failed when it should not be.
+ // The solution: make sure to check proxy activation
+ // with the *original* request URL, `texture.Src`, not
+ // the one that may have been updated, `this.URL`.
+ var new_url = URLHelpers.singleton.activateProxy($this.texture.src);
+ if (new_url != null) {
+ // null => don't bother: we know that the proxy won't help
+ $this.texture.src = new_url;
+ return;
+ }
+ }
+ $this.downloading = false;
+ $this.readyToRender = false;
+ $this.errored = true;
+ $this.requestPending = false;
+ tileCacheRemoveFromQueue($this.get_key(), true);
+ }, false);
+ xdomimg.crossOrigin = 'anonymous';
+ this.texture.src = this.get_URL();
+ }
+ }
+ },
+
+ createDemFromParent: function () {
+ return false;
+ },
+
+ _loadDemData: function () {
+ if (this.demFile == null) {
+ return this.createDemFromParent();
+ }
+ this.demData = this.demFile;
+ if (this.demFile.length !== 1089 && this.demFile.length !== 513) {
+ return this.createDemFromParent();
+ }
+ var total = 0;
+ var $enum1 = ss.enumerate(this.demData);
+ while ($enum1.moveNext()) {
+ var fv = $enum1.current;
+ total += fv;
+ }
+ this.demAverage /= this.demData.length;
+ return true;
+ },
+
+ requestDem: function () {
+ var $this = this;
+
+ if (!this.readyToRender && !this.demDownloading) {
+ this.demTile = true;
+ this.demDownloading = true;
+ Tile.callCount++;
+ var xhr = new XMLHttpRequest();
+ xhr.addEventListener('load', function (e) {
+ $this.demReady = true;
+ $this.demDownloading = false;
+ $this.readyToRender = $this.texReady && ($this.demReady || !$this.demTile);
+ $this.requestPending = false;
+ try {
+ $this.demFile = new Float32Array(xhr.response);
+ }
+ catch ($e1) {
+ }
+ tileCacheRemoveFromQueue($this.get_key(), true);
+ }, false);
+ xhr.addEventListener('error', function (e) {
+ $this.demDownloading = false;
+ $this.demReady = false;
+ $this.readyToRender = false;
+ $this.errored = true;
+ $this.requestPending = false;
+ tileCacheRemoveFromQueue($this.get_key(), true);
+ }, false);
+ xhr.open('GET', this.get_demURL(), true);
+ xhr.responseType = 'arraybuffer';
+ xhr.send();
+ }
+ },
+
+ draw3D: function (renderContext, opacity) {
+ this.renderedGeneration = Tile.currentRenderGeneration;
+ Tile.tilesTouched++;
+ this.accessCount = inc_tileCacheAccessID();
+ if (this.errored) {
+ return false;
+ }
+ var xMax = 2;
+ this.inViewFrustum = true;
+ if (!this.readyToRender) {
+ tileCacheAddTileToQueue(this);
+ return false;
+ }
+ var transitioning = false;
+ var childIndex = 0;
+ var yOffset = 0;
+ if (this.dataset.get_mercator() || this.dataset.get_bottomsUp()) {
+ yOffset = 1;
+ }
+ var xOffset = 0;
+ var anythingToRender = false;
+ var childRendered = false;
+ for (var y1 = 0; y1 < 2; y1++) {
+ for (var x1 = 0; x1 < xMax; x1++) {
+ if (this.level < this.dataset.get_levels()) {
+ // make children
+ if (this.children[childIndex] == null) {
+ this.children[childIndex] = tileCacheGetTile(this.level + 1, this.tileX * 2 + ((x1 + xOffset) % 2), this.tileY * 2 + ((y1 + yOffset) % 2), this.dataset, this);
+ }
+ if (this.children[childIndex].isTileInFrustum(renderContext.get_frustum())) {
+ this.inViewFrustum = true;
+ if (this.children[childIndex].isTileBigEnough(renderContext)) {
+ this.renderChildPart[childIndex].set_targetState(!this.children[childIndex].draw3D(renderContext, opacity));
+ if (this.renderChildPart[childIndex].get_targetState()) {
+ childRendered = true;
+ }
+ }
+ else {
+ this.renderChildPart[childIndex].set_targetState(true);
+ }
+ }
+ else {
+ this.renderChildPart[childIndex].set_targetState(this.renderChildPart[childIndex].set_state(false));
+ }
+ if (this.renderChildPart[childIndex].get_targetState() !== this.renderChildPart[childIndex].get_state()) {
+ transitioning = true;
+ }
+ }
+ else {
+ this.renderChildPart[childIndex].set_state(true);
+ }
+ if (!!this.renderChildPart[childIndex].get_state()) {
+ anythingToRender = true;
+ }
+ childIndex++;
+ }
+ }
+ if (childRendered || anythingToRender) {
+ this.renderedAtOrBelowGeneration = Tile.currentRenderGeneration;
+ if (this.parent != null) {
+ this.parent.renderedAtOrBelowGeneration = this.renderedAtOrBelowGeneration;
+ }
+ }
+ if (!anythingToRender) {
+ return true;
+ }
+ if (!this.createGeometry(renderContext)) {
+ return false;
+ }
+ Tile.tilesInView++;
+ this.accomidation = this._computeAccomidation();
+ for (var i = 0; i < 4; i++) {
+ if (this.renderChildPart[i].get_targetState()) {
+ this.renderPart(renderContext, i, (opacity / 100), false);
+ }
+ }
+ return true;
+ },
+
+ _computeAccomidation: function () {
+ var accVal = 0;
+ if (!Tile.useAccomidation) {
+ return 0;
+ }
+ var top = tileCacheGetCachedTile(this.level, this.tileX, this.tileY + 1, this.dataset, this);
+ if (top == null || top.renderedAtOrBelowGeneration < Tile.currentRenderGeneration - 2) {
+ accVal += 1;
+ }
+ var right = tileCacheGetCachedTile(this.level, this.tileX + 1, this.tileY, this.dataset, this);
+ if (right == null || right.renderedAtOrBelowGeneration < Tile.currentRenderGeneration - 2) {
+ accVal += 2;
+ }
+ var bottom = tileCacheGetCachedTile(this.level, this.tileX, this.tileY - 1, this.dataset, this);
+ if (bottom == null || bottom.renderedAtOrBelowGeneration < Tile.currentRenderGeneration - 2) {
+ accVal += 4;
+ }
+ var left = tileCacheGetCachedTile(this.level, this.tileX - 1, this.tileY, this.dataset, this);
+ if (left == null || left.renderedAtOrBelowGeneration < Tile.currentRenderGeneration - 2) {
+ accVal += 8;
+ }
+ return accVal;
+ },
+
+ renderPart: function (renderContext, part, opacity, combine) {
+ if (tilePrepDevice == null) {
+ var lighting = renderContext.lighting && renderContext.get_sunPosition() != null;
+ var $enum1 = ss.enumerate(this._renderTriangleLists[part]);
+ while ($enum1.moveNext()) {
+ var tri = $enum1.current;
+ tri.opacity = opacity;
+ if (lighting) {
+ // transform normal by WV
+ var norm = tri.normal.copy();
+ renderContext.get_world().multiplyVector(norm);
+ norm.normalize();
+
+ // Dot product from sun angle
+ var light = Vector3d.dot(norm, renderContext.get_sunPosition());
+ if (light < 0) {
+ light = 0;
+ }
+ else {
+ light = Math.min(1, (light * 1));
+ }
+
+ // set lighting
+ tri.lighting = light;
+ }
+ else {
+ tri.lighting = 1;
+ }
+ tri.draw(renderContext.device, renderContext.WVP);
+ }
+ } else {
+ if (useGlVersion2 && this.fitsImage != null) {
+ ColorMapContainer.bindColorMapTexture(tilePrepDevice, this.dataset.get_fitsProperties().colorMapName);
+ FitsShader.min = this.dataset.get_fitsProperties().lowerCut;
+ FitsShader.max = this.dataset.get_fitsProperties().upperCut;
+ FitsShader.containsBlanks = this.dataset.get_fitsProperties().containsBlanks;
+ FitsShader.blankValue = this.dataset.get_fitsProperties().blankValue;
+ FitsShader.bZero = this.dataset.get_fitsProperties().bZero;
+ FitsShader.bScale = this.dataset.get_fitsProperties().bScale;
+ FitsShader.scaleType = this.dataset.get_fitsProperties().scaleType;
+ FitsShader.transparentBlack = this.dataset.get_fitsProperties().transparentBlack;
+ FitsShader.use(renderContext, this._vertexBuffer, this.getIndexBuffer(part, this.accomidation), this.texture2d, opacity, false, this.globalCenter);
+ }
+ else {
+ TileShader.use(renderContext, this._vertexBuffer, this.getIndexBuffer(part, this.accomidation), this.texture2d, opacity, false, this.globalCenter);
+ }
+ renderContext.gl.drawElements(WEBGL.TRIANGLES, this.triangleCount * 3, WEBGL.UNSIGNED_SHORT, 0);
+ }
+ },
+
+ cleanUp: function (removeFromParent) {
+ this.readyToRender = false;
+ this.demData = null;
+ this.demFile = null;
+ this.demDownloading = false;
+ this.texReady = false;
+ this.demReady = false;
+ this.errored = false;
+ if (this.texture != null) {
+ this.texture = null;
+ }
+ this._renderTriangleLists = new Array(4);
+ this.geometryCreated = false;
+ if (removeFromParent && this.parent != null) {
+ this.parent.removeChild(this);
+ this.parent = null;
+ }
+ if (tilePrepDevice != null) {
+ var $enum1 = ss.enumerate(this._indexBuffers);
+ while ($enum1.moveNext()) {
+ var buf = $enum1.current;
+ tilePrepDevice.deleteBuffer(buf);
+ }
+ this._indexBuffers = new Array(4);
+ if (this._vertexBuffer != null) {
+ tilePrepDevice.deleteBuffer(this._vertexBuffer);
+ this._vertexBuffer = null;
+ }
+ if (this.texture2d != null) {
+ tilePrepDevice.deleteTexture(this.texture2d);
+ this.texture2d = null;
+ }
+ }
+ },
+
+ removeChild: function (child) {
+ for (var i = 0; i < 4; i++) {
+ if (this.children[i] === child) {
+ this.children[i] = null;
+ return;
+ }
+ }
+ },
+
+ createGeometry: function (renderContext) {
+ if (tileDemEnabled && this.demReady && this.demData == null) {
+ if (!this._loadDemData()) {
+ return false;
+ }
+ }
+ if (tileDemEnabled && this.demData == null) {
+ return false;
+ }
+ this.readyToRender = true;
+ return true;
+ },
+
+ calcSphere: function () {
+ var corners = new Array(4);
+ corners[0] = this.topLeft;
+ corners[1] = this.bottomRight;
+ corners[2] = this.topRight;
+ corners[3] = this.bottomLeft;
+ var result = ConvexHull.findEnclosingSphere(corners);
+ this.sphereCenter = result.center;
+ this.sphereRadius = result.radius;
+ },
+
+ isTileBigEnough: function (renderContext) {
+ if (this.level > 1) {
+ // Test for tile scale in view.
+ var wvp = renderContext.WVP;
+ wvp._transformTo(this.topLeft, this._topLeftScreen);
+ wvp._transformTo(this.bottomRight, this._bottomRightScreen);
+ wvp._transformTo(this.topRight, this._topRightScreen);
+ wvp._transformTo(this.bottomLeft, this._bottomLeftScreen);
+ var top = this._topLeftScreen;
+ top.subtract(this._topRightScreen);
+ var topLength = top.length();
+ var bottom = this._bottomLeftScreen;
+ bottom.subtract(this._bottomRightScreen);
+ var bottomLength = bottom.length();
+ var left = this._bottomLeftScreen;
+ left.subtract(this._topLeftScreen);
+ var leftLength = left.length();
+ var right = this._bottomRightScreen;
+ right.subtract(this._topRightScreen);
+ var rightLength = right.length();
+ var lengthMax = Math.max(Math.max(rightLength, leftLength), Math.max(bottomLength, topLength));
+ if (lengthMax < 300) { // was 220
+ return false;
+ }
+ else {
+ Tile.deepestLevel = (this.level > Tile.deepestLevel) ? this.level : Tile.deepestLevel;
+ }
+ }
+ return true;
+ },
+
+ isTileInFrustum: function (frustum) {
+ if (this.level < 2 && (!this.dataset.get_projection() || this.dataset.get_projection() === 3)) {
+ // return true;
+ }
+ this.inViewFrustum = false;
+ var centerV4 = new Vector4d(this.sphereCenter.x, this.sphereCenter.y, this.sphereCenter.z, 1);
+ for (var i = 0; i < 6; i++) {
+ if (frustum[i].dot(centerV4) < -this.sphereRadius) {
+ return false;
+ }
+ }
+ this.inViewFrustum = true;
+ return true;
+ },
+
+ get_sphereRadius: function () {
+ return this.sphereRadius;
+ },
+
+ get_sphereCenter: function () {
+ return this.sphereCenter;
+ },
+
+ geoTo3d: function (lat, lng, useLocalCenter) {
+ if (this.dataset.get_dataSetType() === 3) {
+ var retVal = Vector3d.create(-(Math.cos(lng * Tile.RC) * Math.cos(lat * Tile.RC) * this.radius), (Math.sin(lat * Tile.RC) * this.radius), (Math.sin(lng * Tile.RC) * Math.cos(lat * Tile.RC) * this.radius));
+ return retVal;
+ } else {
+ lng -= 180;
+ var retVal = Vector3d.create((Math.cos(lng * Tile.RC) * Math.cos(lat * Tile.RC) * this.radius), (Math.sin(lat * Tile.RC) * this.radius), (Math.sin(lng * Tile.RC) * Math.cos(lat * Tile.RC) * this.radius));
+ return retVal;
+ }
+ },
+
+ onCreateVertexBuffer: function (sender, e) { },
+
+ get_dataset: function () {
+ return this.dataset;
+ },
+
+ set_dataset: function (value) {
+ this.dataset = value;
+ return value;
+ },
+
+ get_key: function () {
+ if (this._key == null) {
+ this._key = getTileKey(this.dataset, this.level, this.tileX, this.tileY, this.parent);
+ }
+ return this._key;
+ },
+
+ // URL parameters
+ //
+ //{0} ImageSetID
+ //{1} level
+ //{2} x tile id
+ //{3} y tile id
+ //{4} quadtree address (VE style)
+ //{5} quadtree address (Google maps style)
+ //{6} top left corner RA
+ //{7} top left corner Dec
+ //{8} bottom right corner RA
+ //{9} bottom right corner dec
+ //{10} bottom left corner RA
+ //{11} bottom left corner dec
+ //{12} top right corner RA
+ //{13} top right corner dec
+ //{X} - Tile X value
+ //{Y} - Tile Y value
+ //{L} - Tile Level
+ //{Q} - Quad Key ID
+ //{S} - Last Digit of Quadkey
+ get_URL: function () {
+ var rewritten_url = URLHelpers.singleton.rewrite(this.dataset.get_url(), 0);
+ var returnUrl = rewritten_url;
+ if (rewritten_url.indexOf('{1}') > -1) {
+ // Old style URL
+ if (!this.dataset.get_projection() && !ss.emptyString(this.dataset.get_quadTreeTileMap())) {
+ returnUrl = ss.format(rewritten_url, this.getServerID(), this.getTileID());
+ if (returnUrl.indexOf('virtualearth.net') > -1) {
+ returnUrl += '&n=z';
+ }
+ return returnUrl;
+ }
+ else {
+ return ss.format(rewritten_url, this.dataset.get_imageSetID(), this.level, this.tileX, this.tileY);
+ }
+ }
+ returnUrl = ss.replaceString(returnUrl, '{X}', this.tileX.toString());
+ returnUrl = ss.replaceString(returnUrl, '{Y}', this.tileY.toString());
+ returnUrl = ss.replaceString(returnUrl, '{L}', this.level.toString());
+ var hash = 0;
+ if (returnUrl.indexOf('{S:0}') > -1) {
+ hash = 0;
+ returnUrl = ss.replaceString(returnUrl, '{S:0}', '{S}');
+ }
+ if (returnUrl.indexOf('{S:1}') > -1) {
+ hash = 1;
+ returnUrl = ss.replaceString(returnUrl, '{S:1}', '{S}');
+ }
+ if (returnUrl.indexOf('{S:2}') > -1) {
+ hash = 2;
+ returnUrl = ss.replaceString(returnUrl, '{S:2}', '{S}');
+ }
+ if (returnUrl.indexOf('{S:3}') > -1) {
+ hash = 3;
+ returnUrl = ss.replaceString(returnUrl, '{S:3}', '{S}');
+ }
+ if (returnUrl.indexOf('a{S}') > -1) {
+ returnUrl = ss.replaceString(returnUrl, 'a{S}', 'r{S}');
+ }
+ if (returnUrl.indexOf('h{S}') > -1) {
+ returnUrl = ss.replaceString(returnUrl, 'h{S}', 'r{S}');
+ }
+ if (returnUrl.indexOf('//r{S}.ortho.tiles.virtualearth.net') > -1) {
+ returnUrl = ss.replaceString(returnUrl, '//r{S}.ortho.tiles.virtualearth.net', '//ecn.t{S}.tiles.virtualearth.net');
+ }
+ var id = this.getTileID();
+ var server = '';
+ if (!id.length) {
+ server = hash.toString();
+ } else {
+ server = id.substr(id.length - 1, 1);
+ }
+ returnUrl = ss.replaceString(returnUrl, '{Q}', id);
+ returnUrl = ss.replaceString(returnUrl, '{S}', server);
+ if (returnUrl.indexOf('virtualearth.net') > -1) {
+ returnUrl += '&n=z';
+ }
+ return returnUrl;
+ },
+
+ get_demURL: function () {
+ var rewritten_url = URLHelpers.singleton.rewrite(this.dataset.get_demUrl(), 0);
+ if (!this.dataset.get_projection() && !freestandingMode) {
+ var baseUrl = URLHelpers.singleton.coreStaticUrl('wwtweb/demtile.aspx?q={0},{1},{2},M');
+ if (!ss.emptyString(rewritten_url)) {
+ baseUrl = rewritten_url;
+ }
+ }
+ if (rewritten_url.indexOf('{1}') > -1) {
+ return ss.format(rewritten_url + '&new', this.level, this.tileX, this.tileY);
+ }
+ var returnUrl = rewritten_url;
+ returnUrl = ss.replaceString(returnUrl, '{X}', this.tileX.toString());
+ returnUrl = ss.replaceString(returnUrl, '{Y}', this.tileY.toString());
+ returnUrl = ss.replaceString(returnUrl, '{L}', this.level.toString());
+ var hash = 0;
+ if (returnUrl.indexOf('{S:0}') > -1) {
+ hash = 0;
+ returnUrl = ss.replaceString(returnUrl, '{S:0}', '{S}');
+ }
+ if (returnUrl.indexOf('{S:1}') > -1) {
+ hash = 1;
+ returnUrl = ss.replaceString(returnUrl, '{S:1}', '{S}');
+ }
+ if (returnUrl.indexOf('{S:2}') > -1) {
+ hash = 2;
+ returnUrl = ss.replaceString(returnUrl, '{S:2}', '{S}');
+ }
+ if (returnUrl.indexOf('{S:3}') > -1) {
+ hash = 3;
+ returnUrl = ss.replaceString(returnUrl, '{S:3}', '{S}');
+ }
+ var id = this.getTileID();
+ var server = '';
+ if (!id.length) {
+ server = hash.toString();
+ } else {
+ server = id.substr(id.length - 1, 1);
+ }
+ returnUrl = ss.replaceString(returnUrl, '{Q}', id);
+ returnUrl = ss.replaceString(returnUrl, '{S}', server);
+ return returnUrl;
+ },
+
+ getServerID: function () {
+ var server = (this.tileX & 1) + ((this.tileY & 1) << 1);
+ return server;
+ },
+
+ getTileID: function () {
+ if (this._tileId != null) {
+ return this._tileId;
+ }
+ var netLevel = this.level;
+ var netX = this.tileX;
+ var netY = this.tileY;
+ if (this.dataset.get_projection() === 1) {
+ netLevel++;
+ }
+ var tileMap = this.dataset.get_quadTreeTileMap();
+ if (!ss.emptyString(tileMap)) {
+ var sb = new ss.StringBuilder();
+ for (var i = netLevel; i > 0; --i) {
+ var mask = 1 << (i - 1);
+ var val = 0;
+ if (!!(netX & mask)) {
+ val = 1;
+ }
+ if (!!(netY & mask)) {
+ val += 2;
+ }
+ sb.append(tileMap.substr(val, 1));
+ }
+ this._tileId = sb.toString();
+ return this._tileId;
+ } else {
+ this._tileId = '0';
+ return this._tileId;
+ }
+ },
+
+ get_vertexCount: function () {
+ return this._vertexCount;
+ },
+
+ set_vertexCount: function (value) {
+ this._vertexCount = value;
+ return value;
+ }
+};
+
+registerType("Tile", [Tile, Tile$, null]);
diff --git a/engine/esm/tile_cache.js b/engine/esm/tile_cache.js
new file mode 100644
index 00000000..724ec64c
--- /dev/null
+++ b/engine/esm/tile_cache.js
@@ -0,0 +1,292 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// The cache of tiles and associated download queue.
+
+import { ss } from "./ss.js";
+import { registerType } from "./typesystem.js";
+import { Vector3d } from "./double3d.js";
+import {
+ set_tileCacheAddTileToQueue,
+ set_tileCacheGetCachedTile,
+ set_tileCacheGetTile,
+ set_tileCacheRemoveFromQueue,
+} from "./render_globals.js";
+import { getTileKey } from "./util.js";
+import { Tile } from "./tile.js";
+import { Imageset, ProjectionType } from "./imageset.js";
+
+
+// wwtlib.TileCache
+
+export function TileCache() { }
+
+TileCache._queue = {};
+TileCache._tiles = {};
+TileCache.openThreads = 8;
+TileCache.readyToRenderCount = 0;
+TileCache.maxTileCacheSize = 800;
+TileCache.maxReadyToRenderSize = 200;
+TileCache._maxTotalToPurge = 0;
+
+TileCache.get_queueCount = function () {
+ return ss.keyCount(TileCache._queue);
+};
+
+// This name is no longer used internally, but preserve it
+// for API compatibility.
+TileCache.getTile = function (level, x, y, dataset, parent) {
+ var retTile = null;
+ var tileKey = getTileKey(dataset, level, x, y, parent);
+ if (!ss.keyExists(TileCache._tiles, tileKey)) {
+ retTile = Imageset.getNewTile(dataset, level, x, y, parent);
+ if (retTile != null) {
+ TileCache._tiles[tileKey] = retTile;
+ }
+ }
+ else {
+ retTile = TileCache._tiles[tileKey];
+ }
+ var p = 0;
+ return retTile;
+};
+
+set_tileCacheGetTile(TileCache.getTile);
+
+// This name is no longer used internally, but preserve it
+// for API compatibility.
+TileCache.getCachedTile = function (level, x, y, dataset, parent) {
+ if (level < dataset.get_baseLevel()) {
+ return null;
+ }
+ var retTile = null;
+ var tileKey = getTileKey(dataset, level, x, y, parent);
+ try {
+ if (!ss.keyExists(TileCache._tiles, tileKey)) {
+ return null;
+ } else {
+ retTile = TileCache._tiles[tileKey];
+ }
+ }
+ catch ($e1) { }
+ return retTile;
+};
+
+set_tileCacheGetCachedTile(TileCache.getCachedTile);
+
+TileCache.getReadyToRenderTileCount = function () {
+ var notReadyCullList = [];
+ var readyCullList = [];
+ try {
+ try {
+ var $enum1 = ss.enumerate(ss.keys(TileCache._tiles));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var tile = TileCache._tiles[key];
+ if (tile.renderedGeneration < (Tile.currentRenderGeneration - 10) && !(tile.requestPending || tile.downloading)) {
+ if (tile.readyToRender) {
+ readyCullList.push(tile);
+ }
+ else {
+ notReadyCullList.push(tile);
+ }
+ }
+ }
+ }
+ catch ($e2) {
+ }
+ return readyCullList.length;
+ }
+ catch ($e3) {
+ return -1;
+ }
+};
+
+TileCache.processQueue = function (renderContext) {
+ while (ss.keyCount(TileCache._queue) > 0 && TileCache.openThreads > 0) {
+ var minDistance = 100000;
+ var overlayTile = false;
+ var maxKey = null;
+ var level = 1000;
+ var $enum1 = ss.enumerate(ss.keys(TileCache._queue));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var t = TileCache._queue[key];
+ if (!t.requestPending && t.inViewFrustum) {
+ var vectTemp = Vector3d.makeCopy(t.get_sphereCenter());
+ vectTemp._transformByMatrics(renderContext.get_world());
+ if (renderContext.space) {
+ vectTemp.subtract(Vector3d.create(0, 0, -1));
+ }
+ else {
+ vectTemp.subtract(renderContext.cameraPosition);
+ }
+ var distTemp = Math.max(0, vectTemp.length() - t.get_sphereRadius());
+ var thisIsOverlay = (t.get_dataset().get_projection() === ProjectionType.tangent) || (t.get_dataset().get_projection() === ProjectionType.skyImage);
+ if (distTemp < minDistance && (!overlayTile || thisIsOverlay)) {
+ minDistance = distTemp;
+ maxKey = t.get_key();
+ level = t.level;
+ overlayTile = thisIsOverlay;
+ }
+ }
+ }
+ if (maxKey != null) {
+ var workTile = TileCache._queue[maxKey];
+ workTile.requestPending = true;
+ TileCache.openThreads--;
+ if (TileCache.openThreads < 0) {
+ TileCache.openThreads = 0;
+ }
+ workTile.requestImage();
+ if (workTile.get_dataset().get_elevationModel()) {
+ workTile.requestDem();
+ }
+ } else {
+ return;
+ }
+ }
+};
+
+// This name is no longer used internally, but preserve it
+// for API compatibility.
+TileCache.addTileToQueue = function (tile) {
+ var hitValue;
+ hitValue = 256;
+ if (!tile.downloading && !tile.readyToRender) {
+ if (ss.keyExists(TileCache._queue, tile.get_key())) {
+ TileCache._queue[tile.get_key()].requestHits += hitValue;
+ } else {
+ tile.requestHits = hitValue;
+ TileCache._queue[tile.get_key()] = tile;
+ }
+ }
+ return true;
+};
+
+set_tileCacheAddTileToQueue(TileCache.addTileToQueue);
+
+// This name is no longer used internally, but preserve it
+// for API compatibility.
+TileCache.removeFromQueue = function (key, complete) {
+ if (complete) {
+ var workTile = TileCache._queue[key];
+ if (workTile != null) {
+ workTile.requestPending = false;
+ delete TileCache._queue[workTile.get_key()];
+ }
+ TileCache.openThreads++;
+ }
+ delete TileCache._queue[key];
+};
+
+set_tileCacheRemoveFromQueue(TileCache.removeFromQueue);
+
+TileCache.clearCache = function () {
+ ss.clearKeys(TileCache._tiles);
+};
+
+TileCache.purgeQueue = function () {
+ ss.clearKeys(TileCache._queue);
+};
+
+TileCache.purgeLRU = function () {
+ if (ss.keyCount(TileCache._tiles) < TileCache.maxReadyToRenderSize) {
+ return;
+ }
+ var notReadyCullList = [];
+ var readyCullList = [];
+ try {
+ try {
+ var $enum1 = ss.enumerate(ss.keys(TileCache._tiles));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var tile = TileCache._tiles[key];
+ if (tile.renderedGeneration < (Tile.currentRenderGeneration - 10) && !(tile.requestPending || tile.downloading)) {
+ if (tile.readyToRender) {
+ readyCullList.push(tile);
+ }
+ else {
+ notReadyCullList.push(tile);
+ }
+ }
+ }
+ }
+ catch ($e2) {
+ }
+ TileCache.readyToRenderCount = readyCullList.length;
+ if (readyCullList.length > TileCache.maxReadyToRenderSize) {
+ readyCullList.sort(function (t1, t2) {
+ return (t2.accessCount < t1.accessCount) ? 1 : ((t2.accessCount === t1.accessCount) ? 0 : -1);
+ });
+ var totalToPurge = readyCullList.length - TileCache.maxReadyToRenderSize;
+ var $enum3 = ss.enumerate(readyCullList);
+ while ($enum3.moveNext()) {
+ var tile = $enum3.current;
+ if (totalToPurge < 1) {
+ break;
+ }
+ tile.cleanUp(false);
+ totalToPurge--;
+ }
+ }
+ if (ss.keyCount(TileCache._tiles) < TileCache.maxTileCacheSize) {
+ return;
+ }
+ if (notReadyCullList.length > TileCache.maxTileCacheSize) {
+ notReadyCullList.sort(function (t1, t2) {
+ return (t2.accessCount < t1.accessCount) ? 1 : ((t2.accessCount === t1.accessCount) ? 0 : -1);
+ });
+ var totalToPurge = notReadyCullList.length - TileCache.maxTileCacheSize;
+ if (totalToPurge > 20) {
+ totalToPurge = 20;
+ }
+ var $enum4 = ss.enumerate(notReadyCullList);
+ while ($enum4.moveNext()) {
+ var tile = $enum4.current;
+ if (totalToPurge < 1) {
+ break;
+ }
+ tile.cleanUp(true);
+ delete TileCache._tiles[tile.get_key()];
+ totalToPurge--;
+ }
+ }
+ }
+ catch ($e5) { }
+ finally { }
+ return;
+};
+
+// Age things in queue. If they are not visible they will go away in time
+TileCache.decimateQueue = function () {
+ var list = [];
+ var $enum1 = ss.enumerate(ss.keys(TileCache._queue));
+ while ($enum1.moveNext()) {
+ var key = $enum1.current;
+ var t = TileCache._queue[key];
+ if (!t.requestPending) {
+ t.requestHits = t.requestHits / 2;
+ try {
+ if (t.requestHits < 2) {
+ list.push(t);
+ }
+ else if (!t.inViewFrustum) {
+ list.push(t);
+ }
+ }
+ catch ($e2) {
+ }
+ }
+ }
+ var $enum3 = ss.enumerate(list);
+ while ($enum3.moveNext()) {
+ var t = $enum3.current;
+ delete TileCache._queue[t.get_key()];
+ }
+};
+
+var TileCache$ = {};
+
+registerType("TileCache", [TileCache, TileCache$, null]);
+
diff --git a/engine/esm/toast_tile.js b/engine/esm/toast_tile.js
new file mode 100644
index 00000000..5e441737
--- /dev/null
+++ b/engine/esm/toast_tile.js
@@ -0,0 +1,603 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A tile in a pyramid that uses a TOAST projection.
+
+import { ss } from "./ss.js";
+import { registerType } from "./typesystem.js";
+import { tileCacheGetTile, tilePrepDevice, tileUvMultiple } from "./render_globals.js";
+import { Vector2d, Vector3d, PositionTexture, ConvexHull } from "./double3d.js";
+import { WEBGL } from "./graphics/webgl_constants.js";
+import { Coordinates } from "./coordinates.js";
+import { RenderTriangle } from "./render_triangle.js";
+import { Tile } from "./tile.js";
+import { Triangle } from "./triangle.js";
+import { DistanceCalc } from "./util.js";
+
+
+// wwtlib.ToastTile
+
+export function ToastTile() {
+ this._topDown$1 = true;
+ this.backslash = false;
+ this._vertexList$1 = null;
+ this._childTriangleList$1 = null;
+ this._subDivisionLevel$1 = 4;
+ this._subDivided$1 = false;
+ Tile.call(this);
+}
+
+ToastTile.slashIndexBuffer = new Array(64);
+ToastTile.backSlashIndexBuffer = new Array(64);
+ToastTile.rootIndexBuffer = new Array(4);
+
+ToastTile._cloneArray$1 = function (indexArray) {
+ var count = indexArray.length;
+ var ui16array = new Uint16Array(count);
+ var indexArrayNew = ui16array;
+ for (var i = 0; i < count; i++) {
+ indexArrayNew[i] = indexArray[i];
+ }
+ return indexArrayNew;
+};
+
+ToastTile.create = function (level, xc, yc, dataset, parent) {
+ var temp = new ToastTile();
+ temp.parent = parent;
+ temp.level = level;
+ temp.tileX = xc;
+ temp.tileY = yc;
+ temp.dataset = dataset;
+ temp._topDown$1 = !dataset.get_bottomsUp();
+ if (temp.tileX !== xc) {
+ alert('bad');
+ }
+ if (!!dataset.get_meanRadius()) {
+ temp.set__demScaleFactor(dataset.get_meanRadius());
+ }
+ else {
+ if (!dataset.get_dataSetType()) {
+ temp.set__demScaleFactor(6371000);
+ } else {
+ temp.set__demScaleFactor(3396010);
+ }
+ }
+ temp.computeBoundingSphere();
+ return temp;
+};
+
+var ToastTile$ = {
+ computeBoundingSphere: function () {
+ this._initializeGrids$1();
+ this.topLeft = this.bounds[0 + 3 * 0].position.copy();
+ this.bottomRight = this.bounds[2 + 3 * 2].position.copy();
+ this.topRight = this.bounds[2 + 3 * 0].position.copy();
+ this.bottomLeft = this.bounds[0 + 3 * 2].position.copy();
+ this.calcSphere();
+ },
+
+ getIndexBuffer: function (index, accomidation) {
+ if (!this.level) {
+ return ToastTile.rootIndexBuffer[index];
+ }
+ if (this.backslash) {
+ return ToastTile.backSlashIndexBuffer[index * 16 + accomidation];
+ } else {
+ return ToastTile.slashIndexBuffer[index * 16 + accomidation];
+ }
+ },
+ _processIndexBuffer$1: function (indexArray, part) {
+ if (!this.level) {
+ ToastTile.rootIndexBuffer[part] = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, ToastTile.rootIndexBuffer[part]);
+ tilePrepDevice.bufferData(WEBGL.ELEMENT_ARRAY_BUFFER, indexArray, WEBGL.STATIC_DRAW);
+ return;
+ }
+ for (var a = 0; a < 16; a++) {
+ var partArray = ToastTile._cloneArray$1(indexArray);
+ this._processAccomindations$1(partArray, a);
+ if (this.backslash) {
+ ToastTile.backSlashIndexBuffer[part * 16 + a] = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, ToastTile.backSlashIndexBuffer[part * 16 + a]);
+ tilePrepDevice.bufferData(WEBGL.ELEMENT_ARRAY_BUFFER, partArray, WEBGL.STATIC_DRAW);
+ }
+ else {
+ ToastTile.slashIndexBuffer[part * 16 + a] = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ELEMENT_ARRAY_BUFFER, ToastTile.slashIndexBuffer[part * 16 + a]);
+ tilePrepDevice.bufferData(WEBGL.ELEMENT_ARRAY_BUFFER, partArray, WEBGL.STATIC_DRAW);
+ }
+ }
+ },
+ _processAccomindations$1: function (indexArray, a) {
+ var map = {};
+ var gridMap = {};
+ var $enum1 = ss.enumerate(indexArray);
+ while ($enum1.moveNext()) {
+ var index = $enum1.current;
+ var vert = this._vertexList$1[index];
+ var arrayX = ss.truncate((vert.tu * 16 + 0.5));
+ var arrayY = ss.truncate((vert.tv * 16 + 0.5));
+ var ii = (arrayY << 8) + arrayX;
+ if (!ss.keyExists(gridMap, ii)) {
+ gridMap[ii] = index;
+ }
+ }
+ var sections = 16;
+ if ((a & 1) === 1) {
+ for (var x = 1; x < sections; x += 2) {
+ var y = sections;
+ var key = (y << 8) + x;
+ var val = (y << 8) + x + 1;
+ if (ss.keyExists(gridMap, key)) {
+ map[gridMap[key]] = gridMap[val];
+ }
+ }
+ }
+ if ((a & 2) === 2) {
+ for (var y = 1; y < sections; y += 2) {
+ var x = sections;
+ var key = (y << 8) + x;
+ var val = ((y + 1) << 8) + x;
+ if (ss.keyExists(gridMap, key)) {
+ map[gridMap[key]] = gridMap[val];
+ }
+ }
+ }
+ if ((a & 4) === 4) {
+ for (var x = 1; x < sections; x += 2) {
+ var y = 0;
+ var key = (y << 8) + x;
+ var val = (y << 8) + x + 1;
+ if (ss.keyExists(gridMap, key)) {
+ map[gridMap[key]] = gridMap[val];
+ }
+ }
+ }
+ if ((a & 8) === 8) {
+ for (var y = 1; y < sections; y += 2) {
+ var x = 0;
+ var key = (y << 8) + x;
+ var val = ((y + 1) << 8) + x;
+ if (ss.keyExists(gridMap, key)) {
+ map[gridMap[key]] = gridMap[val];
+ }
+ }
+ }
+ if (!ss.keyCount(map)) {
+ //nothing to process
+ return;
+ }
+ for (var i = 0; i < indexArray.length; i++) {
+ if (ss.keyExists(map, indexArray[i])) {
+ indexArray[i] = map[indexArray[i]];
+ }
+ }
+ },
+
+ calculateFullSphere: function (list) {
+ var result = ConvexHull.findEnclosingSphere(list);
+ this.sphereCenter = result.center;
+ this.sphereRadius = result.radius;
+ },
+
+ isPointInTile: function (lat, lng) {
+ if (!this.level) {
+ return true;
+ }
+ if (this.level === 1) {
+ if ((lng >= 0 && lng <= 90) && (!this.tileX && this.tileY === 1)) {
+ return true;
+ }
+ if ((lng > 90 && lng <= 180) && (this.tileX === 1 && this.tileY === 1)) {
+ return true;
+ }
+ if ((lng < 0 && lng >= -90) && (!this.tileX && !this.tileY)) {
+ return true;
+ }
+ if ((lng < -90 && lng >= -180) && (this.tileX === 1 && !this.tileY)) {
+ return true;
+ }
+ return false;
+ }
+ if (!this.demReady || this.demData == null) {
+ return false;
+ }
+ var testPoint = Coordinates.geoTo3dDouble(-lat, lng);
+ var top = this._isLeftOfHalfSpace$1(this.topLeft.copy(), this.topRight.copy(), testPoint);
+ var right = this._isLeftOfHalfSpace$1(this.topRight.copy(), this.bottomRight.copy(), testPoint);
+ var bottom = this._isLeftOfHalfSpace$1(this.bottomRight.copy(), this.bottomLeft.copy(), testPoint);
+ var left = this._isLeftOfHalfSpace$1(this.bottomLeft.copy(), this.topLeft.copy(), testPoint);
+ if (top && right && bottom && left) {
+ return true;
+ }
+ return false;
+ },
+ _isLeftOfHalfSpace$1: function (pntA, pntB, pntTest) {
+ pntA.normalize();
+ pntB.normalize();
+ var cross = Vector3d.cross(pntA, pntB);
+ var dot = Vector3d.dot(cross, pntTest);
+ return dot < 0;
+ },
+
+ getSurfacePointAltitude: function (lat, lng, meters) {
+ if (this.level < Tile.lastDeepestLevel) {
+ for (var ii = 0; ii < 4; ii++) {
+ var child = this.children[ii];
+ if (child != null) {
+ if (child.isPointInTile(lat, lng)) {
+ var retVal = child.getSurfacePointAltitude(lat, lng, meters);
+ if (!!retVal) {
+ return retVal;
+ }
+ else {
+ break;
+ }
+ }
+ }
+ }
+ }
+ Tile.tileTargetLevel = this.level;
+ Tile.tileTargetX = this.tileX;
+ Tile.tileTargetY = this.tileY;
+ var testPoint = Coordinates.geoTo3dDouble(-lat, lng);
+ testPoint = Vector3d.subtractVectors(new Vector3d(), testPoint);
+ var uv = DistanceCalc.getUVFromInnerPoint(this.topLeft.copy(), this.topRight.copy(), this.bottomLeft.copy(), this.bottomRight.copy(), testPoint.copy());
+
+ // Get 4 samples and interpolate
+ var uud = Math.max(0, Math.min(16, (uv.x * 16)));
+ var vvd = Math.max(0, Math.min(16, (uv.y * 16)));
+ var uu = Math.max(0, Math.min(15, ss.truncate((uv.x * 16))));
+ var vv = Math.max(0, Math.min(15, ss.truncate((uv.y * 16))));
+ var ha = uud - uu;
+ var va = vvd - vv;
+
+ if (this.demArray != null) {
+ // 4 nearest neighbors
+ var ul = this.demArray[uu + 17 * vv];
+ var ur = this.demArray[(uu + 1) + 17 * vv];
+ var ll = this.demArray[uu + 17 * (vv + 1)];
+ var lr = this.demArray[(uu + 1) + 17 * (vv + 1)];
+ var top = ul * (1 - ha) + ha * ur;
+ var bottom = ll * (1 - ha) + ha * lr;
+ var val = top * (1 - va) + va * bottom;
+ return val / this.get__demScaleFactor();
+ }
+ return this.demAverage / this.get__demScaleFactor();
+ },
+ _initializeGrids$1: function () {
+ this._vertexList$1 = [];
+ this._childTriangleList$1 = new Array(4);
+ this._childTriangleList$1[0] = [];
+ this._childTriangleList$1[1] = [];
+ this._childTriangleList$1[2] = [];
+ this._childTriangleList$1[3] = [];
+ this.bounds = new Array(9);
+ if (this.level > 0) {
+ if (this.parent == null) {
+ this.parent = tileCacheGetTile(this.level - 1, this.tileX / 2, this.tileY / 2, this.dataset, null);
+ }
+ var parent = this.parent;
+ var xIndex = this.tileX % 2;
+ var yIndex = this.tileY % 2;
+ if (this.level > 1) {
+ this.backslash = parent.backslash;
+ }
+ else {
+ this.backslash = (xIndex === 1 ^ yIndex === 1) === 1;
+ }
+ this.bounds[0 + 3 * 0] = parent.bounds[xIndex + 3 * yIndex].copy();
+ this.bounds[1 + 3 * 0] = this._midpoint$1(parent.bounds[xIndex + 3 * yIndex], parent.bounds[xIndex + 1 + 3 * yIndex]);
+ this.bounds[2 + 3 * 0] = parent.bounds[xIndex + 1 + 3 * yIndex].copy();
+ this.bounds[0 + 3 * 1] = this._midpoint$1(parent.bounds[xIndex + 3 * yIndex], parent.bounds[xIndex + 3 * (yIndex + 1)]);
+ if (this.backslash) {
+ this.bounds[1 + 3 * 1] = this._midpoint$1(parent.bounds[xIndex + 3 * yIndex], parent.bounds[xIndex + 1 + 3 * (yIndex + 1)]);
+ }
+ else {
+ this.bounds[1 + 3 * 1] = this._midpoint$1(parent.bounds[xIndex + 1 + 3 * yIndex], parent.bounds[xIndex + 3 * (yIndex + 1)]);
+ }
+ this.bounds[2 + 3 * 1] = this._midpoint$1(parent.bounds[xIndex + 1 + 3 * yIndex], parent.bounds[xIndex + 1 + 3 * (yIndex + 1)]);
+ this.bounds[0 + 3 * 2] = parent.bounds[xIndex + 3 * (yIndex + 1)].copy();
+ this.bounds[1 + 3 * 2] = this._midpoint$1(parent.bounds[xIndex + 3 * (yIndex + 1)], parent.bounds[xIndex + 1 + 3 * (yIndex + 1)]);
+ this.bounds[2 + 3 * 2] = parent.bounds[xIndex + 1 + 3 * (yIndex + 1)].copy();
+ this.bounds[0 + 3 * 0].tu = 0 * tileUvMultiple;
+ this.bounds[0 + 3 * 0].tv = 0 * tileUvMultiple;
+ this.bounds[1 + 3 * 0].tu = 0.5 * tileUvMultiple;
+ this.bounds[1 + 3 * 0].tv = 0 * tileUvMultiple;
+ this.bounds[2 + 3 * 0].tu = 1 * tileUvMultiple;
+ this.bounds[2 + 3 * 0].tv = 0 * tileUvMultiple;
+ this.bounds[0 + 3 * 1].tu = 0 * tileUvMultiple;
+ this.bounds[0 + 3 * 1].tv = 0.5 * tileUvMultiple;
+ this.bounds[1 + 3 * 1].tu = 0.5 * tileUvMultiple;
+ this.bounds[1 + 3 * 1].tv = 0.5 * tileUvMultiple;
+ this.bounds[2 + 3 * 1].tu = 1 * tileUvMultiple;
+ this.bounds[2 + 3 * 1].tv = 0.5 * tileUvMultiple;
+ this.bounds[0 + 3 * 2].tu = 0 * tileUvMultiple;
+ this.bounds[0 + 3 * 2].tv = 1 * tileUvMultiple;
+ this.bounds[1 + 3 * 2].tu = 0.5 * tileUvMultiple;
+ this.bounds[1 + 3 * 2].tv = 1 * tileUvMultiple;
+ this.bounds[2 + 3 * 2].tu = 1 * tileUvMultiple;
+ this.bounds[2 + 3 * 2].tv = 1 * tileUvMultiple;
+ this._vertexList$1.push(this.bounds[0 + 3 * 0]);
+ this._vertexList$1.push(this.bounds[1 + 3 * 0]);
+ this._vertexList$1.push(this.bounds[2 + 3 * 0]);
+ this._vertexList$1.push(this.bounds[0 + 3 * 1]);
+ this._vertexList$1.push(this.bounds[1 + 3 * 1]);
+ this._vertexList$1.push(this.bounds[2 + 3 * 1]);
+ this._vertexList$1.push(this.bounds[0 + 3 * 2]);
+ this._vertexList$1.push(this.bounds[1 + 3 * 2]);
+ this._vertexList$1.push(this.bounds[2 + 3 * 2]);
+ if (this.backslash) {
+ this._childTriangleList$1[0].push(Triangle.create(4, 1, 0));
+ this._childTriangleList$1[0].push(Triangle.create(3, 4, 0));
+ this._childTriangleList$1[1].push(Triangle.create(5, 2, 1));
+ this._childTriangleList$1[1].push(Triangle.create(4, 5, 1));
+ this._childTriangleList$1[2].push(Triangle.create(7, 4, 3));
+ this._childTriangleList$1[2].push(Triangle.create(6, 7, 3));
+ this._childTriangleList$1[3].push(Triangle.create(8, 5, 4));
+ this._childTriangleList$1[3].push(Triangle.create(7, 8, 4));
+ }
+ else {
+ this._childTriangleList$1[0].push(Triangle.create(3, 1, 0));
+ this._childTriangleList$1[0].push(Triangle.create(4, 1, 3));
+ this._childTriangleList$1[1].push(Triangle.create(4, 2, 1));
+ this._childTriangleList$1[1].push(Triangle.create(5, 2, 4));
+ this._childTriangleList$1[2].push(Triangle.create(6, 4, 3));
+ this._childTriangleList$1[2].push(Triangle.create(7, 4, 6));
+ this._childTriangleList$1[3].push(Triangle.create(7, 5, 4));
+ this._childTriangleList$1[3].push(Triangle.create(8, 5, 7));
+ }
+ } else {
+ this.bounds[0 + 3 * 0] = PositionTexture.create(0, -1, 0, 0, 0);
+ this.bounds[1 + 3 * 0] = PositionTexture.create(0, 0, 1, 0.5, 0);
+ this.bounds[2 + 3 * 0] = PositionTexture.create(0, -1, 0, 1, 0);
+ this.bounds[0 + 3 * 1] = PositionTexture.create(-1, 0, 0, 0, 0.5);
+ this.bounds[1 + 3 * 1] = PositionTexture.create(0, 1, 0, 0.5, 0.5);
+ this.bounds[2 + 3 * 1] = PositionTexture.create(1, 0, 0, 1, 0.5);
+ this.bounds[0 + 3 * 2] = PositionTexture.create(0, -1, 0, 0, 1);
+ this.bounds[1 + 3 * 2] = PositionTexture.create(0, 0, -1, 0.5, 1);
+ this.bounds[2 + 3 * 2] = PositionTexture.create(0, -1, 0, 1, 1);
+ this._vertexList$1.push(this.bounds[0 + 3 * 0]);
+ this._vertexList$1.push(this.bounds[1 + 3 * 0]);
+ this._vertexList$1.push(this.bounds[2 + 3 * 0]);
+ this._vertexList$1.push(this.bounds[0 + 3 * 1]);
+ this._vertexList$1.push(this.bounds[1 + 3 * 1]);
+ this._vertexList$1.push(this.bounds[2 + 3 * 1]);
+ this._vertexList$1.push(this.bounds[0 + 3 * 2]);
+ this._vertexList$1.push(this.bounds[1 + 3 * 2]);
+ this._vertexList$1.push(this.bounds[2 + 3 * 2]);
+ this._childTriangleList$1[0].push(Triangle.create(3, 1, 0));
+ this._childTriangleList$1[0].push(Triangle.create(4, 1, 3));
+ this._childTriangleList$1[1].push(Triangle.create(5, 2, 1));
+ this._childTriangleList$1[1].push(Triangle.create(4, 5, 1));
+ this._childTriangleList$1[2].push(Triangle.create(7, 4, 3));
+ this._childTriangleList$1[2].push(Triangle.create(6, 7, 3));
+ this._childTriangleList$1[3].push(Triangle.create(7, 5, 4));
+ this._childTriangleList$1[3].push(Triangle.create(8, 5, 7));
+ }
+ },
+ _midpoint$1: function (positionNormalTextured, positionNormalTextured_2) {
+ var a1 = Vector3d.lerp(positionNormalTextured.position, positionNormalTextured_2.position, 0.5);
+ var a1uv = Vector2d.lerp(Vector2d.create(positionNormalTextured.tu, positionNormalTextured.tv), Vector2d.create(positionNormalTextured_2.tu, positionNormalTextured_2.tv), 0.5);
+ a1.normalize();
+ return PositionTexture.createPos(a1, a1uv.x, a1uv.y);
+ },
+
+ createGeometry: function (renderContext) {
+ if (this.geometryCreated) {
+ return true;
+ }
+ this.geometryCreated = true;
+ Tile.prototype.createGeometry.call(this, renderContext);
+ if (!this._subDivided$1) {
+ if (this._vertexList$1 == null) {
+ this._initializeGrids$1();
+ }
+ if (tileUvMultiple == 256) {
+ if (!this.dataset.get_dataSetType() || this.dataset.get_dataSetType() === 1) {
+ this._subDivisionLevel$1 = Math.min(5, Math.max(0, 5 - this.level));
+ }
+ else {
+ this._subDivisionLevel$1 = Math.min(5, Math.max(0, 5 - this.level));
+ }
+ }
+ else {
+ if (this.demTile && this.level > 1) {
+ this.demArray = new Array(17 * 17);
+ this.demSize = 17 * 17;
+ if (this.backslash) {
+ if (ToastTile._backslashYIndex$1 == null) {
+ this._tempBackslashYIndex$1 = new Array(this.demSize);
+ this._tempBackslashXIndex$1 = new Array(this.demSize);
+ }
+ }
+ else {
+ if (ToastTile._slashYIndex$1 == null) {
+ this._tempSlashYIndex$1 = new Array(this.demSize);
+ this._tempSlashXIndex$1 = new Array(this.demSize);
+ }
+ }
+ }
+ }
+ for (var i = 0; i < 4; i++) {
+ var count = this._subDivisionLevel$1;
+ while (count-- > 1) {
+ var newList = [];
+ var $enum1 = ss.enumerate(this._childTriangleList$1[i]);
+ while ($enum1.moveNext()) {
+ var tri = $enum1.current;
+ tri.subDivide(newList, this._vertexList$1);
+ }
+ this._childTriangleList$1[i] = newList;
+ }
+ }
+ if (renderContext.gl == null) {
+ for (var i = 0; i < 4; i++) {
+ this._renderTriangleLists[i] = [];
+ var $enum2 = ss.enumerate(this._childTriangleList$1[i]);
+ while ($enum2.moveNext()) {
+ var tri = $enum2.current;
+ var p1 = this._vertexList$1[tri.c];
+ var p2 = this._vertexList$1[tri.b];
+ var p3 = this._vertexList$1[tri.a];
+ this._renderTriangleLists[i].push(RenderTriangle.create(p1, p2, p3, this.texture, this.level));
+ }
+ }
+ }
+ else {
+ this._vertexBuffer = tilePrepDevice.createBuffer();
+ tilePrepDevice.bindBuffer(WEBGL.ARRAY_BUFFER, this._vertexBuffer);
+ var f32array = new Float32Array(this._vertexList$1.length * 5);
+ var buffer = f32array;
+ var index = 0;
+ var $enum3 = ss.enumerate(this._vertexList$1);
+ while ($enum3.moveNext()) {
+ var pt = $enum3.current;
+ if (this.demTile) {
+ index = this.addVertex(buffer, index, this._getMappedVertex(pt));
+ this.demIndex++;
+ }
+ else {
+ index = this.addVertex(buffer, index, pt);
+ }
+ }
+ if (this.demTile) {
+ if (this.backslash) {
+ if (this._tempBackslashXIndex$1 != null) {
+ ToastTile._backslashXIndex$1 = this._tempBackslashXIndex$1;
+ ToastTile._backslashYIndex$1 = this._tempBackslashYIndex$1;
+ this._tempBackslashXIndex$1 = null;
+ this._tempBackslashYIndex$1 = null;
+ }
+ }
+ else {
+ if (this._tempSlashYIndex$1 != null) {
+ ToastTile._slashXIndex$1 = this._tempSlashXIndex$1;
+ ToastTile._slashYIndex$1 = this._tempSlashYIndex$1;
+ this._tempSlashYIndex$1 = null;
+ this._tempSlashXIndex$1 = null;
+ }
+ }
+ }
+ tilePrepDevice.bufferData(WEBGL.ARRAY_BUFFER, f32array, WEBGL.STATIC_DRAW);
+ for (var i = 0; i < 4; i++) {
+ this.triangleCount = this._childTriangleList$1[i].length;
+ if (this.getIndexBuffer(i, 0) == null) {
+ var ui16array = new Uint16Array(this.triangleCount * 3);
+ var indexArray = ui16array;
+ index = 0;
+ var $enum4 = ss.enumerate(this._childTriangleList$1[i]);
+ while ($enum4.moveNext()) {
+ var tri = $enum4.current;
+ indexArray[index++] = tri.c;
+ indexArray[index++] = tri.b;
+ indexArray[index++] = tri.a;
+ }
+ this._processIndexBuffer$1(indexArray, i);
+ }
+ }
+ }
+ this._subDivided$1 = true;
+ }
+ return true;
+ },
+
+ _getMappedVertex: function (vert) {
+ var vertOut = new PositionTexture();
+ var latLng = Coordinates.cartesianToSpherical2(vert.position);
+ if (latLng.get_lng() < -180) {
+ latLng.set_lng(latLng.get_lng() + 360);
+ }
+ if (latLng.get_lng() > 180) {
+ latLng.set_lng(latLng.get_lng() - 360);
+ }
+ if (this.level > 1) {
+ var arrayX = ss.truncate((vert.tu * 16 + 0.5));
+ var arrayY = ss.truncate((vert.tv * 16 + 0.5));
+ this.demArray[arrayX + arrayY * 17] = this.demData[this.demIndex];
+ if (this.backslash) {
+ if (this._tempBackslashYIndex$1 != null) {
+ this._tempBackslashXIndex$1[this.demIndex] = arrayX;
+ this._tempBackslashYIndex$1[this.demIndex] = arrayY;
+ }
+ }
+ else {
+ if (this._tempSlashYIndex$1 != null) {
+ this._tempSlashXIndex$1[this.demIndex] = arrayX;
+ this._tempSlashYIndex$1[this.demIndex] = arrayY;
+ }
+ }
+ }
+ var pos = this.geoTo3dWithAlt(latLng.get_lat(), latLng.get_lng(), false, false);
+ vertOut.tu = vert.tu;
+ vertOut.tv = vert.tv;
+ pos.subtract(this.localCenter);
+ vertOut.position = pos;
+ return vertOut;
+ },
+
+ cleanUp: function (removeFromParent) {
+ Tile.prototype.cleanUp.call(this, removeFromParent);
+ if (this._vertexList$1 != null) {
+ this._vertexList$1 = null;
+ }
+ if (this._childTriangleList$1 != null) {
+ this._childTriangleList$1 = null;
+ }
+ this._subDivided$1 = false;
+ this.demArray = null;
+ },
+ _getDemSample$1: function (xc, yc) {
+ return this.demArray[(16 - yc) * 17 + xc];
+ },
+
+ createDemFromParent: function () {
+ var parent = ss.safeCast(this.parent, ToastTile);
+ if (parent == null) {
+ return false;
+ }
+ var offsetX = (((this.tileX % 2) === 1) ? 8 : 0);
+ var offsetY = ((!(this.tileY % 2)) ? 8 : 0);
+ this.demArray = new Array(17 * 17);
+
+ // Interpolate across
+ for (var yy1 = 0; yy1 < 17; yy1 += 2) {
+ var copy = true;
+ for (var xx1 = 0; xx1 < 17; xx1++) {
+ if (copy) {
+ this.demArray[(16 - yy1) * 17 + xx1] = parent._getDemSample$1((xx1 / 2) + offsetX, (yy1 / 2) + offsetY);
+ }
+ else {
+ this.demArray[(16 - yy1) * 17 + xx1] = ((parent._getDemSample$1((xx1 / 2) + offsetX, (yy1 / 2) + offsetY) + parent._getDemSample$1(((xx1 / 2) + offsetX) + 1, (yy1 / 2) + offsetY)) / 2);
+ }
+ copy = !copy;
+ }
+ }
+
+ // Interpolate down
+ for (var yy2 = 1; yy2 < 17; yy2 += 2) {
+ for (var xx2 = 0; xx2 < 17; xx2++) {
+ this.demArray[(16 - yy2) * 17 + xx2] = ((this._getDemSample$1(xx2, yy2 - 1) + this._getDemSample$1(xx2, yy2 + 1)) / 2);
+ }
+ }
+
+ // Convert the dem array back to the arranged DEM list thu slash/backslash mapping tables
+ this.demData = new Array(this.demSize);
+ for (var i = 0; i < this.demSize; i++) {
+ if (this.backslash) {
+ this.demData[i] = this.demArray[ToastTile._backslashXIndex$1[i] + ToastTile._backslashYIndex$1[i] * 17];
+ }
+ else {
+ this.demData[i] = this.demArray[ToastTile._slashXIndex$1[i] + ToastTile._slashYIndex$1[i] * 17];
+ }
+ this.demAverage += this.demData[i];
+ }
+
+ // Get Average value for new DemData table
+ this.demAverage /= this.demData.length;
+ this.demReady = true;
+ return true;
+ }
+};
+
+registerType("ToastTile", [ToastTile, ToastTile$, Tile]);
diff --git a/engine/esm/tour.js b/engine/esm/tour.js
new file mode 100644
index 00000000..7f4d1b6d
--- /dev/null
+++ b/engine/esm/tour.js
@@ -0,0 +1,151 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// Top-level information about a tour.
+
+import { ss } from "./ss.js";
+import { registerType, Enums } from "./typesystem.js";
+import { freestandingMode } from "./data_globals.js";
+import { IThumbnail } from "./interfaces.js";
+import { URLHelpers } from "./url_helpers.js";
+
+
+// wwtlib.Tour
+
+export function Tour() {
+ this.userLevel = 0;
+ this.classification = 0;
+ this.averageRating = 0;
+ this.lengthInSecs = 0;
+ this._thumbnailUrlField = '';
+}
+
+Tour._fromXml = function (child) {
+ var temp = new Tour();
+ if (child.attributes.getNamedItem('ID') != null) {
+ temp.id = child.attributes.getNamedItem('ID').nodeValue;
+ }
+ if (child.attributes.getNamedItem('TourUrl') != null) {
+ temp._tourUrl = child.attributes.getNamedItem('TourUrl').nodeValue;
+ }
+ if (child.attributes.getNamedItem('Title') != null) {
+ temp.title = child.attributes.getNamedItem('Title').nodeValue;
+ }
+ if (child.attributes.getNamedItem('Description') != null) {
+ temp.description = child.attributes.getNamedItem('Description').nodeValue;
+ }
+ if (child.attributes.getNamedItem('Classification') != null) {
+ temp.classification = Enums.parse('Classification', child.attributes.getNamedItem('Classification').nodeValue);
+ }
+ if (child.attributes.getNamedItem('AuthorEmail') != null) {
+ temp.authorEmail = child.attributes.getNamedItem('AuthorEmail').nodeValue;
+ }
+ if (child.attributes.getNamedItem('Author') != null) {
+ temp.author = child.attributes.getNamedItem('Author').nodeValue;
+ }
+ if (child.attributes.getNamedItem('AuthorURL') != null) {
+ temp.authorURL = child.attributes.getNamedItem('AuthorURL').nodeValue;
+ }
+ if (child.attributes.getNamedItem('AuthorImageUrl') != null) {
+ temp.authorImageUrl = child.attributes.getNamedItem('AuthorImageUrl').nodeValue;
+ }
+ if (child.attributes.getNamedItem('AverageRating') != null) {
+ temp.averageRating = parseFloat(child.attributes.getNamedItem('AverageRating').nodeValue);
+ }
+ if (child.attributes.getNamedItem('LengthInSecs') != null) {
+ temp.lengthInSecs = parseFloat(child.attributes.getNamedItem('LengthInSecs').nodeValue);
+ }
+ if (child.attributes.getNamedItem('OrganizationUrl') != null) {
+ temp.organizationUrl = child.attributes.getNamedItem('OrganizationUrl').nodeValue;
+ }
+ if (child.attributes.getNamedItem('OrganizationName') != null) {
+ temp.organizationName = child.attributes.getNamedItem('OrganizationName').nodeValue;
+ }
+ if (child.attributes.getNamedItem('RelatedTours') != null) {
+ temp.relatedTours = child.attributes.getNamedItem('RelatedTours').nodeValue;
+ }
+ if (child.attributes.getNamedItem('Keywords') != null) {
+ temp.keywords = child.attributes.getNamedItem('Keywords').nodeValue;
+ }
+ if (child.attributes.getNamedItem('ThumbnailUrl') != null) {
+ temp.set_thumbnailUrl(child.attributes.getNamedItem('ThumbnailUrl').nodeValue);
+ }
+ return temp;
+};
+
+var Tour$ = {
+ get_name: function () {
+ return this.title;
+ },
+
+ get_thumbnail: function () {
+ return this._thumbnail;
+ },
+
+ set_thumbnail: function (value) {
+ this._thumbnail = value;
+ return value;
+ },
+
+ get_thumbnailUrl: function () {
+ if (!ss.emptyString(this._thumbnailUrlField)) {
+ return this._thumbnailUrlField;
+ } else if (freestandingMode) {
+ return URLHelpers.singleton.engineAssetUrl('thumb_star.jpg');
+ }
+ return ss.format(URLHelpers.singleton.coreStaticUrl('wwtweb/GetTourThumbnail.aspx?GUID={0}'), this.id);
+ },
+
+ set_thumbnailUrl: function (value) {
+ this._thumbnailUrlField = value;
+ return value;
+ },
+
+ get_tourUrl: function () {
+ if (ss.emptyString(this._tourUrl) && !freestandingMode) {
+ return ss.format(URLHelpers.singleton.coreStaticUrl('wwtweb/GetTour.aspx?GUID={0}'), this.id);
+ } else {
+ return this._tourUrl;
+ }
+ },
+
+ set_tourUrl: function (value) {
+ this._tourUrl = value;
+ return value;
+ },
+
+ get_bounds: function () {
+ return this._bounds;
+ },
+
+ set_bounds: function (value) {
+ this._bounds = value;
+ return value;
+ },
+
+ get_isImage: function () {
+ return false;
+ },
+
+ get_isTour: function () {
+ return true;
+ },
+
+ get_isFolder: function () {
+ return false;
+ },
+
+ get_isCloudCommunityItem: function () {
+ return false;
+ },
+
+ get_readOnly: function () {
+ return false;
+ },
+
+ get_children: function () {
+ return [];
+ }
+};
+
+registerType("Tour", [Tour, Tour$, null, IThumbnail]);
diff --git a/engine/esm/tours/file_cabinet.js b/engine/esm/tours/file_cabinet.js
new file mode 100644
index 00000000..181cfa7f
--- /dev/null
+++ b/engine/esm/tours/file_cabinet.js
@@ -0,0 +1,232 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A simple XML-based file archive format.
+
+import { ss } from "../ss.js";
+import { registerType } from "../typesystem.js";
+import { Util } from "../baseutil.js";
+import { XmlTextWriter } from "../utilities/xml_text_writer.js";
+import { WebFile } from "../web_file.js";
+
+
+// wwtlib.FileEntry
+
+export function FileEntry(filename, size) {
+ this.size = 0;
+ this.offset = 0;
+ this.filename = filename;
+ this.size = size;
+}
+
+var FileEntry$ = {
+ toString: function () {
+ return this.filename;
+ }
+};
+
+registerType("FileEntry", [FileEntry, FileEntry$, null]);
+
+
+// wwtlib.FileCabinet
+
+export function FileCabinet() {
+ this.tempDirectory = '';
+ this._currentOffset = 0;
+ this._packageID = '';
+ this.url = '';
+ this.clearFileList();
+}
+
+FileCabinet.fromUrl = function (url, callMe) {
+ var temp = new FileCabinet();
+ temp.url = url;
+ temp._callMe = callMe;
+ temp._webFile = new WebFile(url);
+ temp._webFile.responseType = 'blob';
+ temp._webFile.onStateChange = ss.bind('_loadCabinet', temp);
+ temp._webFile.send();
+ return temp;
+};
+
+var FileCabinet$ = {
+ get_packageID: function () {
+ return this._packageID;
+ },
+
+ set_packageID: function (value) {
+ this._packageID = value;
+ return value;
+ },
+
+ addFile: function (filename, data) {
+ if (data == null) {
+ return;
+ }
+ if (!ss.keyExists(this._fileDirectory, filename)) {
+ var fe = new FileEntry(filename, data.size);
+ fe.offset = this._currentOffset;
+ fe.blob = data;
+ this.fileList.push(fe);
+ this._fileDirectory[filename] = fe;
+ this._currentOffset += fe.size;
+ }
+ },
+
+ clearFileList: function () {
+ if (this.fileList == null) {
+ this.fileList = [];
+ }
+ if (this._fileDirectory == null) {
+ this._fileDirectory = {};
+ }
+ this.fileList.length = 0;
+ ss.clearKeys(this._fileDirectory);
+ this._currentOffset = 0;
+ },
+
+ packageFiles: function () {
+ var xmlWriter = new XmlTextWriter();
+ xmlWriter.formatting = 1;
+ xmlWriter._writeProcessingInstruction('xml', "version='1.0' encoding='UTF-8'");
+ xmlWriter._writeStartElement('FileCabinet');
+ xmlWriter._writeAttributeString('HeaderSize', '0x0BADFOOD');
+ xmlWriter._writeStartElement('Files');
+ var $enum1 = ss.enumerate(this.fileList);
+ while ($enum1.moveNext()) {
+ var entry = $enum1.current;
+ xmlWriter._writeStartElement('File');
+ xmlWriter._writeAttributeString('Name', entry.filename);
+ xmlWriter._writeAttributeString('Size', entry.size.toString());
+ xmlWriter._writeAttributeString('Offset', entry.offset.toString());
+ xmlWriter._writeEndElement();
+ }
+ xmlWriter._writeEndElement();
+ xmlWriter._writeFullEndElement();
+ xmlWriter._close();
+ var data = xmlWriter.body;
+ var blob = new Blob([data]);
+ var sizeText = ss.format('0x{0:x8}', blob.size);
+ data = ss.replaceString(data, '0x0BADFOOD', sizeText);
+ blob = new Blob([data]);
+ var blobs = [];
+ blobs.push(blob);
+ var $enum2 = ss.enumerate(this.fileList);
+
+ // add the blobs to array to append in order
+ while ($enum2.moveNext()) {
+ var entry = $enum2.current;
+ blobs.push(entry.blob);
+ }
+ var cabBlob = new Blob(blobs, { type: 'application/x-wtt' });
+ return cabBlob;
+ },
+
+ _loadCabinet: function () {
+ var $this = this;
+
+ if (this._webFile.get_state() === 2) {
+ alert(this._webFile.get_message());
+ } else if (this._webFile.get_state() === 1) {
+ this._mainBlob = this._webFile.getBlob();
+ var chunck = new FileReader();
+ chunck.onloadend = function (e) {
+ var offset = $this._getSize(chunck.result);
+ var header = new FileReader();
+ header.onloadend = function (ee) {
+ var data = ss.safeCast(header.result, String);
+ var xParser = new DOMParser();
+ $this.extract(xParser.parseFromString(data, 'text/xml'), offset);
+ $this._callMe();
+ };
+ header.readAsText($this._mainBlob.slice(0, offset));
+ };
+ chunck.readAsText(this._mainBlob.slice(0, 255));
+ }
+ },
+
+ _getSize: function (data) {
+ var start = data.indexOf('0x');
+ if (start === -1) {
+ return 0;
+ }
+ return parseInt(data.substring(start, start + 10), 16);
+ },
+
+ extract: function (doc, offset) {
+ try {
+ var cab = Util.selectSingleNode(doc, 'FileCabinet');
+ var files = Util.selectSingleNode(cab, 'Files');
+ this.fileList.length = 0;
+ var $enum1 = ss.enumerate(files.childNodes);
+ while ($enum1.moveNext()) {
+ var child = $enum1.current;
+ if (child.nodeName === 'File') {
+ var fe = new FileEntry(child.attributes.getNamedItem('Name').nodeValue, parseInt(child.attributes.getNamedItem('Size').nodeValue));
+ fe.offset = offset;
+ offset += fe.size;
+ this.fileList.push(fe);
+ }
+ }
+ }
+ catch ($e2) {
+ }
+ },
+
+ getFileBlob: function (filename) {
+ var fe = this.getFileEntry(filename);
+ if (fe != null) {
+ var ext = filename.substr(filename.lastIndexOf('.')).toLowerCase();
+ var type = null;
+ switch (ext) {
+ case '.png':
+ type = 'image/png';
+ break;
+ case '.jpg':
+ case '.jpeg':
+ type = 'image/jpeg';
+ break;
+ case '.mp3':
+ type = 'audio/mpeg3';
+ break;
+ case '.txt':
+ type = 'text/plain';
+ break;
+ case '.fit':
+ case '.fits':
+ type = 'application/octet-stream';
+ break;
+ }
+ return this._mainBlob.slice(fe.offset, fe.offset + fe.size, type);
+ }
+ return null;
+ },
+
+ getFileEntry: function (filename) {
+ var $enum1 = ss.enumerate(this.fileList);
+ while ($enum1.moveNext()) {
+ var entry = $enum1.current;
+ if (entry.filename === filename) {
+ return entry;
+ }
+ }
+ return null;
+ },
+
+ get_masterFile: function () {
+ if (this.fileList.length > 0) {
+ return this.fileList[0].filename;
+ } else {
+ return null;
+ }
+ },
+
+ clearTempFiles: function () {
+ var $enum1 = ss.enumerate(this.fileList);
+ while ($enum1.moveNext()) {
+ var entry = $enum1.current;
+ }
+ }
+};
+
+registerType("FileCabinet", [FileCabinet, FileCabinet$, null]);
diff --git a/engine/esm/tours/overlay.js b/engine/esm/tours/overlay.js
new file mode 100644
index 00000000..59518e97
--- /dev/null
+++ b/engine/esm/tours/overlay.js
@@ -0,0 +1,1794 @@
+// Copyright 2023 the .NET Foundation
+// Licensed under the MIT License
+
+// A graphical overlay shown inside a tour.
+
+import { ss } from "../ss.js";
+import { registerType, registerEnum, Enums } from "../typesystem.js";
+import { Vector2d, Vector3d, Matrix2d, Matrix3d, PositionColoredTextured } from "../double3d.js";
+import { globalRenderContext, useGl } from "../render_globals.js";
+import { Texture } from "../graphics/texture.js";
+import { Sprite2d } from "../graphics/sprite2d.js";
+import { Util } from "../baseutil.js";
+import { Color, Colors } from "../color.js";
+import { Coordinates } from "../coordinates.js";
+import { SpaceTimeController } from "../space_time_controller.js";
+import { UiTools } from "../ui_tools.js";
+import { Rectangle } from "../util.js";
+import { TextObject } from "./text_object.js";
+
+
+// wwtlib.OverlayAnchor
+
+export var OverlayAnchor = {
+ sky: 0,
+ screen: 1
+};
+
+registerType("OverlayAnchor", OverlayAnchor);
+registerEnum("OverlayAnchor", OverlayAnchor);
+
+
+// wwtlib.AudioType
+
+export var AudioType = {
+ music: 0,
+ voice: 1
+};
+
+registerType("AudioType", AudioType);
+registerEnum("AudioType", AudioType);
+
+
+// wwtlib.ShapeType
+
+export var ShapeType = {
+ circle: 0,
+ rectagle: 1,
+ star: 2,
+ donut: 3,
+ arrow: 4,
+ line: 5,
+ openRectagle: 6
+};
+
+registerType("ShapeType", ShapeType);
+registerEnum("ShapeType", ShapeType);
+
+
+// wwtlib.LoopTypes
+
+export var LoopTypes = {
+ loop: 0,
+ upDown: 1,
+ down: 2,
+ upDownOnce: 3,
+ once: 4,
+ begin: 5,
+ end: 6
+};
+
+registerType("LoopTypes", LoopTypes);
+registerEnum("LoopTypes", LoopTypes);
+
+
+// wwtlib.Overlay
+
+export function Overlay() {
+ this.isDynamic = false;
+ this.isDesignTimeOnly = false;
+ this._name = '';
+
+ // this used to be a GUID and should become that again now that we have
+ // proper support for them in the web engine.
+ this.id = (Overlay.nextId++).toString();
+ this._owner = null;
+ this._url = '';
+ this._linkID = '';
+ this._domeMatrix = Matrix3d.get_identity();
+ this._domeMatX = 0;
+ this._domeMatY = 0;
+ this._domeAngle = 0;
+ this.points = null;
+ this._animate = false;
+ this._tweenFactor = 0;
+ this._endX = 0;
+ this._endY = 0;
+ this._endOpacity = 0;
+ this._endColor = new Color();
+ this._endWidth = 0;
+ this._endHeight = 0;
+ this._endRotationAngle = 0;
+ this._anchor = 1;
+ this._x = 0;
+ this._y = 0;
+ this._width = 0;
+ this._height = 0;
+ this._color = Colors.get_white();
+ this._opacity = 0.5;
+ this._rotationAngle = 0;
+ this.currentRotation = 0;
+ this.texture = null;
+ this.texture2d = null;
+ this._interpolationType = 5;
+}
+
+Overlay.defaultAnchor = 1;
+Overlay.clipboardFormat = 'WorldWideTelescope.Overlay';
+Overlay.nextId = 11231;
+Overlay.RC = 3.1415927 / 180;
+
+Overlay._fromXml = function (owner, overlay) {
+ if (overlay.attributes == null) {
+ return null;
+ }
+ if (overlay.attributes.getNamedItem('Type') == null) {
+ return null;
+ }
+ var overlayClassName = overlay.attributes.getNamedItem('Type').nodeValue;
+ var overLayType = ss.replaceString(overlayClassName, 'TerraViewer.', '');
+ var newOverlay = null;
+ switch (overLayType) {
+ case 'AudioOverlay':
+ newOverlay = new AudioOverlay();
+ break;
+ case 'BitmapOverlay':
+ newOverlay = new BitmapOverlay();
+ break;
+ case 'FlipBookOverlay':
+ newOverlay = new FlipbookOverlay();
+ break;
+ case 'ShapeOverlay':
+ newOverlay = new ShapeOverlay();
+ break;
+ case 'TextOverlay':
+ newOverlay = new TextOverlay();
+ break;
+ default:
+ return null;
+ }
+ newOverlay._owner = owner;
+ newOverlay._initOverlayFromXml(overlay);
+ return newOverlay;
+};
+
+var Overlay$ = {
+ get_name: function () {
+ return this._name;
+ },
+
+ set_name: function (value) {
+ this._name = value;
+ return value;
+ },
+
+ get_owner: function () {
+ return this._owner;
+ },
+
+ set_owner: function (value) {
+ this._owner = value;
+ return value;
+ },
+
+ get_zOrder: function () {
+ var index = 0;
+ var $enum1 = ss.enumerate(this._owner.get_overlays());
+ while ($enum1.moveNext()) {
+ var item = $enum1.current;
+ if (item === this) {
+ break;
+ }
+ index++;
+ }
+ return index;
+ },
+
+ get_url: function () {
+ return this._url;
+ },
+
+ set_url: function (value) {
+ this._url = value;
+ return value;
+ },
+
+ get_linkID: function () {
+ return this._linkID;
+ },
+
+ set_linkID: function (value) {
+ this._linkID = value;
+ return value;
+ },
+
+ play: function () { },
+
+ pause: function () { },
+
+ stop: function () { },
+
+ seek: function (time) { },
+
+ makePosition: function (centerX, centerY, offsetX, offsetY, angle) {
+ centerX -= 960;
+ centerY -= 558;
+ var point = Vector3d.create(centerX + offsetX, centerY + offsetY, 1347);
+ if (!!this._domeMatX || !!this._domeMatY || this._domeAngle !== angle) {
+ this._domeMatX = centerX;
+ this._domeMatY = centerY;
+ this._domeMatrix = Matrix3d.translation(Vector3d.create(-centerX, -centerY, 0));
+ this._domeMatrix._multiply(Matrix3d._rotationZ((angle / 180 * Math.PI)));
+ this._domeMatrix._multiply(Matrix3d.translation(Vector3d.create(centerX, centerY, 0)));
+ }
+ point = Vector3d._transformCoordinate(point, this._domeMatrix);
+ return point;
+ },
+
+ draw3D: function (renderContext, designTime) {
+ if (useGl) {
+ if (this.texture == null || this.isDynamic) {
+ this.initializeTexture();
+ }
+ if (!this.isDesignTimeOnly || designTime) {
+ this.initializeGeometry();
+ this.updateRotation();
+ }
+ } else {
+ }
+ },
+
+ cleanUp: function () {
+ if (this.texture != null) {
+ this.texture = null;
+ }
+ this.texture2d = null;
+ },
+
+ initializeTexture: function () { },
+
+ // This hook exists to deal with web browser autoplay restrictions. In the
+ // strictest case, we can't just start playing media files at will -- we
+ // need to start playing them in response to a user-initiated event. But
+ // there is a generally a scheme in which files are "unlocked" once they've
+ // started to be played, and after that point we can control their playback
+ // more precisely. So, this function should do any multimedia playback
+ // initialization needed. It will be called when the user initiates tour
+ // playback.
+ //
+ // Repeated calls should be idempotent.
+ prepMultimedia: function () { },
+
+ cleanUpGeometry: function () {
+ this.currentRotation = 0;
+ this.points = null;
+ },
+
+ initializeGeometry: function () {
+ if (this.points == null) {
+ this.currentRotation = 0;
+ this.points = new Array(4);
+ this.points[0] = new PositionColoredTextured();
+ this.points[0].position = this.makePosition(this.get_x(), this.get_y(), -this.get_width() / 2, -this.get_height() / 2, this.get_rotationAngle());
+ this.points[0].tu = 0;
+ this.points[0].tv = 0;
+ this.points[0].color = this.get_color();
+ this.points[1] = new PositionColoredTextured();
+ this.points[1].position = this.makePosition(this.get_x(), this.get_y(), this.get_width() / 2, -this.get_height() / 2, this.get_rotationAngle());
+ this.points[1].tu = 1;
+ this.points[1].tv = 0;
+ this.points[1].color = this.get_color();
+ this.points[2] = new PositionColoredTextured();
+ this.points[2].position = this.makePosition(this.get_x(), this.get_y(), -this.get_width() / 2, this.get_height() / 2, this.get_rotationAngle());
+ this.points[2].tu = 0;
+ this.points[2].tv = 1;
+ this.points[2].color = this.get_color();
+ this.points[3] = new PositionColoredTextured();
+ this.points[3].position = this.makePosition(this.get_x(), this.get_y(), this.get_width() / 2, this.get_height() / 2, this.get_rotationAngle());
+ this.points[3].tu = 1;
+ this.points[3].tv = 1;
+ this.points[3].color = this.get_color();
+ }
+ },
+
+ updateRotation: function () { },
+
+ // Animation Support
+
+ get_animate: function () {
+ return this._animate;
+ },
+
+ set_animate: function (value) {
+ if (this._animate !== value) {
+ this._animate = value;
+ if (this._animate) {
+ this._endX = this._x;
+ this._endY = this._y;
+ this._endRotationAngle = this._rotationAngle;
+ this._endColor = this._color;
+ this._endWidth = this._width;
+ this._endHeight = this._height;
+ this.cleanUpGeometry();
+ }
+ else {
+ this._endX = this._x = this.get_x();
+ this._endY = this._y = this.get_y();
+ this._endRotationAngle = this._rotationAngle = this.get_rotationAngle();
+ this._endColor = this._color = this.get_color();
+ this._endWidth = this._width = this.get_width();
+ this._endHeight = this._height = this.get_height();
+ this.cleanUpGeometry();
+ this._tweenFactor = 0;
+ }
+ }
+ return value;
+ },
+
+ get_tweenFactor: function () {
+ return this._tweenFactor;
+ },
+
+ set_tweenFactor: function (value) {
+ if (!this._animate) {
+ this._tweenFactor = 0;
+ } else {
+ if (this._tweenFactor !== value) {
+ this._tweenFactor = value;
+ this.cleanUpGeometry();
+ }
+ }
+ return value;
+ },
+
+ get_anchor: function () {
+ return this._anchor;
+ },
+
+ set_anchor: function (value) {
+ this._anchor = value;
+ return value;
+ },
+
+ get_position: function () {
+ return Vector2d.create(this.get_x(), this.get_y());
+ },
+
+ set_position: function (value) {
+ this.set_x(value.x);
+ this.set_y(value.y);
+ return value;
+ },
+
+ get_x: function () {
+ return (this._x * (1 - this._tweenFactor)) + (this._endX * this._tweenFactor);
+ },
+
+ set_x: function (value) {
+ if (this._tweenFactor < 0.5) {
+ if (this._x !== value) {
+ this._x = value;
+ this.cleanUpGeometry();
+ }
+ } else {
+ if (this._endX !== value) {
+ this._endX = value;
+ this.cleanUpGeometry();
+ }
+ }
+ return value;
+ },
+
+ get_y: function () {
+ return (this._y * (1 - this._tweenFactor)) + (this._endY * this._tweenFactor);
+ },
+
+ set_y: function (value) {
+ if (this._tweenFactor < 0.5) {
+ if (this._y !== value) {
+ this._y = value;
+ this.cleanUpGeometry();
+ }
+ } else {
+ if (this._endY !== value) {
+ this._endY = value;
+ this.cleanUpGeometry();
+ }
+ }
+ return value;
+ },
+
+ get_width: function () {
+ return (this._width * (1 - this._tweenFactor)) + (this._endWidth * this._tweenFactor);
+ },
+
+ set_width: function (value) {
+ if (value < 5 && !!value) {
+ value = 5;
+ }
+ if (this._tweenFactor < 0.5) {
+ if (this._width !== value) {
+ this._width = value;
+ this.cleanUpGeometry();
+ }
+ } else {
+ if (this._endWidth !== value) {
+ this._endWidth = value;
+ this.cleanUpGeometry();
+ }
+ }
+ return value;
+ },
+
+ get_height: function () {
+ return (this._height * (1 - this._tweenFactor)) + (this._endHeight * this._tweenFactor);
+ },
+
+ set_height: function (value) {
+ if (value < 5 && !!value) {
+ value = 5;
+ }
+ if (this._tweenFactor < 0.5) {
+ if (this._height !== value) {
+ this._height = value;
+ this.cleanUpGeometry();
+ }
+ } else {
+ if (this._endHeight !== value) {
+ this._endHeight = value;
+ this.cleanUpGeometry();
+ }
+ }
+ return value;
+ },
+
+ get_color: function () {
+ var red = ss.truncate(((this._color.r * (1 - this._tweenFactor)) + (this._endColor.r * this._tweenFactor)));
+ var green = ss.truncate(((this._color.g * (1 - this._tweenFactor)) + (this._endColor.g * this._tweenFactor)));
+ var blue = ss.truncate(((this._color.b * (1 - this._tweenFactor)) + (this._endColor.b * this._tweenFactor)));
+ var alpha = ss.truncate(((this._color.a * (1 - this._tweenFactor)) + (this._endColor.a * this._tweenFactor)));
+ return Color.fromArgb(Math.max(0, Math.min(255, alpha)), Math.max(0, Math.min(255, red)), Math.max(0, Math.min(255, green)), Math.max(0, Math.min(255, blue)));
+ },
+
+ set_color: function (value) {
+ if (this._tweenFactor < 0.5) {
+ if (this._color !== value) {
+ this._color = value;
+ this.cleanUpGeometry();
+ }
+ } else {
+ if (this._endColor !== value) {
+ this._endColor = value;
+ this.cleanUpGeometry();
+ }
+ }
+ return value;
+ },
+
+ get_opacity: function () {
+ return this.get_color().a / 255;
+ },
+
+ set_opacity: function (value) {
+ var col = this.get_color();
+ this.set_color(Color.fromArgb(Math.min(255, ss.truncate((value * 255))), col.r, col.g, col.b));
+ this._opacity = value;
+ return value;
+ },
+
+ get_rotationAngle: function () {
+ return (this._rotationAngle * (1 - this._tweenFactor)) + (this._endRotationAngle * this._tweenFactor);
+ },
+
+ set_rotationAngle: function (value) {
+ if (this._tweenFactor < 0.5) {
+ if (this._rotationAngle !== value) {
+ this._rotationAngle = value;
+ this.cleanUpGeometry();
+ }
+ } else {
+ if (this._endRotationAngle !== value) {
+ this._endRotationAngle = value;
+ this.cleanUpGeometry();
+ }
+ }
+ return value;
+ },
+
+ hitTest: function (pntTest) {
+ var tempPoints = new Array(1);
+ tempPoints[0] = Vector2d.create(pntTest.x, pntTest.y);
+ var mat = Matrix2d.rotateAt(-this.get_rotationAngle() / 180 * Math.PI, Vector2d.create(this.get_x(), this.get_y()));
+ mat._transformPoints(tempPoints);
+ var rect = Rectangle.create((this.get_x() - (this.get_width() / 2)), (this.get_y() - (this.get_height() / 2)), this.get_width(), this.get_height());
+ return rect.contains(tempPoints[0]);
+ },
+
+ get_bounds: function () {
+ return this._bounds;
+ },
+
+ set_bounds: function (value) {
+ this._bounds = value;
+ return value;
+ },
+
+ get_interpolationType: function () {
+ return this._interpolationType;
+ },
+
+ set_interpolationType: function (value) {
+ this._interpolationType = value;
+ return value;
+ },
+
+ saveToXml: function (xmlWriter, saveKeys) {
+ xmlWriter._writeStartElement('Overlay');
+ xmlWriter._writeAttributeString('Id', this.id);
+ xmlWriter._writeAttributeString('Type', this.getTypeName());
+ xmlWriter._writeAttributeString('Name', this.get_name());
+ xmlWriter._writeAttributeString('X', this._x.toString());
+ xmlWriter._writeAttributeString('Y', this._y.toString());
+ xmlWriter._writeAttributeString('Width', this._width.toString());
+ xmlWriter._writeAttributeString('Height', this._height.toString());
+ xmlWriter._writeAttributeString('Rotation', this._rotationAngle.toString());
+ xmlWriter._writeAttributeString('Color', this._color.save());
+ xmlWriter._writeAttributeString('Url', this._url);
+ xmlWriter._writeAttributeString('LinkID', this._linkID);
+ xmlWriter._writeAttributeString('Animate', this._animate.toString());
+ if (this._animate) {
+ xmlWriter._writeAttributeString('EndX', this._endX.toString());
+ xmlWriter._writeAttributeString('EndY', this._endY.toString());
+ xmlWriter._writeAttributeString('EndWidth', this._endWidth.toString());
+ xmlWriter._writeAttributeString('EndHeight', this._endHeight.toString());
+ xmlWriter._writeAttributeString('EndRotation', this._endRotationAngle.toString());
+ xmlWriter._writeAttributeString('EndColor', this._endColor.save());
+ xmlWriter._writeAttributeString('InterpolationType', Enums.toXml('InterpolationType', this._interpolationType));
+ }
+ xmlWriter._writeAttributeString('Anchor', Enums.toXml('OverlayAnchor', this._anchor));
+ this.writeOverlayProperties(xmlWriter);
+ xmlWriter._writeEndElement();
+ },
+
+ getTypeName: function () {
+ return 'TerraViewer.Overlay';
+ },
+
+ addFilesToCabinet: function (fc) { },
+
+ writeOverlayProperties: function (xmlWriter) { },
+
+ _initOverlayFromXml: function (node) {
+ this.id = node.attributes.getNamedItem('Id').nodeValue;
+ this.set_name(node.attributes.getNamedItem('Name').nodeValue);
+ this._x = parseFloat(node.attributes.getNamedItem('X').nodeValue);
+ this._y = parseFloat(node.attributes.getNamedItem('Y').nodeValue);
+ this._width = parseFloat(node.attributes.getNamedItem('Width').nodeValue);
+ this._height = parseFloat(node.attributes.getNamedItem('Height').nodeValue);
+ this._rotationAngle = parseFloat(node.attributes.getNamedItem('Rotation').nodeValue);
+ this._color = Color.load(node.attributes.getNamedItem('Color').nodeValue);
+ if (node.attributes.getNamedItem('Url') != null) {
+ this.set_url(node.attributes.getNamedItem('Url').nodeValue);
+ }
+ if (node.attributes.getNamedItem('LinkID') != null) {
+ this.set_linkID(node.attributes.getNamedItem('LinkID').nodeValue);
+ }
+ if (node.attributes.getNamedItem('Animate') != null) {
+ this._animate = ss.boolean(node.attributes.getNamedItem('Animate').nodeValue);
+ if (this._animate) {
+ this._endX = parseFloat(node.attributes.getNamedItem('EndX').nodeValue);
+ this._endY = parseFloat(node.attributes.getNamedItem('EndY').nodeValue);
+ this._endColor = Color.load(node.attributes.getNamedItem('EndColor').nodeValue);
+ this._endWidth = parseFloat(node.attributes.getNamedItem('EndWidth').nodeValue);
+ this._endHeight = parseFloat(node.attributes.getNamedItem('EndHeight').nodeValue);
+ this._endRotationAngle = parseFloat(node.attributes.getNamedItem('EndRotation').nodeValue);
+ if (node.attributes.getNamedItem('InterpolationType') != null) {
+ this.set_interpolationType(Enums.parse('InterpolationType', node.attributes.getNamedItem('InterpolationType').nodeValue));
+ }
+ }
+ }
+ this.initializeFromXml(node);
+ },
+
+ initializeFromXml: function (node) { },
+
+ toString: function () {
+ return this.get_name();
+ }
+};
+
+registerType("Overlay", [Overlay, Overlay$, null]);
+
+// wwtlib.BitmapOverlay
+
+export function BitmapOverlay() {
+ this._textureReady$1 = false;
+ this._sprite$1 = new Sprite2d();
+ Overlay.call(this);
+}
+
+//todo figure out how to load local files into cloud and to cabinet
+BitmapOverlay.create = function (owner, file) {
+ var temp = new BitmapOverlay();
+ temp.set_owner(owner);
+ // to make directory and guid filename in tour temp dir.
+ temp._filename$1 = file.name;
+ temp.set_name(owner.getNextDefaultName('Image'));
+ temp.set_x(0);
+ temp.set_y(0);
+ owner.get_owner().addCachedFile(file.name, file);
+ return temp;
+};
+
+var BitmapOverlay$ = {
+ getTypeName: function () {
+ return 'TerraViewer.BitmapOverlay';
+ },
+
+ copy: function (owner) {
+ var newBmpOverlay = new BitmapOverlay();
+ newBmpOverlay.set_owner(owner);
+ newBmpOverlay._filename$1 = this._filename$1;
+ newBmpOverlay.set_x(this.get_x());
+ newBmpOverlay.set_y(this.get_y());
+ newBmpOverlay.set_width(this.get_width());
+ newBmpOverlay.set_height(this.get_height());
+ newBmpOverlay.set_color(this.get_color());
+ newBmpOverlay.set_opacity(this.get_opacity());
+ newBmpOverlay.set_rotationAngle(this.get_rotationAngle());
+ newBmpOverlay.set_name(this.get_name() + ' - Copy');
+ return newBmpOverlay;
+ },
+
+ cleanUp: function () {
+ this.texture = null;
+ if (this.texture2d != null) {
+ this.texture2d.cleanUp();
+ this.texture2d = null;
+ }
+ },
+
+ initializeTexture: function () {
+ var $this = this;
+
+ try {
+ if (useGl) {
+ this.texture2d = this.get_owner().get_owner().getCachedTexture2d(this._filename$1);
+ this._textureReady$1 = true;
+ }
+ else {
+ this.texture = this.get_owner().get_owner().getCachedTexture(this._filename$1, function () {
+ $this._textureReady$1 = true;
+ });
+ }
+ }
+ catch ($e1) {
+ }
+ },
+
+ draw3D: function (renderContext, designTime) {
+ if (useGl) {
+ if (this.texture2d == null) {
+ this.initializeTexture();
+ }
+ if (!this.get_width() && !this.get_height()) {
+ this.set_width(this.texture2d.imageElement.width);
+ this.set_height(this.texture2d.imageElement.height);
+ }
+ this.initializeGeometry();
+ this.updateRotation();
+ this._sprite$1.draw(renderContext, this.points, this.points.length, this.texture2d, true, 1);
+ } else {
+ if (this.texture == null) {
+ this.initializeTexture();
+ }
+ if (!this._textureReady$1) {
+ return;
+ }
+ if (!this.get_width() && !this.get_height()) {
+ this.set_width(this.texture.width);
+ this.set_height(this.texture.height);
+ }
+ var ctx = renderContext.device;
+ ctx.save();
+ ctx.translate(this.get_x(), this.get_y());
+ ctx.rotate(this.get_rotationAngle() * Overlay.RC);
+ ctx.globalAlpha = this.get_opacity();
+ ctx.drawImage(this.texture, -this.get_width() / 2, -this.get_height() / 2, this.get_width(), this.get_height());
+ ctx.restore();
+ }
+ },
+
+ addFilesToCabinet: function (fc) {
+ fc.addFile(this.get_owner().get_owner().get_workingDirectory() + this._filename$1, this.get_owner().get_owner().getFileBlob(this._filename$1));
+ },
+
+ writeOverlayProperties: function (xmlWriter) {
+ xmlWriter._writeStartElement('Bitmap');
+ xmlWriter._writeAttributeString('Filename', this._filename$1);
+ xmlWriter._writeEndElement();
+ },
+
+ initializeFromXml: function (node) {
+ var bitmap = Util.selectSingleNode(node, 'Bitmap');
+ this._filename$1 = bitmap.attributes.getNamedItem('Filename').nodeValue;
+ }
+};
+
+registerType("BitmapOverlay", [BitmapOverlay, BitmapOverlay$, Overlay]);
+
+// wwtlib.TextOverlay
+
+export function TextOverlay() {
+ this._sprite$1 = new Sprite2d();
+ this._ctx$1 = null;
+ this._ce$1 = null;
+ Overlay.call(this);
+}
+
+TextOverlay.create = function (textObject) {
+ var to = new TextOverlay();
+ to.textObject = textObject;
+ to._calculateTextSize$1();
+ return to;
+};
+
+var TextOverlay$ = {
+ getTypeName: function () {
+ return 'TerraViewer.TextOverlay';
+ },
+
+ get_color: function () {
+ return Overlay.prototype.get_color.call(this);
+ },
+
+ set_color: function (value) {
+ if (this.textObject.foregroundColor !== value) {
+ this.textObject.foregroundColor = value;
+ Overlay.prototype.set_color.call(this, value);
+ this.cleanUp();
+ }
+ return value;
+ },
+
+ draw3D: function (renderContext, designTime) {
+ if (useGl) {
+ this.initializeTexture();
+ this.initializeGeometry();
+ this.updateRotation();
+ this._sprite$1.draw(renderContext, this.points, this.points.length, this.texture2d, true, 1);
+ } else {
+ var ctx = renderContext.device;
+ ctx.save();
+ ctx.translate(this.get_x(), this.get_y());
+ ctx.rotate(this.get_rotationAngle() * Overlay.RC);
+ ctx.globalAlpha = this.get_opacity();
+ this._drawCanvasText$1(ctx);
+ ctx.restore();
+ }
+ },
+ _drawCanvasText$1: function (ctx) {
+ ctx.fillStyle = this.textObject.foregroundColor.toString();
+ ctx.font = ((this.textObject.italic) ? 'italic' : 'normal') + ' ' + ((this.textObject.bold) ? 'bold' : 'normal') + ' ' + Math.round(this.textObject.fontSize * 1.2).toString() + 'px ' + this.textObject.fontName;
+ ctx.textBaseline = 'top';
+ var text = this.textObject.text;
+ if (text.indexOf('{$') > -1) {
+ if (text.indexOf('{$DATE}') > -1) {
+ var date = ss.format('{0:yyyy/MM/dd}', SpaceTimeController.get_now());
+ text = ss.replaceString(text, '{$DATE}', date);
+ }
+ if (text.indexOf('{$TIME}') > -1) {
+ var time = ss.format('{0:HH:mm:ss}', SpaceTimeController.get_now());
+ text = ss.replaceString(text, '{$TIME}', time);
+ }
+ text = ss.replaceString(text, '{$DIST}', UiTools.formatDistance(globalRenderContext.get_solarSystemCameraDistance()));
+ text = ss.replaceString(text, '{$LAT}', Coordinates.formatDMS(globalRenderContext.viewCamera.lat));
+ text = ss.replaceString(text, '{$LNG}', Coordinates.formatDMS(globalRenderContext.viewCamera.lat));
+ text = ss.replaceString(text, '{$RA}', Coordinates.formatDMS(globalRenderContext.viewCamera.get_RA()));
+ text = ss.replaceString(text, '{$DEC}', Coordinates.formatDMS(globalRenderContext.viewCamera.get_dec()));
+ text = ss.replaceString(text, '{$FOV}', Coordinates.formatDMS(globalRenderContext.get_fovAngle()));
+ }
+ var lines = text.split('\n');
+ var baseline = -(this.get_height() / 2);
+ var lineSpace = this.textObject.fontSize * 1.7;
+ var $enum1 = ss.enumerate(lines);
+ while ($enum1.moveNext()) {
+ var line = $enum1.current;
+ var parts = Util.getWrappedText(ctx, line, this.get_width());
+ var $enum2 = ss.enumerate(parts);
+ while ($enum2.moveNext()) {
+ var part = $enum2.current;
+ ctx.fillText(part, -this.get_width() / 2, baseline);
+ baseline += lineSpace;
+ }
+ }
+ },
+ _calculateTextSize$1: function () {
+ if (this._ctx$1 == null || this._ce$1 == null) {
+ this._ce$1 = document.createElement('canvas');
+ this._ce$1.height = 100;
+ this._ce$1.width = 100;
+ this._ctx$1 = this._ce$1.getContext('2d');
+ }
+ this._ctx$1.fillStyle = this.textObject.foregroundColor.toString();
+ this._ctx$1.font = ((this.textObject.italic) ? 'italic' : 'normal') + ' ' + ((this.textObject.bold) ? 'bold' : 'normal') + ' ' + Math.round(this.textObject.fontSize * 1.2).toString() + 'px ' + this.textObject.fontName;
+ this._ctx$1.textBaseline = 'top';
+ var text = this.textObject.text;
+ if (text.indexOf('{$') > -1) {
+ if (text.indexOf('{$DATE}') > -1) {
+ var date = ss.format('{0:yyyy/MM/dd}', SpaceTimeController.get_now());
+ text = ss.replaceString(text, '{$DATE}', date);
+ }
+ if (text.indexOf('{$TIME}') > -1) {
+ var time = ss.format('{0:HH:mm:ss}', SpaceTimeController.get_now());
+ text = ss.replaceString(text, '{$TIME}', time);
+ }
+ text = ss.replaceString(text, '{$DIST}', UiTools.formatDistance(globalRenderContext.get_solarSystemCameraDistance()));
+ text = ss.replaceString(text, '{$LAT}', Coordinates.formatDMS(globalRenderContext.viewCamera.lat));
+ text = ss.replaceString(text, '{$LNG}', Coordinates.formatDMS(globalRenderContext.viewCamera.lat));
+ text = ss.replaceString(text, '{$RA}', Coordinates.formatDMS(globalRenderContext.viewCamera.get_RA()));
+ text = ss.replaceString(text, '{$DEC}', Coordinates.formatDMS(globalRenderContext.viewCamera.get_dec()));
+ text = ss.replaceString(text, '{$FOV}', Coordinates.formatDMS(globalRenderContext.get_fovAngle()));
+ }
+ var lines = text.split('\n');
+ var baseline = 0;
+ var lineSpace = this.textObject.fontSize * 1.7;
+ var maxWidth = 0;
+ var $enum1 = ss.enumerate(lines);
+ while ($enum1.moveNext()) {
+ var line = $enum1.current;
+ var width = this._ctx$1.measureText(line).width;
+ maxWidth = Math.max(width, maxWidth);
+ baseline += lineSpace;
+ }
+
+ //Width + fudge factor
+ this.set_width(maxWidth * 1.01);
+ this.set_height(baseline);
+ this._ce$1 = null;
+ this._ctx$1 = null;
+ },
+
+ initializeTexture: function () {
+ if (this.texture2d == null || (this.textObject.text.indexOf('{$') > -1)) {
+ if (!this.get_height() || !this.get_width()) {
+ this._calculateTextSize$1();
+ }
+ if (this._ctx$1 == null || this._ce$1 == null) {
+ this._ce$1 = document.createElement('canvas');
+ this._ce$1.height = ss.truncate(this.get_height());
+ this._ce$1.width = ss.truncate(this.get_width());
+ this._ctx$1 = this._ce$1.getContext('2d');
+ }
+ this._ctx$1.translate(this.get_width() / 2, this.get_height() / 2);
+ this._ctx$1.clearRect(0, 0, this.get_width(), this.get_height());
+ this._drawCanvasText$1(this._ctx$1);
+ this.texture2d = new Texture();
+ this.texture2d.imageElement = this._ce$1;
+ this.texture2d.makeTexture();
+ this._ce$1 = null;
+ this._ctx$1 = null;
+ }
+ },
+
+ writeOverlayProperties: function (xmlWriter) {
+ xmlWriter._writeStartElement('Text');
+ this.textObject._saveToXml(xmlWriter);
+ xmlWriter._writeEndElement();
+ },
+
+ initializeFromXml: function (node) {
+ var text = Util.selectSingleNode(node, 'Text');
+ this.textObject = TextObject._fromXml(Util.selectSingleNode(text, 'TextObject'));
+ },
+
+ initializeGeometry: function () {
+ if (useGl) {
+ Overlay.prototype.initializeGeometry.call(this);
+ }
+ }
+};
+
+registerType("TextOverlay", [TextOverlay, TextOverlay$, Overlay]);
+
+// wwtlib.ShapeOverlay
+
+export function ShapeOverlay() {
+ this._shapeType$1 = 1;
+ this._sprite$1 = new Sprite2d();
+ this._triangleStrip$1 = true;
+ Overlay.call(this);
+}
+
+ShapeOverlay._create = function (currentTourStop, shapeType) {
+ var overlay = new ShapeOverlay();
+ overlay._shapeType$1 = shapeType;
+ overlay.set_owner(currentTourStop);
+ return overlay;
+};
+
+var ShapeOverlay$ = {
+ getTypeName: function () {
+ return 'TerraViewer.ShapeOverlay';
+ },
+
+ get_shapeType: function () {
+ return this._shapeType$1;
+ },
+
+ set_shapeType: function (value) {
+ this._shapeType$1 = value;
+ this.cleanUpGeometry();
+ return value;
+ },
+
+ draw3D: function (renderContext, designTime) {
+ if (useGl) {
+ this.initializeGeometry();
+ this._sprite$1.draw(renderContext, this.points, this.points.length, null, this._triangleStrip$1, this.get_opacity());
+ } else {
+ switch (this._shapeType$1) {
+ case 0:
+ this._drawCircleGeometry$1(renderContext);
+ break;
+ case 1:
+ this._drawRectGeometry$1(renderContext);
+ break;
+ case 6:
+ this._drawOpenRectGeometry$1(renderContext);
+ break;
+ case 2:
+ this._drawStarGeometry$1(renderContext);
+ break;
+ case 3:
+ this._drawDonutGeometry$1(renderContext);
+ break;
+ case 4:
+ this._drawArrowGeometry$1(renderContext);
+ break;
+ case 5:
+ this._drawLineGeometry$1(renderContext);
+ break;
+ default:
+ break;
+ }
+ }
+ },
+
+ initializeGeometry: function () {
+ if (this.points == null) {
+ switch (this._shapeType$1) {
+ case 0:
+ this._createCircleGeometry$1();
+ break;
+ case 1:
+ Overlay.prototype.initializeGeometry.call(this);
+ break;
+ case 6:
+ this._createOpenRectGeometry$1();
+ break;
+ case 2:
+ this._createStarGeometry$1();
+ break;
+ case 3:
+ this._createDonutGeometry$1();
+ break;
+ case 4:
+ this._createArrowGeometry$1();
+ break;
+ case 5:
+ this._createLineGeometry$1();
+ break;
+ default:
+ break;
+ }
+ }
+ },
+ _createLineGeometry$1: function () {
+ var centerX = this.get_x();
+ var centerY = this.get_y();
+ var radius = this.get_width() / 2;
+ var length = this.get_width();
+ var segments = ss.truncate((length / 12)) + 1;
+ var radiansPerSegment = (Math.PI * 2) / segments;
+ if (this.points == null) {
+ this.points = new Array(segments * 2 + 2);
+ }
+ for (var j = 0; j <= segments; j++) {
+ var i = j * 2;
+ this.points[i] = new PositionColoredTextured();
+ this.points[i].position = this.makePosition(this.get_x(), this.get_y(), ((j / segments) * this.get_width() - (this.get_width() / 2)), 6, this.get_rotationAngle());
+ this.points[i].tu = (j % 2);
+ this.points[i].tv = 0;
+ this.points[i].color = this.get_color();
+ this.points[i + 1] = new PositionColoredTextured();
+ this.points[i + 1].position = this.makePosition(this.get_x(), this.get_y(), ((j / segments) * this.get_width() - (this.get_width() / 2)), -6, this.get_rotationAngle());
+ this.points[i + 1].tu = (j % 2);
+ this.points[i + 1].tv = 1;
+ this.points[i + 1].color = this.get_color();
+ }
+ },
+ _createOpenRectGeometry$1: function () {
+ var centerX = this.get_x();
+ var centerY = this.get_y();
+ var radius = this.get_width() / 2;
+ var length = this.get_width();
+ var segments = ss.truncate((length / 12)) + 1;
+ var segmentsHigh = ss.truncate((this.get_height() / 12)) + 1;
+ var totalPoints = (((segments + 1) * 2) + ((segmentsHigh + 1) * 2)) * 2;
+ if (this.points == null) {
+ this.points = new Array(totalPoints);
+ }
+ for (var j = 0; j <= segments; j++) {
+ var i = j * 2;
+ this.points[i] = new PositionColoredTextured();
+ this.points[i].position = this.makePosition(centerX, centerY, (j / segments) * this.get_width() - (this.get_width() / 2), (this.get_height() / 2), this.get_rotationAngle());
+ this.points[i].tu = (j % 2);
+ this.points[i].tv = 0;
+ this.points[i].color = this.get_color();
+ this.points[i + 1] = new PositionColoredTextured();
+ this.points[i + 1].position = this.makePosition(centerX, centerY, (j / segments) * this.get_width() - (this.get_width() / 2), ((this.get_height() / 2) - 12), this.get_rotationAngle());
+ this.points[i + 1].tu = (j % 2);
+ this.points[i + 1].tv = 1;
+ this.points[i + 1].color = this.get_color();
+ var k = (((segments + 1) * 4) + ((segmentsHigh + 1) * 2) - 2) - i;
+ this.points[k] = new PositionColoredTextured();
+ this.points[k].position = this.makePosition(centerX, centerY, (j / segments) * this.get_width() - (this.get_width() / 2), (-(this.get_height() / 2)) + 12, this.get_rotationAngle());
+ this.points[k].tu = (j % 2);
+ this.points[k].tv = 0;
+ this.points[k].color = this.get_color();
+ this.points[k + 1] = new PositionColoredTextured();
+ this.points[k + 1].position = this.makePosition(centerX, centerY, (j / segments) * this.get_width() - (this.get_width() / 2), (-(this.get_height() / 2)), this.get_rotationAngle());
+ this.points[k + 1].tu = (j % 2);
+ this.points[k + 1].tv = 1;
+ this.points[k + 1].color = this.get_color();
+ }
+ var offset = ((segments + 1) * 2);
+ for (var j = 0; j <= segmentsHigh; j++) {
+ var top = ((segmentsHigh + 1) * 2) + offset - 2;
+ var i = j * 2;
+ this.points[top - i] = new PositionColoredTextured();
+ this.points[top - i].position = this.makePosition(centerX, centerY, (this.get_width() / 2), ((j / segmentsHigh) * this.get_height() - (this.get_height() / 2)), this.get_rotationAngle());
+ this.points[top - i].tu = (j % 2);
+ this.points[top - i].tv = 0;
+ this.points[top - i].color = this.get_color();
+ this.points[top - i + 1] = new PositionColoredTextured();
+ this.points[top - i + 1].position = this.makePosition(centerX, centerY, ((this.get_width() / 2) - 12), ((j / segmentsHigh) * this.get_height() - (this.get_height() / 2)), this.get_rotationAngle());
+ this.points[top - i + 1].tu = (j % 2);
+ this.points[top - i + 1].tv = 1;
+ this.points[top - i + 1].color = this.get_color();
+ var k = i + ((segments + 1) * 4) + ((segmentsHigh + 1) * 2);
+ this.points[k] = new PositionColoredTextured();
+ this.points[k].position = this.makePosition(centerX, centerY, (-(this.get_width() / 2) + 12), ((j / segmentsHigh) * this.get_height() - (this.get_height() / 2)), this.get_rotationAngle());
+ this.points[k].tu = (j % 2);
+ this.points[k].tv = 0;
+ this.points[k].color = this.get_color();
+ this.points[k + 1] = new PositionColoredTextured();
+ this.points[k + 1].position = this.makePosition(centerX, centerY, (-(this.get_width() / 2)), ((j / segmentsHigh) * this.get_height() - (this.get_height() / 2)), this.get_rotationAngle());
+ this.points[k + 1].tu = (j % 2);
+ this.points[k + 1].tv = 1;
+ this.points[k + 1].color = this.get_color();
+ }
+ },
+ _createStarGeometry$1: function () {
+ var centerX = this.get_x();
+ var centerY = this.get_y();
+ var radius = this.get_width() / 2;
+ var radiansPerSegment = (Math.PI * 2) / 5;
+ if (this.points == null) {
+ this.points = new Array(12);
+ }
+ if (this._pnts$1 == null) {
+ this._pnts$1 = new Array(10);
+ }
+ for (var i = 0; i < 5; i++) {
+ var rads = i * radiansPerSegment - (Math.PI / 2);
+ this._pnts$1[i] = new PositionColoredTextured();
+ this._pnts$1[i].position = this.makePosition(centerX, centerY, (Math.cos(rads) * (this.get_width() / 2)), (Math.sin(rads) * (this.get_height() / 2)), this.get_rotationAngle());
+ this._pnts$1[i].tu = 0;
+ this._pnts$1[i].tv = 0;
+ this._pnts$1[i].color = this.get_color();
+ }
+ for (var i = 5; i < 10; i++) {
+ var rads = i * radiansPerSegment + (radiansPerSegment / 2) - (Math.PI / 2);
+ this._pnts$1[i] = new PositionColoredTextured();
+ this._pnts$1[i].position = this.makePosition(centerX, centerY, (Math.cos(rads) * (this.get_width() / 5.3)), (Math.sin(rads) * (this.get_height() / 5.3)), this.get_rotationAngle());
+ this._pnts$1[i].tu = 0;
+ this._pnts$1[i].tv = 0;
+ this._pnts$1[i].color = this.get_color();
+ }
+ this.points[0] = this._pnts$1[0];
+ this.points[1] = this._pnts$1[5];
+ this.points[2] = this._pnts$1[9];
+ this.points[3] = this._pnts$1[1];
+ this.points[4] = this._pnts$1[7];
+ this.points[5] = this._pnts$1[4];
+ this.points[6] = this._pnts$1[6];
+ this.points[7] = this._pnts$1[2];
+ this.points[8] = this._pnts$1[7];
+ this.points[9] = this._pnts$1[7];
+ this.points[10] = this._pnts$1[3];
+ this.points[11] = this._pnts$1[8];
+ this._triangleStrip$1 = false;
+ },
+ _createArrowGeometry$1: function () {
+ if (this.points == null) {
+ this.points = new Array(9);
+ }
+ this.points[0] = new PositionColoredTextured();
+ this.points[0].position = this.makePosition(this.get_x(), this.get_y(), -this.get_width() / 2, -this.get_height() / 4, this.get_rotationAngle());
+ this.points[0].tu = 0;
+ this.points[0].tv = 0;
+ this.points[0].color = this.get_color();
+ this.points[1] = new PositionColoredTextured();
+ this.points[1].position = this.makePosition(this.get_x(), this.get_y(), this.get_width() / 4, -this.get_height() / 4, this.get_rotationAngle());
+ this.points[1].tu = 1;
+ this.points[1].tv = 0;
+ this.points[1].color = this.get_color();
+ this.points[2] = new PositionColoredTextured();
+ this.points[2].position = this.makePosition(this.get_x(), this.get_y(), -this.get_width() / 2, this.get_height() / 4, this.get_rotationAngle());
+ this.points[2].tu = 0;
+ this.points[2].tv = 1;
+ this.points[2].color = this.get_color();
+ this.points[3] = new PositionColoredTextured();
+ this.points[3].position = this.makePosition(this.get_x(), this.get_y(), this.get_width() / 4, -this.get_height() / 4, this.get_rotationAngle());
+ this.points[3].tu = 1;
+ this.points[3].tv = 0;
+ this.points[3].color = this.get_color();
+ this.points[4] = new PositionColoredTextured();
+ this.points[4].position = this.makePosition(this.get_x(), this.get_y(), -this.get_width() / 2, this.get_height() / 4, this.get_rotationAngle());
+ this.points[4].tu = 0;
+ this.points[4].tv = 1;
+ this.points[4].color = this.get_color();
+ this.points[5] = new PositionColoredTextured();
+ this.points[5].position = this.makePosition(this.get_x(), this.get_y(), this.get_width() / 4, this.get_height() / 4, this.get_rotationAngle());
+ this.points[5].tu = 1;
+ this.points[5].tv = 1;
+ this.points[5].color = this.get_color();
+ this.points[6] = new PositionColoredTextured();
+ this.points[6].position = this.makePosition(this.get_x(), this.get_y(), this.get_width() / 4, -this.get_height() / 2, this.get_rotationAngle());
+ this.points[6].tu = 1;
+ this.points[6].tv = 1;
+ this.points[6].color = this.get_color();
+ this.points[7] = new PositionColoredTextured();
+ this.points[7].position = this.makePosition(this.get_x(), this.get_y(), this.get_width() / 2, 0, this.get_rotationAngle());
+ this.points[7].tu = 1;
+ this.points[7].tv = 0.5;
+ this.points[7].color = this.get_color();
+ this.points[8] = new PositionColoredTextured();
+ this.points[8].position = this.makePosition(this.get_x(), this.get_y(), this.get_width() / 4, this.get_height() / 2, this.get_rotationAngle());
+ this.points[8].tu = 1;
+ this.points[8].tv = 1;
+ this.points[8].color = this.get_color();
+ this._triangleStrip$1 = false;
+ },
+ _createDonutGeometry$1: function () {
+ var centerX = this.get_x();
+ var centerY = this.get_y();
+ var radius = this.get_width() / 2;
+ var circumference = Math.PI * 2 * radius;
+ var segments = ss.truncate((circumference / 12)) + 1;
+ var radiansPerSegment = (Math.PI * 2) / segments;
+ if (this.points == null) {
+ this.points = new Array(segments * 2 + 2);
+ }
+ for (var j = 0; j <= segments; j++) {
+ var i = j * 2;
+ this.points[i] = new PositionColoredTextured();
+ this.points[i].position = this.makePosition(centerX, centerY, (Math.cos(j * radiansPerSegment) * (this.get_width() / 2)), (Math.sin(j * radiansPerSegment) * (this.get_height() / 2)), this.get_rotationAngle());
+ this.points[i].tu = (j % 2);
+ this.points[i].tv = 0;
+ this.points[i].color = this.get_color();
+ this.points[i + 1] = new PositionColoredTextured();
+ this.points[i + 1].position = this.makePosition(centerX, centerY, (Math.cos(j * radiansPerSegment) * ((this.get_width() / 2) - 10)), (Math.sin(j * radiansPerSegment) * ((this.get_height() / 2) - 10)), this.get_rotationAngle());
+ this.points[i + 1].tu = (j % 2);
+ this.points[i + 1].tv = 1;
+ this.points[i + 1].color = this.get_color();
+ }
+ },
+ _createCircleGeometry$1: function () {
+ var centerX = this.get_x();
+ var centerY = this.get_y();
+ var radius = this.get_width() / 2;
+ var circumference = Math.PI * 2 * radius;
+ var segments = ss.truncate((circumference / 12)) + 1;
+ var radiansPerSegment = (Math.PI * 2) / segments;
+ if (this.points == null) {
+ this.points = new Array(segments * 2 + 2);
+ }
+ for (var j = 0; j <= segments; j++) {
+ var i = j * 2;
+ this.points[i] = new PositionColoredTextured();
+ this.points[i].position = this.makePosition(centerX, centerY, (Math.cos(j * radiansPerSegment) * (this.get_width() / 2)), (Math.sin(j * radiansPerSegment) * (this.get_height() / 2)), this.get_rotationAngle());
+ this.points[i].tu = (j % 2);
+ this.points[i].tv = 0;
+ this.points[i].color = this.get_color();
+ this.points[i + 1] = new PositionColoredTextured();
+ this.points[i + 1].position = this.makePosition(centerX, centerY, 0, 0, this.get_rotationAngle());
+ this.points[i + 1].tu = (j % 2);
+ this.points[i + 1].tv = 1;
+ this.points[i + 1].color = this.get_color();
+ }
+ },
+
+ initializeTexture: function () {
+ switch (this.get_shapeType()) {
+ case 5:
+ case 3:
+ case 6:
+ break;
+ case 0:
+ case 1:
+ case 2:
+ case 4:
+ default:
+ this.texture = null;
+ break;
+ }
+ },
+
+ //todo this needs to be Dashed rounded lines..
+ _drawLineGeometry$1: function (renderContext) {
+ var ctx = renderContext.device;
+ ctx.save();
+ var radius = this.get_width() / 2;
+ ctx.translate(this.get_x(), this.get_y());
+ ctx.rotate(this.get_rotationAngle() * Overlay.RC);
+ ctx.moveTo(-radius, 0);
+ ctx.lineTo(radius, 0);
+ ctx.lineWidth = 9;
+ ctx.strokeStyle = this.get_color().toString();
+ ctx.globalAlpha = this.get_opacity();
+ ctx.stroke();
+ ctx.restore();
+ },
+
+ _drawOpenRectGeometry$1: function (renderContext) {
+ var ctx = renderContext.device;
+ ctx.save();
+ ctx.translate(this.get_x(), this.get_y());
+ ctx.rotate(this.get_rotationAngle() * Overlay.RC);
+ ctx.beginPath();
+ ctx.moveTo(-this.get_width() / 2, -this.get_height() / 2);
+ ctx.lineTo(this.get_width() / 2, -this.get_height() / 2);
+ ctx.lineTo(this.get_width() / 2, this.get_height() / 2);
+ ctx.lineTo(-this.get_width() / 2, this.get_height() / 2);
+ ctx.closePath();
+ ctx.lineWidth = 9;
+ ctx.strokeStyle = this.get_color().toString();
+ ctx.globalAlpha = this.get_opacity();
+ ctx.stroke();
+ ctx.restore();
+ },
+
+ _drawRectGeometry$1: function (renderContext) {
+ var ctx = renderContext.device;
+ ctx.save();
+ ctx.translate(this.get_x(), this.get_y());
+ ctx.rotate(this.get_rotationAngle() * Overlay.RC);
+ ctx.beginPath();
+ ctx.moveTo(-this.get_width() / 2, -this.get_height() / 2);
+ ctx.lineTo(this.get_width() / 2, -this.get_height() / 2);
+ ctx.lineTo(this.get_width() / 2, this.get_height() / 2);
+ ctx.lineTo(-this.get_width() / 2, this.get_height() / 2);
+ ctx.closePath();
+ ctx.lineWidth = 0;
+ ctx.fillStyle = this.get_color().toString();
+ ctx.globalAlpha = this.get_opacity();
+ ctx.fill();
+ ctx.restore();
+ },
+
+ _drawStarGeometry$1: function (renderContext) {
+ var ctx = renderContext.device;
+ ctx.save();
+ ctx.translate(this.get_x(), this.get_y());
+ ctx.rotate(this.get_rotationAngle() * Overlay.RC);
+ ctx.beginPath();
+ var centerX = 0;
+ var centerY = 0;
+ var radius = this.get_width() / 2;
+ var radiansPerSegment = (Math.PI * 2) / 5;
+ var first = true;
+ for (var i = 0; i < 5; i++) {
+ var rads = i * radiansPerSegment - (Math.PI / 2);
+ if (first) {
+ first = false;
+ ctx.moveTo(centerX + Math.cos(rads) * (this.get_width() / 2), centerY + Math.sin(rads) * (this.get_height() / 2));
+ }
+ else {
+ ctx.lineTo(centerX + Math.cos(rads) * (this.get_width() / 2), centerY + Math.sin(rads) * (this.get_height() / 2));
+ }
+ var rads2 = i * radiansPerSegment + (radiansPerSegment / 2) - (Math.PI / 2);
+ ctx.lineTo(centerX + Math.cos(rads2) * (this.get_width() / 5.3), centerY + Math.sin(rads2) * (this.get_height() / 5.3));
+ }
+ ctx.closePath();
+ ctx.lineWidth = 0;
+ ctx.fillStyle = this.get_color().toString();
+ ctx.globalAlpha = this.get_opacity();
+ ctx.fill();
+ ctx.restore();
+ },
+
+ _drawArrowGeometry$1: function (renderContext) {
+ var ctx = renderContext.device;
+ ctx.save();
+ ctx.translate(this.get_x(), this.get_y());
+ ctx.rotate(this.get_rotationAngle() * Overlay.RC);
+ ctx.beginPath();
+ ctx.moveTo((-(this.get_width() / 2)), (-(this.get_height() / 4)));
+ ctx.lineTo((this.get_width() / 4), (-(this.get_height() / 4)));
+ ctx.lineTo((this.get_width() / 4), (-(this.get_height() / 2)));
+ ctx.lineTo((this.get_width() / 2), 0);
+ ctx.lineTo((this.get_width() / 4), (this.get_height() / 2));
+ ctx.lineTo((this.get_width() / 4), (this.get_height() / 4));
+ ctx.lineTo((-(this.get_width() / 2)), (this.get_height() / 4));
+ ctx.closePath();
+ ctx.lineWidth = 0;
+ ctx.fillStyle = this.get_color().toString();
+ ctx.globalAlpha = this.get_opacity();
+ ctx.fill();
+ ctx.restore();
+ },
+
+ //todo move to dashed lines in future
+ _drawDonutGeometry$1: function (renderContext) {
+ var ctx = renderContext.device;
+ ctx.save();
+ ctx.translate(this.get_x(), this.get_y());
+ ctx.scale(1, this.get_height() / this.get_width());
+ ctx.rotate(this.get_rotationAngle() * Overlay.RC);
+ ctx.beginPath();
+ ctx.arc(0, 0, this.get_width() / 2, 0, Math.PI * 2, false);
+ ctx.closePath();
+ ctx.lineWidth = 9;
+ ctx.strokeStyle = this.get_color().toString();
+ ctx.globalAlpha = this.get_opacity();
+ ctx.stroke();
+ ctx.restore();
+ },
+
+ _drawCircleGeometry$1: function (renderContext) {
+ var ctx = renderContext.device;
+ ctx.save();
+ ctx.scale(1, this.get_width() / this.get_height());
+ ctx.translate(this.get_x(), this.get_y());
+ ctx.rotate(this.get_rotationAngle() * Overlay.RC);
+ ctx.beginPath();
+ ctx.arc(0, 0, this.get_width(), 0, Math.PI * 2, false);
+ ctx.closePath();
+ ctx.lineWidth = 0;
+ ctx.fillStyle = this.get_color().toString();
+ ctx.globalAlpha = this.get_opacity();
+ ctx.fill();
+ ctx.restore();
+ },
+
+ cleanUpGeometry: function () {
+ Overlay.prototype.cleanUpGeometry.call(this);
+ this.cleanUp();
+ },
+
+ writeOverlayProperties: function (xmlWriter) {
+ xmlWriter._writeStartElement('Shape');
+ xmlWriter._writeAttributeString('ShapeType', Enums.toXml('ShapeType', this._shapeType$1));
+ xmlWriter._writeEndElement();
+ },
+
+ initializeFromXml: function (node) {
+ var shape = Util.selectSingleNode(node, 'Shape');
+ this._shapeType$1 = Enums.parse('ShapeType', shape.attributes.getNamedItem('ShapeType').nodeValue);
+ }
+};
+
+registerType("ShapeOverlay", [ShapeOverlay, ShapeOverlay$, Overlay]);
+
+// wwtlib.AudioOverlay
+
+export function AudioOverlay() {
+ this._audio$1 = null;
+ this._audioReady$1 = false;
+ this._wantPlaying$1 = false;
+ this._volume$1 = 100;
+ this._mute$1 = false;
+ this._position$1 = 0;
+ this._trackType$1 = 0;
+ Overlay.call(this);
+ this.isDesignTimeOnly = true;
+}
+
+AudioOverlay.create = function (currentTourStop, file) {
+ var ao = new AudioOverlay();
+ ao.set_owner(currentTourStop);
+ ao._filename$1 = file.name;
+ ao.get_owner().get_owner().addCachedFile(file.name, file);
+ return ao;
+};
+
+var AudioOverlay$ = {
+ getTypeName: function () {
+ return 'TerraViewer.AudioOverlay';
+ },
+
+ get_mute: function () {
+ return this._mute$1;
+ },
+
+ set_mute: function (value) {
+ this._mute$1 = value;
+ this.set_volume(this.get_volume());
+ return value;
+ },
+
+ get_volume: function () {
+ return this._volume$1;
+ },
+
+ set_volume: function (value) {
+ this._volume$1 = value;
+ if (this._audio$1 != null) {
+ this._audio$1.volume = (this._mute$1) ? 0 : (this._volume$1 / 100);
+ }
+ return value;
+ },
+
+ addFilesToCabinet: function (fc) {
+ fc.addFile(this.get_owner().get_owner().get_workingDirectory() + this._filename$1, this.get_owner().get_owner().getFileBlob(this._filename$1));
+ },
+
+ play: function () {
+ if (this._audio$1 == null) {
+ this.prepMultimedia();
+ }
+ this._wantPlaying$1 = true;
+ if (this._audio$1 != null && this._audioReady$1) {
+ this._audio$1.play();
+ this.set_volume(this.get_volume());
+ this._audio$1.currentTime = this._position$1;
+ }
+ },
+
+ pause: function () {
+ if (this._audio$1 == null) {
+ this.prepMultimedia();
+ }
+ this._wantPlaying$1 = false;
+ if (this._audio$1 != null && this._audioReady$1) {
+ this._audio$1.pause();
+ }
+ },
+
+ stop: function () {
+ this.pause(); // these operations are identical for audio
+ },
+
+ seek: function (time) {
+ this._position$1 = time;
+ if (this._audio$1 == null) {
+ this.prepMultimedia();
+ }
+ if (this._audioReady$1) {
+ if (this._audio$1.duration < time) {
+ this._audio$1.pause();
+ }
+ else {
+ this._audio$1.currentTime = this._position$1;
+ }
+ }
+ },
+
+ prepMultimedia: function () {
+ var $this = this;
+
+ if (this._audio$1 != null) {
+ return;
+ }
+ this._audio$1 = document.createElement('audio');
+ this._audio$1.addEventListener('canplaythrough', function () {
+ if (!$this._audioReady$1) {
+ $this._audioReady$1 = true;
+ if ($this._wantPlaying$1) {
+ $this.play();
+ }
+ }
+ }, false);
+
+ // As of December 2020, on Safari, we need to use a