Compare commits
77 Commits
Author | SHA1 | Date | |
---|---|---|---|
d90230ef14 | |||
26c6f75ae9 | |||
3705d78dcd | |||
7dc841fe5c | |||
|
61ed34899d | ||
c96941b048 | |||
c4c8f6164b | |||
0a60a82b8c | |||
|
88003a17bb | ||
65c5f500d1 | |||
|
977e5415fd | ||
655e010a53 | |||
479a3b72d4 | |||
bef2f6d129 | |||
88344a64c4 | |||
1e0690fed1 | |||
da34f0566d | |||
ec2500d72f | |||
07045a8450 | |||
1082a85ad5 | |||
f8cd3b4037 | |||
8e93703e2a | |||
17c20a9b69 | |||
0739e18714 | |||
71b43d1c9d | |||
8db03227fe | |||
4cca4351bc | |||
f43971e8be | |||
986a122333 | |||
377bdfe9e0 | |||
521bb6c4c6 | |||
6b1fca9109 | |||
286f931e59 | |||
7641cb50eb | |||
fa02c89674 | |||
7c7e15e1b2 | |||
617eef2f5f | |||
cec861cd7c | |||
69e1ff73b0 | |||
df0593ee38 | |||
f192cc7b52 | |||
10f9e32678 | |||
1f3d864249 | |||
1d0d64d314 | |||
de28446c0d | |||
968f6f411b | |||
3fda36ecbc | |||
98bd2cafe9 | |||
26bbf9c6c5 | |||
28bf1c585b | |||
438584f4b9 | |||
e388eb6626 | |||
84162714fe | |||
680b4b5d82 | |||
9f9c8e63ef | |||
c4a23751c1 | |||
f65b81b369 | |||
36a6b86a5b | |||
b1832da477 | |||
a2b3f2c5da | |||
d0a4430d0e | |||
82d51c5dc1 | |||
123411eca6 | |||
22c37456e9 | |||
f4efe2ab66 | |||
b214aaecee | |||
3542b87156 | |||
4f628a5a01 | |||
137edb6011 | |||
18f80904b3 | |||
a1b669cd68 | |||
51689abb64 | |||
7924214b66 | |||
fbefdd156f | |||
c4dbea12b3 | |||
7be6245ed3 | |||
1d74703504 |
106
.github/workflows/dotnetcore.yml
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
name: Build, Test, Publish and Dockerise Lora-Map
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build, pack and release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout parent project with dependencys
|
||||
uses: actions/checkout@v1
|
||||
with:
|
||||
repository: MONICA-Project/map-project
|
||||
ref: refs/heads/master
|
||||
submodules: true
|
||||
|
||||
- name: Checkout last versions
|
||||
run: git -C Lora-Map checkout --progress --force ${{ github.sha }}
|
||||
working-directory: ../map-project
|
||||
|
||||
- name: Install dotnet
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '3.1.x'
|
||||
|
||||
- name: Build with dotnet
|
||||
run: dotnet build Lora-Map.sln --configuration Release
|
||||
working-directory: ../map-project/Lora-Map
|
||||
|
||||
- name: Create deb files
|
||||
if: success()
|
||||
run: |
|
||||
mkdir ../../../Builds
|
||||
chmod oug+x make-deb.sh
|
||||
./make-deb.sh amd64
|
||||
./make-deb.sh armhf
|
||||
id: create_deb
|
||||
working-directory: ../map-project/Lora-Map/Lora-Map/dpkg
|
||||
|
||||
- name: Create release
|
||||
if: success()
|
||||
id: nightly_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ steps.create_deb.outputs.builddaterelease }}
|
||||
release_name: Nightly from ${{ steps.create_deb.outputs.builddaterelease }}
|
||||
body: This is a nightly release. It may be not working properly.
|
||||
draft: false
|
||||
prerelease: true
|
||||
|
||||
- name: Upload release asset amd64
|
||||
if: success()
|
||||
id: upload-release-asset-amd64
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.nightly_release.outputs.upload_url }}
|
||||
asset_path: ../map-project/Builds/amd64-${{ steps.create_deb.outputs.debuilderfile }}
|
||||
asset_name: amd64-${{ steps.create_deb.outputs.debuilderfile }}
|
||||
asset_content_type: application/x-deb
|
||||
|
||||
- name: Upload release asset armhf
|
||||
if: success()
|
||||
id: upload-release-asset-armhf
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.nightly_release.outputs.upload_url }}
|
||||
asset_path: ../map-project/Builds/armhf-${{ steps.create_deb.outputs.debuilderfile }}
|
||||
asset_name: armhf-${{ steps.create_deb.outputs.debuilderfile }}
|
||||
asset_content_type: application/x-deb
|
||||
|
||||
docker:
|
||||
name: Build and push dockerfile
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout parent project with dependencys
|
||||
uses: actions/checkout@v1
|
||||
with:
|
||||
repository: MONICA-Project/map-project
|
||||
ref: refs/heads/master
|
||||
submodules: true
|
||||
|
||||
- name: Checkout last versions
|
||||
run: git -C Lora-Map checkout --progress --force ${{ github.sha }}
|
||||
working-directory: ../map-project
|
||||
|
||||
- name: Docker build
|
||||
id: docker_build
|
||||
run: |
|
||||
DOCKERTAG=$(date +%Y%m%d%H%M%S)
|
||||
echo "##[set-output name=dockertag;]$DOCKERTAG"
|
||||
docker build . -t monicaproject/lora-map:latest -t monicaproject/lora-map:$DOCKERTAG
|
||||
working-directory: ../map-project
|
||||
|
||||
- name: Docker-compose publish
|
||||
if: success()
|
||||
run: |
|
||||
echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin ${INPUT_REGISTRY}
|
||||
docker push monicaproject/lora-map:latest
|
||||
docker push monicaproject/lora-map:${{ steps.docker_build.outputs.dockertag }}
|
||||
working-directory: ../map-project
|
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
/.vs
|
||||
/Lora-Map/obj
|
||||
/Lora-Map/bin
|
||||
/Doku/.vs
|
||||
|
14
CHANGELOG
@ -1,14 +0,0 @@
|
||||
1.1.1 Add Debian package config
|
||||
1.1.2 #2 Show versions number in Site
|
||||
1.1.3 #1 Click on icon and show details
|
||||
1.1.4 #3 Create icons for devices
|
||||
1.1.5 Add support for alert button
|
||||
1.1.6 #5 Create admin area
|
||||
1.1.7 #8 Editor for Names
|
||||
1.2.0 #4 Possible to Ex and Import Setting
|
||||
1.2.1 #6 Load the map from the Device
|
||||
1.2.2 Bugfix, if only recieve panic packet with gps data, update the marker on the map also
|
||||
1.2.3 #9 display polygons and marker on the map
|
||||
1.2.4 Can draw Textmarkers on the Map, use MGRS (UTM) on the Map
|
||||
1.2.5 #10 text Letzer Datenempfang is too long when scrollbar is there and #11 set textsize for every zoomlevel
|
||||
1.2.6 New Types of marker for person
|
166
CHANGELOG.md
Normal file
@ -0,0 +1,166 @@
|
||||
# Changelogs
|
||||
|
||||
## 1.3.0 - New Gateway
|
||||
### New Features
|
||||
* Implement Lora-Gateway-Data 1.1.0 Format
|
||||
### Bugfixes
|
||||
### Changes
|
||||
* Refactoring
|
||||
* Make requests.conf not needed anymore.
|
||||
|
||||
## 1.2.10
|
||||
### New Features
|
||||
* Posibility to display sensor data on map
|
||||
### Bugfixes
|
||||
* Parse also all Doublevalues as Int
|
||||
### Changes
|
||||
* Change Online Map MaxZoom to 19
|
||||
* Searchfunction case insensitive
|
||||
* Show Numbers from a Place not with linebreaking
|
||||
* Numbers on places are not clickable, also as the grid
|
||||
* Search in Description of Polygons
|
||||
* Change Sani to Rettungsdienst
|
||||
* Display GateCounting Boxes in a line not a collumn
|
||||
* Create Aliases for Camera Count
|
||||
* Filter Fight under level
|
||||
* Refactoring
|
||||
* Porting to .NET Core
|
||||
|
||||
## 1.2.9
|
||||
### New Features
|
||||
* Add setting model to code
|
||||
* #19 grid automatisch generieren
|
||||
* #24 Add information about weather/warning
|
||||
* #28 Fightdedection Plygon on Map
|
||||
* #27 Draw Camera-Desity bock on map
|
||||
* #16 filter nach kategorien/tracker einbauen
|
||||
* #15 suche nach ständen einbauen
|
||||
### Bugfixes
|
||||
* Add Correct Dispose Handling
|
||||
* TimeCalculation now handle negative values correct
|
||||
### Changes
|
||||
* Refactoring of all JS
|
||||
* Make only one request per second instead of four per AJAX
|
||||
* Refactoring adminpannel and add settings.json
|
||||
* New function in TimeCalculation, so you can not have negative Timespans
|
||||
|
||||
## 1.2.8
|
||||
### New Features
|
||||
* Implement #12 Make icon transparent if there is no data update
|
||||
* Implement #18 history an panikbutton pressed
|
||||
### Bugfixes
|
||||
* Implement #13 fixing issue with port when using proxy
|
||||
* Implement #14 show description on map in tooltip on area
|
||||
* Implement #25 Icons flickering when using ssl
|
||||
* Add some errorhandling with locks
|
||||
### Changes
|
||||
* Move CoordinateSharp to own Library
|
||||
* Changes to new Mqtt topic for camera density
|
||||
|
||||
## 1.2.7
|
||||
### New Features
|
||||
* Add support to display camera values that counts people. needs to be on a mqtt toipc camera/counting
|
||||
* Display Crowd-Density Data on Map
|
||||
### Bugfixes
|
||||
* Rename Adminmodel.cs to AdminModel.cs, cause it sould be Uppercase!
|
||||
* Fix a Parsing Bug in Lora-Map/Model/PositionItem.cs
|
||||
### Changes
|
||||
* Move the Dockerfile to the parent project Repository
|
||||
|
||||
## 1.2.6
|
||||
### New Features
|
||||
* New types of marker for a person, so you can add drawing inside
|
||||
|
||||
## 1.2.5
|
||||
### New Features
|
||||
* Implement #10 text Letzer Datenempfang is too long when scrollbar is there
|
||||
### Bugfixes
|
||||
* Implement #11 set textsize for every zoomlevel
|
||||
### Changes
|
||||
* Add an link to kml to geojson converter
|
||||
|
||||
## 1.2.4
|
||||
### New Features
|
||||
* Possible to draw textmarkers on map (eg. for static text in a polygon)
|
||||
* Now using MGRS as default output
|
||||
|
||||
## 1.2.3
|
||||
### New Features
|
||||
* Implement #9 display polygons and marker on the map
|
||||
### Bugfixes
|
||||
* change the wort get to post
|
||||
### Changes
|
||||
* Default zoomlevel is now 16
|
||||
|
||||
## 1.2.2
|
||||
### Bugfixes
|
||||
* When only recieve a panic packet with gps data, update also the normal location on the map
|
||||
|
||||
## 1.2.1
|
||||
### New Features
|
||||
* Implement #6 Load the map from the Device
|
||||
### Bugfixes
|
||||
* Show now output 200 of images from Webserver
|
||||
### Changes
|
||||
* Now layers.png is also exported
|
||||
|
||||
## 1.2.0
|
||||
### New Features
|
||||
* Implement #4 Possible to Ex and Import Settings
|
||||
### Bugfixes
|
||||
* Move username and password to configfile
|
||||
### Changes
|
||||
* Verifiy names.json when sending
|
||||
* Add logger to Programm
|
||||
|
||||
## 1.1.7
|
||||
### New Features
|
||||
* Implement #8 Editor for Names and Icons
|
||||
### Bugfixes
|
||||
* Fixing missing dependencys of Mono.System.Web in deb packet
|
||||
* Fixing a Bug when map is not running on port 8080
|
||||
### Changes
|
||||
* New Batterylevels
|
||||
* Change textcolors in Marker.svg
|
||||
|
||||
## 1.1.6
|
||||
### New Features
|
||||
* new Levels for Battery, so that is ~ 1/5 of time for each Icon
|
||||
* #5 Create adminpannel
|
||||
|
||||
## 1.1.5
|
||||
### New Features
|
||||
* Shows a red border on the marker on the map, when the panicbutton is pressed
|
||||
* Icons are now created by a script from the SVG directly, so all big marker icons are SVGs
|
||||
* Icons are also now shown in the marker list
|
||||
* Using Leaflet 1.4.0 now
|
||||
* Menu with new markers
|
||||
### Bugfixes
|
||||
* Times are now complete in UTC internaly and will calculated in the browser to local time.
|
||||
### Changes
|
||||
* requests.conf must now have a section `js/map.js` instead of `js/nav.js`
|
||||
* names.json format has changed
|
||||
|
||||
## 1.1.4
|
||||
### New Features
|
||||
* Implement #3 Create icons for devices
|
||||
|
||||
## 1.1.3
|
||||
### New Features
|
||||
* Implement #1 Click on icon and show details
|
||||
|
||||
## 1.1.2
|
||||
### New Features
|
||||
* Implement #2 Show versions number in Site
|
||||
|
||||
## 1.1.1
|
||||
### New Features
|
||||
* Add Debian package config
|
||||
|
||||
## 1.1.0.0
|
||||
### New Features
|
||||
* Change to new JSON format, and make it usable for more than one listener
|
||||
|
||||
## 1.0.0.0
|
||||
### New Features
|
||||
* First Version, only used as a testoutput for debugging tracker
|
BIN
Lora-Map.jpg
Normal file
After Width: | Height: | Size: 17 KiB |
97
Lora-Map.sln
@ -1,23 +1,34 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27703.2026
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29519.87
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mora-Map", "Lora-Map\Lora-Map.csproj", "{95D6F48A-9488-42A6-A973-941B45B26DB8}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lora-Map_Core", "Lora-Map\Lora-Map.csproj", "{78136B15-FF0B-4DCE-94CA-1D6148DEA232}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utils-IoT", "..\Utils\Utils-IoT\Utils-IoT\Utils-IoT.csproj", "{B870E4D5-6806-4A0B-B233-8907EEDC5AFC}"
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7DD32F31-ACB0-4F5E-B3D8-78564A83ACEF}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
..\.dockerignore = ..\.dockerignore
|
||||
..\CONTRIBUTING.md = ..\CONTRIBUTING.md
|
||||
..\docker-compose.yml = ..\docker-compose.yml
|
||||
..\Dockerfile = ..\Dockerfile
|
||||
..\LICENSE = ..\LICENSE
|
||||
..\README.md = ..\README.md
|
||||
..\update.sh = ..\update.sh
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConnectorDataMqtt", "..\Utils\ConnectorDataMqtt\ConnectorDataMqtt\ConnectorDataMqtt.csproj", "{EE6C8F68-ED46-4C1C-ABDD-CFCDF75104F2}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bot-Utils", "..\Utils\Bot-Utils\Bot-Utils\Bot-Utils.csproj", "{ED37370F-AE65-498D-A425-413FEE69C0A8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "litjson_4.7.1", "..\Librarys\litjson\litjson\litjson_4.7.1.csproj", "{91A14CD2-2940-4500-8193-56D37EDDDBAA}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utils", "..\Utils\Utils\Utils\Utils.csproj", "{E8268FE5-D6F0-4805-9BDE-9DBC9CB517FF}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "M2Mqtt_4.7.1", "..\Librarys\mqtt\M2Mqtt\M2Mqtt_4.7.1.csproj", "{A11AEF5A-B246-4FE8-8330-06DB73CC8074}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utils-IoT", "..\Utils\Utils-IoT\Utils-IoT\Utils-IoT.csproj", "{04CF6328-3976-44D3-9959-A3B1A2C5C45A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bot-Utils", "..\Utils\Bot-Utils\Bot-Utils\Bot-Utils.csproj", "{BB7BFCB5-3DB0-49E1-802A-3CE3EECC59F9}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConnectorDataMqtt", "..\Utils\ConnectorDataMqtt\ConnectorDataMqtt\ConnectorDataMqtt.csproj", "{E40D29CB-B499-4FA6-AEA1-18E8CEAA911B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utils", "..\Utils\Utils\Utils\Utils.csproj", "{FAC8CE64-BF13-4ECE-8097-AEB5DD060098}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "litjson", "..\Librarys\litjson\litjson\litjson.csproj", "{FFC66B7F-B4FB-4E42-B896-2C6772D899AA}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Posix", "..\Librarys\Mono.Posix\Mono.Posix\Mono.Posix.csproj", "{E2CA132E-E85C-40AD-BE94-B138AA68772B}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "M2Mqtt", "..\Librarys\mqtt\M2Mqtt\M2Mqtt.csproj", "{00C678EE-6BAA-4FCB-AAA5-7755E65C6CC5}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoordinateSharp", "..\Librarys\Coordinates\CoordinateSharp\CoordinateSharp.csproj", "{D9D4C842-5818-4E96-9BFE-7ADFB4D811BA}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@ -25,43 +36,43 @@ Global
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{95D6F48A-9488-42A6-A973-941B45B26DB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{95D6F48A-9488-42A6-A973-941B45B26DB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{95D6F48A-9488-42A6-A973-941B45B26DB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{95D6F48A-9488-42A6-A973-941B45B26DB8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B870E4D5-6806-4A0B-B233-8907EEDC5AFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B870E4D5-6806-4A0B-B233-8907EEDC5AFC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B870E4D5-6806-4A0B-B233-8907EEDC5AFC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B870E4D5-6806-4A0B-B233-8907EEDC5AFC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EE6C8F68-ED46-4C1C-ABDD-CFCDF75104F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EE6C8F68-ED46-4C1C-ABDD-CFCDF75104F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EE6C8F68-ED46-4C1C-ABDD-CFCDF75104F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EE6C8F68-ED46-4C1C-ABDD-CFCDF75104F2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{91A14CD2-2940-4500-8193-56D37EDDDBAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{91A14CD2-2940-4500-8193-56D37EDDDBAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{91A14CD2-2940-4500-8193-56D37EDDDBAA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{91A14CD2-2940-4500-8193-56D37EDDDBAA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A11AEF5A-B246-4FE8-8330-06DB73CC8074}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A11AEF5A-B246-4FE8-8330-06DB73CC8074}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A11AEF5A-B246-4FE8-8330-06DB73CC8074}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A11AEF5A-B246-4FE8-8330-06DB73CC8074}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BB7BFCB5-3DB0-49E1-802A-3CE3EECC59F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BB7BFCB5-3DB0-49E1-802A-3CE3EECC59F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BB7BFCB5-3DB0-49E1-802A-3CE3EECC59F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BB7BFCB5-3DB0-49E1-802A-3CE3EECC59F9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FAC8CE64-BF13-4ECE-8097-AEB5DD060098}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FAC8CE64-BF13-4ECE-8097-AEB5DD060098}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FAC8CE64-BF13-4ECE-8097-AEB5DD060098}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FAC8CE64-BF13-4ECE-8097-AEB5DD060098}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E2CA132E-E85C-40AD-BE94-B138AA68772B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E2CA132E-E85C-40AD-BE94-B138AA68772B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E2CA132E-E85C-40AD-BE94-B138AA68772B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E2CA132E-E85C-40AD-BE94-B138AA68772B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{78136B15-FF0B-4DCE-94CA-1D6148DEA232}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{78136B15-FF0B-4DCE-94CA-1D6148DEA232}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{78136B15-FF0B-4DCE-94CA-1D6148DEA232}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{78136B15-FF0B-4DCE-94CA-1D6148DEA232}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ED37370F-AE65-498D-A425-413FEE69C0A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ED37370F-AE65-498D-A425-413FEE69C0A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ED37370F-AE65-498D-A425-413FEE69C0A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ED37370F-AE65-498D-A425-413FEE69C0A8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E8268FE5-D6F0-4805-9BDE-9DBC9CB517FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E8268FE5-D6F0-4805-9BDE-9DBC9CB517FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E8268FE5-D6F0-4805-9BDE-9DBC9CB517FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E8268FE5-D6F0-4805-9BDE-9DBC9CB517FF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{04CF6328-3976-44D3-9959-A3B1A2C5C45A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{04CF6328-3976-44D3-9959-A3B1A2C5C45A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{04CF6328-3976-44D3-9959-A3B1A2C5C45A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{04CF6328-3976-44D3-9959-A3B1A2C5C45A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E40D29CB-B499-4FA6-AEA1-18E8CEAA911B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E40D29CB-B499-4FA6-AEA1-18E8CEAA911B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E40D29CB-B499-4FA6-AEA1-18E8CEAA911B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E40D29CB-B499-4FA6-AEA1-18E8CEAA911B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FFC66B7F-B4FB-4E42-B896-2C6772D899AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FFC66B7F-B4FB-4E42-B896-2C6772D899AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FFC66B7F-B4FB-4E42-B896-2C6772D899AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FFC66B7F-B4FB-4E42-B896-2C6772D899AA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{00C678EE-6BAA-4FCB-AAA5-7755E65C6CC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{00C678EE-6BAA-4FCB-AAA5-7755E65C6CC5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{00C678EE-6BAA-4FCB-AAA5-7755E65C6CC5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{00C678EE-6BAA-4FCB-AAA5-7755E65C6CC5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D9D4C842-5818-4E96-9BFE-7ADFB4D811BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D9D4C842-5818-4E96-9BFE-7ADFB4D811BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D9D4C842-5818-4E96-9BFE-7ADFB4D811BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D9D4C842-5818-4E96-9BFE-7ADFB4D811BA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {1534B636-9FC8-49BB-BB14-FC403ECDF889}
|
||||
SolutionGuid = {7B1C516B-2EDC-4F6A-A1A5-A9BCA14C8603}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
@ -4,73 +4,8 @@
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||
<security>
|
||||
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<!-- UAC-Manifestoptionen
|
||||
Wenn Sie die Ebene der Benutzerkontensteuerung für Windows ändern möchten, ersetzen Sie den
|
||||
Knoten "requestedExecutionLevel" wie folgt.
|
||||
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
|
||||
|
||||
Durch Angabe des Elements "requestedExecutionLevel" wird die Datei- und Registrierungsvirtualisierung deaktiviert.
|
||||
Entfernen Sie dieses Element, wenn diese Virtualisierung aus Gründen der Abwärtskompatibilität
|
||||
für die Anwendung erforderlich ist.
|
||||
-->
|
||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- Eine Liste der Windows-Versionen, unter denen diese Anwendung getestet
|
||||
und für die sie entwickelt wurde. Wenn Sie die Auskommentierung der entsprechenden Elemente aufheben,
|
||||
wird von Windows automatisch die kompatibelste Umgebung ausgewählt. -->
|
||||
|
||||
<!-- Windows Vista -->
|
||||
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
|
||||
|
||||
<!-- Windows 7 -->
|
||||
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />-->
|
||||
|
||||
<!-- Windows 8 -->
|
||||
<!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />-->
|
||||
|
||||
<!-- Windows 8.1 -->
|
||||
<!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->
|
||||
|
||||
<!-- Windows 10 -->
|
||||
<!--<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />-->
|
||||
|
||||
</application>
|
||||
</compatibility>
|
||||
|
||||
<!-- Gibt an, dass die Anwendung mit DPI-Werten kompatibel ist und von Windows nicht automatisch auf höhere
|
||||
DPI-Werte skaliert wird. WPF-Anwendungen (Windows Presentation Foundation) sind automatisch mit DPI-Werten kompatibel und müssen sich nicht
|
||||
anmelden. Für Windows Forms-Anwendungen für .NET Framework 4.6, die sich für diese Einstellung anmelden, muss
|
||||
auch die Einstellung "'EnableWindowsFormsHighDpiAutoResizing" in der "app.config" auf "true" festgelegt werden. -->
|
||||
<!--
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
-->
|
||||
|
||||
<!-- Designs für allgemeine Windows-Steuerelemente und -Dialogfelder (Windows XP und höher) aktivieren -->
|
||||
<!--
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="Microsoft.Windows.Common-Controls"
|
||||
version="6.0.0.0"
|
||||
processorArchitecture="*"
|
||||
publicKeyToken="6595b64144ccf1df"
|
||||
language="*"
|
||||
/>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
</assembly>
|
||||
|
@ -1,412 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
//CURRENT ALTITUDE IS SET CONSTANT AT 100M. POSSIBLY NEED TO ADJUST TO ALLOW USER PASS.
|
||||
//Altitude adjustments appear to have minimal effect on eclipse timing. These were mainly used
|
||||
//to signify eclipses that had already started during rise and set times on the NASA calculator
|
||||
|
||||
//SOME TIMES AND ALTS WERE RETURNED WITH COLOR AND STYLING. DETERMINE WHY AND ADJUST VALUE AS REQUIRED. SEARCH "WAS ITALIC".
|
||||
|
||||
//ELLIPSOID ADJUSTMENT
|
||||
//6378140.0 Ellipsoid is used in the NASA Calculator
|
||||
//WGS84 Ellipsoid is 6378137.0. Adjustments to the ellipsoid appear to effect eclipse seconds in fractions.
|
||||
//This can be modified if need to allow users to pass custom number with the Coordinate SetDatum() functions.
|
||||
|
||||
//CURRENT RANGE 1601-2600.
|
||||
internal class LunarEclipseCalc
|
||||
{
|
||||
public static List<List<string>> CalculateLunarEclipse(DateTime d, double latRad, double longRad)
|
||||
{
|
||||
return Calculate(d, latRad, longRad);
|
||||
}
|
||||
public static List<LunarEclipseDetails> CalculateLunarEclipse(DateTime d, double latRad, double longRad, double[] events)
|
||||
{
|
||||
List<List<string>> evs = Calculate(d, latRad, longRad, events);
|
||||
List<LunarEclipseDetails> deetsList = new List<LunarEclipseDetails>();
|
||||
foreach (List<string> ls in evs)
|
||||
{
|
||||
LunarEclipseDetails deets = new LunarEclipseDetails(ls);
|
||||
deetsList.Add(deets);
|
||||
}
|
||||
return deetsList;
|
||||
}
|
||||
public static List<List<string>> CalculateLunarEclipse(DateTime d, Coordinate coord)
|
||||
{
|
||||
return Calculate(d, coord.Latitude.ToRadians(), coord.Longitude.ToRadians());
|
||||
}
|
||||
|
||||
|
||||
// CALCULATE!
|
||||
private static List<List<string>> Calculate(DateTime d, double latRad, double longRad, double[] ev = null)
|
||||
{
|
||||
//DECLARE ARRAYS
|
||||
double[] obsvconst = new double[6];
|
||||
double[] mid = new double[41];
|
||||
double[] p1 = new double[41];
|
||||
double[] u1 = new double[41];
|
||||
double[] u2 = new double[41];
|
||||
double[] u3 = new double[41];
|
||||
double[] u4 = new double[41];
|
||||
double[] p4 = new double[41];
|
||||
|
||||
List<List<string>> events = new List<List<string>>();
|
||||
|
||||
double[] el;
|
||||
if (ev == null)
|
||||
{
|
||||
el = Eclipse.LunarData.LunarDateData(d);//Get 100 year solar data;
|
||||
}
|
||||
else
|
||||
{
|
||||
el = ev;
|
||||
}
|
||||
|
||||
events = new List<List<string>>();
|
||||
ReadData(latRad, longRad, obsvconst);
|
||||
|
||||
for (int i = 0; i < el.Length; i += 22)
|
||||
{
|
||||
if (el[5 + i] <= obsvconst[5])
|
||||
{
|
||||
List<string> values = new List<string>();
|
||||
obsvconst[4] = i;
|
||||
GetAll(el, obsvconst, mid, p1, u1, u2,u3,u4,p4);
|
||||
// Is there an event...
|
||||
if (mid[5] != 1)
|
||||
{
|
||||
|
||||
values.Add(GetDate(el, p1, obsvconst));
|
||||
|
||||
if (el[5 + i] == 1)
|
||||
{
|
||||
values.Add("T");
|
||||
}
|
||||
else if (el[5 + i] == 2)
|
||||
{
|
||||
values.Add("P");
|
||||
}
|
||||
else
|
||||
{
|
||||
values.Add("N");
|
||||
}
|
||||
|
||||
// Pen. Mag
|
||||
values.Add(el[3 + i].ToString());
|
||||
|
||||
// Umbral Mag
|
||||
values.Add(el[4 + i].ToString());
|
||||
|
||||
// P1
|
||||
values.Add(GetTime(el, p1, obsvconst));
|
||||
|
||||
// P1 alt
|
||||
values.Add(GetAlt(p1));
|
||||
|
||||
if (u1[5] == 1)
|
||||
{
|
||||
values.Add("-");
|
||||
values.Add("-");
|
||||
}
|
||||
else
|
||||
{
|
||||
// U1
|
||||
values.Add(GetTime(el, u1, obsvconst));
|
||||
|
||||
// U1 alt
|
||||
values.Add(GetAlt(u1));
|
||||
}
|
||||
if (u2[5] == 1)
|
||||
{
|
||||
values.Add("-");
|
||||
values.Add("-");
|
||||
}
|
||||
else
|
||||
{
|
||||
// U2
|
||||
values.Add(GetTime(el, u2, obsvconst));
|
||||
|
||||
// U2 alt
|
||||
values.Add(GetAlt(u2));
|
||||
}
|
||||
// mid
|
||||
|
||||
values.Add(GetTime(el, mid, obsvconst));
|
||||
|
||||
// mid alt
|
||||
|
||||
values.Add(GetAlt(mid));
|
||||
|
||||
if (u3[5] == 1)
|
||||
{
|
||||
values.Add("-");
|
||||
values.Add("-");
|
||||
}
|
||||
else
|
||||
{
|
||||
// u3
|
||||
values.Add(GetTime(el, u3, obsvconst));
|
||||
|
||||
// u3 alt
|
||||
values.Add(GetAlt(u3));
|
||||
}
|
||||
if (u4[5] == 1)
|
||||
{
|
||||
values.Add("-");
|
||||
values.Add("-");
|
||||
}
|
||||
else
|
||||
{
|
||||
// u4
|
||||
values.Add(GetTime(el, u4, obsvconst));
|
||||
|
||||
// u4 alt
|
||||
values.Add(GetAlt(u4));
|
||||
|
||||
}
|
||||
// P4
|
||||
values.Add(GetTime(el, p4, obsvconst));
|
||||
|
||||
// P4 alt
|
||||
values.Add(GetAlt(p4));
|
||||
events.Add(values);
|
||||
}
|
||||
}
|
||||
}
|
||||
return events;
|
||||
}
|
||||
// Read the data that's in the form, and populate the obsvconst array
|
||||
private static void ReadData(double latRad, double longRad, double[] obsvconst)
|
||||
{
|
||||
|
||||
// Get the latitude
|
||||
obsvconst[0] = latRad;
|
||||
|
||||
// Get the longitude
|
||||
obsvconst[1] = -1 * longRad; //PASS REVERSE RADIAN.
|
||||
|
||||
// Get the altitude
|
||||
obsvconst[2] = 100; //CHANGE TO ALLOW USER TO PASS.
|
||||
|
||||
// Get the time zone
|
||||
obsvconst[3] = 0; //GMT TIME
|
||||
|
||||
obsvconst[4] = 0; //INDEX
|
||||
|
||||
//SET MAX ECLIPSE TYPE
|
||||
obsvconst[5] = 4;//4 is ALL Eclipses
|
||||
|
||||
}
|
||||
// Populate the p1, u1, u2, mid, u3, u4 and p4 arrays
|
||||
private static void GetAll(double[] elements, double[] obsvconst, double[] mid, double[] p1, double[] u1, double[] u2, double[] u3, double[] u4, double[] p4)
|
||||
{
|
||||
int index = (int)obsvconst[4];
|
||||
p1[1] = elements[index + 9];
|
||||
PopulateCircumstances(elements, p1, obsvconst);
|
||||
mid[1] = elements[index + 12];
|
||||
PopulateCircumstances(elements, mid, obsvconst);
|
||||
p4[1] = elements[index + 15];
|
||||
PopulateCircumstances(elements, p4, obsvconst);
|
||||
if (elements[index + 5] < 3)
|
||||
{
|
||||
u1[1] = elements[index + 10];
|
||||
PopulateCircumstances(elements, u1, obsvconst);
|
||||
u4[1] = elements[index + 14];
|
||||
PopulateCircumstances(elements, u4, obsvconst);
|
||||
if (elements[index + 5] < 2)
|
||||
{
|
||||
u2[1] = elements[index + 11];
|
||||
u3[1] = elements[index + 13];
|
||||
PopulateCircumstances(elements, u2, obsvconst);
|
||||
PopulateCircumstances(elements, u3, obsvconst);
|
||||
}
|
||||
else
|
||||
{
|
||||
u2[5] = 1;
|
||||
u3[5] = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
u1[5] = 1;
|
||||
u2[5] = 1;
|
||||
u3[5] = 1;
|
||||
u4[5] = 1;
|
||||
}
|
||||
if ((p1[5] != 0) && (u1[5] != 0) && (u2[5] != 0) && (mid[5] != 0) && (u3[5] != 0) && (u4[5] != 0) && (p4[5] != 0))
|
||||
{
|
||||
mid[5] = 1;
|
||||
}
|
||||
}
|
||||
// Populate the circumstances array
|
||||
// entry condition - circumstances[1] must contain the correct value
|
||||
private static void PopulateCircumstances(double[] elements, double[] circumstances, double[] obsvconst)
|
||||
{
|
||||
double t, ra, dec, h;
|
||||
|
||||
int index = (int)obsvconst[4];
|
||||
t = circumstances[1];
|
||||
ra = elements[18 + index] * t + elements[17 + index];
|
||||
ra = ra * t + elements[16 + index];
|
||||
dec = elements[21 + index] * t + elements[20 + index];
|
||||
dec = dec * t + elements[19 + index];
|
||||
dec = dec * Math.PI / 180.0;
|
||||
circumstances[3] = dec;
|
||||
h = 15.0 * (elements[6 + index] + (t - elements[2 + index] / 3600.0) * 1.00273791) - ra;
|
||||
h = h * Math.PI / 180.0 - obsvconst[1];
|
||||
circumstances[2] = h;
|
||||
circumstances[4] = Math.Asin(Math.Sin(obsvconst[0]) * Math.Sin(dec) + Math.Cos(obsvconst[0]) * Math.Cos(dec) * Math.Cos(h));
|
||||
circumstances[4] -= Math.Asin(Math.Sin(elements[7 + index] * Math.PI / 180.0) * Math.Cos(circumstances[4]));
|
||||
if (circumstances[4] * 180.0 / Math.PI < elements[8 + index] - 0.5667)
|
||||
{
|
||||
circumstances[5] = 2;
|
||||
}
|
||||
else if (circumstances[4] < 0.0)
|
||||
{
|
||||
circumstances[4] = 0.0;
|
||||
circumstances[5] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
circumstances[5] = 0;
|
||||
}
|
||||
}
|
||||
// Get the date of an event
|
||||
private static string GetDate(double[] elements, double[] circumstances, double[] obsvconst)
|
||||
{
|
||||
string[] month = new string[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };//Month string array
|
||||
double t, jd, a, b, c, d, e;
|
||||
string ans = "";
|
||||
int index = (int)obsvconst[4];
|
||||
// Calculate the JD for noon (TDT) the day before the day that contains T0
|
||||
jd = Math.Floor(elements[index] - (elements[1 + index] / 24.0));
|
||||
// Calculate the local time (ie the offset in hours since midnight TDT on the day containing T0).
|
||||
t = circumstances[1] + elements[1 + index] - obsvconst[3] - (elements[2 + index] - 30.0) / 3600.0;
|
||||
|
||||
if (t < 0.0)
|
||||
{
|
||||
jd--;
|
||||
}
|
||||
if (t >= 24.0)
|
||||
{
|
||||
jd++;
|
||||
}
|
||||
if (jd >= 2299160.0)
|
||||
{
|
||||
a = Math.Floor((jd - 1867216.25) / 36524.25);
|
||||
a = jd + 1 + a - Math.Floor(a / 4.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
a = jd;
|
||||
}
|
||||
b = a + 1525.0;
|
||||
c = Math.Floor((b - 122.1) / 365.25);
|
||||
d = Math.Floor(365.25 * c);
|
||||
e = Math.Floor((b - d) / 30.6001);
|
||||
d = b - d - Math.Floor(30.6001 * e);
|
||||
if (e < 13.5)
|
||||
{
|
||||
e = e - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
e = e - 13;
|
||||
}
|
||||
double year;
|
||||
if (e > 2.5)
|
||||
{
|
||||
ans = c - 4716 + "-";
|
||||
year = c - 4716;
|
||||
}
|
||||
else
|
||||
{
|
||||
ans = c - 4715 + "-";
|
||||
year = c - 4715;
|
||||
}
|
||||
string m = month[(int)e - 1];
|
||||
ans += m+ "-";
|
||||
if (d < 10)
|
||||
{
|
||||
ans = ans + "0";
|
||||
}
|
||||
ans = ans + d;
|
||||
//Leap Year Integrity Check
|
||||
|
||||
if (m == "Feb" && d == 29 && !DateTime.IsLeapYear((int)year))
|
||||
{
|
||||
ans = year.ToString() + "-Mar-01";
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
// Get the time of an event
|
||||
private static string GetTime(double[] elements, double[] circumstances, double[] obsvconst)
|
||||
{
|
||||
double t;
|
||||
string ans = "";
|
||||
|
||||
int index = (int)obsvconst[4];
|
||||
t = circumstances[1] + elements[1 + index] - obsvconst[3] - (elements[2 + index] - 30.0) / 3600.0;
|
||||
if (t < 0.0)
|
||||
{
|
||||
t = t + 24.0;
|
||||
}
|
||||
if (t >= 24.0)
|
||||
{
|
||||
t = t - 24.0;
|
||||
}
|
||||
if (t < 10.0)
|
||||
{
|
||||
ans = ans + "0";
|
||||
}
|
||||
ans = ans + Math.Floor(t) + ":";
|
||||
t = (t * 60.0) - 60.0 * Math.Floor(t);
|
||||
if (t < 10.0)
|
||||
{
|
||||
ans = ans + "0";
|
||||
}
|
||||
ans = ans + Math.Floor(t);
|
||||
if (circumstances[5] == 2)
|
||||
{
|
||||
return ans; //RETURNED IN ITAL DETERMINE WHY
|
||||
}
|
||||
else
|
||||
{
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
// Get the altitude
|
||||
private static string GetAlt(double[] circumstances)
|
||||
{
|
||||
double t;
|
||||
string ans = "";
|
||||
t = circumstances[4] * 180.0 / Math.PI;
|
||||
t = Math.Floor(t + 0.5);
|
||||
if (t < 0.0)
|
||||
{
|
||||
ans = "-";
|
||||
t = -t;
|
||||
}
|
||||
else
|
||||
{
|
||||
ans = "+";
|
||||
}
|
||||
if (t < 10.0)
|
||||
{
|
||||
ans = ans + "0";
|
||||
}
|
||||
ans = ans + t;
|
||||
if (circumstances[5] == 2)
|
||||
{
|
||||
return ans; //returned in italics determine why
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,221 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
internal partial class MeeusTables
|
||||
{
|
||||
//Ch 47
|
||||
private static double[] Table47A_Arguments = new double[]
|
||||
{
|
||||
0,0,1,0,
|
||||
2,0,-1,0,
|
||||
2,0,0,0,
|
||||
0,0,2,0,
|
||||
0,1,0,0,
|
||||
0,0,0,2,
|
||||
2,0,-2,0,
|
||||
2,-1,-1,0,
|
||||
2,0,1,0,
|
||||
2,-1,0,0,
|
||||
0,1,-1,0,
|
||||
1,0,0,0,
|
||||
0,1,1,0,
|
||||
2,0,0,-2,
|
||||
0,0,1,2,
|
||||
0,0,1,-2,
|
||||
4,0,-1,0,
|
||||
0,0,3,0,
|
||||
4,0,-2,0,
|
||||
2,1,-1,0,
|
||||
2,1,0,0,
|
||||
1,0,-1,0,
|
||||
1,1,0,0,
|
||||
2,-1,1,0,
|
||||
2,0,2,0,
|
||||
4,0,0,0,
|
||||
2,0,-3,0,
|
||||
0,1,-2,0,
|
||||
2,0,-1,2,
|
||||
2,-1,-2,0,
|
||||
1,0,1,0,
|
||||
2,-2,0,0,
|
||||
|
||||
0,1,2,0,
|
||||
0,2,0,0,
|
||||
2,-2,-1,0,
|
||||
2,0,1,-2,
|
||||
2,0,0,2,
|
||||
4,-1,-1,0,
|
||||
0,0,2,2,
|
||||
3,0,-1,0,
|
||||
2,1,1,0,
|
||||
4,-1,-2,0,
|
||||
0,2,-1,0,
|
||||
2,2,-1,0,
|
||||
2,1,-2,0,
|
||||
2,-1,0,-2,
|
||||
4,0,1,0,
|
||||
0,0,4,0,
|
||||
4,-1,0,0,
|
||||
1,0,-2,0,
|
||||
2,1,0,-2,
|
||||
0,0,2,-2,
|
||||
1,1,1,0,
|
||||
3,0,-2,0,
|
||||
4,0,-3,0,
|
||||
2,-1,2,0,
|
||||
0,2,1,0,
|
||||
1,1,-1,0,
|
||||
2,0,3,0,
|
||||
2,0,-1,-2
|
||||
};
|
||||
private static double[] Table47B_Arguments = new double[]
|
||||
{
|
||||
0,0,0,1,
|
||||
0,0,1,1,
|
||||
0,0,1,-1,
|
||||
2,0,0,-1,
|
||||
2,0,-1,1,
|
||||
2,0,-1,-1,
|
||||
2,0,0,1,
|
||||
0,0,2,1,
|
||||
2,0,1,-1,
|
||||
0,0,2,-1,
|
||||
2,-1,0,-1,
|
||||
2,0,-2,-1,
|
||||
2,0,1,1,
|
||||
2,1,0,-1,
|
||||
2,-1,-1,1,
|
||||
2,-1,0,1,
|
||||
2,-1,-1,-1,
|
||||
0,1,-1,-1,
|
||||
4,0,-1,-1,
|
||||
0,1,0,1,
|
||||
0,0,0,3,
|
||||
0,1,-1,1,
|
||||
1,0,0,1,
|
||||
0,1,1,1,
|
||||
0,1,1,-1,
|
||||
0,1,0,-1,
|
||||
1,0,0,-1,
|
||||
0,0,3,1,
|
||||
4,0,0,-1,
|
||||
4,0,-1,1,
|
||||
|
||||
0,0,1,-3,
|
||||
4,0,-2,1,
|
||||
2,0,0,-3,
|
||||
2,0,2,-1,
|
||||
2,-1,1,-1,
|
||||
2,0,-2,1,
|
||||
0,0,3,-1,
|
||||
2,0,2,1,
|
||||
2,0,-3,-1,
|
||||
2,1,-1,1,
|
||||
2,1,0,1,
|
||||
4,0,0,1,
|
||||
2,-1,1,1,
|
||||
2,-2,0,-1,
|
||||
0,0,1,3,
|
||||
2,1,1,-1,
|
||||
1,1,0,-1,
|
||||
1,1,0,1,
|
||||
0,1,-2,-1,
|
||||
2,1,-1,-1,
|
||||
1,0,1,1,
|
||||
2,-1,-2,-1,
|
||||
0,1,2,1,
|
||||
4,0,-2,-1,
|
||||
4,-1,-1,-1,
|
||||
1,0,1,-1,
|
||||
4,0,1,-1,
|
||||
1,0,-1,-1,
|
||||
4,-1,0,-1,
|
||||
2,-2,0,1,
|
||||
};
|
||||
private static double[] Table47A_El_Er = new double[]
|
||||
{
|
||||
//El
|
||||
6288774, 1274027,658314,213618,-185116,-114332,58793,57066,53322,45758,
|
||||
-40923,-34720,-30383,15327,-12528,10980,10675,10034,8548,-7888,-6766,-5163,
|
||||
4987,4036,3994,3861,3665,-2689,-2602,2390,-2348,2236,-2120,-2069,2048,-1773,
|
||||
-1595,1215,-1110,-892,-810,759,-713,-700,691,596,549,537,520,-487,-399,-381,
|
||||
351,-340,330,327,-323,299,294,0,
|
||||
//Er
|
||||
-20905355,-3699111,-2955968,-569925,48888,-3149,246158,-152138,-170733,-204586,
|
||||
-129620,108743,104755,10321,0,79661,-34782,-23210,-21636,24208,30824,-8379,-16675,
|
||||
-12831,-10445,-11650,14403,-7003,0,10056,6322,-9884,5751,0,-4950,4130,0,-3958,0,3258,
|
||||
2616,-1897,-2117,2354,0,0,-1423,-1117,-1571,-1739,0,-4421,0,0,0,0,1165,0,0,8752
|
||||
|
||||
};
|
||||
private static double[] Table47B_Eb = new double[]
|
||||
{
|
||||
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
|
||||
};
|
||||
private static double Get_Table47A_Values(double[] values, int l, double t, bool sine)
|
||||
{
|
||||
//sine true returns El
|
||||
//sine false return Er
|
||||
//Er values start at 60 in the Table47A_El_Er array.
|
||||
|
||||
int nl = l * 4;
|
||||
|
||||
if (sine)
|
||||
{
|
||||
double e = 1;
|
||||
|
||||
if (Table47A_Arguments[nl + 1] != 0)
|
||||
{
|
||||
e = 1 - .002516 * t - .0000074 * Math.Pow(t, 2);
|
||||
|
||||
if (Math.Abs(Table47A_Arguments[nl + 1]) == 2)
|
||||
{
|
||||
e *= e;
|
||||
}
|
||||
}
|
||||
return (Table47A_El_Er[l] * e) * Math.Sin(Table47A_Arguments[nl] * values[0] + Table47A_Arguments[nl + 1] * values[1] +
|
||||
Table47A_Arguments[nl + 2] * values[2] + Table47A_Arguments[nl + 3] * values[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
double e = 1;
|
||||
if (Table47A_Arguments[nl + 1] != 0)
|
||||
{
|
||||
e = 1 - .002516 * t - .0000074 * Math.Pow(t, 2);
|
||||
|
||||
if (Math.Abs(Table47A_Arguments[nl + 1]) == 2)
|
||||
{
|
||||
e *= e;
|
||||
}
|
||||
}
|
||||
return (Table47A_El_Er[l + 60] * e) * Math.Cos(Table47A_Arguments[nl] * values[0] + Table47A_Arguments[nl + 1] * values[1] +
|
||||
Table47A_Arguments[nl + 2] * values[2] + Table47A_Arguments[nl + 3] * values[3]);
|
||||
}
|
||||
}
|
||||
private static double Get_Table47B_Values(double[] values, int l, double t)
|
||||
{
|
||||
int nl = l * 4;
|
||||
double e = 1;
|
||||
|
||||
if (Table47B_Arguments[nl + 1] != 0)
|
||||
{
|
||||
e = 1 - .002516 * t - .0000074 * Math.Pow(t, 2);
|
||||
|
||||
if (Math.Abs(Table47B_Arguments[nl + 1]) == 2)
|
||||
{
|
||||
e *= e;
|
||||
}
|
||||
}
|
||||
return (Table47B_Eb[l] * e) * Math.Sin(Table47B_Arguments[nl] * values[0] + Table47B_Arguments[nl + 1] * values[1] +
|
||||
Table47B_Arguments[nl + 2] * values[2] + Table47B_Arguments[nl + 3] * values[3]);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,872 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
internal class MoonCalc
|
||||
{
|
||||
static double rad = Math.PI / 180; //For converting radians
|
||||
|
||||
//obliquity of the ecliptic in radians based on standard equinox 2000.
|
||||
static double e = rad * 23.4392911;
|
||||
/// <summary>
|
||||
/// Gets Moon Times, Altitude and Azimuth
|
||||
/// </summary>
|
||||
/// <param name="date">Date</param>
|
||||
/// <param name="lat">Latitude</param>
|
||||
/// <param name="lng">Longitude</param>
|
||||
/// <param name="c">Celestial</param>
|
||||
public static void GetMoonTimes(DateTime date, double lat, double lng, Celestial c)
|
||||
{
|
||||
//Get current Moon Position to populate passed Alt / Azi for user specified date
|
||||
MoonPosition mp = GetMoonPosition(date, lat, lng, c);
|
||||
double altRad = mp.Altitude / Math.PI*180; //Convert alt to degrees
|
||||
c.moonAltitude = (altRad - mp.ParallaxCorection); //Set altitude with adjusted parallax
|
||||
c.moonAzimuth = mp.Azimuth / Math.PI*180 + 180; //Azimuth in degrees + 180 for E by N.
|
||||
|
||||
////New Iterations for Moon set / rise
|
||||
bool moonRise = false;
|
||||
bool moonSet = false;
|
||||
|
||||
//Start at beginning of day
|
||||
DateTime t = new DateTime(date.Year, date.Month, date.Day, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
//Get start of day Moon Pos
|
||||
MoonPosition moonPos = GetMoonPosition(t, lat, lng, c);
|
||||
double alt1 = moonPos.Altitude - (moonPos.ParallaxCorection * rad);
|
||||
|
||||
DateTime? setTime = null;
|
||||
DateTime? riseTime = null;
|
||||
double hz = -.3 * rad;//Horizon degrees at -.3 for appearant rise / set
|
||||
|
||||
//Iterate for each hour of the day
|
||||
for(int x = 1;x<=24;x++)
|
||||
{
|
||||
moonPos = GetMoonPosition(t.AddHours(x), lat, lng, c);//Get the next hours altitude for comparison
|
||||
double alt2 = moonPos.Altitude - (moonPos.ParallaxCorection * rad);
|
||||
//If hour 1 is below horizon and hour 2 is above
|
||||
if(alt1 <hz && alt2 >=hz)
|
||||
{
|
||||
//Moon Rise Occurred
|
||||
moonRise = true;
|
||||
DateTime dt1 = t.AddHours(x - 1);
|
||||
moonPos = GetMoonPosition(dt1, lat, lng, c);//Get the next hours altitude for comparison
|
||||
double altM1 = moonPos.Altitude - (moonPos.ParallaxCorection * rad);
|
||||
//Iterate through each minute to determine at which minute the horizon is crossed.
|
||||
//Interpolation is more efficient, but yielded results with deviations up to 5 minutes.
|
||||
//Investigate formula efficiency
|
||||
for (int y = 1;y<=60;y++)
|
||||
{
|
||||
DateTime dt2 = t.AddHours(x-1).AddMinutes(y);
|
||||
moonPos = GetMoonPosition(dt2, lat, lng, c);//Get the next hours altitude for comparison
|
||||
double altM2 = moonPos.Altitude - (moonPos.ParallaxCorection * rad);
|
||||
if (altM1<hz && altM2>=hz)
|
||||
{
|
||||
//interpolate seconds
|
||||
double p = 60 * ((hz - altM1) / (altM2 - altM1));
|
||||
riseTime = dt1.AddMinutes(y-1).AddSeconds(p);
|
||||
break;
|
||||
}
|
||||
altM1 = altM2;
|
||||
|
||||
}
|
||||
}
|
||||
//if hour 2 is above horizon and hour 1 below
|
||||
if(alt1>=hz && alt2 <hz)
|
||||
{
|
||||
//Moon Set Occured
|
||||
moonSet = true;
|
||||
DateTime dt1 = t.AddHours(x - 1);
|
||||
moonPos = GetMoonPosition(dt1, lat, lng, c);//Get the next hours altitude for comparison
|
||||
double altM1 = moonPos.Altitude - (moonPos.ParallaxCorection * rad);
|
||||
//Iterate through each minute to determine at which minute the horizon is crossed.
|
||||
//Interpolation is more efficient, but yielded results with deviations up to 5 minutes.
|
||||
//Investigate formula efficiency
|
||||
for (int y = 1; y <= 60; y++)
|
||||
{
|
||||
DateTime dt2 = t.AddHours(x - 1).AddMinutes(y);
|
||||
moonPos = GetMoonPosition(dt2, lat, lng, c);//Get the next hours altitude for comparison
|
||||
double altM2 = moonPos.Altitude - (moonPos.ParallaxCorection * rad);
|
||||
if (altM1 >= hz && altM2 < hz)
|
||||
{
|
||||
//Interpolate seconds
|
||||
double p = 60 * ((hz - altM2) / (altM1 - altM2));
|
||||
setTime = dt1.AddMinutes(y).AddSeconds(-p);
|
||||
break;
|
||||
}
|
||||
altM1 = altM2;
|
||||
|
||||
}
|
||||
}
|
||||
alt1 = alt2;
|
||||
if(moonRise && moonSet) { break; }
|
||||
}
|
||||
|
||||
c.moonSet = setTime;
|
||||
c.moonRise = riseTime;
|
||||
if (moonRise && moonSet) { c.moonCondition = CelestialStatus.RiseAndSet; }
|
||||
else
|
||||
{
|
||||
if (!moonRise && !moonSet)
|
||||
{
|
||||
if (alt1 >= 0) { c.moonCondition = CelestialStatus.UpAllDay; }
|
||||
else { c.moonCondition = CelestialStatus.DownAllDay; }
|
||||
}
|
||||
if (!moonRise && moonSet) { c.moonCondition = CelestialStatus.NoRise; }
|
||||
if (moonRise && !moonSet) { c.moonCondition = CelestialStatus.NoSet; }
|
||||
}
|
||||
}
|
||||
|
||||
private static MoonPosition GetMoonPosition(DateTime date, double lat, double lng, Celestial cel)
|
||||
{
|
||||
//Set UTC date integrity
|
||||
date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, DateTimeKind.Utc);
|
||||
|
||||
double d = JulianConversions.GetJulian_Epoch2000(date);
|
||||
|
||||
//Ch 47
|
||||
double JDE = JulianConversions.GetJulian(date);//Get julian
|
||||
|
||||
double T = (JDE - 2451545) / 36525; //Get dynamic time.
|
||||
double[] LDMNF = Get_Moon_LDMNF(T);
|
||||
CelCoords c = GetMoonCoords(d, cel, LDMNF, T);
|
||||
Distance dist = GetMoonDistance(date);
|
||||
double lw = rad * -lng;
|
||||
double phi = rad * lat;
|
||||
|
||||
double H = rad * MeeusFormulas.Get_Sidereal_Time(JDE) - lw - c.ra;
|
||||
|
||||
double ra = c.ra; //Adjust current RA formula to avoid needless RAD conversions
|
||||
double dec = c.dec; //Adjust current RA formula to avoid needless RAD conversions
|
||||
|
||||
//Adjust for parallax (low accuracry increases may not be worth cost)
|
||||
//Investigate
|
||||
double pSinE = Get_pSinE(dec, dist.Meters) * Math.PI / 180;
|
||||
double pCosE = Get_pCosE(dec, dist.Meters) * Math.PI / 180;
|
||||
double cRA = Parallax_RA(dist.Meters, H, pCosE, dec, ra);
|
||||
double tDEC = Parallax_Dec(dist.Meters, H, pCosE, pSinE, dec, cRA);
|
||||
double tRA = ra - cRA;
|
||||
dec = tDEC;
|
||||
ra = tRA;
|
||||
|
||||
//Get true altitude
|
||||
double h = altitude(H, phi, dec);
|
||||
|
||||
// formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998.
|
||||
double pa = Math.Atan2(Math.Sin(H), Math.Tan(phi) * Math.Cos(dec) - Math.Sin(dec) * Math.Cos(H));
|
||||
|
||||
//altitude correction for refraction
|
||||
h = h + astroRefraction(h);
|
||||
|
||||
MoonPosition mp = new MoonPosition();
|
||||
mp.Azimuth = azimuth(H, phi, dec);
|
||||
mp.Altitude = h / Math.PI * 180;
|
||||
mp.Distance = dist;
|
||||
mp.ParallacticAngle = pa;
|
||||
|
||||
double horParal = 8.794 / (dist.Meters / 149.59787E6); // horizontal parallax (arcseconds), Meeus S. 263
|
||||
double p = Math.Asin(Math.Cos(h) * Math.Sin(horParal/3600)); // parallax in altitude (degrees)
|
||||
p *= 1000;
|
||||
|
||||
mp.ParallaxCorection = p;
|
||||
mp.Altitude *= rad;
|
||||
|
||||
return mp;
|
||||
}
|
||||
private static CelCoords GetMoonCoords(double d, Celestial c, double[] LDMNF, double t)
|
||||
{
|
||||
// Legacy function. Updated with Meeus Calcs for increased accuracy.
|
||||
// geocentric ecliptic coordinates of the moon
|
||||
// Meeus Ch 47
|
||||
double[] cs = Get_Moon_Coordinates(LDMNF, t);
|
||||
|
||||
double l = cs[0]; // longitude
|
||||
double b = cs[1]; // latitude
|
||||
|
||||
CelCoords mc = new CelCoords();
|
||||
|
||||
mc.ra = rightAscension(l, b);
|
||||
double ra = mc.ra / Math.PI * 180;
|
||||
|
||||
mc.dec = declination(l, b);
|
||||
double dec = mc.dec / Math.PI * 180;
|
||||
|
||||
return mc;
|
||||
}
|
||||
|
||||
public static void GetMoonIllumination(DateTime date, Celestial c, double lat, double lng)
|
||||
{
|
||||
date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, DateTimeKind.Utc);
|
||||
|
||||
double d = JulianConversions.GetJulian_Epoch2000(date);
|
||||
CelCoords s = GetSunCoords(d);
|
||||
double JDE = JulianConversions.GetJulian(date);//Get julian
|
||||
double T = (JDE - 2451545) / 36525; //Get dynamic time.
|
||||
double[] LDMNF = Get_Moon_LDMNF(T);
|
||||
|
||||
CelCoords m = GetMoonCoords(d, c,LDMNF, T);
|
||||
|
||||
double sdist = 149598000,
|
||||
phi = Math.Acos(Math.Sin(s.dec) * Math.Sin(m.dec) + Math.Cos(s.dec) * Math.Cos(m.dec) * Math.Cos(s.ra - m.ra)),
|
||||
inc = Math.Atan2(sdist * Math.Sin(phi), m.dist - sdist * Math.Cos(phi)),
|
||||
angle = Math.Atan2(Math.Cos(s.dec) * Math.Sin(s.ra - m.ra), Math.Sin(s.dec) * Math.Cos(m.dec) -
|
||||
Math.Cos(s.dec) * Math.Sin(m.dec) * Math.Cos(s.ra - m.ra));
|
||||
|
||||
|
||||
MoonIllum mi = new MoonIllum();
|
||||
|
||||
mi.Fraction = (1 + Math.Cos(inc)) / 2;
|
||||
mi.Phase = 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / Math.PI;
|
||||
mi.Angle = angle;
|
||||
|
||||
|
||||
c.moonIllum = mi;
|
||||
|
||||
string moonName = "";
|
||||
int moonDate = 0;
|
||||
//GET PHASE NAME
|
||||
|
||||
//CHECK MOON AT BEGINNING AT END OF DAY TO GET DAY PHASE
|
||||
DateTime dMon = new DateTime(date.Year, date.Month, 1);
|
||||
for(int x = 1;x<= date.Day;x++)
|
||||
{
|
||||
DateTime nDate = new DateTime(dMon.Year, dMon.Month, x, 0, 0, 0, DateTimeKind.Utc);
|
||||
d = JulianConversions.GetJulian_Epoch2000(nDate);
|
||||
s = GetSunCoords(d);
|
||||
JDE = JulianConversions.GetJulian(nDate);//Get julian
|
||||
T = (JDE - 2451545) / 36525; //Get dynamic time.
|
||||
LDMNF = Get_Moon_LDMNF(T);
|
||||
m = GetMoonCoords(d, c,LDMNF,T);
|
||||
|
||||
phi = Math.Acos(Math.Sin(s.dec) * Math.Sin(m.dec) + Math.Cos(s.dec) * Math.Cos(m.dec) * Math.Cos(s.ra - m.ra));
|
||||
inc = Math.Atan2(sdist * Math.Sin(phi), m.dist - sdist * Math.Cos(phi));
|
||||
angle = Math.Atan2(Math.Cos(s.dec) * Math.Sin(s.ra - m.ra), Math.Sin(s.dec) * Math.Cos(m.dec) -
|
||||
Math.Cos(s.dec) * Math.Sin(m.dec) * Math.Cos(s.ra - m.ra));
|
||||
|
||||
double startPhase = 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / Math.PI;
|
||||
|
||||
nDate = new DateTime(dMon.Year, dMon.Month, x, 23, 59, 59, DateTimeKind.Utc);
|
||||
d = JulianConversions.GetJulian_Epoch2000(nDate);
|
||||
s = GetSunCoords(d);
|
||||
JDE = JulianConversions.GetJulian(nDate);//Get julian
|
||||
T = (JDE - 2451545) / 36525; //Get dynamic time.
|
||||
LDMNF = Get_Moon_LDMNF(T);
|
||||
m = GetMoonCoords(d, c,LDMNF,T);
|
||||
|
||||
phi = Math.Acos(Math.Sin(s.dec) * Math.Sin(m.dec) + Math.Cos(s.dec) * Math.Cos(m.dec) * Math.Cos(s.ra - m.ra));
|
||||
inc = Math.Atan2(sdist * Math.Sin(phi), m.dist - sdist * Math.Cos(phi));
|
||||
angle = Math.Atan2(Math.Cos(s.dec) * Math.Sin(s.ra - m.ra), Math.Sin(s.dec) * Math.Cos(m.dec) -
|
||||
Math.Cos(s.dec) * Math.Sin(m.dec) * Math.Cos(s.ra - m.ra));
|
||||
|
||||
double endPhase = 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / Math.PI;
|
||||
//Determine Moon Name.
|
||||
if (startPhase <= .5 && endPhase >= .5)
|
||||
{
|
||||
moonDate = x;
|
||||
moonName = GetMoonName(dMon.Month, moonName);
|
||||
}
|
||||
//Get Moon Name (month, string);
|
||||
//Get Moon Phase Name
|
||||
if (date.Day == x)
|
||||
{
|
||||
if (startPhase > endPhase)
|
||||
{
|
||||
mi.PhaseName = "New Moon";
|
||||
break;
|
||||
}
|
||||
if (startPhase <= .25 && endPhase >= .25)
|
||||
{
|
||||
mi.PhaseName = "First Quarter";
|
||||
break;
|
||||
}
|
||||
if (startPhase <= .5 && endPhase >= .5)
|
||||
{
|
||||
mi.PhaseName = "Full Moon";
|
||||
break;
|
||||
}
|
||||
if (startPhase <= .75 && endPhase >= .75)
|
||||
{
|
||||
mi.PhaseName = "Last Quarter";
|
||||
break;
|
||||
}
|
||||
|
||||
if (startPhase > 0 && startPhase < .25 && endPhase > 0 && endPhase < .25)
|
||||
{
|
||||
mi.PhaseName = "Waxing Crescent";
|
||||
break;
|
||||
}
|
||||
if (startPhase > .25 && startPhase < .5 && endPhase > .25 && endPhase < .5)
|
||||
{
|
||||
mi.PhaseName = "Waxing Gibbous";
|
||||
break;
|
||||
}
|
||||
if (startPhase > .5 && startPhase < .75 && endPhase > .5 && endPhase < .75)
|
||||
{
|
||||
mi.PhaseName = "Waning Gibbous";
|
||||
break;
|
||||
}
|
||||
if (startPhase > .75 && startPhase < 1 && endPhase > .75 && endPhase < 1)
|
||||
{
|
||||
mi.PhaseName = "Waning Crescent";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (date.Day == moonDate)
|
||||
{
|
||||
c.AstrologicalSigns.MoonName = moonName;
|
||||
}
|
||||
else { c.AstrologicalSigns.MoonName = ""; }
|
||||
CalculateLunarEclipse(date, lat, lng, c);
|
||||
|
||||
}
|
||||
public static void CalculateLunarEclipse(DateTime date, double lat, double longi, Celestial c)
|
||||
{
|
||||
//Convert to Radian
|
||||
double latR = lat * Math.PI / 180;
|
||||
double longR = longi * Math.PI / 180;
|
||||
List<List<string>> se = LunarEclipseCalc.CalculateLunarEclipse(date, latR, longR);
|
||||
//RETURN FIRST AND LAST
|
||||
if (se.Count == 0) { return; }
|
||||
//FIND LAST AND NEXT ECLIPSE
|
||||
int lastE = -1;
|
||||
int nextE = -1;
|
||||
int currentE = 0;
|
||||
DateTime lastDate = new DateTime();
|
||||
DateTime nextDate = new DateTime(3300, 1, 1);
|
||||
//Iterate to get last and next eclipse
|
||||
|
||||
foreach (List<string> values in se)
|
||||
{
|
||||
DateTime ld = DateTime.ParseExact(values[0], "yyyy-MMM-dd", System.Globalization.CultureInfo.InvariantCulture);
|
||||
if (ld < date && ld > lastDate) { lastDate = ld; lastE = currentE; }
|
||||
if (ld >= date && ld < nextDate) { nextDate = ld; nextE = currentE; }
|
||||
currentE++;
|
||||
}
|
||||
//SET ECLIPSE DATA
|
||||
if (lastE >= 0)
|
||||
{
|
||||
c.LunarEclipse.LastEclipse = new LunarEclipseDetails(se[lastE]);
|
||||
}
|
||||
if (nextE >= 0)
|
||||
{
|
||||
c.LunarEclipse.NextEclipse = new LunarEclipseDetails(se[nextE]);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetMoonName(int month, string name)
|
||||
{
|
||||
if (name != "") { return "Blue Moon"; }
|
||||
switch (month)
|
||||
{
|
||||
case 1:
|
||||
return "Wolf Moon";
|
||||
case 2:
|
||||
return "Snow Moon";
|
||||
case 3:
|
||||
return "Worm Moon";
|
||||
case 4:
|
||||
return "Pink Moon";
|
||||
case 5:
|
||||
return "Flower Moon";
|
||||
case 6:
|
||||
return "Strawberry Moon";
|
||||
case 7:
|
||||
return "Buck Moon";
|
||||
case 8:
|
||||
return "Sturgeon Moon";
|
||||
case 9:
|
||||
return "Corn Moon";
|
||||
case 10:
|
||||
return "Hunters Moon";
|
||||
case 11:
|
||||
return "Beaver Moon";
|
||||
case 12:
|
||||
return "Cold Moon";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
public static void GetMoonDistance(DateTime date, Celestial c)
|
||||
{
|
||||
date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, DateTimeKind.Utc);
|
||||
|
||||
c.moonDistance = GetMoonDistance(date); //Updating distance formula
|
||||
}
|
||||
//Moon Time Functions
|
||||
private static CelCoords GetSunCoords(double d)
|
||||
{
|
||||
double M = solarMeanAnomaly(d),
|
||||
L = eclipticLongitude(M);
|
||||
CelCoords c = new CelCoords();
|
||||
c.dec = declination(L, 0);
|
||||
c.ra = rightAscension(L, 0);
|
||||
return c;
|
||||
}
|
||||
private static double solarMeanAnomaly(double d) { return rad * (357.5291 + 0.98560028 * d); }
|
||||
private static double eclipticLongitude(double M)
|
||||
{
|
||||
double C = rad * (1.9148 * Math.Sin(M) + 0.02 * Math.Sin(2 * M) + 0.0003 * Math.Sin(3 * M)), // equation of center
|
||||
P = rad * 102.9372; // perihelion of the Earth
|
||||
|
||||
return M + C + P + Math.PI;
|
||||
}
|
||||
|
||||
public static void GetMoonSign(DateTime date, Celestial c)
|
||||
{
|
||||
//Formulas taken from https://www.astrocal.co.uk/moon-sign-calculator/
|
||||
double d = date.Day;
|
||||
double m = date.Month;
|
||||
double y = date.Year;
|
||||
double hr = date.Hour;
|
||||
double mi = date.Minute;
|
||||
|
||||
double f = hr + (mi / 60);
|
||||
double im = 12 * (y + 4800) + m - 3;
|
||||
double j = (2 * (im - Math.Floor(im / 12) * 12) + 7 + 365 * im) / 12;
|
||||
j = Math.Floor(j) + d + Math.Floor(im / 48) - 32083;
|
||||
double jd = j + Math.Floor(im / 4800) - Math.Floor(im / 1200) + 38;
|
||||
double T = ((jd - 2415020) + f / 24 - .5) / 36525;
|
||||
double ob = FNr(23.452294 - .0130125 * T);
|
||||
double ll = 973563 + 1732564379 * T - 4 * T * T;
|
||||
double g = 1012395 + 6189 * T;
|
||||
double n = 933060 - 6962911 * T + 7.5 * T * T;
|
||||
double g1 = 1203586 + 14648523 * T - 37 * T * T;
|
||||
d = 1262655 + 1602961611 * T - 5 * T * T;
|
||||
double M = 3600;
|
||||
double l = (ll - g1) / M;
|
||||
double l1 = ((ll - d) - g) / M;
|
||||
f = (ll - n) / M;
|
||||
d = d / M;
|
||||
y = 2 * d;
|
||||
double ml = 22639.6 * FNs(l) - 4586.4 * FNs(l - y);
|
||||
ml = ml + 2369.9 * FNs(y) + 769 * FNs(2 * l) - 669 * FNs(l1);
|
||||
ml = ml - 411.6 * FNs(2 * f) - 212 * FNs(2 * l - y);
|
||||
ml = ml - 206 * FNs(l + l1 - y) + 192 * FNs(l + y);
|
||||
ml = ml - 165 * FNs(l1 - y) + 148 * FNs(l - l1) - 125 * FNs(d);
|
||||
ml = ml - 110 * FNs(l + l1) - 55 * FNs(2 * f - y);
|
||||
ml = ml - 45 * FNs(l + 2 * f) + 40 * FNs(l - 2 * f);
|
||||
double tn = n + 5392 * FNs(2 * f - y) - 541 * FNs(l1) - 442 * FNs(y);
|
||||
tn = tn + 423 * FNs(2 * f) - 291 * FNs(2 * l - 2 * f);
|
||||
g = FNu(FNp(ll + ml));
|
||||
double sign = Math.Floor(g / 30);
|
||||
double degree = (g - (sign * 30));
|
||||
sign = sign + 1;
|
||||
|
||||
switch (sign.ToString())
|
||||
{
|
||||
case "1": c.AstrologicalSigns.MoonSign = "Aries"; break;
|
||||
case "2": c.AstrologicalSigns.MoonSign = "Taurus"; break;
|
||||
case "3": c.AstrologicalSigns.MoonSign = "Gemini"; break;
|
||||
case "4": c.AstrologicalSigns.MoonSign = "Cancer"; break;
|
||||
case "5": c.AstrologicalSigns.MoonSign = "Leo"; break;
|
||||
case "6": c.AstrologicalSigns.MoonSign = "Virgo"; break;
|
||||
case "7": c.AstrologicalSigns.MoonSign = "Libra"; break;
|
||||
case "8": c.AstrologicalSigns.MoonSign = "Scorpio"; break;
|
||||
case "9": c.AstrologicalSigns.MoonSign = "Sagitarius"; break;
|
||||
case "10": c.AstrologicalSigns.MoonSign = "Capricorn"; break;
|
||||
case "11": c.AstrologicalSigns.MoonSign = "Aquarius"; break;
|
||||
case "12": c.AstrologicalSigns.MoonSign = "Pisces"; break;
|
||||
default: c.AstrologicalSigns.MoonSign = "Pisces"; break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static double FNp(double x)
|
||||
{
|
||||
double sgn;
|
||||
if (x < 0)
|
||||
{ sgn = -1; }
|
||||
else
|
||||
{ sgn = 1; }
|
||||
return sgn * ((Math.Abs(x) / 3600) / 360 - Math.Floor((Math.Abs(x) / 3600.0) / 360.0)) * 360;
|
||||
}
|
||||
private static double FNu(double x)
|
||||
{ return x - (Math.Floor(x / 360) * 360); }
|
||||
private static double FNr(double x)
|
||||
{ return Math.PI / 180 * x; }
|
||||
private static double FNs(double x)
|
||||
{ return Math.Sin(Math.PI / 180 * x); }
|
||||
|
||||
//v1.1.3 Formulas
|
||||
//The following formulas are either additions
|
||||
//or conversions of SunCalcs formulas into Meeus
|
||||
|
||||
/// <summary>
|
||||
/// Grabs Perigee or Apogee of Moon based on specified time.
|
||||
/// Results will return event just before, or just after specified DateTime
|
||||
/// </summary>
|
||||
/// <param name="d">DateTime</param>
|
||||
/// <param name="md">Event Type</param>
|
||||
/// <returns>PerigeeApogee</returns>
|
||||
private static PerigeeApogee MoonPerigeeOrApogee(DateTime d, MoonDistanceType md)
|
||||
{
|
||||
//Perigee & Apogee Algorithms from Jean Meeus Astronomical Algorithms Ch. 50
|
||||
|
||||
//50.1
|
||||
//JDE = 2451534.6698 + 27.55454989 * k
|
||||
// -0.0006691 * Math.Pow(T,2)
|
||||
// -0.000.01098 * Math.Pow(T,3)
|
||||
// -0.0000000052 * Math.Pow(T,4)
|
||||
|
||||
//50.2
|
||||
//K approx = (yv - 1999.97)*13.2555
|
||||
//yv is the year + percentage of days that have occured in the year. 1998 Oct 1 is approx 1998.75
|
||||
//k ending in .0 represent perigee and .5 apogee. Anything > .5 is an error.
|
||||
|
||||
//50.3
|
||||
//T = k/1325.55
|
||||
|
||||
double yt = 365; //days in year
|
||||
if (DateTime.IsLeapYear(d.Year)) { yt = 366; } //days in year if leap year
|
||||
double f = d.DayOfYear / yt; //Get percentage of year that as passed
|
||||
double yv = d.Year + f; //add percentage of year passed to year.
|
||||
double k = (yv - 1999.97) * 13.2555; //find approximate k using formula 50.2
|
||||
|
||||
//Set k decimal based on apogee or perigee
|
||||
if (md == MoonDistanceType.Apogee)
|
||||
{
|
||||
k = Math.Floor(k) + .5;
|
||||
}
|
||||
else
|
||||
{
|
||||
k = Math.Floor(k);
|
||||
}
|
||||
|
||||
//Find T using formula 50.3
|
||||
double T = k / 1325.55;
|
||||
//Find JDE using formula 50.1
|
||||
double JDE = 2451534.6698 + 27.55454989 * k -
|
||||
0.0006691 * Math.Pow(T, 2) -
|
||||
0.00001098 * Math.Pow(T, 3) -
|
||||
0.0000000052 * Math.Pow(T, 4);
|
||||
|
||||
//Find Moon's mean elongation at time JDE.
|
||||
double D = 171.9179 + 335.9106046 * k -
|
||||
0.0100383 * Math.Pow(T, 2) -
|
||||
0.00001156 * Math.Pow(T, 3) +
|
||||
0.000000055 * Math.Pow(T, 4);
|
||||
|
||||
//Find Sun's mean anomaly at time JDE
|
||||
double M = 347.3477 + 27.1577721 * k -
|
||||
0.0008130 * Math.Pow(T, 2) -
|
||||
0.0000010 * Math.Pow(T, 3);
|
||||
|
||||
|
||||
//Find Moon's argument of latitude at Time JDE
|
||||
double F = 316.6109 + 364.5287911 * k -
|
||||
0.0125053 * Math.Pow(T, 2) -
|
||||
0.0000148 * Math.Pow(T, 3);
|
||||
|
||||
//Normalize DMF to a 0-360 degree number
|
||||
D %= 360;
|
||||
if (D < 0) { D += 360; }
|
||||
M %= 360;
|
||||
if (M < 0) { M += 360; }
|
||||
F %= 360;
|
||||
if (F < 0) { F += 360; }
|
||||
|
||||
//Convert DMF to radians
|
||||
D = D * Math.PI / 180;
|
||||
M = M * Math.PI / 180;
|
||||
F = F * Math.PI / 180;
|
||||
double termsA;
|
||||
//Find Terms A from Table 50.A
|
||||
if (md == MoonDistanceType.Apogee)
|
||||
{
|
||||
termsA = MeeusTables.ApogeeTermsA(D, M, F, T);
|
||||
}
|
||||
else
|
||||
{
|
||||
termsA = MeeusTables.PerigeeTermsA(D, M, F, T);
|
||||
}
|
||||
JDE += termsA;
|
||||
double termsB;
|
||||
if (md == MoonDistanceType.Apogee)
|
||||
{
|
||||
termsB = MeeusTables.ApogeeTermsB(D, M, F, T);
|
||||
}
|
||||
else
|
||||
{
|
||||
termsB = MeeusTables.PerigeeTermsB(D, M, F, T);
|
||||
}
|
||||
//Convert julian back to date
|
||||
DateTime date = JulianConversions.GetDate_FromJulian(JDE).Value;
|
||||
//Obtain distance
|
||||
Distance dist = GetMoonDistance(date);
|
||||
|
||||
PerigeeApogee ap = new PerigeeApogee(date, termsB, dist);
|
||||
return ap;
|
||||
}
|
||||
|
||||
public static Perigee GetPerigeeEvents(DateTime d)
|
||||
{
|
||||
//Iterate in 15 day increments due to formula variations.
|
||||
//Determine closest events to date.
|
||||
//per1 is last date
|
||||
//per2 is next date
|
||||
|
||||
//integrity for new date.
|
||||
if (d.Year <= 0001) { return new Perigee(new PerigeeApogee(new DateTime(), 0, new Distance(0)), new PerigeeApogee(new DateTime(), 0, new Distance(0))); }
|
||||
//Start at lowest increment
|
||||
PerigeeApogee per1 = MoonPerigeeOrApogee(d.AddDays(-45), MoonDistanceType.Perigee);
|
||||
PerigeeApogee per2 = MoonPerigeeOrApogee(d.AddDays(-45), MoonDistanceType.Perigee);
|
||||
|
||||
for (int x = -30; x <= 45; x+=15)
|
||||
{
|
||||
//used for comparison
|
||||
PerigeeApogee t = MoonPerigeeOrApogee(d.AddDays(x), MoonDistanceType.Perigee);
|
||||
|
||||
//Find the next pergiee after specified date
|
||||
if (t.Date > per2.Date && t.Date >= d)
|
||||
{
|
||||
per2 = t;
|
||||
break;
|
||||
}
|
||||
//Find last perigee before specified date
|
||||
if (t.Date > per1.Date && t.Date < d)
|
||||
{
|
||||
per1 = t;
|
||||
per2 = t;
|
||||
}
|
||||
|
||||
}
|
||||
return new Perigee(per1, per2);
|
||||
}
|
||||
public static Apogee GetApogeeEvents(DateTime d)
|
||||
{
|
||||
//Iterate in 5 month increments due to formula variations.
|
||||
//Determine closest events to date.
|
||||
//apo1 is last date
|
||||
//apo2 is next date
|
||||
|
||||
//integrity for new date.
|
||||
if (d.Year <= 0001) { return new Apogee(new PerigeeApogee(new DateTime(), 0, new Distance(0)), new PerigeeApogee(new DateTime(), 0, new Distance(0))); }
|
||||
|
||||
PerigeeApogee apo1 = MoonPerigeeOrApogee(d.AddDays(-45), MoonDistanceType.Apogee);
|
||||
PerigeeApogee apo2 = MoonPerigeeOrApogee(d.AddDays(-45), MoonDistanceType.Apogee);
|
||||
for (int x = -30; x <= 45; x+=15)
|
||||
{
|
||||
PerigeeApogee t = MoonPerigeeOrApogee(d.AddDays(x), MoonDistanceType.Apogee);
|
||||
//Find next apogee after specified date
|
||||
if (t.Date > apo2.Date && t.Date >= d)
|
||||
{
|
||||
apo2 = t;
|
||||
break;
|
||||
}
|
||||
//Find last apogee before specified date
|
||||
if (t.Date > apo1.Date && t.Date < d)
|
||||
{
|
||||
apo1 = t;
|
||||
apo2 = t;
|
||||
}
|
||||
|
||||
}
|
||||
return new Apogee(apo1, apo2);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets moon distance (Ch 47).
|
||||
/// </summary>
|
||||
/// <param name="d">DateTime</param>
|
||||
/// <returns>Distance</returns>
|
||||
public static Distance GetMoonDistance(DateTime d)
|
||||
{
|
||||
//Ch 47
|
||||
double JDE = JulianConversions.GetJulian(d);//Get julian
|
||||
double T = (JDE - 2451545) / 36525; //Get dynamic time.
|
||||
|
||||
double[] values = Get_Moon_LDMNF(T);
|
||||
|
||||
double D = values[1];
|
||||
double M = values[2];
|
||||
double N = values[3];
|
||||
double F = values[4];
|
||||
|
||||
//Ch 47 distance formula
|
||||
double dist = 385000.56 + (MeeusTables.Moon_Periodic_Er(D, M, N, F, T) / 1000);
|
||||
return new Distance(dist);
|
||||
}
|
||||
|
||||
private static Distance GetMoonDistance(DateTime d, double[] values)
|
||||
{
|
||||
//Ch 47
|
||||
double JDE = JulianConversions.GetJulian(d);//Get julian
|
||||
double T = (JDE - 2451545) / 36525; //Get dynamic time.
|
||||
|
||||
double D = values[1];
|
||||
double M = values[2];
|
||||
double N = values[3];
|
||||
double F = values[4];
|
||||
|
||||
double dist = 385000.56 + (MeeusTables.Moon_Periodic_Er(D, M, N, F, T) / 1000);
|
||||
return new Distance(dist);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets Moon L, D, M, N, F values
|
||||
/// Ch. 47
|
||||
/// </summary>
|
||||
/// <param name="T">Dynamic Time</param>
|
||||
/// <returns>double[] containing L,D,M,N,F</returns>
|
||||
static double[] Get_Moon_LDMNF(double T)
|
||||
{
|
||||
//T = dynamic time
|
||||
|
||||
//Moon's mean longitude
|
||||
double L = 218.316447 + 481267.88123421 * T -
|
||||
.0015786 * Math.Pow(T, 2) + Math.Pow(T, 3) / 538841 -
|
||||
Math.Pow(T, 4) / 65194000;
|
||||
|
||||
//Moon's mean elongation
|
||||
double D = 297.8501921 + 445267.1114034 * T -
|
||||
0.0018819 * Math.Pow(T, 2) + Math.Pow(T, 3) / 545868 - Math.Pow(T, 4) / 113065000;
|
||||
//Sun's mean anomaly
|
||||
double M = 357.5291092 + 35999.0502909 * T -
|
||||
.0001536 * Math.Pow(T, 2) + Math.Pow(T, 3) / 24490000;
|
||||
//Moon's mean anomaly
|
||||
double N = 134.9633964 + 477198.8675055 * T + .0087414 * Math.Pow(T, 2) +
|
||||
Math.Pow(T, 3) / 69699 - Math.Pow(T, 4) / 14712000;
|
||||
//Moon's argument of latitude
|
||||
double F = 93.2720950 + 483202.0175233 * T - .0036539 * Math.Pow(T, 2) - Math.Pow(T, 3) /
|
||||
3526000 + Math.Pow(T, 4) / 863310000;
|
||||
|
||||
//Normalize DMF to a 0-360 degree number
|
||||
D %= 360;
|
||||
if (D < 0) { D += 360; }
|
||||
M %= 360;
|
||||
if (M < 0) { M += 360; }
|
||||
N %= 360;
|
||||
if (N < 0) { N += 360; }
|
||||
F %= 360;
|
||||
if (F < 0) { F += 360; }
|
||||
|
||||
//Convert DMF to radians
|
||||
|
||||
D = D * Math.PI / 180;
|
||||
M = M * Math.PI / 180;
|
||||
N = N * Math.PI / 180;
|
||||
F = F * Math.PI / 180;
|
||||
|
||||
return new double[] { L, D, M, N, F };
|
||||
}
|
||||
/// <summary>
|
||||
/// Get moons lat/long in radians (Ch 47).
|
||||
/// </summary>
|
||||
/// <param name="LDMNF">L,D,M,N,F</param>
|
||||
/// <param name="T">Dynamic Time</param>
|
||||
/// <returns>Lat[0], Long[1]</returns>
|
||||
private static double[] Get_Moon_Coordinates(double[] LDMNF,double T)
|
||||
{
|
||||
//Refence Ch 47.
|
||||
double lat = LDMNF[0] + (MeeusTables.Moon_Periodic_El(LDMNF[0], LDMNF[1], LDMNF[2], LDMNF[3], LDMNF[4],T)/1000000);
|
||||
double longi = MeeusTables.Moon_Periodic_Eb(LDMNF[0], LDMNF[1], LDMNF[2], LDMNF[3], LDMNF[4], T) / 1000000;
|
||||
lat %= 360;
|
||||
if (lat < 0) { lat += 360; }
|
||||
|
||||
//Convert to radians
|
||||
double l = rad * lat; // longitude
|
||||
double b = rad * longi; // latitude
|
||||
|
||||
return new double[] { l, b };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets right Ascension of celestial object (Ch 13 Fig 13.3)
|
||||
/// </summary>
|
||||
/// <param name="l">latitude in radians</param>
|
||||
/// <param name="b">longitude in radian</param>
|
||||
/// <returns>Right Ascension</returns>
|
||||
private static double rightAscension(double l, double b)
|
||||
{
|
||||
//Ch 13 Fig 13.3
|
||||
//tan a = ( sin(l) * cos(e) - tan(b)-sin(e) ) / cons(l)
|
||||
//Converts to the following using Atan2 for 4 quadriatic regions
|
||||
return Math.Atan2(Math.Sin(l) * Math.Cos(e) - Math.Tan(b) * Math.Sin(e), Math.Cos(l));
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets declination of celestial object (Ch 13 Fig 13.4)
|
||||
/// </summary>
|
||||
/// <param name="l">latitude in radians</param>
|
||||
/// <param name="b">longitude in radian</param>
|
||||
/// <returns>Declination</returns>
|
||||
private static double declination(double l, double b)
|
||||
{
|
||||
//Ch 13 Fig 13.4
|
||||
//sin o = sin(b) * cos(e) + cos(b)*sin(e) * sin(l)
|
||||
//Converts to the following using Asin
|
||||
return Math.Asin(Math.Sin(b) * Math.Cos(e) + Math.Cos(b) * Math.Sin(e) * Math.Sin(l));
|
||||
}
|
||||
|
||||
static double Parallax_Dec(double distance, double H, double pCosE, double pSinE, double dec, double cRA)
|
||||
{
|
||||
//Ch 40 (Correction for parallax
|
||||
//H - geocentric hour angle of the body (sidereal) IAW Ch 12
|
||||
double pi = Math.Asin((Math.Sin(8.794 / distance))) * Math.PI / 180; // 40.1 in radians
|
||||
H = H * Math.PI / 180;
|
||||
//Directly to topocencric dec
|
||||
double tDEC = Math.Atan2((Math.Sin(dec) - pSinE * Math.Sin(pi)) * Math.Cos(cRA), Math.Cos(dec) - pCosE * Math.Sin(pi) * Math.Cos(H));
|
||||
return tDEC;
|
||||
|
||||
}
|
||||
static double Parallax_RA(double distance, double H, double pCosE, double dec, double ra)
|
||||
{
|
||||
//ENSURE RADIANS
|
||||
|
||||
//Ch 40 (Correction for parallax
|
||||
//H - geocentric hour angle of the body (sidereal) IAW Ch 12
|
||||
|
||||
double pi = Math.Asin((Math.Sin(8.794 / distance))) * Math.PI / 180; // 40.1
|
||||
|
||||
|
||||
//Convert to Radian
|
||||
double t = -pCosE * Math.Sin(pi) * Math.Sin(H);
|
||||
double b = Math.Cos(dec) - pCosE * Math.Sin(pi) * Math.Cos(H);
|
||||
double cRA = Math.Atan2(t, b);
|
||||
return cRA;
|
||||
//Topocencric RA = RA - cRA
|
||||
}
|
||||
static double Get_pSinE(double dec, double H)
|
||||
{
|
||||
//ASSUME WGS 84 FOR NOW
|
||||
double a = 6378.14;
|
||||
double f = 1 / 298.257;
|
||||
double b = a * (1 - f);
|
||||
double ba = .99664719; // or 1-f
|
||||
double u = (ba * dec) * Math.PI / 180;
|
||||
|
||||
double ps = ba * Math.Sin(u) + (H / 6378140) * Math.Sin(dec);
|
||||
return ps;
|
||||
|
||||
}
|
||||
static double Get_pCosE(double dec, double H)
|
||||
{
|
||||
//ASSUME WGS 84 FOR NOW
|
||||
double a = 6378.14;
|
||||
double f = 1 / 298.257;
|
||||
double b = a * (1 - f);
|
||||
double ba = .99664719; // or 1-f
|
||||
double u = (ba * dec) * Math.PI / 180;
|
||||
|
||||
double ps = Math.Cos(u) + (H / 6378140) * Math.Cos(dec);
|
||||
return ps;
|
||||
}
|
||||
|
||||
static double azimuth(double H, double phi, double dec) { return Math.Atan2(Math.Sin(H), Math.Cos(H) * Math.Sin(phi) - Math.Tan(dec) * Math.Cos(phi)); }
|
||||
static double altitude(double H, double phi, double dec)
|
||||
{
|
||||
return Math.Asin(Math.Sin(phi) * Math.Sin(dec) + Math.Cos(phi) * Math.Cos(dec) * Math.Cos(H));
|
||||
}
|
||||
static double astroRefraction(double h)
|
||||
{
|
||||
//CH 16
|
||||
double P = 1013.25; //Average pressure of earth
|
||||
double T = 16; //Average temp of earth
|
||||
double alt = h / Math.PI * 180;
|
||||
double Ref = P * (.1594 + .0196 * alt + .00002 * Math.Pow(alt, 2)) / ((273 + T) * (1 + .505 * alt + .0845 * Math.Pow(alt, 2)));
|
||||
return Ref / 60;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,971 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
//CURRENT ALTITUDE IS SET CONSTANT AT 100M. POSSIBLY NEED TO ADJUST TO ALLOW USER PASS.
|
||||
//Altitude adjustments appear to have minimal effect on eclipse timing. These were mainly used
|
||||
//to signify eclipses that had already started during rise and set times on the NASA calculator
|
||||
|
||||
//SOME TIMES AND ALTS WERE RETURNED WITH COLOR AND STYLING. DETERMINE WHY AND ADJUST VALUE AS REQUIRED. SEARCH "WAS ITALIC".
|
||||
|
||||
//ELLIPSOID ADJUSTMENT
|
||||
//6378140.0 Ellipsoid is used in the NASA Calculator
|
||||
//WGS84 Ellipsoid is 6378137.0. Adjustments to the ellipsoid appear to effect eclipse seconds in fractions.
|
||||
//This can be modified if need to allow users to pass custom number with the Coordinate SetDatum() functions.
|
||||
|
||||
//CURRENT RANGE 1601-2600.
|
||||
internal class SolarEclipseCalc
|
||||
{
|
||||
public static List<List<string>> CalculateSolarEclipse(DateTime d, double latRad, double longRad)
|
||||
{
|
||||
return Calculate(d, latRad, longRad, null);
|
||||
}
|
||||
public static List<SolarEclipseDetails> CalculateSolarEclipse(DateTime d, double latRad, double longRad, double[] events)
|
||||
{
|
||||
List<List<string>> evs = Calculate(d, latRad, longRad, events);
|
||||
List<SolarEclipseDetails> deetsList = new List<SolarEclipseDetails>();
|
||||
foreach(List<string> ls in evs)
|
||||
{
|
||||
SolarEclipseDetails deets = new SolarEclipseDetails(ls);
|
||||
deetsList.Add(deets);
|
||||
}
|
||||
return deetsList;
|
||||
}
|
||||
public static List<List<string>> CalculateSolarEclipse(DateTime d, Coordinate coord)
|
||||
{
|
||||
return Calculate(d, coord.Latitude.ToRadians(), coord.Longitude.ToRadians(), null);
|
||||
}
|
||||
|
||||
private static List<List<string>> Calculate(DateTime d, double latRad, double longRad, double[] ev)
|
||||
{
|
||||
//Declare storage arrays
|
||||
double[] obsvconst = new double[7];
|
||||
double[] mid = new double[41];//Check index to see if array needs to be this size
|
||||
double[] c1 = new double[41];
|
||||
double[] c2 = new double[41];
|
||||
double[] c3 = new double[41];
|
||||
double[] c4 = new double[41];
|
||||
|
||||
List<List<string>> events = new List<List<string>>();
|
||||
double[] el;
|
||||
if (ev == null)
|
||||
{
|
||||
el = Eclipse.SolarData.SolarDateData(d);//Get 100 year solar data;
|
||||
}
|
||||
else
|
||||
{
|
||||
el = ev;
|
||||
}
|
||||
|
||||
events = new List<List<string>>();
|
||||
ReadData(latRad, longRad, obsvconst);
|
||||
for (int i = 0; i < el.Length; i += 28)
|
||||
{
|
||||
obsvconst[6] = i;
|
||||
GetAll(el, obsvconst, mid,c1,c2,c3,c4);
|
||||
// Is there an event...
|
||||
if (mid[39] > 0)
|
||||
{
|
||||
List<string> values = new List<string>();
|
||||
values.Add(GetDate(el, mid, obsvconst));
|
||||
if (mid[39] == 1)
|
||||
{
|
||||
values.Add("P");
|
||||
}
|
||||
else if (mid[39] == 2)
|
||||
{
|
||||
values.Add("A");
|
||||
}
|
||||
else
|
||||
{
|
||||
values.Add("T");
|
||||
}
|
||||
|
||||
// Partial eclipse start
|
||||
if (c1[40] == 4)
|
||||
{
|
||||
values.Add("-");
|
||||
values.Add(" ");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Partial eclipse start time
|
||||
values.Add(GetTime(el, c1, obsvconst));
|
||||
values.Add(GetAlt(c1));
|
||||
}
|
||||
// Central eclipse time
|
||||
if ((mid[39] > 1) && (c2[40] != 4))
|
||||
{
|
||||
values.Add(GetTime(el, c2, obsvconst));
|
||||
}
|
||||
else
|
||||
{
|
||||
values.Add("-");
|
||||
}
|
||||
|
||||
//Mid Time
|
||||
values.Add(GetTime(el, mid, obsvconst));
|
||||
|
||||
// Maximum eclipse alt
|
||||
values.Add(GetAlt(mid));
|
||||
|
||||
// Maximum eclipse azi
|
||||
values.Add(GetAzi(mid));
|
||||
// Central eclipse ends
|
||||
if ((mid[39] > 1) && (c3[40] != 4))
|
||||
{
|
||||
values.Add(GetTime(el, c3, obsvconst));
|
||||
}
|
||||
else
|
||||
{
|
||||
values.Add("-");
|
||||
}
|
||||
// Partial eclipse ends
|
||||
if (c4[40] == 4)
|
||||
{
|
||||
values.Add("-");
|
||||
values.Add(" ");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Partial eclipse ends
|
||||
values.Add(GetTime(el, c4, obsvconst));
|
||||
|
||||
// ... sun alt
|
||||
values.Add(GetAlt(c4));
|
||||
}
|
||||
// Eclipse magnitude
|
||||
values.Add(GetMagnitude(mid));
|
||||
|
||||
|
||||
// Coverage
|
||||
values.Add(GetCoverage(mid));
|
||||
|
||||
// Central duration
|
||||
if (mid[39] > 1)
|
||||
{
|
||||
values.Add(GetDuration(mid,c2,c3));
|
||||
}
|
||||
else
|
||||
{
|
||||
values.Add("-");
|
||||
}
|
||||
|
||||
events.Add(values);
|
||||
}
|
||||
}
|
||||
return events;
|
||||
}
|
||||
//Populates the obsvcont array
|
||||
private static void ReadData(double latRad, double longRad, double[] obsvconst)
|
||||
{
|
||||
// Get the latitude
|
||||
obsvconst[0] = latRad;
|
||||
|
||||
//// Get the longitude
|
||||
obsvconst[1] = -1 * longRad; //PASS REVERSE RADIAN.
|
||||
|
||||
// Get the altitude
|
||||
obsvconst[2] = 100; //CHANGE TO ALLOW USER TO PASS.
|
||||
|
||||
// Get the time zone
|
||||
obsvconst[3] = 0; //ALWAYS GMT
|
||||
|
||||
// Get the observer's geocentric position
|
||||
double tmp = Math.Atan(0.99664719 * Math.Tan(obsvconst[0]));
|
||||
obsvconst[4] = 0.99664719 * Math.Sin(tmp) + (obsvconst[2] / 6378140.0) * Math.Sin(obsvconst[0]);
|
||||
obsvconst[5] = Math.Cos(tmp) + (obsvconst[2] / 6378140.0 * Math.Cos(obsvconst[0]));
|
||||
|
||||
}
|
||||
// Populate the c1, c2, mid, c3 and c4 arrays
|
||||
private static void GetAll(double[] elements, double[] obsvconst, double[] mid, double[] c1, double[] c2,double[] c3, double[] c4)
|
||||
{
|
||||
GetMid(elements, obsvconst, mid);
|
||||
MidObservational(obsvconst, mid);
|
||||
if (mid[37] > 0.0)
|
||||
{
|
||||
Getc1c4(elements, obsvconst, mid,c1,c2,c3,c4);
|
||||
if ((mid[36] < mid[29]) || (mid[36] < -mid[29]))
|
||||
{
|
||||
Getc2c3(elements, obsvconst, mid,c2,c3);
|
||||
if (mid[29] < 0.0)
|
||||
{
|
||||
mid[39] = 3; // Total eclipse
|
||||
}
|
||||
else
|
||||
{
|
||||
mid[39] = 2; // Annular eclipse
|
||||
}
|
||||
Observational(c1, obsvconst, mid);
|
||||
Observational(c2, obsvconst, mid);
|
||||
Observational(c3, obsvconst, mid);
|
||||
Observational(c4, obsvconst, mid);
|
||||
c2[36] = 999.9;
|
||||
c3[36] = 999.9;
|
||||
// Calculate how much of the eclipse is above the horizon
|
||||
double pattern = 0;
|
||||
if (c1[40] == 0) { pattern += 10000; }
|
||||
if (c2[40] == 0) { pattern += 1000; }
|
||||
if (mid[40] == 0) { pattern += 100; }
|
||||
if (c3[40] == 0) { pattern += 10; }
|
||||
if (c4[40] == 0) { pattern += 1; }
|
||||
// Now, time to make sure that all my Observational[39] and Observational[40] are OK
|
||||
if (pattern == 11110)
|
||||
{
|
||||
GetSunset(elements, c4, obsvconst);
|
||||
Observational(c4, obsvconst, mid);
|
||||
c4[40] = 3;
|
||||
}
|
||||
else if (pattern == 11100)
|
||||
{
|
||||
GetSunset(elements, c3, obsvconst);
|
||||
Observational(c3, obsvconst, mid);
|
||||
c3[40] = 3;
|
||||
CopyCircumstances(c3, c4);
|
||||
}
|
||||
else if (pattern == 11000)
|
||||
{
|
||||
c3[40] = 4;
|
||||
GetSunset(elements, mid, obsvconst);
|
||||
MidObservational(obsvconst, mid);
|
||||
mid[40] = 3;
|
||||
CopyCircumstances(mid, c4);
|
||||
}
|
||||
else if (pattern == 10000)
|
||||
{
|
||||
mid[39] = 1;
|
||||
GetSunset(elements, mid, obsvconst);
|
||||
MidObservational(obsvconst, mid);
|
||||
mid[40] = 3;
|
||||
CopyCircumstances(mid, c4);
|
||||
}
|
||||
else if (pattern == 1111)
|
||||
{
|
||||
GetSunrise(elements, c1, obsvconst);
|
||||
Observational(c1, obsvconst, mid);
|
||||
c1[40] = 2;
|
||||
}
|
||||
else if (pattern == 111)
|
||||
{
|
||||
GetSunrise(elements, c2, obsvconst);
|
||||
Observational(c2, obsvconst, mid);
|
||||
c2[40] = 2;
|
||||
CopyCircumstances(c2, c1);
|
||||
}
|
||||
else if (pattern == 11)
|
||||
{
|
||||
c2[40] = 4;
|
||||
GetSunrise(elements, mid, obsvconst);
|
||||
MidObservational(obsvconst, mid);
|
||||
mid[40] = 2;
|
||||
CopyCircumstances(mid, c1);
|
||||
}
|
||||
else if (pattern == 1)
|
||||
{
|
||||
mid[39] = 1;
|
||||
GetSunrise(elements, mid, obsvconst);
|
||||
MidObservational(obsvconst, mid);
|
||||
mid[40] = 2;
|
||||
CopyCircumstances(mid, c1);
|
||||
}
|
||||
else if (pattern == 0)
|
||||
{
|
||||
mid[39] = 0;
|
||||
}
|
||||
// There are other patterns, but those are the only ones we're covering!
|
||||
}
|
||||
else
|
||||
{
|
||||
mid[39] = 1; // Partial eclipse
|
||||
double pattern = 0;
|
||||
Observational(c1, obsvconst, mid);
|
||||
Observational(c4, obsvconst, mid);
|
||||
if (c1[40] == 0) { pattern += 100; }
|
||||
if (mid[40] == 0) { pattern += 10; }
|
||||
if (c4[40] == 0) { pattern += 1; }
|
||||
if (pattern == 110)
|
||||
{
|
||||
GetSunset(elements, c4, obsvconst);
|
||||
Observational(c4, obsvconst, mid);
|
||||
c4[40] = 3;
|
||||
}
|
||||
else if (pattern == 100)
|
||||
{
|
||||
GetSunset(elements, mid, obsvconst);
|
||||
MidObservational(obsvconst, mid);
|
||||
mid[40] = 3;
|
||||
CopyCircumstances(mid, c4);
|
||||
}
|
||||
else if (pattern == 11)
|
||||
{
|
||||
GetSunrise(elements, c1, obsvconst);
|
||||
Observational(c1, obsvconst, mid);
|
||||
c1[40] = 2;
|
||||
}
|
||||
else if (pattern == 1)
|
||||
{
|
||||
GetSunrise(elements, mid, obsvconst);
|
||||
MidObservational(obsvconst, mid);
|
||||
mid[40] = 2;
|
||||
CopyCircumstances(mid, c1);
|
||||
}
|
||||
else if (pattern == 0)
|
||||
{
|
||||
mid[39] = 0;
|
||||
}
|
||||
// There are other patterns, but those are the only ones we're covering!
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mid[39] = 0; // No eclipse
|
||||
}
|
||||
// Magnitude for total and annular eclipse is moon/sun ratio
|
||||
if ((mid[39] == 2) || (mid[39] == 3))
|
||||
{
|
||||
mid[37] = mid[38];
|
||||
}
|
||||
}
|
||||
// Calculate mid eclipse
|
||||
private static void GetMid(double[] elements, double[] obsvconst, double[] mid)
|
||||
{
|
||||
double iter, tmp;
|
||||
|
||||
mid[0] = 0;
|
||||
mid[1] = 0.0;
|
||||
iter = 0;
|
||||
tmp = 1.0;
|
||||
TimeLocDependent(elements, mid, obsvconst);
|
||||
while (((tmp > 0.000001) || (tmp < -0.000001)) && (iter < 50))
|
||||
{
|
||||
tmp = (mid[24] * mid[26] + mid[25] * mid[27]) / mid[30];
|
||||
mid[1] = mid[1] - tmp;
|
||||
iter++;
|
||||
TimeLocDependent(elements, mid, obsvconst);
|
||||
}
|
||||
}
|
||||
// Populate the circumstances array with the time and location dependent circumstances
|
||||
private static double[] TimeLocDependent(double[] elements, double[] circumstances, double[] obsvconst)
|
||||
{
|
||||
double index, type;
|
||||
|
||||
TimeDependent(elements, circumstances, obsvconst);
|
||||
index = obsvconst[6];
|
||||
// Calculate h, sin h, cos h
|
||||
circumstances[16] = circumstances[7] - obsvconst[1] - (elements[(int)index + 5] / 13713.44);
|
||||
circumstances[17] = Math.Sin(circumstances[16]);
|
||||
circumstances[18] = Math.Cos(circumstances[16]);
|
||||
// Calculate xi
|
||||
circumstances[19] = obsvconst[5] * circumstances[17];
|
||||
// Calculate eta
|
||||
circumstances[20] = obsvconst[4] * circumstances[6] - obsvconst[5] * circumstances[18] * circumstances[5];
|
||||
// Calculate zeta
|
||||
circumstances[21] = obsvconst[4] * circumstances[5] + obsvconst[5] * circumstances[18] * circumstances[6];
|
||||
// Calculate dxi
|
||||
circumstances[22] = circumstances[13] * obsvconst[5] * circumstances[18];
|
||||
// Calculate deta
|
||||
circumstances[23] = circumstances[13] * circumstances[19] * circumstances[5] - circumstances[21] * circumstances[12];
|
||||
// Calculate u
|
||||
circumstances[24] = circumstances[2] - circumstances[19];
|
||||
// Calculate v
|
||||
circumstances[25] = circumstances[3] - circumstances[20];
|
||||
// Calculate a
|
||||
circumstances[26] = circumstances[10] - circumstances[22];
|
||||
// Calculate b
|
||||
circumstances[27] = circumstances[11] - circumstances[23];
|
||||
// Calculate l1'
|
||||
type = circumstances[0];
|
||||
if ((type == -2) || (type == 0) || (type == 2))
|
||||
{
|
||||
circumstances[28] = circumstances[8] - circumstances[21] * elements[26 + (int)index];
|
||||
}
|
||||
// Calculate l2'
|
||||
if ((type == -1) || (type == 0) || (type == 1))
|
||||
{
|
||||
circumstances[29] = circumstances[9] - circumstances[21] * elements[27 + (int)index];
|
||||
}
|
||||
// Calculate n^2
|
||||
circumstances[30] = circumstances[26] * circumstances[26] + circumstances[27] * circumstances[27];
|
||||
return circumstances;
|
||||
}
|
||||
// Populate the circumstances array with the time-only dependent circumstances (x, y, d, m, ...)
|
||||
private static double[] TimeDependent(double[] elements, double[] circumstances, double[] obsvconst)
|
||||
{
|
||||
double type, t, ans;
|
||||
|
||||
t = circumstances[1];
|
||||
int index = (int)obsvconst[6];
|
||||
// Calculate x
|
||||
ans = elements[9 + index] * t + elements[8 + index];
|
||||
ans = ans * t + elements[7 + index];
|
||||
ans = ans * t + elements[6 + index];
|
||||
circumstances[2] = ans;
|
||||
// Calculate dx
|
||||
ans = 3.0 * elements[9 + index] * t + 2.0 * elements[8 + index];
|
||||
ans = ans * t + elements[7 + index];
|
||||
circumstances[10] = ans;
|
||||
// Calculate y
|
||||
ans = elements[13 + index] * t + elements[12 + index];
|
||||
ans = ans * t + elements[11 + index];
|
||||
ans = ans * t + elements[10 + index];
|
||||
circumstances[3] = ans;
|
||||
// Calculate dy
|
||||
ans = 3.0 * elements[13 + index] * t + 2.0 * elements[12 + index];
|
||||
ans = ans * t + elements[11 + index];
|
||||
circumstances[11] = ans;
|
||||
// Calculate d
|
||||
ans = elements[16 + index] * t + elements[15 + index];
|
||||
ans = ans * t + elements[14 + index];
|
||||
ans = ans * Math.PI / 180.0;
|
||||
circumstances[4] = ans;
|
||||
// sin d and cos d
|
||||
circumstances[5] = Math.Sin(ans);
|
||||
circumstances[6] = Math.Cos(ans);
|
||||
// Calculate dd
|
||||
ans = 2.0 * elements[16 + index] * t + elements[15 + index];
|
||||
ans = ans * Math.PI / 180.0;
|
||||
circumstances[12] = ans;
|
||||
// Calculate m
|
||||
ans = elements[19 + index] * t + elements[18 + index];
|
||||
ans = ans * t + elements[17 + index];
|
||||
if (ans >= 360.0)
|
||||
{
|
||||
ans = ans - 360.0;
|
||||
}
|
||||
ans = ans * Math.PI / 180.0;
|
||||
circumstances[7] = ans;
|
||||
// Calculate dm
|
||||
ans = 2.0 * elements[19 + index] * t + elements[18 + index];
|
||||
ans = ans * Math.PI / 180.0;
|
||||
circumstances[13] = ans;
|
||||
// Calculate l1 and dl1
|
||||
type = circumstances[0];
|
||||
if ((type == -2) || (type == 0) || (type == 2))
|
||||
{
|
||||
ans = elements[22 + index] * t + elements[21 + index];
|
||||
ans = ans * t + elements[20 + index];
|
||||
circumstances[8] = ans;
|
||||
circumstances[14] = 2.0 * elements[22 + index] * t + elements[21 + index];
|
||||
}
|
||||
// Calculate l2 and dl2
|
||||
if ((type == -1) || (type == 0) || (type == 1))
|
||||
{
|
||||
ans = elements[25 + index] * t + elements[24 + index];
|
||||
ans = ans * t + elements[23 + index];
|
||||
circumstances[9] = ans;
|
||||
circumstances[15] = 2.0 * elements[25 + index] * t + elements[24 + index];
|
||||
}
|
||||
return circumstances;
|
||||
}
|
||||
// Get the observational circumstances for mid eclipse
|
||||
private static void MidObservational(double[] obsvconst, double[] mid)
|
||||
{
|
||||
Observational(mid, obsvconst, mid);
|
||||
// Calculate m, magnitude and moon/sun
|
||||
mid[36] = Math.Sqrt(mid[24] * mid[24] + mid[25] * mid[25]);
|
||||
mid[37] = (mid[28] - mid[36]) / (mid[28] + mid[29]);
|
||||
mid[38] = (mid[28] - mid[29]) / (mid[28] + mid[29]);
|
||||
}
|
||||
// Get the observational circumstances
|
||||
private static void Observational(double[] circumstances, double[] obsvconst, double[] mid)
|
||||
{
|
||||
double contacttype, coslat, sinlat;
|
||||
|
||||
// We are looking at an "external" contact UNLESS this is a total eclipse AND we are looking at
|
||||
// c2 or c3, in which case it is an INTERNAL contact! Note that if we are looking at mid eclipse,
|
||||
// then we may not have determined the type of eclipse (mid[39]) just yet!
|
||||
if (circumstances[0] == 0)
|
||||
{
|
||||
contacttype = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((mid[39] == 3) && ((circumstances[0] == -1) || (circumstances[0] == 1)))
|
||||
{
|
||||
contacttype = -1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
contacttype = 1.0;
|
||||
}
|
||||
}
|
||||
// Calculate p
|
||||
circumstances[31] = Math.Atan2(contacttype * circumstances[24], contacttype * circumstances[25]);
|
||||
// Calculate alt
|
||||
sinlat = Math.Sin(obsvconst[0]);
|
||||
coslat = Math.Cos(obsvconst[0]);
|
||||
circumstances[32] = Math.Asin(circumstances[5] * sinlat + circumstances[6] * coslat * circumstances[18]);
|
||||
// Calculate q
|
||||
circumstances[33] = Math.Asin(coslat * circumstances[17] / Math.Cos(circumstances[32]));
|
||||
if (circumstances[20] < 0.0)
|
||||
{
|
||||
circumstances[33] = Math.PI - circumstances[33];
|
||||
}
|
||||
// Calculate v
|
||||
circumstances[34] = circumstances[31] - circumstances[33];
|
||||
// Calculate azi
|
||||
circumstances[35] = Math.Atan2(-1.0 * circumstances[17] * circumstances[6], circumstances[5] * coslat - circumstances[18] * sinlat * circumstances[6]);
|
||||
// Calculate visibility
|
||||
if (circumstances[32] > -0.00524)
|
||||
{
|
||||
circumstances[40] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
circumstances[40] = 1;
|
||||
}
|
||||
}
|
||||
// Get C1 and C4 data
|
||||
// Entry conditions -
|
||||
// 1. The mid array must be populated
|
||||
// 2. The magnitude at mid eclipse must be > 0.0
|
||||
private static void Getc1c4(double[] elements, double[] obsvconst, double[] mid, double[] c1, double[] c2, double[] c3, double[] c4)
|
||||
{
|
||||
double tmp, n;
|
||||
|
||||
n = Math.Sqrt(mid[30]);
|
||||
tmp = mid[26] * mid[25] - mid[24] * mid[27];
|
||||
tmp = tmp / n / mid[28];
|
||||
tmp = Math.Sqrt(1.0 - tmp * tmp) * mid[28] / n;
|
||||
c1[0] = -2;
|
||||
c4[0] = 2;
|
||||
c1[1] = mid[1] - tmp;
|
||||
c4[1] = mid[1] + tmp;
|
||||
c1c4iterate(elements, c1, obsvconst);
|
||||
c1c4iterate(elements, c4, obsvconst);
|
||||
}
|
||||
// Iterate on C1 or C4
|
||||
private static double[] c1c4iterate(double[] elements, double[] circumstances, double[] obsvconst)
|
||||
{
|
||||
double sign, iter, tmp, n;
|
||||
|
||||
TimeLocDependent(elements, circumstances, obsvconst);
|
||||
if (circumstances[0] < 0)
|
||||
{
|
||||
sign = -1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sign = 1.0;
|
||||
}
|
||||
tmp = 1.0;
|
||||
iter = 0;
|
||||
while (((tmp > 0.000001) || (tmp < -0.000001)) && (iter < 50))
|
||||
{
|
||||
n = Math.Sqrt(circumstances[30]);
|
||||
tmp = circumstances[26] * circumstances[25] - circumstances[24] * circumstances[27];
|
||||
tmp = tmp / n / circumstances[28];
|
||||
tmp = sign * Math.Sqrt(1.0 - tmp * tmp) * circumstances[28] / n;
|
||||
tmp = (circumstances[24] * circumstances[26] + circumstances[25] * circumstances[27]) / circumstances[30] - tmp;
|
||||
circumstances[1] = circumstances[1] - tmp;
|
||||
TimeLocDependent(elements, circumstances, obsvconst);
|
||||
iter++;
|
||||
}
|
||||
return circumstances;
|
||||
}
|
||||
// Get C2 and C3 data
|
||||
// Entry conditions -
|
||||
// 1. The mid array must be populated
|
||||
// 2. There must be either a total or annular eclipse at the location!
|
||||
private static void Getc2c3(double[] elements, double[] obsvconst, double[] mid, double[] c2, double[] c3)
|
||||
{
|
||||
double tmp, n;
|
||||
|
||||
n = Math.Sqrt(mid[30]);
|
||||
tmp = mid[26] * mid[25] - mid[24] * mid[27];
|
||||
tmp = tmp / n / mid[29];
|
||||
tmp = Math.Sqrt(1.0 - tmp * tmp) * mid[29] / n;
|
||||
c2[0] = -1;
|
||||
c3[0] = 1;
|
||||
if (mid[29] < 0.0)
|
||||
{
|
||||
c2[1] = mid[1] + tmp;
|
||||
c3[1] = mid[1] - tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
c2[1] = mid[1] - tmp;
|
||||
c3[1] = mid[1] + tmp;
|
||||
}
|
||||
c2c3iterate(elements, c2, obsvconst, mid);
|
||||
c2c3iterate(elements, c3, obsvconst, mid);
|
||||
}
|
||||
// Iterate on C2 or C3
|
||||
private static double[] c2c3iterate(double[] elements, double[] circumstances, double[] obsvconst, double[] mid)
|
||||
{
|
||||
double sign, iter, tmp, n;
|
||||
|
||||
TimeLocDependent(elements, circumstances, obsvconst);
|
||||
if (circumstances[0] < 0)
|
||||
{
|
||||
sign = -1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sign = 1.0;
|
||||
}
|
||||
if (mid[29] < 0.0)
|
||||
{
|
||||
sign = -sign;
|
||||
}
|
||||
tmp = 1.0;
|
||||
iter = 0;
|
||||
while (((tmp > 0.000001) || (tmp < -0.000001)) && (iter < 50))
|
||||
{
|
||||
n = Math.Sqrt(circumstances[30]);
|
||||
tmp = circumstances[26] * circumstances[25] - circumstances[24] * circumstances[27];
|
||||
tmp = tmp / n / circumstances[29];
|
||||
tmp = sign * Math.Sqrt(1.0 - tmp * tmp) * circumstances[29] / n;
|
||||
tmp = (circumstances[24] * circumstances[26] + circumstances[25] * circumstances[27]) / circumstances[30] - tmp;
|
||||
circumstances[1] = circumstances[1] - tmp;
|
||||
TimeLocDependent(elements, circumstances, obsvconst);
|
||||
iter++;
|
||||
}
|
||||
return circumstances;
|
||||
}
|
||||
// Get the date of an event
|
||||
private static string GetDate(double[] elements, double[] circumstances, double[] obsvconst)
|
||||
{
|
||||
string[] month = new string[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
|
||||
double t, jd, a, b, c, d, e, index;
|
||||
string ans = "";
|
||||
index = obsvconst[6];
|
||||
// Calculate the JD for noon (TDT) the day before the day that contains T0
|
||||
jd = Math.Floor(elements[(int)index] - (elements[1 + (int)index] / 24.0));
|
||||
// Calculate the local time (ie the offset in hours since midnight TDT on the day containing T0).
|
||||
t = circumstances[1] + elements[1 + (int)index] - obsvconst[3] - (elements[4 + (int)index] - 0.5) / 3600.0;
|
||||
if (t < 0.0)
|
||||
{
|
||||
jd--;
|
||||
}
|
||||
if (t >= 24.0)
|
||||
{
|
||||
jd++;
|
||||
}
|
||||
if (jd >= 2299160.0)
|
||||
{
|
||||
a = Math.Floor((jd - 1867216.25) / 36524.25);
|
||||
a = jd + 1 + a - Math.Floor(a / 4.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
a = jd;
|
||||
}
|
||||
b = a + 1525.0;
|
||||
c = Math.Floor((b - 122.1) / 365.25);
|
||||
d = Math.Floor(365.25 * c);
|
||||
e = Math.Floor((b - d) / 30.6001);
|
||||
d = b - d - Math.Floor(30.6001 * e);
|
||||
if (e < 13.5)
|
||||
{
|
||||
e = e - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
e = e - 13;
|
||||
}
|
||||
double year;
|
||||
if (e > 2.5)
|
||||
{
|
||||
ans = c - 4716 + "-";
|
||||
year = c - 4716;
|
||||
}
|
||||
else
|
||||
{
|
||||
ans = c - 4715 + "-";
|
||||
year = c - 4715;
|
||||
}
|
||||
string m = month[(int)e - 1];
|
||||
ans += m + "-";
|
||||
if (d < 10)
|
||||
{
|
||||
ans = ans + "0";
|
||||
}
|
||||
|
||||
ans = ans + d;
|
||||
//Leap Year Integrity Check
|
||||
|
||||
if(m =="Feb" && d ==29 && !DateTime.IsLeapYear((int)year))
|
||||
{
|
||||
ans = year.ToString() + "-Mar-01";
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
// Calculate the time of sunset
|
||||
private static void GetSunset(double[] elements, double[] circumstances, double[] obsvconst)
|
||||
{
|
||||
GetSunriset(elements, circumstances, 1.0, obsvconst);
|
||||
}
|
||||
// Calculate the time of sunrise
|
||||
private static void GetSunrise(double[] elements, double[] circumstances, double[] obsvconst)
|
||||
{
|
||||
GetSunriset(elements, circumstances, -1.0, obsvconst);
|
||||
}
|
||||
// Calculate the time of sunrise or sunset
|
||||
private static void GetSunriset(double[] elements, double[] circumstances, double riset, double[] obsvconst)
|
||||
{
|
||||
double h0, diff, iter;
|
||||
|
||||
diff = 1.0;
|
||||
iter = 0;
|
||||
while ((diff > 0.00001) || (diff < -0.00001))
|
||||
{
|
||||
iter++;
|
||||
if (iter == 4) { return; }
|
||||
h0 = Math.Acos((Math.Sin(-0.00524) - Math.Sin(obsvconst[0]) * circumstances[5]) / Math.Cos(obsvconst[0]) / circumstances[6]);
|
||||
diff = (riset * h0 - circumstances[16]) / circumstances[13];
|
||||
while (diff >= 12.0) { diff -= 24.0; }
|
||||
while (diff <= -12.0) { diff += 24.0; }
|
||||
circumstances[1] += diff;
|
||||
TimeLocDependent(elements, circumstances, obsvconst);
|
||||
}
|
||||
}
|
||||
// Copy a set of circumstances
|
||||
private static void CopyCircumstances(double[] circumstancesfrom, double[] circumstancesto)
|
||||
{
|
||||
for (int i = 1; i < 41; i++)
|
||||
{
|
||||
circumstancesto[i] = circumstancesfrom[i];
|
||||
}
|
||||
}
|
||||
// Get the local time of an event
|
||||
private static string GetTime(double[] elements, double[] circumstances, double[] obsvconst)
|
||||
{
|
||||
string ans = "";
|
||||
int index = (int)obsvconst[6];
|
||||
double t = circumstances[1] + elements[1 + index] - obsvconst[3] - (elements[4 + index] - 0.5) / 3600.0;
|
||||
if (t < 0.0)
|
||||
{
|
||||
t = t + 24.0;
|
||||
}
|
||||
if (t >= 24.0)
|
||||
{
|
||||
t = t - 24.0;
|
||||
}
|
||||
if (t < 10.0)
|
||||
{
|
||||
ans = ans + "0";
|
||||
}
|
||||
ans = ans + Math.Floor(t) + ":";
|
||||
t = (t * 60.0) - 60.0 * Math.Floor(t);
|
||||
if (t < 10.0)
|
||||
{
|
||||
ans = ans + "0";
|
||||
}
|
||||
ans = ans + Math.Floor(t);
|
||||
if (circumstances[40] <= 1)
|
||||
{ // not sunrise or sunset
|
||||
ans = ans + ":";
|
||||
t = (t * 60.0) - 60.0 * Math.Floor(t);
|
||||
if (t < 10.0)
|
||||
{
|
||||
ans = ans + "0";
|
||||
}
|
||||
ans = ans + Math.Floor(t);
|
||||
}
|
||||
if (circumstances[40] == 1)
|
||||
{
|
||||
//WAS ITALIC
|
||||
return ans;
|
||||
}
|
||||
else if (circumstances[40] == 2)
|
||||
{
|
||||
//Rise (CHANGED FROM NASA CALC THE INDICATES (r) WITH STRING, INVESTIGATE REMOVAL)
|
||||
return ans;
|
||||
}
|
||||
else if (circumstances[40] == 3)
|
||||
{
|
||||
//Set (CHANGED FROM NASA CALC THE INDICATES (s) WITH STRING, INVESTIGATE REMOVAL)
|
||||
return ans;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
// Get the altitude
|
||||
private static string GetAlt(double[] circumstances)
|
||||
{
|
||||
double t;
|
||||
string ans = "";
|
||||
|
||||
if (circumstances[40] == 2)
|
||||
{
|
||||
return "0(r)";
|
||||
}
|
||||
if (circumstances[40] == 3)
|
||||
{
|
||||
return "0(s)";
|
||||
}
|
||||
if ((circumstances[32] < 0.0) && (circumstances[32] >= -0.00524))
|
||||
{
|
||||
// Crude correction for refraction (and for consistency's sake)
|
||||
t = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
t = circumstances[32] * 180.0 / Math.PI;
|
||||
}
|
||||
if (t < 0.0)
|
||||
{
|
||||
ans = "-";
|
||||
t = -t;
|
||||
}
|
||||
else
|
||||
{
|
||||
ans = "";
|
||||
}
|
||||
t = Math.Floor(t + 0.5);
|
||||
if (t < 10.0)
|
||||
{
|
||||
ans = ans + "0";
|
||||
}
|
||||
ans = ans + t;
|
||||
if (circumstances[40] == 1)
|
||||
{
|
||||
//WAS ITALIC
|
||||
return ans;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
// Get the azimuth
|
||||
private static string GetAzi(double[] circumstances)
|
||||
{
|
||||
string ans = "";
|
||||
double t = circumstances[35] * 180.0 / Math.PI;
|
||||
if (t < 0.0)
|
||||
{
|
||||
t = t + 360.0;
|
||||
}
|
||||
if (t >= 360.0)
|
||||
{
|
||||
t = t - 360.0;
|
||||
}
|
||||
t = Math.Floor(t + 0.5);
|
||||
if (t < 100.0)
|
||||
{
|
||||
ans = ans + "0";
|
||||
}
|
||||
if (t < 10.0)
|
||||
{
|
||||
ans = ans + "0";
|
||||
}
|
||||
ans = ans + t;
|
||||
if (circumstances[40] == 1)
|
||||
{
|
||||
//WAS ITALIC
|
||||
return ans;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
// Get the magnitude
|
||||
private static string GetMagnitude(double[] mid)
|
||||
{
|
||||
double a = Math.Floor(1000.0 * mid[37] + 0.5) / 1000.0;
|
||||
string ans = a.ToString();
|
||||
if (mid[40] == 1)
|
||||
{
|
||||
return ans;
|
||||
}
|
||||
if (mid[40] == 2)
|
||||
{
|
||||
ans = a.ToString() + "(r)";
|
||||
}
|
||||
if (mid[40] == 3)
|
||||
{
|
||||
ans = a.ToString() + "(s)";
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
// Get the coverage
|
||||
private static string GetCoverage(double[] mid)
|
||||
{
|
||||
double a=0, b, c;
|
||||
string ans = "";
|
||||
if (mid[37] <= 0.0)
|
||||
{
|
||||
ans = "0.0";
|
||||
}
|
||||
else if (mid[37] >= 1.0)
|
||||
{
|
||||
ans = "1.000";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mid[39] == 2)
|
||||
{
|
||||
c = mid[38] * mid[38];
|
||||
}
|
||||
else
|
||||
{
|
||||
c = Math.Acos((mid[28] * mid[28] + mid[29] * mid[29] - 2.0 * mid[36] * mid[36]) / (mid[28] * mid[28] - mid[29] * mid[29]));
|
||||
b = Math.Acos((mid[28] * mid[29] + mid[36] * mid[36]) / mid[36] / (mid[28] + mid[29]));
|
||||
a = Math.PI - b - c;
|
||||
c = ((mid[38] * mid[38] * a + b) - mid[38] * Math.Sin(c)) / Math.PI;
|
||||
}
|
||||
a = Math.Floor(1000.0 * c + 0.5) / 1000.0;
|
||||
ans = a.ToString();
|
||||
}
|
||||
if (mid[40] == 1)
|
||||
{
|
||||
//WAS ITALIC
|
||||
return ans;
|
||||
}
|
||||
if (mid[40] == 2)
|
||||
{
|
||||
ans = a.ToString() + "(r)";
|
||||
}
|
||||
if (mid[40] == 3)
|
||||
{
|
||||
ans = a + "(s)";
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
// Get the duration in mm:ss.s format
|
||||
// Adapted from code written by Stephen McCann - 27/04/2001
|
||||
private static string GetDuration(double[] mid, double[] c2, double[] c3)
|
||||
{
|
||||
double tmp;
|
||||
string ans;
|
||||
|
||||
if (c3[40] == 4)
|
||||
{
|
||||
tmp = mid[1] - c2[1];
|
||||
}
|
||||
else if (c2[40] == 4)
|
||||
{
|
||||
tmp = c3[1] - mid[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp = c3[1] - c2[1];
|
||||
}
|
||||
if (tmp < 0.0)
|
||||
{
|
||||
tmp = tmp + 24.0;
|
||||
}
|
||||
else if (tmp >= 24.0)
|
||||
{
|
||||
tmp = tmp - 24.0;
|
||||
}
|
||||
tmp = (tmp * 60.0) - 60.0 * Math.Floor(tmp) + 0.05 / 60.0;
|
||||
ans = Math.Floor(tmp) + "m";
|
||||
tmp = (tmp * 60.0) - 60.0 * Math.Floor(tmp);
|
||||
if (tmp < 10.0)
|
||||
{
|
||||
ans = ans + "0";
|
||||
}
|
||||
ans += Math.Floor(tmp) + "s";
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,374 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
internal class SunCalc
|
||||
{
|
||||
public static void CalculateSunTime(double lat, double longi, DateTime date, Celestial c,double offset = 0)
|
||||
{
|
||||
if (date.Year == 0001) { return; } //Return if date vaue hasn't been established.
|
||||
DateTime actualDate = new DateTime(date.Year,date.Month,date.Day,0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
////Sun Time Calculations
|
||||
|
||||
//Get Julian
|
||||
double lw = rad * -longi;
|
||||
double phi = rad * lat;
|
||||
|
||||
//Rise Set
|
||||
DateTime?[] evDate = Get_Event_Time(lw, phi, -.8333, actualDate);
|
||||
c.sunRise = evDate[0];
|
||||
c.sunSet = evDate[1];
|
||||
|
||||
c.sunCondition = CelestialStatus.RiseAndSet;
|
||||
//Azimuth and Altitude
|
||||
CalculateSunAngle(date, longi, lat, c);
|
||||
// neither sunrise nor sunset
|
||||
if ((!c.SunRise.HasValue) && (!c.SunSet.HasValue))
|
||||
{
|
||||
if (c.SunAltitude < 0)
|
||||
{
|
||||
c.sunCondition = CelestialStatus.DownAllDay;
|
||||
}
|
||||
else
|
||||
{
|
||||
c.sunCondition = CelestialStatus.UpAllDay;
|
||||
}
|
||||
}
|
||||
// sunrise or sunset
|
||||
else
|
||||
{
|
||||
if (!c.SunRise.HasValue)
|
||||
{
|
||||
// No sunrise this date
|
||||
c.sunCondition = CelestialStatus.NoRise;
|
||||
|
||||
}
|
||||
else if (!c.SunSet.HasValue)
|
||||
{
|
||||
// No sunset this date
|
||||
c.sunCondition = CelestialStatus.NoSet;
|
||||
}
|
||||
}
|
||||
//Additional Times
|
||||
c.additionalSolarTimes = new AdditionalSolarTimes();
|
||||
//Dusk and Dawn
|
||||
//Civil
|
||||
evDate = Get_Event_Time(lw, phi, -6, actualDate);
|
||||
c.AdditionalSolarTimes.CivilDawn = evDate[0];
|
||||
c.AdditionalSolarTimes.CivilDusk = evDate[1];
|
||||
|
||||
|
||||
//Nautical
|
||||
evDate = Get_Event_Time(lw, phi, -12, actualDate);
|
||||
c.AdditionalSolarTimes.NauticalDawn = evDate[0];
|
||||
c.AdditionalSolarTimes.NauticalDusk = evDate[1];
|
||||
|
||||
//Astronomical
|
||||
evDate = Get_Event_Time(lw, phi, -18, actualDate);
|
||||
|
||||
c.AdditionalSolarTimes.AstronomicalDawn = evDate[0];
|
||||
c.AdditionalSolarTimes.AstronomicalDusk = evDate[1];
|
||||
|
||||
//BottomDisc
|
||||
evDate = Get_Event_Time(lw, phi, -.2998, actualDate);
|
||||
c.AdditionalSolarTimes.SunriseBottomDisc = evDate[0];
|
||||
c.AdditionalSolarTimes.SunsetBottomDisc = evDate[1];
|
||||
|
||||
CalculateSolarEclipse(date, lat, longi, c);
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets time of event based on specified degree below horizon
|
||||
/// </summary>
|
||||
/// <param name="lw">Observer Longitude in radians</param>
|
||||
/// <param name="phi">Observer Latitude in radians</param>
|
||||
/// <param name="h">Angle in Degrees</param>
|
||||
/// <param name="date">Date of Event</param>
|
||||
/// <returns>DateTime?[]{rise, set}</returns>
|
||||
private static DateTime?[] Get_Event_Time(double lw, double phi, double h,DateTime date)
|
||||
{
|
||||
//Create arrays. Index 0 = Day -1, 1 = Day, 2 = Day + 1;
|
||||
//These will be used to find exact day event occurs for comparison
|
||||
DateTime?[] sets = new DateTime?[] { null, null, null, null, null };
|
||||
DateTime?[] rises = new DateTime?[] { null, null, null,null, null };
|
||||
|
||||
//Iterate starting with day -1;
|
||||
for (int x = 0; x < 5; x++)
|
||||
{
|
||||
double d = JulianConversions.GetJulian(date.AddDays(x-2)) - j2000 + .5; //LESS PRECISE JULIAN NEEDED
|
||||
|
||||
double n = julianCycle(d, lw);
|
||||
double ds = approxTransit(0, lw, n);
|
||||
|
||||
double M = solarMeanAnomaly(ds);
|
||||
double L = eclipticLongitude(M);
|
||||
|
||||
double dec = declination(L, 0);
|
||||
|
||||
double Jnoon = solarTransitJ(ds, M, L);
|
||||
|
||||
double Jset;
|
||||
double Jrise;
|
||||
|
||||
|
||||
DateTime? solarNoon = JulianConversions.GetDate_FromJulian(Jnoon);
|
||||
DateTime? nadir = JulianConversions.GetDate_FromJulian(Jnoon - 0.5);
|
||||
|
||||
//Rise Set
|
||||
Jset = GetTime(h * rad, lw, phi, dec, n, M, L);
|
||||
Jrise = Jnoon - (Jset - Jnoon);
|
||||
|
||||
DateTime? rise = JulianConversions.GetDate_FromJulian(Jrise);
|
||||
DateTime? set = JulianConversions.GetDate_FromJulian(Jset);
|
||||
|
||||
rises[x] = rise;
|
||||
sets[x] = set;
|
||||
}
|
||||
|
||||
//Compare and send
|
||||
DateTime? tRise = null;
|
||||
for(int x=0;x<5;x++)
|
||||
{
|
||||
if(rises[x].HasValue)
|
||||
{
|
||||
if(rises[x].Value.Day == date.Day)
|
||||
{
|
||||
tRise = rises[x];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
DateTime? tSet = null;
|
||||
for (int x = 0; x < 5; x++)
|
||||
{
|
||||
if (sets[x].HasValue)
|
||||
{
|
||||
if (sets[x].Value.Day == date.Day)
|
||||
{
|
||||
tSet = sets[x];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new DateTime?[] { tRise, tSet };
|
||||
}
|
||||
|
||||
public static void CalculateZodiacSign(DateTime date, Celestial c)
|
||||
{
|
||||
//Aquarius (January 20 to February 18)
|
||||
//Pisces (February 19 to March 20)
|
||||
//Aries (March 21-April 19)
|
||||
//Taurus (April 20-May 20)
|
||||
//Gemini (May 21-June 20)
|
||||
//Cancer (June 21-July 22)
|
||||
//Leo (July 23-August 22)
|
||||
//Virgo (August 23-September 22)
|
||||
//Libra (September 23-October 22)
|
||||
//Scorpio (October 23-November 21)
|
||||
//Sagittarius (November 22-December 21)
|
||||
//Capricorn (December 22-January 19)
|
||||
if (date >= new DateTime(date.Year, 1, 1) && date <= new DateTime(date.Year, 1, 19, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Capricorn";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 1, 20) && date <= new DateTime(date.Year, 2, 18, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Aquarius";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 2, 19) && date <= new DateTime(date.Year, 3, 20, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Pisces";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 3, 21) && date <= new DateTime(date.Year, 4, 19, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Aries";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 4, 20) && date <= new DateTime(date.Year, 5, 20, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Taurus";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 5, 21) && date <= new DateTime(date.Year, 6, 20,23,59,59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Gemini";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 6, 21) && date <= new DateTime(date.Year, 7, 22, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Cancer";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 7, 23) && date <= new DateTime(date.Year, 8, 22, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Leo";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 8, 23) && date <= new DateTime(date.Year, 9, 22, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Virgo";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 9, 23) && date <= new DateTime(date.Year, 10, 22, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Libra";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 9, 23) && date <= new DateTime(date.Year, 11, 21, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Scorpio";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 11, 21) && date <= new DateTime(date.Year, 12, 21, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Sagittarius";
|
||||
return;
|
||||
}
|
||||
if (date >= new DateTime(date.Year, 12, 22) && date <= new DateTime(date.Year, 12, 31, 23, 59, 59))
|
||||
{
|
||||
c.AstrologicalSigns.ZodiacSign = "Capricorn";
|
||||
return;
|
||||
}
|
||||
}
|
||||
public static void CalculateSolarEclipse(DateTime date, double lat, double longi, Celestial c)
|
||||
{
|
||||
//Convert to Radian
|
||||
double latR = lat * Math.PI / 180;
|
||||
double longR = longi * Math.PI / 180;
|
||||
List<List<string>> se = SolarEclipseCalc.CalculateSolarEclipse(date, latR, longR);
|
||||
//RETURN FIRST AND LAST
|
||||
if (se.Count == 0) { return; }
|
||||
//FIND LAST AND NEXT ECLIPSE
|
||||
int lastE = -1;
|
||||
int nextE = -1;
|
||||
int currentE = 0;
|
||||
DateTime lastDate = new DateTime();
|
||||
DateTime nextDate = new DateTime(3300, 1, 1);
|
||||
//Iterate to get last and next eclipse
|
||||
foreach(List<string> values in se)
|
||||
{
|
||||
DateTime ld = DateTime.ParseExact(values[0], "yyyy-MMM-dd", System.Globalization.CultureInfo.InvariantCulture);
|
||||
|
||||
if (ld < date && ld>lastDate) { lastDate = ld;lastE = currentE; }
|
||||
if(ld>= date && ld < nextDate) { nextDate = ld;nextE = currentE; }
|
||||
currentE++;
|
||||
}
|
||||
//SET ECLIPSE DATA
|
||||
if (lastE >= 0)
|
||||
{
|
||||
c.SolarEclipse.LastEclipse = new SolarEclipseDetails(se[lastE]);
|
||||
}
|
||||
if (nextE >= 0)
|
||||
{
|
||||
c.SolarEclipse.NextEclipse = new SolarEclipseDetails(se[nextE]);
|
||||
}
|
||||
}
|
||||
|
||||
#region Private Suntime Members
|
||||
private static readonly double dayMS = 1000 * 60 * 60 * 24, j1970 = 2440588, j2000 = 2451545;
|
||||
private static readonly double rad = Math.PI / 180;
|
||||
|
||||
private static double LocalSiderealTimeForTimeZone(double lon, double jd, double z)
|
||||
{
|
||||
double s = 24110.5 + 8640184.812999999 * jd / 36525 + 86636.6 * z + 86400 * lon;
|
||||
s = s / 86400;
|
||||
s = s - Math.Truncate(s);
|
||||
double lst = s * 360 *rad;
|
||||
|
||||
return lst;
|
||||
}
|
||||
private static double SideRealTime(double d, double lw)
|
||||
{
|
||||
double s = rad * (280.16 + 360.9856235 * d) - lw;
|
||||
return s;
|
||||
}
|
||||
private static double solarTransitJ(double ds, double M, double L)
|
||||
{
|
||||
return j2000 + ds + 0.0053 * Math.Sin(M) - 0.0069 * Math.Sin(2 * L);
|
||||
}
|
||||
|
||||
//CH15
|
||||
//Formula 15.1
|
||||
//Returns Approximate Time
|
||||
private static double hourAngle(double h, double phi, double d)
|
||||
{
|
||||
//NUMBER RETURNING > and < 1 NaN;
|
||||
double d1 = Math.Sin(h) - Math.Sin(phi) * Math.Sin(d);
|
||||
double d2 = Math.Cos(phi) * Math.Cos(d);
|
||||
double d3 = (d1 / d2);
|
||||
|
||||
return Math.Acos(d3);
|
||||
}
|
||||
private static double approxTransit(double Ht, double lw, double n)
|
||||
{
|
||||
return 0.0009 + (Ht + lw) / (2 * Math.PI) + n;
|
||||
}
|
||||
|
||||
private static double julianCycle(double d, double lw) { return Math.Round(d - 0.0009 - lw / (2 * Math.PI)); }
|
||||
|
||||
//Returns Time of specified event based on suns angle
|
||||
private static double GetTime(double h, double lw, double phi, double dec, double n,double M, double L)
|
||||
{
|
||||
double approxTime = hourAngle(h, phi, dec); //Ch15 Formula 15.1
|
||||
|
||||
double a = approxTransit(approxTime, lw, n);
|
||||
double st = solarTransitJ(a, M, L);
|
||||
|
||||
return st;
|
||||
}
|
||||
private static double declination(double l, double b)
|
||||
{
|
||||
double e = (Math.PI/180) * 23.4392911; // obliquity of the Earth
|
||||
|
||||
return Math.Asin(Math.Sin(b) * Math.Cos(e) + Math.Cos(b) * Math.Sin(e) * Math.Sin(l));
|
||||
}
|
||||
|
||||
private static void CalculateSunAngle(DateTime date, double longi, double lat, Celestial c)
|
||||
{
|
||||
TimeSpan ts = date - new DateTime(1970, 1, 1,0,0,0, DateTimeKind.Utc);
|
||||
double dms = (ts.TotalMilliseconds / dayMS -.5 + j1970)-j2000;
|
||||
|
||||
double lw = rad * -longi;
|
||||
double phi = rad * lat;
|
||||
double e = rad * 23.4397;
|
||||
|
||||
double[] sc = sunCoords(dms);
|
||||
|
||||
double H = SideRealTime(dms, lw) - sc[1];
|
||||
|
||||
c.sunAzimuth = Math.Atan2(Math.Sin(H), Math.Cos(H) * Math.Sin(phi) - Math.Tan(sc[0]) * Math.Cos(phi)) * 180 / Math.PI + 180;
|
||||
c.sunAltitude = Math.Asin(Math.Sin(phi) * Math.Sin(sc[0]) + Math.Cos(phi) * Math.Cos(sc[0]) * Math.Cos(H)) * 180 / Math.PI;
|
||||
}
|
||||
|
||||
private static double solarMeanAnomaly(double d)
|
||||
{
|
||||
return rad * (357.5291 + 0.98560028 * d);
|
||||
}
|
||||
|
||||
private static double eclipticLongitude(double m)
|
||||
{
|
||||
double c = rad * (1.9148 * Math.Sin(m) + 0.02 * Math.Sin(2 * m) + 0.0003 * Math.Sin(3 * m)); // equation of center
|
||||
double p = rad * 102.9372; // perihelion of the Earth
|
||||
|
||||
return m + c + p + Math.PI;
|
||||
}
|
||||
private static double[] sunCoords(double d)
|
||||
{
|
||||
|
||||
double m = solarMeanAnomaly(d);
|
||||
double l = eclipticLongitude(m);
|
||||
double[] sc = new double[2];
|
||||
double b = 0;
|
||||
double e = rad * 23.4397; // obliquity of the Earth
|
||||
sc[0] = Math.Asin(Math.Sin(b) * Math.Cos(e) + Math.Cos(b) * Math.Sin(e) * Math.Sin(l)); //declination
|
||||
sc[1] = Math.Atan2(Math.Sin(l) * Math.Cos(e) - Math.Tan(b) * Math.Sin(e), Math.Cos(l)); //rightAscension
|
||||
return sc;
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
@ -1,620 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Collections.Generic;
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// The main class for handling location based celestial information.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class can calculate various pieces of solar and lunar data, based on location and date
|
||||
/// </remarks>
|
||||
[Serializable]
|
||||
public class Celestial
|
||||
{
|
||||
|
||||
//When a rise or a set does not occur, the DateTime will return null
|
||||
|
||||
/// <summary>
|
||||
/// Creates an empty Celestial.
|
||||
/// </summary>
|
||||
public Celestial()
|
||||
{
|
||||
astrologicalSigns = new AstrologicalSigns();
|
||||
lunarEclipse = new LunarEclipse();
|
||||
solarEclipse = new SolarEclipse();
|
||||
CalculateCelestialTime(0, 0, new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc));
|
||||
}
|
||||
|
||||
private Celestial(bool hasCalcs)
|
||||
{
|
||||
|
||||
astrologicalSigns = new AstrologicalSigns();
|
||||
lunarEclipse = new LunarEclipse();
|
||||
solarEclipse = new SolarEclipse();
|
||||
if (hasCalcs) { CalculateCelestialTime(0, 0, new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc)); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a Celestial based on a location and specified date
|
||||
/// </summary>
|
||||
/// <param name="lat">latitude</param>
|
||||
/// <param name="longi">longitude</param>
|
||||
/// <param name="geoDate">DateTime (UTC)</param>
|
||||
public Celestial(double lat, double longi, DateTime geoDate)
|
||||
{
|
||||
DateTime d = new DateTime(geoDate.Year, geoDate.Month, geoDate.Day, geoDate.Hour, geoDate.Minute, geoDate.Second, DateTimeKind.Utc);
|
||||
astrologicalSigns = new AstrologicalSigns();
|
||||
lunarEclipse = new LunarEclipse();
|
||||
solarEclipse = new SolarEclipse();
|
||||
CalculateCelestialTime(lat, longi, d);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a Celestial based on a location and date in the provided Coordinate.
|
||||
/// </summary>
|
||||
/// <param name="c">Coordinate</param>
|
||||
/// <returns>Celestial</returns>
|
||||
public static Celestial LoadCelestial(Coordinate c)
|
||||
{
|
||||
DateTime geoDate = c.GeoDate;
|
||||
|
||||
DateTime d = new DateTime(geoDate.Year, geoDate.Month, geoDate.Day, geoDate.Hour, geoDate.Minute, geoDate.Second, DateTimeKind.Utc);
|
||||
Celestial cel = new Celestial(c.Latitude.ToDouble(), c.Longitude.ToDouble(), c.GeoDate);
|
||||
|
||||
return cel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts Celestial values to local times.
|
||||
/// </summary>
|
||||
/// <param name="c">Coordinate</param>
|
||||
/// <param name="offset">UTC offset</param>
|
||||
/// <returns></returns>
|
||||
public static Celestial Celestial_LocalTime(Coordinate c, double offset)
|
||||
{
|
||||
if(offset < -12 || offset > 12) { throw new ArgumentOutOfRangeException("Time offsets cannot be greater 12 or less than -12."); }
|
||||
//Probably need to offset initial UTC date so user can op in local
|
||||
//Determine best way to do this.
|
||||
DateTime d = c.GeoDate.AddHours(offset);
|
||||
|
||||
//Get 3 objects for comparison
|
||||
Celestial cel = new Celestial(c.Latitude.ToDouble(), c.Longitude.ToDouble(), c.GeoDate);
|
||||
Celestial celPre = new Celestial(c.Latitude.ToDouble(), c.Longitude.ToDouble(), c.GeoDate.AddDays(-1));
|
||||
Celestial celPost = new Celestial(c.Latitude.ToDouble(), c.Longitude.ToDouble(), c.GeoDate.AddDays(1));
|
||||
|
||||
//Slip objects for comparison. Compare with slipped date.
|
||||
celPre.Local_Convert(c, offset);
|
||||
cel.Local_Convert(c, offset);
|
||||
celPost.Local_Convert(c, offset);
|
||||
|
||||
//Get SunSet
|
||||
int i = Determine_Slipped_Event_Index(cel.SunSet, celPre.SunSet, celPost.SunSet, d);
|
||||
cel.sunSet = Get_Correct_Slipped_Date(cel.SunSet, celPre.SunSet, celPost.SunSet, i);
|
||||
cel.AdditionalSolarTimes.CivilDusk = Get_Correct_Slipped_Date(cel.AdditionalSolarTimes.CivilDusk,
|
||||
celPre.AdditionalSolarTimes.CivilDusk, celPost.AdditionalSolarTimes.CivilDusk, i);
|
||||
cel.AdditionalSolarTimes.NauticalDusk = Get_Correct_Slipped_Date(cel.AdditionalSolarTimes.NauticalDusk,
|
||||
celPre.AdditionalSolarTimes.NauticalDusk, celPost.AdditionalSolarTimes.NauticalDusk, i);
|
||||
//Get SunRise
|
||||
i = Determine_Slipped_Event_Index(cel.SunRise, celPre.SunRise, celPost.SunRise, d);
|
||||
cel.sunRise = Get_Correct_Slipped_Date(cel.SunRise, celPre.SunRise, celPost.SunRise, i);
|
||||
cel.AdditionalSolarTimes.CivilDawn = Get_Correct_Slipped_Date(cel.AdditionalSolarTimes.CivilDawn,
|
||||
celPre.AdditionalSolarTimes.CivilDawn, celPost.AdditionalSolarTimes.CivilDawn, i);
|
||||
cel.AdditionalSolarTimes.NauticalDawn = Get_Correct_Slipped_Date(cel.AdditionalSolarTimes.NauticalDawn,
|
||||
celPre.AdditionalSolarTimes.NauticalDawn, celPost.AdditionalSolarTimes.NauticalDawn, i);
|
||||
|
||||
//MoonRise
|
||||
i = Determine_Slipped_Event_Index(cel.MoonRise, celPre.MoonRise, celPost.MoonRise, d);
|
||||
cel.moonRise = Get_Correct_Slipped_Date(cel.MoonRise, celPre.MoonRise, celPost.MoonRise, i);
|
||||
|
||||
//MoonSet
|
||||
i = Determine_Slipped_Event_Index(cel.MoonSet, celPre.MoonSet, celPost.MoonSet, d);
|
||||
cel.moonSet = Get_Correct_Slipped_Date(cel.MoonSet, celPre.MoonSet, celPost.MoonSet, i);
|
||||
|
||||
//Local Conditions
|
||||
CelestialStatus[] cels = new CelestialStatus[]
|
||||
{
|
||||
celPre.MoonCondition,cel.MoonCondition,celPost.MoonCondition
|
||||
};
|
||||
cel.moonCondition = Celestial.GetStatus(cel.MoonRise, cel.MoonSet, cels);
|
||||
cels = new CelestialStatus[]
|
||||
{
|
||||
celPre.SunCondition, cel.SunCondition, celPost.SunCondition
|
||||
};
|
||||
cel.sunCondition = Celestial.GetStatus(cel.SunRise, cel.SunSet, cels);
|
||||
|
||||
//Load IsUp values based on local time with populated Celestial
|
||||
Celestial.Calculate_Celestial_IsUp_Booleans(d, cel);
|
||||
|
||||
return cel;
|
||||
}
|
||||
|
||||
private static CelestialStatus GetStatus(DateTime? rise, DateTime? set, CelestialStatus[] cels)
|
||||
{
|
||||
if (set.HasValue && rise.HasValue) { return CelestialStatus.RiseAndSet; }
|
||||
if (set.HasValue && !rise.HasValue) { return CelestialStatus.NoRise; }
|
||||
if (!set.HasValue && rise.HasValue) { return CelestialStatus.NoSet; }
|
||||
for (int x=0; x < 3;x++)
|
||||
{
|
||||
if(cels[x] == CelestialStatus.DownAllDay || cels[x] == CelestialStatus.UpAllDay)
|
||||
{
|
||||
return cels[x];
|
||||
}
|
||||
}
|
||||
return cels[1];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// In place time slip
|
||||
/// </summary>
|
||||
/// <param name="c">Coordinate</param>
|
||||
/// <param name="offset">hour offset</param>
|
||||
private void Local_Convert(Coordinate c, double offset)
|
||||
{
|
||||
//Find new lunar set rise times
|
||||
if (MoonSet.HasValue) { moonSet = moonSet.Value.AddHours(offset); }
|
||||
if (MoonRise.HasValue) { moonRise = moonRise.Value.AddHours(offset); }
|
||||
//Perigee
|
||||
Perigee.ConvertTo_Local_Time(offset);
|
||||
//Apogee
|
||||
Apogee.ConvertTo_Local_Time(offset);
|
||||
//Eclipse
|
||||
LunarEclipse.ConvertTo_LocalTime(offset);
|
||||
|
||||
////Solar
|
||||
if (sunSet.HasValue) { sunSet = sunSet.Value.AddHours(offset); }
|
||||
if (SunRise.HasValue) { sunRise = SunRise.Value.AddHours(offset); }
|
||||
AdditionalSolarTimes.Convert_To_Local_Time(offset);
|
||||
|
||||
//Eclipse
|
||||
SolarEclipse.ConvertTo_LocalTime(offset);
|
||||
SunCalc.CalculateZodiacSign(c.GeoDate.AddHours(offset), this);
|
||||
MoonCalc.GetMoonSign(c.GeoDate.AddHours(offset), this);
|
||||
|
||||
}
|
||||
|
||||
private PerigeeApogee Get_Correct_Slipped_Date(PerigeeApogee actual, PerigeeApogee pre, PerigeeApogee post, int i)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
return pre;
|
||||
case 1:
|
||||
return actual;
|
||||
case 2:
|
||||
return post;
|
||||
default:
|
||||
return actual;
|
||||
}
|
||||
}
|
||||
private static DateTime? Get_Correct_Slipped_Date(DateTime? actual, DateTime? pre, DateTime? post, int i)
|
||||
{
|
||||
switch(i)
|
||||
{
|
||||
case 0:
|
||||
return pre;
|
||||
case 1:
|
||||
return actual;
|
||||
case 2:
|
||||
return post;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
private static int Determine_Slipped_Event_Index(DateTime? actual, DateTime? pre, DateTime? post, DateTime d)
|
||||
{
|
||||
|
||||
if (actual.HasValue)
|
||||
{
|
||||
if (actual.Value.Day != d.Day)
|
||||
{
|
||||
if (pre.HasValue)
|
||||
{
|
||||
if (pre.Value.Day == d.Day) { return 0; }
|
||||
}
|
||||
if (post.HasValue)
|
||||
{
|
||||
if (post.Value.Day == d.Day) { return 2; }
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pre.HasValue)
|
||||
{
|
||||
if (pre.Value.Day == d.Day) { return 0; }
|
||||
}
|
||||
if (post.HasValue)
|
||||
{
|
||||
if (post.Value.Day == d.Day) { return 2; }
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
internal DateTime? sunSet;
|
||||
internal DateTime? sunRise;
|
||||
internal DateTime? moonSet;
|
||||
internal DateTime? moonRise;
|
||||
|
||||
internal double sunAltitude;
|
||||
internal double sunAzimuth;
|
||||
internal double moonAltitude;
|
||||
internal double moonAzimuth;
|
||||
|
||||
internal Distance moonDistance;
|
||||
|
||||
internal CelestialStatus sunCondition;
|
||||
internal CelestialStatus moonCondition;
|
||||
|
||||
internal bool isSunUp;
|
||||
internal bool isMoonUp;
|
||||
|
||||
internal MoonIllum moonIllum;
|
||||
internal Perigee perigee;
|
||||
internal Apogee apogee;
|
||||
internal AdditionalSolarTimes additionalSolarTimes;
|
||||
internal AstrologicalSigns astrologicalSigns;
|
||||
internal SolarEclipse solarEclipse;
|
||||
internal LunarEclipse lunarEclipse;
|
||||
|
||||
/// <summary>
|
||||
/// Sunset time.
|
||||
/// </summary>
|
||||
public DateTime? SunSet { get { return sunSet; } }
|
||||
/// <summary>
|
||||
/// Sunrise time.
|
||||
/// </summary>
|
||||
public DateTime? SunRise { get { return sunRise; } }
|
||||
/// <summary>
|
||||
/// Moonset time.
|
||||
/// </summary>
|
||||
public DateTime? MoonSet { get { return moonSet; } }
|
||||
/// <summary>
|
||||
/// Moonrise time.
|
||||
/// </summary>
|
||||
public DateTime? MoonRise { get { return moonRise; } }
|
||||
|
||||
/// <summary>
|
||||
/// Sun altitude in degrees (E of N).
|
||||
/// </summary>
|
||||
public double SunAltitude { get { return sunAltitude; } }
|
||||
/// <summary>
|
||||
/// Sun azimuth in degrees (E of N).
|
||||
/// </summary>
|
||||
public double SunAzimuth { get { return sunAzimuth; } }
|
||||
/// <summary>
|
||||
/// Moon altitude in degrees (corrected for parallax and refraction).
|
||||
/// </summary>
|
||||
public double MoonAltitude { get { return moonAltitude; } }
|
||||
/// <summary>
|
||||
/// Moon azimuth in degrees (E of N).
|
||||
/// </summary>
|
||||
public double MoonAzimuth { get { return moonAzimuth; } }
|
||||
|
||||
/// <summary>
|
||||
/// Estimated moon distance from the earth.
|
||||
/// </summary>
|
||||
public Distance MoonDistance { get { return moonDistance; } }
|
||||
/// <summary>
|
||||
/// Sun's Condition based on the provided date.
|
||||
/// </summary>
|
||||
public CelestialStatus SunCondition { get { return sunCondition; } }
|
||||
/// <summary>
|
||||
/// Moon's condition based on the provided date.
|
||||
/// </summary>
|
||||
public CelestialStatus MoonCondition { get { return moonCondition; } }
|
||||
|
||||
/// <summary>
|
||||
/// Determine if the sun is currently up, based on sunset and sunrise time at the provided location and date.
|
||||
/// </summary>
|
||||
public bool IsSunUp{ get { return isSunUp; } }
|
||||
|
||||
/// <summary>
|
||||
/// Determine if the moon is currently up, based on moonset and moonrise time at the provided location and date.
|
||||
/// </summary>
|
||||
public bool IsMoonUp { get { return isMoonUp; } }
|
||||
|
||||
/// <summary>
|
||||
/// Moon ilumination details based on the provided date.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Contains phase, phase name, fraction and angle
|
||||
/// </remarks>
|
||||
public MoonIllum MoonIllum { get { return moonIllum; } }
|
||||
/// <summary>
|
||||
/// Moons perigee details based on the provided date.
|
||||
/// </summary>
|
||||
public Perigee Perigee { get { return perigee; } }
|
||||
/// <summary>
|
||||
/// Moons apogee details based on the provided date.
|
||||
/// </summary>
|
||||
public Apogee Apogee { get { return apogee; } }
|
||||
|
||||
/// <summary>
|
||||
/// Additional solar event times based on the provided date and location.
|
||||
/// </summary>
|
||||
/// <remarks>Contains civil and nautical dawn and dusk times.</remarks>
|
||||
public AdditionalSolarTimes AdditionalSolarTimes { get { return additionalSolarTimes; } }
|
||||
/// <summary>
|
||||
/// Astrological signs based on the provided date.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Contains zodiac, moon sign and moon name during full moon events
|
||||
/// </remarks>
|
||||
public AstrologicalSigns AstrologicalSigns { get { return astrologicalSigns; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a SolarEclipse.
|
||||
/// </summary>
|
||||
public SolarEclipse SolarEclipse { get { return solarEclipse; } }
|
||||
/// <summary>
|
||||
/// Returns a LunarEclipse.
|
||||
/// </summary>
|
||||
public LunarEclipse LunarEclipse { get { return lunarEclipse; } }
|
||||
|
||||
/// <summary>
|
||||
/// Calculates all celestial data. Coordinates will notify as changes occur
|
||||
/// </summary>
|
||||
/// <param name="lat">Decimal format latitude</param>
|
||||
/// <param name="longi">Decimal format longitude</param>
|
||||
/// <param name="date">Geographic DateTime</param>
|
||||
internal void CalculateCelestialTime(double lat, double longi, DateTime date)
|
||||
{
|
||||
date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, DateTimeKind.Utc);
|
||||
SunCalc.CalculateSunTime(lat, longi, date, this);
|
||||
MoonCalc.GetMoonTimes(date, lat, longi, this);
|
||||
MoonCalc.GetMoonDistance(date, this);
|
||||
|
||||
SunCalc.CalculateZodiacSign(date, this);
|
||||
MoonCalc.GetMoonSign(date, this);
|
||||
|
||||
MoonCalc.GetMoonIllumination(date, this,lat,longi);
|
||||
|
||||
|
||||
perigee = MoonCalc.GetPerigeeEvents(date);
|
||||
apogee = MoonCalc.GetApogeeEvents(date);
|
||||
|
||||
Calculate_Celestial_IsUp_Booleans(date, this);
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Calculate celestial data based on lat/long and date.
|
||||
/// </summary>
|
||||
/// <param name="lat">Decimal format latitude</param>
|
||||
/// <param name="longi">Decimal format longitude</param>
|
||||
/// <param name="date">Geographic DateTime</param>
|
||||
/// <returns>Fully populated Celestial object</returns>
|
||||
public static Celestial CalculateCelestialTimes(double lat, double longi, DateTime date)
|
||||
{
|
||||
date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, DateTimeKind.Utc);
|
||||
|
||||
Celestial c = new Celestial(false);
|
||||
|
||||
SunCalc.CalculateSunTime(lat, longi, date, c);
|
||||
MoonCalc.GetMoonTimes(date, lat, longi, c);
|
||||
MoonCalc.GetMoonDistance(date, c);
|
||||
SunCalc.CalculateZodiacSign(date, c);
|
||||
MoonCalc.GetMoonSign(date, c);
|
||||
MoonCalc.GetMoonIllumination(date, c,lat,longi);
|
||||
|
||||
c.perigee = MoonCalc.GetPerigeeEvents(date);
|
||||
c.apogee = MoonCalc.GetApogeeEvents(date);
|
||||
|
||||
Calculate_Celestial_IsUp_Booleans(date, c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate sun data based on lat/long and date.
|
||||
/// </summary>
|
||||
/// <param name="lat">latitude</param>
|
||||
/// <param name="longi">longitude</param>
|
||||
/// <param name="date">DateTime</param>
|
||||
/// <returns>Celestial (Partially Populated)</returns>
|
||||
public static Celestial CalculateSunData(double lat, double longi, DateTime date)
|
||||
{
|
||||
date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, DateTimeKind.Utc);
|
||||
|
||||
Celestial c = new Celestial(false);
|
||||
SunCalc.CalculateSunTime(lat, longi, date, c);
|
||||
SunCalc.CalculateZodiacSign(date, c);
|
||||
|
||||
return c;
|
||||
}
|
||||
/// <summary>
|
||||
/// Calculate moon data based on lat/long and date.
|
||||
/// </summary>
|
||||
/// <param name="lat">latitude</param>
|
||||
/// <param name="longi">longitude</param>
|
||||
/// <param name="date">DateTime</param>
|
||||
/// <returns>Celestial (Partially Populated)</returns>
|
||||
public static Celestial CalculateMoonData(double lat, double longi, DateTime date)
|
||||
{
|
||||
date = new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, DateTimeKind.Utc);
|
||||
|
||||
Celestial c = new Celestial(false);
|
||||
|
||||
MoonCalc.GetMoonTimes(date, lat, longi, c);
|
||||
MoonCalc.GetMoonDistance(date, c);
|
||||
MoonCalc.GetMoonSign(date, c);
|
||||
MoonCalc.GetMoonIllumination(date, c,lat,longi);
|
||||
|
||||
c.perigee = MoonCalc.GetPerigeeEvents(date);
|
||||
c.apogee = MoonCalc.GetApogeeEvents(date);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a List containing solar eclipse data for the century.
|
||||
/// Century return is based on the date passed.
|
||||
/// </summary>
|
||||
/// <param name="lat">latitude</param>
|
||||
/// <param name="longi">longitude</param>
|
||||
/// <param name="date">DateTime</param>
|
||||
/// <returns></returns>
|
||||
public static List<SolarEclipseDetails> Get_Solar_Eclipse_Table(double lat, double longi, DateTime date)
|
||||
{
|
||||
//Convert to Radians
|
||||
double latR = lat * Math.PI / 180;
|
||||
double longR = longi * Math.PI / 180;
|
||||
//Get solar data based on date
|
||||
double[] events = Eclipse.SolarData.SolarDateData_100Year(date);
|
||||
//Return list of solar data.
|
||||
return SolarEclipseCalc.CalculateSolarEclipse(date, latR, longR, events);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a List containing solar eclipse data for the century.
|
||||
/// Century return is based on the date passed.
|
||||
/// </summary>
|
||||
/// <param name="lat">latitude</param>
|
||||
/// <param name="longi">longitude</param>
|
||||
/// <param name="date">DateTime</param>
|
||||
/// <returns></returns>
|
||||
public static List<LunarEclipseDetails> Get_Lunar_Eclipse_Table(double lat, double longi, DateTime date)
|
||||
{
|
||||
//Convert to Radians
|
||||
double latR = lat * Math.PI / 180;
|
||||
double longR = longi * Math.PI / 180;
|
||||
//Get solar data based on date
|
||||
double[] events = Eclipse.LunarData.LunarDateData_100Year(date);
|
||||
//Return list of solar data.
|
||||
return LunarEclipseCalc.CalculateLunarEclipse(date, latR, longR, events);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set bool SunIsUp and MoonIsUp values
|
||||
/// </summary>
|
||||
/// <param name="date">Coordinate GeoDate</param>
|
||||
/// <param name="cel">Celestial Object</param>
|
||||
private static void Calculate_Celestial_IsUp_Booleans(DateTime date, Celestial cel)
|
||||
{
|
||||
//SUN
|
||||
switch (cel.SunCondition)
|
||||
{
|
||||
case CelestialStatus.DownAllDay:
|
||||
cel.isSunUp = false;
|
||||
break;
|
||||
case CelestialStatus.UpAllDay:
|
||||
cel.isSunUp = true;
|
||||
break;
|
||||
case CelestialStatus.NoRise:
|
||||
if(date<cel.SunSet)
|
||||
{
|
||||
cel.isSunUp = true;
|
||||
}
|
||||
else { cel.isSunUp = false; }
|
||||
break;
|
||||
case CelestialStatus.NoSet:
|
||||
if (date > cel.SunRise)
|
||||
{
|
||||
cel.isSunUp = true;
|
||||
}
|
||||
else { cel.isSunUp = false; }
|
||||
break;
|
||||
case CelestialStatus.RiseAndSet:
|
||||
if (cel.SunRise < cel.SunSet)
|
||||
{
|
||||
if (date > cel.SunRise && date < cel.SunSet)
|
||||
{
|
||||
cel.isSunUp = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
cel.isSunUp = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (date > cel.SunRise || date < cel.SunSet)
|
||||
{
|
||||
cel.isSunUp = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
cel.isSunUp = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//Should never be reached. If reached, previous calculations failed somewhere.
|
||||
break;
|
||||
}
|
||||
|
||||
//MOON
|
||||
switch (cel.MoonCondition)
|
||||
{
|
||||
case CelestialStatus.DownAllDay:
|
||||
cel.isMoonUp = false;
|
||||
break;
|
||||
case CelestialStatus.UpAllDay:
|
||||
cel.isMoonUp = true;
|
||||
break;
|
||||
case CelestialStatus.NoRise:
|
||||
if (date < cel.MoonSet)
|
||||
{
|
||||
cel.isMoonUp = true;
|
||||
}
|
||||
else { cel.isMoonUp = false; }
|
||||
break;
|
||||
case CelestialStatus.NoSet:
|
||||
if (date > cel.MoonRise)
|
||||
{
|
||||
cel.isMoonUp = true;
|
||||
}
|
||||
else { cel.isMoonUp = false; }
|
||||
break;
|
||||
case CelestialStatus.RiseAndSet:
|
||||
if (cel.MoonRise < cel.MoonSet)
|
||||
{
|
||||
if (date > cel.MoonRise && date < cel.MoonSet)
|
||||
{
|
||||
cel.isMoonUp = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
cel.isMoonUp = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (date > cel.MoonRise || date < cel.MoonSet)
|
||||
{
|
||||
cel.isMoonUp = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
cel.isMoonUp = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//Should never be reached. If reached, previous calculations failed somewhere.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns Apogee object containing last and next apogee based on the specified date.
|
||||
/// </summary>
|
||||
/// <param name="d">DateTime</param>
|
||||
/// <returns>Apogee</returns>
|
||||
public static Apogee GetApogees(DateTime d)
|
||||
{
|
||||
return MoonCalc.GetApogeeEvents(d);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns Perigee object containing last and next perigee based on the specified date.
|
||||
/// </summary>
|
||||
/// <param name="d">DateTime</param>
|
||||
/// <returns>Perigee</returns>
|
||||
public static Perigee GetPerigees(DateTime d)
|
||||
{
|
||||
return MoonCalc.GetPerigeeEvents(d);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,269 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used for UTM/MGRS Conversions
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal class LatZones
|
||||
{
|
||||
public static List<string> longZongLetters = new List<string>(new string[]{"C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T",
|
||||
"U", "V", "W", "X"});
|
||||
}
|
||||
/// <summary>
|
||||
/// Used for handling diagraph determination
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal class Digraphs
|
||||
{
|
||||
private List<Digraph> digraph1;
|
||||
private List<Digraph> digraph2;
|
||||
|
||||
private String[] digraph1Array = { "A", "B", "C", "D", "E", "F", "G", "H",
|
||||
"J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X",
|
||||
"Y", "Z" };
|
||||
|
||||
private String[] digraph2Array = { "V", "A", "B", "C", "D", "E", "F", "G",
|
||||
"H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V" };
|
||||
|
||||
public Digraphs()
|
||||
{
|
||||
digraph1 = new List<Digraph>();
|
||||
digraph2 = new List<Digraph>();
|
||||
|
||||
digraph1.Add(new Digraph() { Zone = 1, Letter = "A" });
|
||||
digraph1.Add(new Digraph() { Zone = 2, Letter = "B" });
|
||||
digraph1.Add(new Digraph() { Zone = 3, Letter = "C" });
|
||||
digraph1.Add(new Digraph() { Zone = 4, Letter = "D" });
|
||||
digraph1.Add(new Digraph() { Zone = 5, Letter = "E" });
|
||||
digraph1.Add(new Digraph() { Zone = 6, Letter = "F" });
|
||||
digraph1.Add(new Digraph() { Zone = 7, Letter = "G" });
|
||||
digraph1.Add(new Digraph() { Zone = 8, Letter = "H" });
|
||||
digraph1.Add(new Digraph() { Zone = 9, Letter = "J" });
|
||||
digraph1.Add(new Digraph() { Zone = 10, Letter = "K" });
|
||||
digraph1.Add(new Digraph() { Zone = 11, Letter = "L" });
|
||||
digraph1.Add(new Digraph() { Zone = 12, Letter = "M" });
|
||||
digraph1.Add(new Digraph() { Zone = 13, Letter = "N" });
|
||||
digraph1.Add(new Digraph() { Zone = 14, Letter = "P" });
|
||||
digraph1.Add(new Digraph() { Zone = 15, Letter = "Q" });
|
||||
digraph1.Add(new Digraph() { Zone = 16, Letter = "R" });
|
||||
digraph1.Add(new Digraph() { Zone = 17, Letter = "S" });
|
||||
digraph1.Add(new Digraph() { Zone = 18, Letter = "T" });
|
||||
digraph1.Add(new Digraph() { Zone = 19, Letter = "U" });
|
||||
digraph1.Add(new Digraph() { Zone = 20, Letter = "V" });
|
||||
digraph1.Add(new Digraph() { Zone = 21, Letter = "W" });
|
||||
digraph1.Add(new Digraph() { Zone = 22, Letter = "X" });
|
||||
digraph1.Add(new Digraph() { Zone = 23, Letter = "Y" });
|
||||
digraph1.Add(new Digraph() { Zone = 24, Letter = "Z" });
|
||||
digraph1.Add(new Digraph() { Zone = 1, Letter = "A" });
|
||||
|
||||
digraph2.Add(new Digraph() { Zone = 0, Letter = "V"});
|
||||
digraph2.Add(new Digraph() { Zone = 1, Letter = "A" });
|
||||
digraph2.Add(new Digraph() { Zone = 2, Letter = "B" });
|
||||
digraph2.Add(new Digraph() { Zone = 3, Letter = "C" });
|
||||
digraph2.Add(new Digraph() { Zone = 4, Letter = "D" });
|
||||
digraph2.Add(new Digraph() { Zone = 5, Letter = "E" });
|
||||
digraph2.Add(new Digraph() { Zone = 6, Letter = "F" });
|
||||
digraph2.Add(new Digraph() { Zone = 7, Letter = "G" });
|
||||
digraph2.Add(new Digraph() { Zone = 8, Letter = "H" });
|
||||
digraph2.Add(new Digraph() { Zone = 9, Letter = "J" });
|
||||
digraph2.Add(new Digraph() { Zone = 10, Letter = "K" });
|
||||
digraph2.Add(new Digraph() { Zone = 11, Letter = "L" });
|
||||
digraph2.Add(new Digraph() { Zone = 12, Letter = "M" });
|
||||
digraph2.Add(new Digraph() { Zone = 13, Letter = "N" });
|
||||
digraph2.Add(new Digraph() { Zone = 14, Letter = "P" });
|
||||
digraph2.Add(new Digraph() { Zone = 15, Letter = "Q" });
|
||||
digraph2.Add(new Digraph() { Zone = 16, Letter = "R" });
|
||||
digraph2.Add(new Digraph() { Zone = 17, Letter = "S" });
|
||||
digraph2.Add(new Digraph() { Zone = 18, Letter = "T" });
|
||||
digraph2.Add(new Digraph() { Zone = 19, Letter = "U" });
|
||||
digraph2.Add(new Digraph() { Zone = 20, Letter = "V" });
|
||||
}
|
||||
|
||||
internal int getDigraph1Index(String letter)
|
||||
{
|
||||
for (int i = 0; i < digraph1Array.Length; i++)
|
||||
{
|
||||
if (digraph1Array[i].Equals(letter))
|
||||
{
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
internal int getDigraph2Index(String letter)
|
||||
{
|
||||
for (int i = 0; i < digraph2Array.Length; i++)
|
||||
{
|
||||
if (digraph2Array[i].Equals(letter))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
internal String getDigraph1(int longZone, double easting)
|
||||
{
|
||||
int a1 = longZone;
|
||||
double a2 = 8 * ((a1 - 1) % 3) + 1;
|
||||
|
||||
double a3 = easting;
|
||||
double a4 = a2 + ((int)(a3 / 100000)) - 1;
|
||||
return digraph1.Where(x=>x.Zone == Math.Floor(a4)).FirstOrDefault().Letter;
|
||||
}
|
||||
|
||||
internal String getDigraph2(int longZone, double northing)
|
||||
{
|
||||
int a1 = longZone;
|
||||
double a2 = 1 + 5 * ((a1 - 1) % 2);
|
||||
double a3 = northing;
|
||||
double a4 = (a2 + ((int)(a3 / 100000)));
|
||||
a4 = (a2 + ((int)(a3 / 100000.0))) % 20;
|
||||
a4 = Math.Floor(a4);
|
||||
if (a4 < 0)
|
||||
{
|
||||
a4 = a4 + 19;
|
||||
}
|
||||
return digraph2.Where(x => x.Zone == Math.Floor(a4)).FirstOrDefault().Letter;
|
||||
}
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Diagraph model
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal class Digraph
|
||||
{
|
||||
public int Zone { get; set; }
|
||||
public string Letter { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Used for setting whether a coordinate part is latitudinal or longitudinal.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public enum CoordinateType
|
||||
{
|
||||
/// <summary>
|
||||
/// Latitude
|
||||
/// </summary>
|
||||
Lat,
|
||||
/// <summary>
|
||||
/// Longitude
|
||||
/// </summary>
|
||||
Long
|
||||
}
|
||||
/// <summary>
|
||||
/// Used to set a coordinate part position.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public enum CoordinatesPosition :int
|
||||
{
|
||||
/// <summary>
|
||||
/// North
|
||||
/// </summary>
|
||||
N,
|
||||
/// <summary>
|
||||
/// East
|
||||
/// </summary>
|
||||
E,
|
||||
/// <summary>
|
||||
/// South
|
||||
/// </summary>
|
||||
S,
|
||||
/// <summary>
|
||||
/// West
|
||||
/// </summary>
|
||||
W
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Coordinate type datum specification
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[Flags]
|
||||
public enum Coordinate_Datum
|
||||
{
|
||||
/// <summary>
|
||||
/// Lat Long GeoDetic
|
||||
/// </summary>
|
||||
LAT_LONG = 1,
|
||||
/// <summary>
|
||||
/// UTM and MGRS
|
||||
/// </summary>
|
||||
UTM_MGRS = 2,
|
||||
/// <summary>
|
||||
/// ECEF
|
||||
/// </summary>
|
||||
ECEF = 4,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cartesian Coordinate Type
|
||||
/// </summary>
|
||||
public enum CartesianType
|
||||
{
|
||||
/// <summary>
|
||||
/// Spherical Cartesian
|
||||
/// </summary>
|
||||
Cartesian,
|
||||
/// <summary>
|
||||
/// Earth Centered Earth Fixed
|
||||
/// </summary>
|
||||
ECEF,
|
||||
}
|
||||
/// <summary>
|
||||
/// Used for easy read math functions
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal static class ModM
|
||||
{
|
||||
public static double Mod(double x, double y)
|
||||
{
|
||||
return x - y * Math.Floor(x / y);
|
||||
}
|
||||
|
||||
public static double ModLon(double x)
|
||||
{
|
||||
return Mod(x + Math.PI, 2 * Math.PI) - Math.PI;
|
||||
}
|
||||
|
||||
public static double ModCrs(double x)
|
||||
{
|
||||
return Mod(x, 2 * Math.PI);
|
||||
}
|
||||
|
||||
public static double ModLat(double x)
|
||||
{
|
||||
return Mod(x + Math.PI / 2, 2 * Math.PI) - Math.PI / 2;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Earth Shape for Calculations.
|
||||
/// </summary>
|
||||
|
||||
[Serializable]
|
||||
public enum Shape
|
||||
{
|
||||
/// <summary>
|
||||
/// Calculate as sphere (less accurate, more efficient).
|
||||
/// </summary>
|
||||
Sphere,
|
||||
/// <summary>
|
||||
/// Calculate as ellipsoid (more accurate, less efficient).
|
||||
/// </summary>
|
||||
Ellipsoid
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,155 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Cartesian (X, Y, Z) Coordinate
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class Cartesian : INotifyPropertyChanged
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a Cartesian Object
|
||||
/// </summary>
|
||||
/// <param name="c"></param>
|
||||
public Cartesian(Coordinate c)
|
||||
{
|
||||
//formulas:
|
||||
x = Math.Cos(c.Latitude.ToRadians()) * Math.Cos(c.Longitude.ToRadians());
|
||||
y = Math.Cos(c.Latitude.ToRadians()) * Math.Sin(c.Longitude.ToRadians());
|
||||
z = Math.Sin(c.Latitude.ToRadians());
|
||||
}
|
||||
/// <summary>
|
||||
/// Create a Cartesian Object
|
||||
/// </summary>
|
||||
/// <param name="xc">X</param>
|
||||
/// <param name="yc">Y</param>
|
||||
/// <param name="zc">Z</param>
|
||||
public Cartesian(double xc, double yc, double zc)
|
||||
{
|
||||
//formulas:
|
||||
x = xc;
|
||||
y = yc;
|
||||
z = zc;
|
||||
}
|
||||
/// <summary>
|
||||
/// Updates Cartesian Values
|
||||
/// </summary>
|
||||
/// <param name="c"></param>
|
||||
public void ToCartesian(Coordinate c)
|
||||
{
|
||||
x = Math.Cos(c.Latitude.ToRadians()) * Math.Cos(c.Longitude.ToRadians());
|
||||
y = Math.Cos(c.Latitude.ToRadians()) * Math.Sin(c.Longitude.ToRadians());
|
||||
z = Math.Sin(c.Latitude.ToRadians());
|
||||
}
|
||||
private double x;
|
||||
private double y;
|
||||
private double z;
|
||||
|
||||
/// <summary>
|
||||
/// X Coordinate
|
||||
/// </summary>
|
||||
public double X
|
||||
{
|
||||
get { return x; }
|
||||
set
|
||||
{
|
||||
if(x != value)
|
||||
{
|
||||
x = value;
|
||||
NotifyPropertyChanged("X");
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// y Coordinate
|
||||
/// </summary>
|
||||
public double Y
|
||||
{
|
||||
get { return y; }
|
||||
set
|
||||
{
|
||||
if (y != value)
|
||||
{
|
||||
y = value;
|
||||
NotifyPropertyChanged("Y");
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Z Coordinate
|
||||
/// </summary>
|
||||
public double Z
|
||||
{
|
||||
get { return z; }
|
||||
set
|
||||
{
|
||||
if (z != value)
|
||||
{
|
||||
z = value;
|
||||
NotifyPropertyChanged("Z");
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a Lat Long Coordinate object based on the provided Cartesian Coordinate
|
||||
/// </summary>
|
||||
/// <param name="x">X</param>
|
||||
/// <param name="y">Y</param>
|
||||
/// <param name="z">Z</param>
|
||||
/// <returns></returns>
|
||||
public static Coordinate CartesianToLatLong(double x, double y, double z)
|
||||
{
|
||||
double lon = Math.Atan2(y, x);
|
||||
double hyp = Math.Sqrt(x * x + y * y);
|
||||
double lat = Math.Atan2(z, hyp);
|
||||
|
||||
double Lat = lat * (180 / Math.PI);
|
||||
double Lon = lon * (180 / Math.PI);
|
||||
return new Coordinate(Lat, Lon);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a Lat Long Coordinate object based on the provided Cartesian Coordinate
|
||||
/// </summary>
|
||||
/// <param name="cart">Cartesian Coordinate</param>
|
||||
/// <returns></returns>
|
||||
public static Coordinate CartesianToLatLong(Cartesian cart)
|
||||
{
|
||||
double x = cart.X;
|
||||
double y = cart.Y;
|
||||
double z = cart.Z;
|
||||
|
||||
double lon = Math.Atan2(y, x);
|
||||
double hyp = Math.Sqrt(x * x + y * y);
|
||||
double lat = Math.Atan2(z, hyp);
|
||||
|
||||
double Lat = lat * (180 / Math.PI);
|
||||
double Lon = lon * (180 / Math.PI);
|
||||
return new Coordinate(Lat, Lon);
|
||||
}
|
||||
/// <summary>
|
||||
/// Cartesian Default String Format
|
||||
/// </summary>
|
||||
/// <returns>Cartesian Formatted Coordinate String</returns>
|
||||
/// <returns>Values rounded to the 8th place</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return Math.Round(x,8).ToString() + " " + Math.Round(y, 8).ToString() + " " + Math.Round(z, 8).ToString();
|
||||
}
|
||||
/// <summary>
|
||||
/// Property changed event
|
||||
/// </summary>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
/// <summary>
|
||||
/// Notify property changed
|
||||
/// </summary>
|
||||
/// <param name="propName">Property name</param>
|
||||
public void NotifyPropertyChanged(string propName)
|
||||
{
|
||||
if (this.PropertyChanged != null)
|
||||
{
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(propName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,566 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.ComponentModel;
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Earth Centered - Earth Fixed (X,Y,Z) Coordinate
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class ECEF : INotifyPropertyChanged
|
||||
{
|
||||
/// <summary>
|
||||
/// Create an ECEF Object
|
||||
/// </summary>
|
||||
/// <param name="c">Coordinate</param>
|
||||
public ECEF(Coordinate c)
|
||||
{
|
||||
equatorial_radius = 6378137.0;
|
||||
inverse_flattening = 298.257223563;
|
||||
WGS84();
|
||||
geodetic_height = new Distance(0);
|
||||
double[] ecef = LatLong_To_ECEF(c.Latitude.DecimalDegree, c.Longitude.DecimalDegree, geodetic_height.Kilometers);
|
||||
x = ecef[0];
|
||||
y = ecef[1];
|
||||
z = ecef[2];
|
||||
}
|
||||
/// <summary>
|
||||
/// Create an ECEF Object
|
||||
/// </summary>
|
||||
/// <param name="c">Coordinate</param>
|
||||
/// <param name="height">Coordinate</param>
|
||||
public ECEF(Coordinate c, Distance height)
|
||||
{
|
||||
equatorial_radius = 6378137.0;
|
||||
inverse_flattening = 298.257223563;
|
||||
WGS84();
|
||||
geodetic_height = height;
|
||||
double[] ecef = LatLong_To_ECEF(c.Latitude.DecimalDegree, c.Longitude.DecimalDegree, geodetic_height.Kilometers);
|
||||
x = ecef[0];
|
||||
y = ecef[1];
|
||||
z = ecef[2];
|
||||
}
|
||||
/// <summary>
|
||||
/// Create an ECEF Object
|
||||
/// </summary>
|
||||
/// <param name="xc">X</param>
|
||||
/// <param name="yc">Y</param>
|
||||
/// <param name="zc">Z</param>
|
||||
public ECEF(double xc, double yc, double zc)
|
||||
{
|
||||
equatorial_radius = 6378137.0;
|
||||
inverse_flattening = 298.257223563;
|
||||
WGS84();
|
||||
geodetic_height = new Distance(0);
|
||||
x = xc;
|
||||
y = yc;
|
||||
z = zc;
|
||||
}
|
||||
/// <summary>
|
||||
/// Updates ECEF Values
|
||||
/// </summary>
|
||||
/// <param name="c">Coordinate</param>
|
||||
public void ToECEF(Coordinate c)
|
||||
{
|
||||
equatorial_radius = 6378137.0;
|
||||
inverse_flattening = 298.257223563;
|
||||
WGS84();
|
||||
double[] ecef = LatLong_To_ECEF(c.Latitude.DecimalDegree, c.Longitude.DecimalDegree, geodetic_height.Kilometers);
|
||||
x = ecef[0];
|
||||
y = ecef[1];
|
||||
z = ecef[2];
|
||||
}
|
||||
|
||||
//Globals for calucations
|
||||
private double EARTH_A;
|
||||
private double EARTH_B;
|
||||
private double EARTH_F;
|
||||
private double EARTH_Ecc;
|
||||
private double EARTH_Esq;
|
||||
|
||||
//ECEF Values
|
||||
private double x;
|
||||
private double y;
|
||||
private double z;
|
||||
private Distance geodetic_height;
|
||||
|
||||
//Datum
|
||||
internal double equatorial_radius;
|
||||
internal double inverse_flattening;
|
||||
|
||||
/// <summary>
|
||||
/// Datum Equatorial Radius / Semi Major Axis
|
||||
/// </summary>
|
||||
public double Equatorial_Radius
|
||||
{
|
||||
get { return equatorial_radius; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Datum Flattening
|
||||
/// </summary>
|
||||
public double Inverse_Flattening
|
||||
{
|
||||
get { return inverse_flattening; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// X Coordinate
|
||||
/// </summary>
|
||||
public double X
|
||||
{
|
||||
get { return x; }
|
||||
set
|
||||
{
|
||||
if (x != value)
|
||||
{
|
||||
x = value;
|
||||
NotifyPropertyChanged("X");
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// y Coordinate
|
||||
/// </summary>
|
||||
public double Y
|
||||
{
|
||||
get { return y; }
|
||||
set
|
||||
{
|
||||
if (y != value)
|
||||
{
|
||||
y = value;
|
||||
NotifyPropertyChanged("Y");
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Z Coordinate
|
||||
/// </summary>
|
||||
public double Z
|
||||
{
|
||||
get { return z; }
|
||||
set
|
||||
{
|
||||
if (z != value)
|
||||
{
|
||||
z = value;
|
||||
NotifyPropertyChanged("Z");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GeoDetic Height from Mean Sea Level.
|
||||
/// Used for converting Lat Long / ECEF.
|
||||
/// Default value is 0. Adjust as needed.
|
||||
/// </summary>
|
||||
public Distance GeoDetic_Height
|
||||
{
|
||||
get { return geodetic_height; }
|
||||
internal set
|
||||
{
|
||||
if (geodetic_height != value)
|
||||
{
|
||||
geodetic_height = value;
|
||||
NotifyPropertyChanged("Height");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets GeoDetic height for ECEF conversion.
|
||||
/// Recalculate ECEF Coordinate
|
||||
/// </summary>
|
||||
/// <param name="c">Coordinate</param>
|
||||
/// <param name="dist">Height</param>
|
||||
public void Set_GeoDetic_Height(Coordinate c, Distance dist)
|
||||
{
|
||||
geodetic_height = dist;
|
||||
double[] values = LatLong_To_ECEF(c.Latitude.DecimalDegree, c.Longitude.DecimalDegree, dist.Kilometers);
|
||||
x = values[0];
|
||||
y = values[1];
|
||||
z = values[2];
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a Geodetic Coordinate object based on the provided ECEF Coordinate
|
||||
/// </summary>
|
||||
/// <param name="x">X</param>
|
||||
/// <param name="y">Y</param>
|
||||
/// <param name="z">Z</param>
|
||||
/// <returns>Coordinate</returns>
|
||||
public static Coordinate ECEFToLatLong(double x, double y, double z)
|
||||
{
|
||||
ECEF ecef = new ECEF(x, y, z);
|
||||
double[] values = ecef.ECEF_To_LatLong(x, y, z);
|
||||
ecef.geodetic_height =new Distance(values[2]);
|
||||
|
||||
Coordinate c = new Coordinate(values[0], values[1]);
|
||||
c.ECEF = ecef;
|
||||
return c;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns a Geodetic Coordinate object based on the provided ECEF Coordinate
|
||||
/// </summary>
|
||||
/// <param name="ecef">ECEF Coordinate</param>
|
||||
/// <returns>Coordinate</returns>
|
||||
public static Coordinate ECEFToLatLong(ECEF ecef)
|
||||
{
|
||||
double[] values = ecef.ECEF_To_LatLong(ecef.X, ecef.Y, ecef.Z);
|
||||
|
||||
Coordinate c = new Coordinate(values[0], values[1]);
|
||||
Distance height = new Distance(values[2]);
|
||||
|
||||
ecef.geodetic_height = new Distance(values[2]);
|
||||
c.ECEF = ecef;
|
||||
|
||||
return c;
|
||||
}
|
||||
/// <summary>
|
||||
/// ECEF Default String Format
|
||||
/// </summary>
|
||||
/// <returns>ECEF Formatted Coordinate String</returns>
|
||||
/// <returns>Values rounded to the 3rd place</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return Math.Round(x, 3).ToString() + " km, " + Math.Round(y, 3).ToString() + " km, " + Math.Round(z, 3).ToString() + " km";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property changed event
|
||||
/// </summary>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
/// <summary>
|
||||
/// Notify property changed
|
||||
/// </summary>
|
||||
/// <param name="propName">Property name</param>
|
||||
public void NotifyPropertyChanged(string propName)
|
||||
{
|
||||
if (PropertyChanged != null)
|
||||
{
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(propName));
|
||||
}
|
||||
}
|
||||
|
||||
//CONVERSION LOGIC
|
||||
/// <summary>
|
||||
/// Initialize EARTH global variables based on the Datum
|
||||
/// </summary>
|
||||
private void WGS84()
|
||||
{
|
||||
double wgs84a = equatorial_radius / 1000;
|
||||
double wgs84f = 1.0 / inverse_flattening;
|
||||
double wgs84b = wgs84a * (1.0 - wgs84f);
|
||||
|
||||
EarthCon(wgs84a, wgs84b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets Earth Constants as Globals
|
||||
/// </summary>
|
||||
/// <param name="a">a</param>
|
||||
/// <param name="b">b</param>
|
||||
private void EarthCon(double a, double b)
|
||||
{
|
||||
double f = 1 - b / a;
|
||||
double eccsq = 1 - b * b / (a * a);
|
||||
double ecc = Math.Sqrt(eccsq);
|
||||
|
||||
EARTH_A = a;
|
||||
EARTH_B = b;
|
||||
EARTH_F = f;
|
||||
EARTH_Ecc = ecc;
|
||||
EARTH_Esq = eccsq;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute the radii at the geodetic latitude (degrees)
|
||||
/// </summary>
|
||||
/// <param name="lat">Latitude in degres</param>
|
||||
/// <returns>double[]</returns>
|
||||
private double[] radcur(double lat)
|
||||
{
|
||||
double[] rrnrm = new double[3];
|
||||
|
||||
double dtr = Math.PI / 180.0;
|
||||
|
||||
double a = EARTH_A;
|
||||
double b = EARTH_B;
|
||||
|
||||
double asq = a * a;
|
||||
double bsq = b * b;
|
||||
double eccsq = 1 - bsq / asq;
|
||||
double ecc = Math.Sqrt(eccsq);
|
||||
|
||||
double clat = Math.Cos(dtr * lat);
|
||||
double slat = Math.Sin(dtr * lat);
|
||||
|
||||
double dsq = 1.0 - eccsq * slat * slat;
|
||||
double d = Math.Sqrt(dsq);
|
||||
|
||||
double rn = a / d;
|
||||
double rm = rn * (1.0 - eccsq) / dsq;
|
||||
|
||||
double rho = rn * clat;
|
||||
double z = (1.0 - eccsq) * rn * slat;
|
||||
double rsq = rho * rho + z * z;
|
||||
double r = Math.Sqrt(rsq);
|
||||
|
||||
rrnrm[0] = r;
|
||||
rrnrm[1] = rn;
|
||||
rrnrm[2] = rm;
|
||||
|
||||
return (rrnrm);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Physical radius of the Earth
|
||||
/// </summary>
|
||||
/// <param name="lat">Latidude in degrees</param>
|
||||
/// <returns>double</returns>
|
||||
private double rearth(double lat)
|
||||
{
|
||||
double[] rrnrm;
|
||||
rrnrm = radcur(lat);
|
||||
double r = rrnrm[0];
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts geocentric latitude to geodetic latitude
|
||||
/// </summary>
|
||||
/// <param name="flatgc">Geocentric latitude</param>
|
||||
/// <param name="altkm">Altitude in KM</param>
|
||||
/// <returns>double</returns>
|
||||
private double gc2gd(double flatgc, double altkm)
|
||||
{
|
||||
var dtr = Math.PI / 180.0;
|
||||
var rtd = 1 / dtr;
|
||||
|
||||
double ecc = EARTH_Ecc;
|
||||
double esq = ecc * ecc;
|
||||
|
||||
//approximation by stages
|
||||
//1st use gc-lat as if is gd, then correct alt dependence
|
||||
|
||||
double altnow = altkm;
|
||||
|
||||
double[] rrnrm = radcur(flatgc);
|
||||
double rn = rrnrm[1];
|
||||
|
||||
double ratio = 1 - esq * rn / (rn + altnow);
|
||||
|
||||
double tlat = Math.Tan(dtr * flatgc) / ratio;
|
||||
double flatgd = rtd * Math.Atan(tlat);
|
||||
|
||||
//now use this approximation for gd-lat to get rn etc.
|
||||
|
||||
rrnrm = radcur(flatgd);
|
||||
rn = rrnrm[1];
|
||||
|
||||
ratio = 1 - esq * rn / (rn + altnow);
|
||||
tlat = Math.Tan(dtr * flatgc) / ratio;
|
||||
flatgd = rtd * Math.Atan(tlat);
|
||||
|
||||
return flatgd;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts geodetic latitude to geocentric latitude
|
||||
/// </summary>
|
||||
/// <param name="flatgd">Geodetic latitude tp geocentric latitide</param>
|
||||
/// <param name="altkm">Altitude in KM</param>
|
||||
/// <returns>double</returns>
|
||||
private double gd2gc(double flatgd, double altkm)
|
||||
{
|
||||
double dtr = Math.PI / 180.0;
|
||||
double rtd = 1 / dtr;
|
||||
|
||||
double ecc = EARTH_Ecc;
|
||||
double esq = ecc * ecc;
|
||||
|
||||
double altnow = altkm;
|
||||
|
||||
double[] rrnrm = radcur(flatgd);
|
||||
double rn = rrnrm[1];
|
||||
|
||||
double ratio = 1 - esq * rn / (rn + altnow);
|
||||
|
||||
double tlat = Math.Tan(dtr * flatgd) * ratio;
|
||||
double flatgc = rtd * Math.Atan(tlat);
|
||||
|
||||
return flatgc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts lat / long to east, north, up vectors
|
||||
/// </summary>
|
||||
/// <param name="flat">Latitude</param>
|
||||
/// <param name="flon">Longitude</param>
|
||||
/// <returns>Array[] of double[]</returns>
|
||||
private Array[] llenu(double flat, double flon)
|
||||
{
|
||||
double clat, slat, clon, slon;
|
||||
double[] ee = new double[3];
|
||||
double[] en = new double[3];
|
||||
double[] eu = new double[3];
|
||||
|
||||
Array[] enu = new Array[3];
|
||||
|
||||
double dtr = Math.PI / 180.0;
|
||||
|
||||
clat = Math.Cos(dtr * flat);
|
||||
slat = Math.Sin(dtr * flat);
|
||||
clon = Math.Cos(dtr * flon);
|
||||
slon = Math.Sin(dtr * flon);
|
||||
|
||||
ee[0] = -slon;
|
||||
ee[1] = clon;
|
||||
ee[2] = 0.0;
|
||||
|
||||
en[0] = -clon * slat;
|
||||
en[1] = -slon * slat;
|
||||
en[2] = clat;
|
||||
|
||||
eu[0] = clon * clat;
|
||||
eu[1] = slon * clat;
|
||||
eu[2] = slat;
|
||||
|
||||
enu[0] = ee;
|
||||
enu[1] = en;
|
||||
enu[2] = eu;
|
||||
|
||||
return enu;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets ECEF vector in KM
|
||||
/// </summary>
|
||||
/// <param name="lat">Latitude</param>
|
||||
/// <param name="longi">Longitude</param>
|
||||
/// <param name="altkm">Altitude in KM</param>
|
||||
/// <returns>double[]</returns>
|
||||
private double[] LatLong_To_ECEF(double lat, double longi, double altkm)
|
||||
{
|
||||
double dtr = Math.PI / 180.0;
|
||||
|
||||
double clat = Math.Cos(dtr * lat);
|
||||
double slat = Math.Sin(dtr * lat);
|
||||
double clon = Math.Cos(dtr * longi);
|
||||
double slon = Math.Sin(dtr * longi);
|
||||
|
||||
double[] rrnrm = radcur(lat);
|
||||
double rn = rrnrm[1];
|
||||
double re = rrnrm[0];
|
||||
|
||||
double ecc = EARTH_Ecc;
|
||||
double esq = ecc * ecc;
|
||||
|
||||
double x = (rn + altkm) * clat * clon;
|
||||
double y = (rn + altkm) * clat * slon;
|
||||
double z = ((1 - esq) * rn + altkm) * slat;
|
||||
|
||||
double[] xvec = new double[3];
|
||||
|
||||
xvec[0] = x;
|
||||
xvec[1] = y;
|
||||
xvec[2] = z;
|
||||
|
||||
return xvec;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts ECEF X, Y, Z to GeoDetic Lat / Long and Height in KM
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
/// <param name="z"></param>
|
||||
/// <returns></returns>
|
||||
private double[] ECEF_To_LatLong(double x, double y, double z)
|
||||
{
|
||||
var dtr = Math.PI / 180.0;
|
||||
|
||||
double[] rrnrm = new double[3];
|
||||
double[] llhvec = new double[3];
|
||||
double slat, tangd, flatn, dlat, clat;
|
||||
double flat;
|
||||
double altkm;
|
||||
|
||||
double esq = EARTH_Esq;
|
||||
|
||||
double rp = Math.Sqrt(x * x + y * y + z * z);
|
||||
|
||||
double flatgc = Math.Asin(z / rp) / dtr;
|
||||
double flon;
|
||||
double testval = Math.Abs(x) + Math.Abs(y);
|
||||
if (testval < 1.0e-10)
|
||||
{ flon = 0.0; }
|
||||
else
|
||||
{ flon = Math.Atan2(y, x) / dtr; }
|
||||
if (flon < 0.0) { flon = flon + 360.0; }
|
||||
|
||||
double p = Math.Sqrt(x * x + y * y);
|
||||
|
||||
//Pole special case
|
||||
|
||||
if (p < 1.0e-10)
|
||||
{
|
||||
flat = 90.0;
|
||||
if (z < 0.0) { flat = -90.0; }
|
||||
|
||||
altkm = rp - rearth(flat);
|
||||
llhvec[0] = flat;
|
||||
llhvec[1] = flon;
|
||||
llhvec[2] = altkm;
|
||||
|
||||
return llhvec;
|
||||
}
|
||||
|
||||
//first iteration, use flatgc to get altitude
|
||||
//and alt needed to convert gc to gd lat.
|
||||
|
||||
double rnow = rearth(flatgc);
|
||||
altkm = rp - rnow;
|
||||
flat = gc2gd(flatgc, altkm);
|
||||
|
||||
rrnrm = radcur(flat);
|
||||
double rn = rrnrm[1];
|
||||
|
||||
for (int kount = 0; kount < 5; kount++)
|
||||
{
|
||||
slat = Math.Sin(dtr * flat);
|
||||
tangd = (z + rn * esq * slat) / p;
|
||||
flatn = Math.Atan(tangd) / dtr;
|
||||
|
||||
dlat = flatn - flat;
|
||||
flat = flatn;
|
||||
clat = Math.Cos(dtr * flat);
|
||||
|
||||
rrnrm = radcur(flat);
|
||||
rn = rrnrm[1];
|
||||
|
||||
altkm = (p / clat) - rn;
|
||||
|
||||
if (Math.Abs(dlat) < 1.0e-12) { break; }
|
||||
|
||||
}
|
||||
//CONVERTER WORKS IN E LAT ONLY, IF E LAT > 180 LAT IS WEST SO IT MUCST BE CONVERTED TO Decimal
|
||||
|
||||
if (flon > 180) { flon = flon - 360; }
|
||||
llhvec[0] = flat;
|
||||
llhvec[1] = flon;
|
||||
llhvec[2] = altkm;
|
||||
|
||||
return llhvec;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -1,119 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Turn on/off eager loading of certain properties.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class EagerLoad
|
||||
{
|
||||
/// <summary>
|
||||
/// Create an EagerLoad object
|
||||
/// </summary>
|
||||
public EagerLoad()
|
||||
{
|
||||
Celestial = true;
|
||||
UTM_MGRS = true;
|
||||
Cartesian = true;
|
||||
ECEF = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an EagerLoad object with all options on or off
|
||||
/// </summary>
|
||||
/// <param name="isOn">Turns EagerLoad on or off</param>
|
||||
public EagerLoad(bool isOn)
|
||||
{
|
||||
Celestial = isOn;
|
||||
UTM_MGRS = isOn;
|
||||
Cartesian = isOn;
|
||||
ECEF = isOn;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an EagerLoad object with only the specified flag options turned on.
|
||||
/// </summary>
|
||||
/// <param name="et">EagerLoadType</param>
|
||||
public EagerLoad(EagerLoadType et)
|
||||
{
|
||||
Cartesian = false;
|
||||
Celestial = false;
|
||||
UTM_MGRS = false;
|
||||
ECEF = false;
|
||||
|
||||
if (et.HasFlag(EagerLoadType.Cartesian))
|
||||
{
|
||||
Cartesian = true;
|
||||
}
|
||||
if (et.HasFlag(EagerLoadType.Celestial))
|
||||
{
|
||||
Celestial = true;
|
||||
}
|
||||
if (et.HasFlag(EagerLoadType.UTM_MGRS))
|
||||
{
|
||||
UTM_MGRS = true;
|
||||
}
|
||||
if (et.HasFlag(EagerLoadType.ECEF))
|
||||
{
|
||||
ECEF = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an EagerLoad object. Only the specified flags will be set to EagerLoad.
|
||||
/// </summary>
|
||||
/// <param name="et">EagerLoadType</param>
|
||||
/// <returns>EagerLoad</returns>
|
||||
public static EagerLoad Create(EagerLoadType et)
|
||||
{
|
||||
EagerLoad el = new EagerLoad(et);
|
||||
return el;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Eager load celestial information.
|
||||
/// </summary>
|
||||
public bool Celestial { get; set; }
|
||||
/// <summary>
|
||||
/// Eager load UTM and MGRS information
|
||||
/// </summary>
|
||||
public bool UTM_MGRS { get; set; }
|
||||
/// <summary>
|
||||
/// Eager load Cartesian information
|
||||
/// </summary>
|
||||
public bool Cartesian { get; set; }
|
||||
/// <summary>
|
||||
/// Eager load ECEF information
|
||||
/// </summary>
|
||||
public bool ECEF { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// EagerLoad Enumerator
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[Flags]
|
||||
public enum EagerLoadType
|
||||
{
|
||||
/// <summary>
|
||||
/// UTM and MGRS
|
||||
/// </summary>
|
||||
UTM_MGRS = 1,
|
||||
/// <summary>
|
||||
/// Celestial
|
||||
/// </summary>
|
||||
Celestial = 2,
|
||||
/// <summary>
|
||||
/// Cartesian
|
||||
/// </summary>
|
||||
Cartesian = 4,
|
||||
/// <summary>
|
||||
/// ECEF
|
||||
/// </summary>
|
||||
ECEF = 8
|
||||
|
||||
}
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Coordinate formatting options for a Coordinate object.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class CoordinateFormatOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Set default values with the constructor.
|
||||
/// </summary>
|
||||
public CoordinateFormatOptions()
|
||||
{
|
||||
Format = CoordinateFormatType.Degree_Minutes_Seconds;
|
||||
Round = 3;
|
||||
Display_Leading_Zeros = false;
|
||||
Display_Trailing_Zeros = false;
|
||||
Display_Symbols = true;
|
||||
Display_Degree_Symbol = true;
|
||||
Display_Minute_Symbol = true;
|
||||
Display_Seconds_Symbol = true;
|
||||
Display_Hyphens = false;
|
||||
Position_First = true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Coordinate format type.
|
||||
/// </summary>
|
||||
public CoordinateFormatType Format { get; set; }
|
||||
/// <summary>
|
||||
/// Rounds Coordinates to the set value.
|
||||
/// </summary>
|
||||
public int Round { get; set; }
|
||||
/// <summary>
|
||||
/// Displays leading zeros.
|
||||
/// </summary>
|
||||
public bool Display_Leading_Zeros { get; set; }
|
||||
/// <summary>
|
||||
/// Display trailing zeros.
|
||||
/// </summary>
|
||||
public bool Display_Trailing_Zeros { get; set; }
|
||||
/// <summary>
|
||||
/// Allow symbols to display.
|
||||
/// </summary>
|
||||
public bool Display_Symbols { get; set; }
|
||||
/// <summary>
|
||||
/// Display degree symbols.
|
||||
/// </summary>
|
||||
public bool Display_Degree_Symbol { get; set; }
|
||||
/// <summary>
|
||||
/// Display minute symbols.
|
||||
/// </summary>
|
||||
public bool Display_Minute_Symbol { get; set; }
|
||||
/// <summary>
|
||||
/// Display secons symbol.
|
||||
/// </summary>
|
||||
public bool Display_Seconds_Symbol { get; set; }
|
||||
/// <summary>
|
||||
/// Display hyphens between values.
|
||||
/// </summary>
|
||||
public bool Display_Hyphens { get; set; }
|
||||
/// <summary>
|
||||
/// Show coordinate position first.
|
||||
/// Will show last if set 'false'.
|
||||
/// </summary>
|
||||
public bool Position_First { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Coordinate Format Types.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public enum CoordinateFormatType
|
||||
{
|
||||
/// <summary>
|
||||
/// Decimal Degree Format
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: N 40.456 W 75.456
|
||||
/// </remarks>
|
||||
Decimal_Degree,
|
||||
/// <summary>
|
||||
/// Decimal Degree Minutes Format
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: N 40º 34.552' W 70º 45.408'
|
||||
/// </remarks>
|
||||
Degree_Decimal_Minutes,
|
||||
/// <summary>
|
||||
/// Decimal Degree Minutes Format
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: N 40º 34" 36.552' W 70º 45" 24.408'
|
||||
/// </remarks>
|
||||
Degree_Minutes_Seconds,
|
||||
/// <summary>
|
||||
/// Decimal Format
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example: 40.57674 -70.46574
|
||||
/// </remarks>
|
||||
Decimal
|
||||
}
|
||||
}
|
@ -1,236 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace CoordinateSharp {
|
||||
/// <summary>
|
||||
/// Military Grid Reference System (MGRS). Uses the WGS 84 Datum.
|
||||
/// Relies upon values from the UniversalTransverseMercator class
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class MilitaryGridReferenceSystem : INotifyPropertyChanged {
|
||||
/// <summary>
|
||||
/// Create an MGRS object with WGS84 datum
|
||||
/// </summary>
|
||||
/// <param name="latz">Lat Zone</param>
|
||||
/// <param name="longz">Long Zone</param>
|
||||
/// <param name="d">Digraph</param>
|
||||
/// <param name="e">Easting</param>
|
||||
/// <param name="n">Northing</param>
|
||||
public MilitaryGridReferenceSystem(String latz, Int32 longz, String d, Double e, Double n) {
|
||||
String digraphLettersE = "ABCDEFGHJKLMNPQRSTUVWXYZ";
|
||||
String digraphLettersN = "ABCDEFGHJKLMNPQRSTUV";
|
||||
if(longz < 1 || longz > 60) { Debug.WriteLine("Longitudinal zone out of range", "UTM longitudinal zones must be between 1-60."); }
|
||||
if(!Verify_Lat_Zone(latz)) { throw new ArgumentException("Latitudinal zone invalid", "UTM latitudinal zone was unrecognized."); }
|
||||
if(n < 0 || n > 10000000) { throw new ArgumentOutOfRangeException("Northing out of range", "Northing must be between 0-10,000,000."); }
|
||||
if(d.Count() < 2 || d.Count() > 2) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
|
||||
if(digraphLettersE.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[0].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
|
||||
if(digraphLettersN.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[1].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
|
||||
this.LatZone = latz;
|
||||
this.LongZone = longz;
|
||||
this.Digraph = d;
|
||||
this.Easting = e;
|
||||
this.Northing = n;
|
||||
//WGS84
|
||||
this.equatorialRadius = 6378137.0;
|
||||
this.inverseFlattening = 298.257223563;
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Create an MGRS object with custom datum
|
||||
/// </summary>
|
||||
/// <param name="latz">Lat Zone</param>
|
||||
/// <param name="longz">Long Zone</param>
|
||||
/// <param name="d">Digraph</param>
|
||||
/// <param name="e">Easting</param>
|
||||
/// <param name="n">Northing</param>
|
||||
/// <param name="rad">Equatorial Radius</param>
|
||||
/// <param name="flt">Inverse Flattening</param>
|
||||
public MilitaryGridReferenceSystem(String latz, Int32 longz, String d, Double e, Double n, Double rad, Double flt) {
|
||||
String digraphLettersE = "ABCDEFGHJKLMNPQRSTUVWXYZ";
|
||||
String digraphLettersN = "ABCDEFGHJKLMNPQRSTUV";
|
||||
if(longz < 1 || longz > 60) { Debug.WriteLine("Longitudinal zone out of range", "UTM longitudinal zones must be between 1-60."); }
|
||||
if(!Verify_Lat_Zone(latz)) { throw new ArgumentException("Latitudinal zone invalid", "UTM latitudinal zone was unrecognized."); }
|
||||
if(n < 0 || n > 10000000) { throw new ArgumentOutOfRangeException("Northing out of range", "Northing must be between 0-10,000,000."); }
|
||||
if(d.Count() < 2 || d.Count() > 2) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
|
||||
if(digraphLettersE.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[0].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
|
||||
if(digraphLettersN.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[1].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); }
|
||||
this.LatZone = latz;
|
||||
this.LongZone = longz;
|
||||
this.Digraph = d;
|
||||
this.Easting = e;
|
||||
this.Northing = n;
|
||||
|
||||
this.equatorialRadius = rad;
|
||||
this.inverseFlattening = flt;
|
||||
}
|
||||
|
||||
private Double equatorialRadius;
|
||||
private Double inverseFlattening;
|
||||
|
||||
private Boolean Verify_Lat_Zone(String l) {
|
||||
if(LatZones.longZongLetters.Where(x => x == l.ToUpper()).Count() != 1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// MGRS Zone Letter
|
||||
/// </summary>
|
||||
public String LatZone { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// MGRS Zone Number
|
||||
/// </summary>
|
||||
public Int32 LongZone { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// MGRS Easting
|
||||
/// </summary>
|
||||
public Double Easting { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// MGRS Northing
|
||||
/// </summary>
|
||||
public Double Northing { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// MGRS Digraph
|
||||
/// </summary>
|
||||
public String Digraph { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is MGRS conversion within the coordinate system's accurate boundaries after conversion from Lat/Long.
|
||||
/// </summary>
|
||||
public Boolean WithinCoordinateSystemBounds { get; private set; } = true;
|
||||
|
||||
internal MilitaryGridReferenceSystem(UniversalTransverseMercator utm) => ToMGRS(utm);
|
||||
internal void ToMGRS(UniversalTransverseMercator utm) {
|
||||
Digraphs digraphs = new Digraphs();
|
||||
|
||||
String digraph1 = digraphs.getDigraph1(utm.LongZone, utm.Easting);
|
||||
String digraph2 = digraphs.getDigraph2(utm.LongZone, utm.Northing);
|
||||
|
||||
this.Digraph = digraph1 + digraph2;
|
||||
this.LatZone = utm.LatZone;
|
||||
this.LongZone = utm.LongZone;
|
||||
|
||||
//String easting = String.valueOf((int)_easting);
|
||||
String e = ((Int32)utm.Easting).ToString();
|
||||
if(e.Length < 5) {
|
||||
e = "00000" + ((Int32)utm.Easting).ToString();
|
||||
}
|
||||
e = e.Substring(e.Length - 5);
|
||||
|
||||
this.Easting = Convert.ToInt32(e);
|
||||
|
||||
String n = ((Int32)utm.Northing).ToString();
|
||||
if(n.Length < 5) {
|
||||
n = "0000" + ((Int32)utm.Northing).ToString();
|
||||
}
|
||||
n = n.Substring(n.Length - 5);
|
||||
|
||||
this.Northing = Convert.ToInt32(n);
|
||||
this.equatorialRadius = utm.equatorial_radius;
|
||||
this.inverseFlattening = utm.inverse_flattening;
|
||||
|
||||
this.WithinCoordinateSystemBounds = utm.WithinCoordinateSystemBounds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a Coordinate object from an MGRS/NATO UTM Coordinate
|
||||
/// </summary>
|
||||
/// <param name="mgrs">MilitaryGridReferenceSystem</param>
|
||||
/// <returns>Coordinate object</returns>
|
||||
public static Coordinate MGRStoLatLong(MilitaryGridReferenceSystem mgrs) {
|
||||
String latz = mgrs.LatZone;
|
||||
String digraph = mgrs.Digraph;
|
||||
|
||||
Char eltr = digraph[0];
|
||||
Char nltr = digraph[1];
|
||||
|
||||
String digraphLettersE = "ABCDEFGHJKLMNPQRSTUVWXYZ";
|
||||
String digraphLettersN = "ABCDEFGHJKLMNPQRSTUV";
|
||||
String digraphLettersAll = "";
|
||||
for(Int32 lt = 1; lt < 25; lt++) {
|
||||
digraphLettersAll += "ABCDEFGHJKLMNPQRSTUV";
|
||||
}
|
||||
|
||||
Int32 eidx = digraphLettersE.IndexOf(eltr);
|
||||
Int32 nidx = digraphLettersN.IndexOf(nltr);
|
||||
if(mgrs.LongZone / 2.0 == Math.Floor(mgrs.LongZone / 2.0)) {
|
||||
nidx -= 5; // correction for even numbered zones
|
||||
}
|
||||
|
||||
Double ebase = 100000 * (1 + eidx - 8 * Math.Floor(Convert.ToDouble(eidx) / 8));
|
||||
Int32 latBand = digraphLettersE.IndexOf(latz);
|
||||
Int32 latBandLow = 8 * latBand - 96;
|
||||
Int32 latBandHigh = 8 * latBand - 88;
|
||||
|
||||
if(latBand < 2) {
|
||||
latBandLow = -90;
|
||||
latBandHigh = -80;
|
||||
} else if(latBand == 21) {
|
||||
latBandLow = 72;
|
||||
latBandHigh = 84;
|
||||
} else if(latBand > 21) {
|
||||
latBandLow = 84;
|
||||
latBandHigh = 90;
|
||||
}
|
||||
|
||||
Double lowLetter = Math.Floor(100 + 1.11 * latBandLow);
|
||||
Double highLetter = Math.Round(100 + 1.11 * latBandHigh);
|
||||
|
||||
String latBandLetters = null;
|
||||
Int32 l = Convert.ToInt32(lowLetter);
|
||||
Int32 h = Convert.ToInt32(highLetter);
|
||||
if(mgrs.LongZone / 2.0 == Math.Floor(mgrs.LongZone / 2.0)) {
|
||||
latBandLetters = digraphLettersAll.Substring(l + 5, h + 5).ToString();
|
||||
} else {
|
||||
latBandLetters = digraphLettersAll.Substring(l, h).ToString();
|
||||
}
|
||||
Double nbase = 100000 * (lowLetter + latBandLetters.IndexOf(nltr));
|
||||
//latBandLetters.IndexOf(nltr) value causing incorrect Northing below -80
|
||||
Double x = ebase + mgrs.Easting;
|
||||
Double y = nbase + mgrs.Northing;
|
||||
if(y > 10000000) {
|
||||
y = y - 10000000;
|
||||
}
|
||||
if(nbase >= 10000000) {
|
||||
y = nbase + mgrs.Northing - 10000000;
|
||||
}
|
||||
|
||||
Boolean southern = nbase < 10000000;
|
||||
UniversalTransverseMercator utm = new UniversalTransverseMercator(mgrs.LatZone, mgrs.LongZone, x, y) {
|
||||
equatorial_radius = mgrs.equatorialRadius,
|
||||
inverse_flattening = mgrs.inverseFlattening
|
||||
};
|
||||
Coordinate c = UniversalTransverseMercator.ConvertUTMtoLatLong(utm);
|
||||
|
||||
c.Set_Datum(mgrs.equatorialRadius, mgrs.inverseFlattening);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MGRS Default String Format
|
||||
/// </summary>
|
||||
/// <returns>MGRS Formatted Coordinate String</returns>
|
||||
public override String ToString() {
|
||||
if(!this.WithinCoordinateSystemBounds) { return ""; }//MGRS Coordinate is outside its reliable boundaries. Return empty.
|
||||
return this.LongZone.ToString() + this.LatZone + " " + this.Digraph + " " + ((Int32)this.Easting).ToString("00000") + " " + ((Int32)this.Northing).ToString("00000");
|
||||
}
|
||||
/// <summary>
|
||||
/// Property changed event
|
||||
/// </summary>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
/// <summary>
|
||||
/// Notify property changed
|
||||
/// </summary>
|
||||
/// <param name="propName">Property name</param>
|
||||
public void NotifyPropertyChanged(String propName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
|
||||
}
|
||||
}
|
@ -1,925 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Type of format a Coordinate parsed from.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public enum Parse_Format_Type
|
||||
{
|
||||
/// <summary>
|
||||
/// Coordinate was not initialized from a parser method.
|
||||
/// </summary>
|
||||
None,
|
||||
/// <summary>
|
||||
/// Signed Degree
|
||||
/// DD.dddd
|
||||
/// </summary>
|
||||
Signed_Degree,
|
||||
/// <summary>
|
||||
/// Decimal Degree
|
||||
/// P DD.dddd
|
||||
/// </summary>
|
||||
Decimal_Degree,
|
||||
/// <summary>
|
||||
/// Degree Decimal Minute
|
||||
/// P DD MM.sss
|
||||
/// </summary>
|
||||
Degree_Decimal_Minute,
|
||||
/// <summary>
|
||||
/// Degree Minute Second
|
||||
/// P DD MM SS.sss
|
||||
/// </summary>
|
||||
Degree_Minute_Second,
|
||||
/// <summary>
|
||||
/// Universal Transverse Mercator
|
||||
/// </summary>
|
||||
UTM,
|
||||
/// <summary>
|
||||
/// Military Grid Reference System
|
||||
/// </summary>
|
||||
MGRS,
|
||||
/// <summary>
|
||||
/// Spherical Cartesian
|
||||
/// </summary>
|
||||
Cartesian_Spherical,
|
||||
/// <summary>
|
||||
/// Earth Centered Earth Fixed
|
||||
/// </summary>
|
||||
Cartesian_ECEF
|
||||
}
|
||||
|
||||
internal class FormatFinder
|
||||
{
|
||||
//Add main to Coordinate and tunnel to Format class. Add private methods to format.
|
||||
//WHEN PARSING NO EXCPETIONS FOR OUT OF RANGE ARGS WILL BE THROWN
|
||||
public static bool TryParse(string coordString, CartesianType ct, out Coordinate c)
|
||||
{
|
||||
//Turn of eagerload for efficiency
|
||||
EagerLoad eg = new EagerLoad();
|
||||
eg.Cartesian = false;
|
||||
eg.Celestial = false;
|
||||
eg.UTM_MGRS = false;
|
||||
|
||||
c = new Coordinate(eg);
|
||||
string s = coordString;
|
||||
s = s.Trim(); //Trim all spaces before and after string
|
||||
double[] d;
|
||||
//Try Signed Degree
|
||||
if (TrySignedDegree(s, out d))
|
||||
{
|
||||
try
|
||||
{
|
||||
c = new Coordinate(d[0], d[1], eg);
|
||||
c.Parse_Format = Parse_Format_Type.Signed_Degree;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{//Parser failed try next method
|
||||
}
|
||||
}
|
||||
|
||||
//Try Decimal Degree
|
||||
if (TryDecimalDegree(s, out d))
|
||||
{
|
||||
try
|
||||
{
|
||||
c = new Coordinate(d[0], d[1], eg);
|
||||
c.Parse_Format = Parse_Format_Type.Decimal_Degree;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{//Parser failed try next method
|
||||
}
|
||||
}
|
||||
//Try DDM
|
||||
if (TryDegreeDecimalMinute(s, out d))
|
||||
{
|
||||
try
|
||||
{
|
||||
//0 Lat Degree
|
||||
//1 Lat Minute
|
||||
//2 Lat Direction (0 = N, 1 = S)
|
||||
//3 Long Degree
|
||||
//4 Long Minute
|
||||
//5 Long Direction (0 = E, 1 = W)
|
||||
CoordinatesPosition latP = CoordinatesPosition.N;
|
||||
CoordinatesPosition lngP = CoordinatesPosition.E;
|
||||
if (d[2] != 0) { latP = CoordinatesPosition.S; }
|
||||
if (d[5] != 0) { lngP = CoordinatesPosition.W; }
|
||||
CoordinatePart lat = new CoordinatePart((int)d[0], d[1], latP);
|
||||
CoordinatePart lng = new CoordinatePart((int)d[3], d[4], lngP);
|
||||
c = new Coordinate(eg);
|
||||
c.Latitude = lat;
|
||||
c.Longitude = lng;
|
||||
c.Parse_Format = Parse_Format_Type.Degree_Decimal_Minute;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{//Parser failed try next method
|
||||
}
|
||||
}
|
||||
//Try DMS
|
||||
if (TryDegreeMinuteSecond(s, out d))
|
||||
{
|
||||
try
|
||||
{
|
||||
//0 Lat Degree
|
||||
//1 Lat Minute
|
||||
//2 Lat Second
|
||||
//3 Lat Direction (0 = N, 1 = S)
|
||||
//4 Long Degree
|
||||
//5 Long Minute
|
||||
//6 Long Second
|
||||
//7 Long Direction (0 = E, 1 = W)
|
||||
CoordinatesPosition latP = CoordinatesPosition.N;
|
||||
CoordinatesPosition lngP = CoordinatesPosition.E;
|
||||
if (d[3] != 0) { latP = CoordinatesPosition.S; }
|
||||
if (d[7] != 0) { lngP = CoordinatesPosition.W; }
|
||||
|
||||
CoordinatePart lat = new CoordinatePart((int)d[0], (int)d[1], d[2], latP);
|
||||
CoordinatePart lng = new CoordinatePart((int)d[4], (int)d[5], d[6], lngP);
|
||||
c = new Coordinate(eg);
|
||||
c.Latitude = lat;
|
||||
c.Longitude = lng;
|
||||
c.Parse_Format = Parse_Format_Type.Degree_Minute_Second;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{//Parser failed try next method
|
||||
}
|
||||
}
|
||||
|
||||
string[] um;
|
||||
//Try MGRS
|
||||
if (TryMGRS(s, out um))
|
||||
{
|
||||
try
|
||||
{
|
||||
double zone = Convert.ToDouble(um[0]);
|
||||
double easting = Convert.ToDouble(um[3]);
|
||||
double northing = Convert.ToDouble(um[4]);
|
||||
MilitaryGridReferenceSystem mgrs = new MilitaryGridReferenceSystem(um[1], (int)zone, um[2], easting, northing);
|
||||
c = MilitaryGridReferenceSystem.MGRStoLatLong(mgrs);
|
||||
c.Parse_Format = Parse_Format_Type.MGRS;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{//Parser failed try next method
|
||||
}
|
||||
}
|
||||
//Try UTM
|
||||
if (TryUTM(s, out um))
|
||||
{
|
||||
try
|
||||
{
|
||||
double zone = Convert.ToDouble(um[0]);
|
||||
double easting = Convert.ToDouble(um[2]);
|
||||
double northing = Convert.ToDouble(um[3]);
|
||||
UniversalTransverseMercator utm = new UniversalTransverseMercator(um[1], (int)zone, easting, northing);
|
||||
c = UniversalTransverseMercator.ConvertUTMtoLatLong(utm);
|
||||
c.Parse_Format = Parse_Format_Type.UTM;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{//Parser failed try next method
|
||||
}
|
||||
}
|
||||
//Try Cartesian
|
||||
if (TryCartesian(s.ToUpper().Replace("KM", "").Replace("X","").Replace("Y", "").Replace("Z", ""), out d))
|
||||
{
|
||||
if (ct == CartesianType.Cartesian)
|
||||
{
|
||||
try
|
||||
{
|
||||
Cartesian cart = new Cartesian(d[0], d[1], d[2]);
|
||||
c = Cartesian.CartesianToLatLong(cart);
|
||||
c.Parse_Format = Parse_Format_Type.Cartesian_Spherical;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{//Parser failed try next method
|
||||
}
|
||||
}
|
||||
if (ct == CartesianType.ECEF)
|
||||
{
|
||||
try
|
||||
{
|
||||
ECEF ecef = new ECEF(d[0], d[1], d[2]);
|
||||
c = ECEF.ECEFToLatLong(ecef);
|
||||
c.Parse_Format = Parse_Format_Type.Cartesian_ECEF;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{//Parser failed try next method
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c = null;
|
||||
return false;
|
||||
}
|
||||
private static bool TrySignedDegree(string s, out double[] d)
|
||||
{
|
||||
d = null;
|
||||
if (Regex.Matches(s, @"[a-zA-Z]").Count != 0) { return false; } //Should contain no letters
|
||||
|
||||
string[] sA = SpecialSplit(s,false);
|
||||
double lat;
|
||||
double lng;
|
||||
|
||||
double degLat;
|
||||
double minLat; //Minutes & MinSeconds
|
||||
double secLat;
|
||||
|
||||
int signLat = 1;
|
||||
|
||||
double degLng;
|
||||
double minLng; //Minutes & MinSeconds
|
||||
double secLng;
|
||||
|
||||
int signLng = 1;
|
||||
|
||||
switch (sA.Count())
|
||||
{
|
||||
case 2:
|
||||
if (!double.TryParse(sA[0], out lat))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[1], out lng))
|
||||
{ return false; }
|
||||
d = new double[] { lat, lng };
|
||||
return true;
|
||||
case 4:
|
||||
if (!double.TryParse(sA[0], out degLat))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[1], out minLat))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[2], out degLng))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[3], out minLng))
|
||||
{ return false; }
|
||||
|
||||
if (degLat < 0) { signLat = -1; }
|
||||
if (degLng < 0) { signLng = -1; }
|
||||
if (minLat >= 60 || minLat < 0) { return false; } //Handle in parser as degree will be incorrect.
|
||||
if (minLng >= 60 || minLng < 0) { return false; } //Handle in parser as degree will be incorrect.
|
||||
lat = (Math.Abs(degLat) + (minLat / 60.0)) * signLat;
|
||||
lng = (Math.Abs(degLng) + (minLng / 60.0)) * signLng;
|
||||
d = new double[] { lat, lng };
|
||||
return true;
|
||||
case 6:
|
||||
if (!double.TryParse(sA[0], out degLat))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[1], out minLat))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[2], out secLat))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[3], out degLng))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[4], out minLng))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[5], out secLng))
|
||||
{ return false; }
|
||||
if (degLat < 0) { signLat = -1; }
|
||||
if (degLng < 0) { signLng = -1; }
|
||||
if (minLat >= 60 || minLat < 0) { return false; } //Handle in parser as degree will be incorrect.
|
||||
if (minLng >= 60 || minLng < 0) { return false; } //Handle in parser as degree will be incorrect.
|
||||
if (secLat >= 60 || secLat < 0) { return false; } //Handle in parser as degree will be incorrect.
|
||||
if (secLng >= 60 || secLng < 0) { return false; } //Handle in parser as degree will be incorrect.
|
||||
lat = (Math.Abs(degLat) + (minLat / 60.0) + (secLat / 3600)) * signLat;
|
||||
lng = (Math.Abs(degLng) + (minLng / 60.0) + (secLng / 3600)) * signLng;
|
||||
d = new double[] { lat, lng };
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
private static bool TryDecimalDegree(string s, out double[] d)
|
||||
{
|
||||
d = null;
|
||||
if (Regex.Matches(s, @"[a-zA-Z]").Count != 2) { return false; } //Should only contain 1 letter.
|
||||
|
||||
string[] sA = SpecialSplit(s,true);
|
||||
if (sA.Count() == 2 || sA.Count() == 4)
|
||||
{
|
||||
double lat;
|
||||
double lng;
|
||||
|
||||
double latR = 1; //Sets negative if South
|
||||
double lngR = 1; //Sets negative if West
|
||||
|
||||
//Contact get brin directional indicator together with string
|
||||
if (sA.Count() == 4)
|
||||
{
|
||||
sA[0] += sA[1];
|
||||
sA[1] = sA[2] + sA[3];
|
||||
}
|
||||
|
||||
//Find Directions
|
||||
if (!sA[0].Contains("N") && !sA[0].Contains("n"))
|
||||
{
|
||||
if (!sA[0].Contains("S") && !sA[0].Contains("s"))
|
||||
{
|
||||
return false;//No Direction Found
|
||||
}
|
||||
latR = -1;
|
||||
}
|
||||
if (!sA[1].Contains("E") && !sA[1].Contains("e"))
|
||||
{
|
||||
if (!sA[1].Contains("W") && !sA[1].Contains("w"))
|
||||
{
|
||||
return false;//No Direction Found
|
||||
}
|
||||
lngR = -1;
|
||||
}
|
||||
|
||||
sA[0] = Regex.Replace(sA[0], "[^0-9.]", "");
|
||||
sA[1] = Regex.Replace(sA[1], "[^0-9.]", "");
|
||||
|
||||
if (!double.TryParse(sA[0], out lat))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[1], out lng))
|
||||
{ return false; }
|
||||
lat *= latR;
|
||||
lng *= lngR;
|
||||
d = new double[] { lat, lng };
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
private static bool TryDegreeDecimalMinute(string s, out double[] d)
|
||||
{
|
||||
d = null;
|
||||
if (Regex.Matches(s, @"[a-zA-Z]").Count != 2) { return false; } //Should only contain 1 letter.
|
||||
|
||||
string[] sA = SpecialSplit(s,true);
|
||||
if (sA.Count() == 4 || sA.Count() == 6)
|
||||
{
|
||||
double latD;
|
||||
double latMS;
|
||||
double lngD;
|
||||
double lngMS;
|
||||
|
||||
double latR = 0; //Sets 1 if South
|
||||
double lngR = 0; //Sets 1 if West
|
||||
|
||||
//Contact get in order to combine directional indicator together with string
|
||||
//Should reduce 6 items to 4
|
||||
if (sA.Count() == 6)
|
||||
{
|
||||
if (char.IsLetter(sA[0][0])) { sA[0] += sA[1]; sA[1] = sA[2]; }
|
||||
else if (char.IsLetter(sA[1][0])) { sA[0] += sA[1]; sA[1] = sA[2]; }
|
||||
else if (char.IsLetter(sA[2][0])) { sA[0] += sA[2]; }
|
||||
else { return false; }
|
||||
|
||||
if (char.IsLetter(sA[3][0])) { sA[3] += sA[4]; sA[4] = sA[5]; }
|
||||
else if (char.IsLetter(sA[4][0])) { sA[3] += sA[4]; sA[4] = sA[5]; }
|
||||
else if (char.IsLetter(sA[5][0])) { sA[3] += sA[5]; }
|
||||
else { return false; }
|
||||
|
||||
//Shift values for below logic
|
||||
sA[2] = sA[3];
|
||||
sA[3] = sA[4];
|
||||
}
|
||||
|
||||
//Find Directions
|
||||
if (!sA[0].Contains("N") && !sA[0].Contains("n") && !sA[1].Contains("N") && !sA[1].Contains("n"))
|
||||
{
|
||||
if (!sA[0].Contains("S") && !sA[0].Contains("s") && !sA[1].Contains("S") && !sA[1].Contains("s"))
|
||||
{
|
||||
return false;//No Direction Found
|
||||
}
|
||||
latR = 1;
|
||||
}
|
||||
if (!sA[2].Contains("E") && !sA[2].Contains("e") && !sA[3].Contains("E") && !sA[3].Contains("e"))
|
||||
{
|
||||
if (!sA[2].Contains("W") && !sA[2].Contains("w") && !sA[3].Contains("W") && !sA[3].Contains("w"))
|
||||
{
|
||||
return false;//No Direction Found
|
||||
}
|
||||
lngR = 1;
|
||||
}
|
||||
|
||||
sA[0] = Regex.Replace(sA[0], "[^0-9.]", "");
|
||||
sA[1] = Regex.Replace(sA[1], "[^0-9.]", "");
|
||||
sA[2] = Regex.Replace(sA[2], "[^0-9.]", "");
|
||||
sA[3] = Regex.Replace(sA[3], "[^0-9.]", "");
|
||||
|
||||
if (!double.TryParse(sA[0], out latD))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[1], out latMS))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[2], out lngD))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[3], out lngMS))
|
||||
{ return false; }
|
||||
|
||||
d = new double[] { latD, latMS, latR, lngD, lngMS, lngR };
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private static bool TryDegreeMinuteSecond(string s, out double[] d)
|
||||
{
|
||||
d = null;
|
||||
if (Regex.Matches(s, @"[a-zA-Z]").Count != 2) { return false; } //Should only contain 1 letter.
|
||||
|
||||
string[] sA = SpecialSplit(s,true);
|
||||
if (sA.Count() == 6 || sA.Count() == 8)
|
||||
{
|
||||
double latD;
|
||||
double latM;
|
||||
double latS;
|
||||
double lngD;
|
||||
double lngM;
|
||||
double lngS;
|
||||
|
||||
double latR = 0; //Sets 1 if South
|
||||
double lngR = 0; //Sets 1 if West
|
||||
|
||||
//Contact get in order to combine directional indicator together with string
|
||||
//Should reduce 8 items to 6
|
||||
if (sA.Count() == 8)
|
||||
{
|
||||
if (char.IsLetter(sA[0][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; }
|
||||
else if (char.IsLetter(sA[1][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; }
|
||||
else if (char.IsLetter(sA[3][0])) { sA[0] += sA[3]; }
|
||||
else { return false; }
|
||||
|
||||
if (char.IsLetter(sA[4][0])) { sA[4] += sA[5]; sA[5] = sA[6]; sA[6] = sA[7]; }
|
||||
else if (char.IsLetter(sA[5][0])) { sA[4] += sA[5]; sA[5] = sA[6]; sA[6] = sA[7]; }
|
||||
else if (char.IsLetter(sA[7][0])) { sA[4] += sA[7]; }
|
||||
else { return false; }
|
||||
|
||||
//Shift values for below logic
|
||||
sA[3] = sA[4];
|
||||
sA[4] = sA[5];
|
||||
sA[5] = sA[6];
|
||||
}
|
||||
|
||||
//Find Directions
|
||||
if (!sA[0].Contains("N") && !sA[0].Contains("n") && !sA[2].Contains("N") && !sA[2].Contains("n"))
|
||||
{
|
||||
if (!sA[0].Contains("S") && !sA[0].Contains("s") && !sA[2].Contains("S") && !sA[2].Contains("s"))
|
||||
{
|
||||
return false;//No Direction Found
|
||||
}
|
||||
latR = 1;
|
||||
}
|
||||
if (!sA[3].Contains("E") && !sA[3].Contains("e") && !sA[5].Contains("E") && !sA[5].Contains("e"))
|
||||
{
|
||||
if (!sA[3].Contains("W") && !sA[3].Contains("w") && !sA[5].Contains("W") && !sA[5].Contains("w"))
|
||||
{
|
||||
return false;//No Direction Found
|
||||
}
|
||||
lngR = 1;
|
||||
}
|
||||
sA[0] = Regex.Replace(sA[0], "[^0-9.]", "");
|
||||
sA[1] = Regex.Replace(sA[1], "[^0-9.]", "");
|
||||
sA[2] = Regex.Replace(sA[2], "[^0-9.]", "");
|
||||
sA[3] = Regex.Replace(sA[3], "[^0-9.]", "");
|
||||
sA[4] = Regex.Replace(sA[4], "[^0-9.]", "");
|
||||
sA[5] = Regex.Replace(sA[5], "[^0-9.]", "");
|
||||
|
||||
if (!double.TryParse(sA[0], out latD))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[1], out latM))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[2], out latS))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[3], out lngD))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[4], out lngM))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[5], out lngS))
|
||||
{ return false; }
|
||||
|
||||
d = new double[] { latD, latM, latS, latR, lngD, lngM, lngS, lngR };
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private static bool TryUTM(string s, out string[] utm)
|
||||
{
|
||||
utm = null;
|
||||
string[] sA = SpecialSplit(s,false);
|
||||
if (sA.Count() == 3 || sA.Count() == 4)
|
||||
{
|
||||
double zone;
|
||||
string zoneL;
|
||||
double easting;
|
||||
double northing;
|
||||
|
||||
if (sA.Count() == 4)
|
||||
{
|
||||
|
||||
if (char.IsLetter(sA[0][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; }
|
||||
else if (char.IsLetter(sA[1][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; }
|
||||
else { return false; }
|
||||
}
|
||||
zoneL = new string(sA[0].Where(Char.IsLetter).ToArray());
|
||||
if (zoneL == string.Empty) { return false; }
|
||||
sA[0] = Regex.Replace(sA[0], "[^0-9.]", "");
|
||||
|
||||
if (!double.TryParse(sA[0], out zone))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[1], out easting))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[2], out northing))
|
||||
{ return false; }
|
||||
|
||||
utm = new string[] { zone.ToString(), zoneL, easting.ToString(), northing.ToString() };
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private static bool TryMGRS(string s, out string[] mgrs)
|
||||
{
|
||||
mgrs = null;
|
||||
string[] sA = SpecialSplit(s,false);
|
||||
if (sA.Count() == 4 || sA.Count() == 5)
|
||||
{
|
||||
double zone;
|
||||
string zoneL;
|
||||
string diagraph;
|
||||
double easting;
|
||||
double northing;
|
||||
|
||||
if (sA.Count() == 5)
|
||||
{
|
||||
if (char.IsLetter(sA[0][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; }
|
||||
else if (char.IsLetter(sA[1][0])) { sA[0] += sA[1]; sA[1] = sA[2]; sA[2] = sA[3]; }
|
||||
else { return false; }
|
||||
}
|
||||
zoneL = new string(sA[0].Where(Char.IsLetter).ToArray());
|
||||
if (zoneL == string.Empty) { return false; }
|
||||
sA[0] = Regex.Replace(sA[0], "[^0-9.]", "");
|
||||
diagraph = sA[1];
|
||||
if (!double.TryParse(sA[0], out zone))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[2], out easting))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[3], out northing))
|
||||
{ return false; }
|
||||
|
||||
mgrs = new string[] { zone.ToString(), zoneL, diagraph, easting.ToString(), northing.ToString() };
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private static bool TryCartesian(string s, out double[] d)
|
||||
{
|
||||
d = null;
|
||||
string[] sA = SpecialSplit(s,false);
|
||||
|
||||
if (sA.Count() == 3)
|
||||
{
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
if (!double.TryParse(sA[0], out x))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[1], out y))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[2], out z))
|
||||
{ return false; }
|
||||
d = new double[] { x, y, z };
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//KEEP DASHES FOR SIGNED AND CARTESIAN AS THEY ARE USED FOR NEGATVE VALUES
|
||||
private static string[] SpecialSplit(string s, bool removeDashes)
|
||||
{
|
||||
s = s.Replace("°", " ");
|
||||
s = s.Replace("º", " ");
|
||||
s = s.Replace("'", " ");
|
||||
s = s.Replace("\"", " ");
|
||||
s = s.Replace(",", " ");
|
||||
s = s.Replace("mE", " ");
|
||||
s = s.Replace("mN", " ");
|
||||
if (removeDashes)
|
||||
{
|
||||
s = s.Replace("-", " ");
|
||||
}
|
||||
return s.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
}
|
||||
internal class FormatFinder_CoordPart
|
||||
{
|
||||
//Add main to Coordinate and tunnel to Format class. Add private methods to format.
|
||||
//WHEN PARSING NO EXCPETIONS FOR OUT OF RANGE ARGS WILL BE THROWN
|
||||
public static bool TryParse(string coordString, out CoordinatePart cp)
|
||||
{
|
||||
//Turn of eagerload for efficiency
|
||||
EagerLoad eg = new EagerLoad();
|
||||
int type = 0; //0 = unspecifed, 1 = lat, 2 = long;
|
||||
eg.Cartesian = false;
|
||||
eg.Celestial = false;
|
||||
eg.UTM_MGRS = false;
|
||||
cp = null;
|
||||
Coordinate c = new Coordinate(eg);
|
||||
string s = coordString;
|
||||
s = s.Trim(); //Trim all spaces before and after string
|
||||
double[] d;
|
||||
|
||||
if (s[0] == ',')
|
||||
{
|
||||
type = 2;
|
||||
s = s.Replace(",", "");
|
||||
s = s.Trim();
|
||||
}
|
||||
if (s[0] == '*')
|
||||
{
|
||||
type = 1;
|
||||
s = s.Replace("*", "");
|
||||
s = s.Trim();
|
||||
}
|
||||
|
||||
if (TrySignedDegree(s, type, out d))
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
//Attempt Lat first (default for signed)
|
||||
try
|
||||
{
|
||||
cp = new CoordinatePart(d[0], CoordinateType.Lat);
|
||||
c.Parse_Format = Parse_Format_Type.Signed_Degree;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
cp = new CoordinatePart(d[0], CoordinateType.Long);
|
||||
c.Parse_Format = Parse_Format_Type.Signed_Degree;
|
||||
return true;
|
||||
}
|
||||
case 1:
|
||||
//Attempt Lat
|
||||
cp = new CoordinatePart(d[0], CoordinateType.Lat);
|
||||
c.Parse_Format = Parse_Format_Type.Signed_Degree;
|
||||
return true;
|
||||
case 2:
|
||||
//Attempt long
|
||||
cp = new CoordinatePart(d[0], CoordinateType.Long);
|
||||
c.Parse_Format = Parse_Format_Type.Signed_Degree;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
//silent fail
|
||||
}
|
||||
}
|
||||
//SIGNED DEGREE FAILED, REMOVE DASHES FOR OTHER FORMATS
|
||||
s = s.Replace("-", " ");
|
||||
|
||||
//All other formats should contain 1 letter.
|
||||
if (Regex.Matches(s, @"[a-zA-Z]").Count != 1) { return false; } //Should only contain 1 letter.
|
||||
//Get Coord Direction
|
||||
int direction = Find_Position(s);
|
||||
|
||||
if (direction == -1)
|
||||
{
|
||||
return false; //No direction found
|
||||
}
|
||||
//If Coordinate type int specified, look for mismatch
|
||||
if (type == 1 && (direction == 1 || direction == 3))
|
||||
{
|
||||
return false; //mismatch
|
||||
}
|
||||
if (type == 2 && (direction == 0 || direction == 2))
|
||||
{
|
||||
return false; //mismatch
|
||||
}
|
||||
CoordinateType t;
|
||||
if (direction == 0 || direction == 2) { t = CoordinateType.Lat; }
|
||||
else { t = CoordinateType.Long; }
|
||||
|
||||
s = Regex.Replace(s, "[^0-9. ]", ""); //Remove directional character
|
||||
s = s.Trim(); //Trim all spaces before and after string
|
||||
|
||||
//Try Decimal Degree with Direction
|
||||
if (TryDecimalDegree(s, direction, out d))
|
||||
{
|
||||
try
|
||||
{
|
||||
cp = new CoordinatePart(d[0], t);
|
||||
c.Parse_Format = Parse_Format_Type.Decimal_Degree;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{//Parser failed try next method
|
||||
}
|
||||
}
|
||||
//Try DDM
|
||||
if (TryDegreeDecimalMinute(s, out d))
|
||||
{
|
||||
try
|
||||
{
|
||||
//0 Degree
|
||||
//1 Minute
|
||||
//2 Direction (0 = N, 1 = E, 2 = S, 3 = W)
|
||||
cp = new CoordinatePart((int)d[0], d[1], (CoordinatesPosition)direction);
|
||||
c.Parse_Format = Parse_Format_Type.Degree_Decimal_Minute;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
//Parser failed try next method
|
||||
}
|
||||
}
|
||||
//Try DMS
|
||||
if (TryDegreeMinuteSecond(s, out d))
|
||||
{
|
||||
try
|
||||
{
|
||||
//0 Degree
|
||||
//1 Minute
|
||||
//2 Second
|
||||
//3 Direction (0 = N, 1 = E, 2 = S, 3 = W)
|
||||
cp = new CoordinatePart((int)d[0], (int)d[1], d[2], (CoordinatesPosition)direction);
|
||||
c.Parse_Format = Parse_Format_Type.Degree_Minute_Second;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{//Parser failed try next method
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TrySignedDegree(string s, int t, out double[] d)
|
||||
{
|
||||
d = null;
|
||||
if (Regex.Matches(s, @"[a-zA-Z]").Count != 0) { return false; } //Should contain no letters
|
||||
|
||||
string[] sA = SpecialSplit(s, false);
|
||||
double deg;
|
||||
double min; //Minutes & MinSeconds
|
||||
double sec;
|
||||
|
||||
int sign = 1;
|
||||
switch (sA.Count())
|
||||
{
|
||||
case 1:
|
||||
if (!double.TryParse(sA[0], out deg))
|
||||
{ return false; }
|
||||
d = new double[] { deg };
|
||||
return true;
|
||||
case 2:
|
||||
if (!double.TryParse(sA[0], out deg))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[1], out min))
|
||||
{ return false; }
|
||||
|
||||
if (deg < 0) { sign = -1; }
|
||||
if (min >= 60 || min < 0) { return false; } //Handle in parser as degree will be incorrect.
|
||||
d = new double[] { (Math.Abs(deg) + (min / 60.0)) * sign };
|
||||
return true;
|
||||
case 3:
|
||||
if (!double.TryParse(sA[0], out deg))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[1], out min))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[2], out sec))
|
||||
{ return false; }
|
||||
if (min >= 60 || min < 0) { return false; } //Handle in parser as degree will be incorrect.
|
||||
if (sec >= 60 || sec < 0) { return false; } //Handle in parser as degree will be incorrect.
|
||||
|
||||
if (deg < 0) { sign = -1; }
|
||||
d = new double[] { (Math.Abs(deg) + (min / 60.0) + (sec / 3600.0)) * sign };
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
private static bool TryDecimalDegree(string s, int direction, out double[] d)
|
||||
{
|
||||
d = null;
|
||||
int sign = 1;
|
||||
//S or W
|
||||
if (direction == 2 || direction == 3)
|
||||
{
|
||||
sign = -1;
|
||||
}
|
||||
double coord;
|
||||
|
||||
string[] sA = SpecialSplit(s, true);
|
||||
|
||||
if (sA.Count() == 1)
|
||||
{
|
||||
if (!double.TryParse(s, out coord))
|
||||
{ return false; }
|
||||
|
||||
coord *= sign;
|
||||
d = new double[] { coord };
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
private static bool TryDegreeDecimalMinute(string s, out double[] d)
|
||||
{
|
||||
d = null;
|
||||
|
||||
double deg;
|
||||
double minSec;
|
||||
|
||||
|
||||
string[] sA = SpecialSplit(s,true);
|
||||
if (sA.Count() == 2)
|
||||
{
|
||||
if (!double.TryParse(sA[0], out deg))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[1], out minSec))
|
||||
{ return false; }
|
||||
|
||||
d = new double[] { deg, minSec };
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private static bool TryDegreeMinuteSecond(string s, out double[] d)
|
||||
{
|
||||
d = null;
|
||||
|
||||
|
||||
double deg;
|
||||
double min;
|
||||
double sec;
|
||||
|
||||
string[] sA = SpecialSplit(s,true);
|
||||
if (sA.Count() == 3)
|
||||
{
|
||||
|
||||
if (!double.TryParse(sA[0], out deg))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[1], out min))
|
||||
{ return false; }
|
||||
if (!double.TryParse(sA[2], out sec))
|
||||
{ return false; }
|
||||
|
||||
d = new double[] { deg, min, sec };
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int Find_Position(string s)
|
||||
{
|
||||
//N=0
|
||||
//E=1
|
||||
//S=2
|
||||
//W=3
|
||||
//NOPOS = -1
|
||||
//Find Directions
|
||||
|
||||
int part = -1;
|
||||
if (s.Contains("N") || s.Contains("n"))
|
||||
{
|
||||
part = 0;
|
||||
}
|
||||
if (s.Contains("E") || s.Contains("e"))
|
||||
{
|
||||
part = 1;
|
||||
}
|
||||
if (s.Contains("S") || s.Contains("s"))
|
||||
{
|
||||
part = 2;
|
||||
|
||||
}
|
||||
if (s.Contains("W") || s.Contains("w"))
|
||||
{
|
||||
part = 3;
|
||||
}
|
||||
return part;
|
||||
}
|
||||
|
||||
//KEEP DASHES FOR SIGNED AND CARTESIAN AS THEY ARE USED FOR NEGATVE VALUES
|
||||
private static string[] SpecialSplit(string s, bool removeDashes)
|
||||
{
|
||||
s = s.Replace("°", " ");
|
||||
s = s.Replace("º", " ");
|
||||
s = s.Replace("'", " ");
|
||||
s = s.Replace("\"", " ");
|
||||
s = s.Replace(",", " ");
|
||||
s = s.Replace("mE", " ");
|
||||
s = s.Replace("mN", " ");
|
||||
if(removeDashes)
|
||||
{
|
||||
s = s.Replace("-", " ");
|
||||
}
|
||||
return s.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,592 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Universal Transverse Mercator (UTM) coordinate system. Uses the WGS 84 Datum.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class UniversalTransverseMercator : INotifyPropertyChanged
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a UniversalTransverMercator object with a WGS84 Datum.
|
||||
/// </summary>
|
||||
/// <param name="latz">Latitude zone</param>
|
||||
/// <param name="longz">Longitude zone</param>
|
||||
/// <param name="est">Easting</param>
|
||||
/// <param name="nrt">Northing</param>
|
||||
public UniversalTransverseMercator(string latz, int longz, double est, double nrt)
|
||||
{
|
||||
if (longz < 1 || longz > 60) { Debug.WriteLine("Longitudinal zone out of range", "UTM longitudinal zones must be between 1-60."); }
|
||||
if (!Verify_Lat_Zone(latz)) { Debug.WriteLine("Latitudinal zone invalid", "UTM latitudinal zone was unrecognized."); }
|
||||
if (est < 160000 || est > 834000) { Debug.WriteLine("The Easting value provided is outside the max allowable range. Use with caution."); }
|
||||
if (nrt < 0 || nrt > 10000000) { Debug.WriteLine("Northing out of range", "Northing must be between 0-10,000,000."); }
|
||||
|
||||
latZone = latz;
|
||||
longZone =longz;
|
||||
easting = est;
|
||||
northing = nrt;
|
||||
|
||||
equatorial_radius = 6378137.0;
|
||||
inverse_flattening = 298.257223563;
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a UniversalTransverMercator object with a custom Datum.
|
||||
/// </summary>
|
||||
/// <param name="latz">Latitude zone</param>
|
||||
/// <param name="longz">Longitude zone</param>
|
||||
/// <param name="est">Easting</param>
|
||||
/// <param name="nrt">Northing</param>
|
||||
/// <param name="radius">Equatorial Radius</param>
|
||||
/// <param name="flaten">Inverse Flattening</param>
|
||||
public UniversalTransverseMercator(string latz, int longz, double est, double nrt, double radius, double flaten)
|
||||
{
|
||||
if (longz < 1 || longz > 60) { Debug.WriteLine("Longitudinal zone out of range", "UTM longitudinal zones must be between 1-60."); }
|
||||
if (!Verify_Lat_Zone(latz)) { Debug.WriteLine("Latitudinal zone invalid", "UTM latitudinal zone was unrecognized."); }
|
||||
if (est < 160000 || est > 834000) { Debug.WriteLine("The Easting value provided is outside the max allowable range. Use with caution."); }
|
||||
if (nrt < 0 || nrt > 10000000) { Debug.WriteLine("Northing out of range", "Northing must be between 0-10,000,000."); }
|
||||
|
||||
latZone = latz;
|
||||
longZone = longz;
|
||||
easting = est;
|
||||
northing = nrt;
|
||||
|
||||
equatorial_radius = radius;
|
||||
inverse_flattening = flaten;
|
||||
}
|
||||
|
||||
private Coordinate coordinate;
|
||||
|
||||
internal double equatorial_radius;
|
||||
internal double inverse_flattening;
|
||||
private string latZone;
|
||||
private int longZone;
|
||||
|
||||
private double easting;
|
||||
private double northing;
|
||||
|
||||
private bool withinCoordinateSystemBounds = true;
|
||||
|
||||
/// <summary>
|
||||
/// UTM Zone Letter
|
||||
/// </summary>
|
||||
public string LatZone
|
||||
{
|
||||
get { return latZone; }
|
||||
set
|
||||
{
|
||||
if (latZone != value)
|
||||
{
|
||||
latZone = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// UTM Zone Number
|
||||
/// </summary>
|
||||
public int LongZone
|
||||
{
|
||||
get { return longZone; }
|
||||
set
|
||||
{
|
||||
if (longZone != value)
|
||||
{
|
||||
longZone = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// UTM Easting
|
||||
/// </summary>
|
||||
public double Easting
|
||||
{
|
||||
get { return easting; }
|
||||
set
|
||||
{
|
||||
if (easting != value)
|
||||
{
|
||||
easting = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// UTM Northing
|
||||
/// </summary>
|
||||
public double Northing
|
||||
{
|
||||
get { return northing; }
|
||||
set
|
||||
{
|
||||
if (northing != value)
|
||||
{
|
||||
northing = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Datum Equatorial Radius / Semi Major Axis
|
||||
/// </summary>
|
||||
public double Equatorial_Radius
|
||||
{
|
||||
get { return equatorial_radius; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Datum Flattening
|
||||
/// </summary>
|
||||
public double Inverse_Flattening
|
||||
{
|
||||
get { return inverse_flattening; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the UTM conversion within the coordinate system's accurate boundaries after conversion from Lat/Long.
|
||||
/// </summary>
|
||||
public bool WithinCoordinateSystemBounds
|
||||
{
|
||||
get { return withinCoordinateSystemBounds; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a UTM object based off DD Lat/Long
|
||||
/// </summary>
|
||||
/// <param name="lat">DD Latitude</param>
|
||||
/// <param name="longi">DD Longitide</param>
|
||||
/// <param name="c">Parent Coordinate Object</param>
|
||||
internal UniversalTransverseMercator(double lat, double longi, Coordinate c)
|
||||
{
|
||||
//validate coords
|
||||
|
||||
//if (lat > 180) { throw new ArgumentOutOfRangeException("Degrees out of range", "Longitudinal coordinate decimal cannot be greater than 180."); }
|
||||
//if (lat < -180) { throw new ArgumentOutOfRangeException("Degrees out of range", "Longitudinal coordinate decimal cannot be less than 180."); }
|
||||
|
||||
//if (longi > 90) { throw new ArgumentOutOfRangeException("Degrees out of range", "Latitudinal coordinate decimal cannot be greater than 90."); }
|
||||
//if (longi < -90) { throw new ArgumentOutOfRangeException("Degrees out of range", "Latitudinal coordinate decimal cannot be less than 90."); }
|
||||
equatorial_radius = 6378137.0;
|
||||
inverse_flattening = 298.257223563;
|
||||
ToUTM(lat, longi, this);
|
||||
|
||||
coordinate = c;
|
||||
}
|
||||
/// <summary>
|
||||
/// Constructs a UTM object based off DD Lat/Long
|
||||
/// </summary>
|
||||
/// <param name="lat">DD Latitude</param>
|
||||
/// <param name="longi">DD Longitide</param>
|
||||
/// <param name="c">Parent Coordinate Object</param>
|
||||
/// <param name="rad">Equatorial Radius</param>
|
||||
/// <param name="flt">Flattening</param>
|
||||
internal UniversalTransverseMercator(double lat, double longi, Coordinate c,double rad,double flt)
|
||||
{
|
||||
equatorial_radius = rad;
|
||||
inverse_flattening = flt;
|
||||
ToUTM(lat, longi, this);
|
||||
|
||||
coordinate = c;
|
||||
}
|
||||
/// <summary>
|
||||
/// Constructs a UTM object based off a UTM coordinate
|
||||
/// Not yet implemented
|
||||
/// </summary>
|
||||
/// <param name="latz">Zone Letter</param>
|
||||
/// <param name="longz">Zone Number</param>
|
||||
/// <param name="e">Easting</param>
|
||||
/// <param name="n">Northing</param>
|
||||
/// <param name="c">Parent Coordinate Object</param>
|
||||
/// <param name="rad">Equatorial Radius</param>
|
||||
/// <param name="flt">Inverse Flattening</param>
|
||||
internal UniversalTransverseMercator(string latz, int longz, double e, double n, Coordinate c, double rad, double flt)
|
||||
{
|
||||
//validate utm
|
||||
if (longz < 1 || longz > 60) { Debug.WriteLine("Longitudinal zone out of range", "UTM longitudinal zones must be between 1-60."); }
|
||||
if (!Verify_Lat_Zone(latz)) { throw new ArgumentException("Latitudinal zone invalid", "UTM latitudinal zone was unrecognized."); }
|
||||
if (e < 160000 || e > 834000) { Debug.WriteLine("The Easting value provided is outside the max allowable range. If this is intentional, use with caution."); }
|
||||
if (n < 0 || n > 10000000) { throw new ArgumentOutOfRangeException("Northing out of range", "Northing must be between 0-10,000,000."); }
|
||||
equatorial_radius = rad;
|
||||
inverse_flattening = flt;
|
||||
latZone = latz;
|
||||
longZone = longz;
|
||||
|
||||
easting = e;
|
||||
northing = n;
|
||||
|
||||
coordinate = c;
|
||||
if (c.Latitude.DecimalDegree <= -80 || c.Latitude.DecimalDegree >= 84) { withinCoordinateSystemBounds = false; }
|
||||
else { withinCoordinateSystemBounds = true; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies Lat zone when convert from UTM to DD Lat/Long
|
||||
/// </summary>
|
||||
/// <param name="l">Zone Letter</param>
|
||||
/// <returns>boolean</returns>
|
||||
private bool Verify_Lat_Zone(string l)
|
||||
{
|
||||
if (LatZones.longZongLetters.Where(x => x == l.ToUpper()).Count() != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private double degreeToRadian(double degree)
|
||||
{
|
||||
return degree * Math.PI / 180;
|
||||
}
|
||||
/// <summary>
|
||||
/// Assigns UTM values based of Lat/Long
|
||||
/// </summary>
|
||||
/// <param name="lat">DD Latitude</param>
|
||||
/// <param name="longi">DD longitude</param>
|
||||
/// <param name="utm">UTM Object to modify</param>
|
||||
internal void ToUTM(double lat, double longi, UniversalTransverseMercator utm)
|
||||
{
|
||||
string letter = "";
|
||||
double easting = 0;
|
||||
double northing = 0;
|
||||
int zone = (int)Math.Floor(longi / 6 + 31);
|
||||
if (lat < -72)
|
||||
letter = "C";
|
||||
else if (lat < -64)
|
||||
letter = "D";
|
||||
else if (lat < -56)
|
||||
letter = "E";
|
||||
else if (lat < -48)
|
||||
letter = "F";
|
||||
else if (lat < -40)
|
||||
letter = "G";
|
||||
else if (lat < -32)
|
||||
letter = "H";
|
||||
else if (lat < -24)
|
||||
letter = "J";
|
||||
else if (lat < -16)
|
||||
letter = "K";
|
||||
else if (lat < -8)
|
||||
letter = "L";
|
||||
else if (lat < 0)
|
||||
letter = "M";
|
||||
else if (lat < 8)
|
||||
letter = "N";
|
||||
else if (lat < 16)
|
||||
letter = "P";
|
||||
else if (lat < 24)
|
||||
letter = "Q";
|
||||
else if (lat < 32)
|
||||
letter = "R";
|
||||
else if (lat < 40)
|
||||
letter = "S";
|
||||
else if (lat < 48)
|
||||
letter = "T";
|
||||
else if (lat < 56)
|
||||
letter = "U";
|
||||
else if (lat < 64)
|
||||
letter = "V";
|
||||
else if (lat < 72)
|
||||
letter = "W";
|
||||
else
|
||||
letter = "X";
|
||||
|
||||
double a = utm.equatorial_radius;
|
||||
double f = 1.0 / utm.inverse_flattening;
|
||||
double b = a * (1 - f); // polar radius
|
||||
|
||||
double e = Math.Sqrt(1 - Math.Pow(b, 2) / Math.Pow(a, 2));
|
||||
double e0 = e / Math.Sqrt(1 - Math.Pow(e, 1));
|
||||
|
||||
double drad = Math.PI / 180;
|
||||
double k0 = 0.9996;
|
||||
|
||||
double phi = lat * drad; // convert latitude to radians
|
||||
double lng = longi * drad; // convert longitude to radians
|
||||
double utmz = 1 + Math.Floor((longi + 180) / 6.0); // longitude to utm zone
|
||||
double zcm = 3 + 6.0 * (utmz - 1) - 180; // central meridian of a zone
|
||||
// this gives us zone A-B for below 80S
|
||||
double esq = (1 - (b / a) * (b / a));
|
||||
double e0sq = e * e / (1 - Math.Pow(e, 2));
|
||||
double M = 0;
|
||||
|
||||
double N = a / Math.Sqrt(1 - Math.Pow(e * Math.Sin(phi), 2));
|
||||
double T = Math.Pow(Math.Tan(phi), 2);
|
||||
double C = e0sq * Math.Pow(Math.Cos(phi), 2);
|
||||
double A = (longi - zcm) * drad * Math.Cos(phi);
|
||||
|
||||
// calculate M (USGS style)
|
||||
M = phi * (1 - esq * (1.0 / 4.0 + esq * (3.0 / 64.0 + 5.0 * esq / 256.0)));
|
||||
M = M - Math.Sin(2.0 * phi) * (esq * (3.0 / 8.0 + esq * (3.0 / 32.0 + 45.0 * esq / 1024.0)));
|
||||
M = M + Math.Sin(4.0 * phi) * (esq * esq * (15.0 / 256.0 + esq * 45.0 / 1024.0));
|
||||
M = M - Math.Sin(6.0 * phi) * (esq * esq * esq * (35.0 / 3072.0));
|
||||
M = M * a;//Arc length along standard meridian
|
||||
|
||||
double M0 = 0;// if another point of origin is used than the equator
|
||||
|
||||
// Calculate the UTM values...
|
||||
// first the easting
|
||||
var x = k0 * N * A * (1 + A * A * ((1 - T + C) / 6 + A * A * (5 - 18 * T + T * T + 72.0 * C - 58 * e0sq) / 120.0)); //Easting relative to CM
|
||||
x = x + 500000; // standard easting
|
||||
|
||||
// Northing
|
||||
|
||||
double y = k0 * (M - M0 + N * Math.Tan(phi) * (A * A * (1 / 2.0 + A * A * ((5 - T + 9 * C + 4 * C * C) / 24.0 + A * A * (61 - 58 * T + T * T + 600 * C - 330 * e0sq) / 720.0)))); // first from the equator
|
||||
double yg = y + 10000000; //yg = y global, from S. Pole
|
||||
if (y < 0)
|
||||
{
|
||||
y = 10000000 + y; // add in false northing if south of the equator
|
||||
}
|
||||
|
||||
|
||||
easting = Math.Round(10 * (x)) / 10.0;
|
||||
northing = Math.Round(10 * y) / 10.0;
|
||||
|
||||
utm.latZone = letter;
|
||||
utm.longZone = zone;
|
||||
utm.easting = easting;
|
||||
utm.northing = northing;
|
||||
|
||||
if(lat<=-80 || lat >= 84) { withinCoordinateSystemBounds = false; }
|
||||
else { withinCoordinateSystemBounds = true; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UTM Default String Format
|
||||
/// </summary>
|
||||
/// <returns>UTM Formatted Coordinate String</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
if (!withinCoordinateSystemBounds) { return ""; }//MGRS Coordinate is outside its reliable boundaries. Return empty.
|
||||
return longZone.ToString() + LatZone + " " + (int)easting + "mE " + (int)northing + "mN";
|
||||
}
|
||||
|
||||
private static Coordinate UTMtoLatLong(double x, double y, double zone, double equatorialRadius, double flattening)
|
||||
{
|
||||
//x easting
|
||||
//y northing
|
||||
|
||||
//http://home.hiwaay.net/~taylorc/toolbox/geography/geoutm.html
|
||||
double phif, Nf, Nfpow, nuf2, ep2, tf, tf2, tf4, cf;
|
||||
double x1frac, x2frac, x3frac, x4frac, x5frac, x6frac, x7frac, x8frac;
|
||||
double x2poly, x3poly, x4poly, x5poly, x6poly, x7poly, x8poly;
|
||||
|
||||
double sm_a = equatorialRadius;
|
||||
double sm_b = equatorialRadius * (1 - (1.0 / flattening)); //Polar Radius
|
||||
|
||||
/* Get the value of phif, the footpoint latitude. */
|
||||
phif = FootpointLatitude(y,equatorialRadius,flattening);
|
||||
|
||||
/* Precalculate ep2 */
|
||||
ep2 = (Math.Pow(sm_a, 2.0) - Math.Pow(sm_b, 2.0))
|
||||
/ Math.Pow(sm_b, 2.0);
|
||||
|
||||
/* Precalculate cos (phif) */
|
||||
cf = Math.Cos(phif);
|
||||
|
||||
/* Precalculate nuf2 */
|
||||
nuf2 = ep2 * Math.Pow(cf, 2.0);
|
||||
|
||||
/* Precalculate Nf and initialize Nfpow */
|
||||
Nf = Math.Pow(sm_a, 2.0) / (sm_b * Math.Sqrt(1 + nuf2));
|
||||
Nfpow = Nf;
|
||||
|
||||
/* Precalculate tf */
|
||||
tf = Math.Tan(phif);
|
||||
tf2 = tf * tf;
|
||||
tf4 = tf2 * tf2;
|
||||
|
||||
/* Precalculate fractional coefficients for x**n in the equations
|
||||
below to simplify the expressions for latitude and longitude. */
|
||||
x1frac = 1.0 / (Nfpow * cf);
|
||||
|
||||
Nfpow *= Nf; /* now equals Nf**2) */
|
||||
x2frac = tf / (2.0 * Nfpow);
|
||||
|
||||
Nfpow *= Nf; /* now equals Nf**3) */
|
||||
x3frac = 1.0 / (6.0 * Nfpow * cf);
|
||||
|
||||
Nfpow *= Nf; /* now equals Nf**4) */
|
||||
x4frac = tf / (24.0 * Nfpow);
|
||||
|
||||
Nfpow *= Nf; /* now equals Nf**5) */
|
||||
x5frac = 1.0 / (120.0 * Nfpow * cf);
|
||||
|
||||
Nfpow *= Nf; /* now equals Nf**6) */
|
||||
x6frac = tf / (720.0 * Nfpow);
|
||||
|
||||
Nfpow *= Nf; /* now equals Nf**7) */
|
||||
x7frac = 1.0 / (5040.0 * Nfpow * cf);
|
||||
|
||||
Nfpow *= Nf; /* now equals Nf**8) */
|
||||
x8frac = tf / (40320.0 * Nfpow);
|
||||
|
||||
/* Precalculate polynomial coefficients for x**n.
|
||||
-- x**1 does not have a polynomial coefficient. */
|
||||
x2poly = -1.0 - nuf2;
|
||||
|
||||
x3poly = -1.0 - 2 * tf2 - nuf2;
|
||||
|
||||
x4poly = 5.0 + 3.0 * tf2 + 6.0 * nuf2 - 6.0 * tf2 * nuf2
|
||||
- 3.0 * (nuf2 * nuf2) - 9.0 * tf2 * (nuf2 * nuf2);
|
||||
|
||||
x5poly = 5.0 + 28.0 * tf2 + 24.0 * tf4 + 6.0 * nuf2 + 8.0 * tf2 * nuf2;
|
||||
|
||||
x6poly = -61.0 - 90.0 * tf2 - 45.0 * tf4 - 107.0 * nuf2
|
||||
+ 162.0 * tf2 * nuf2;
|
||||
|
||||
x7poly = -61.0 - 662.0 * tf2 - 1320.0 * tf4 - 720.0 * (tf4 * tf2);
|
||||
|
||||
x8poly = 1385.0 + 3633.0 * tf2 + 4095.0 * tf4 + 1575 * (tf4 * tf2);
|
||||
|
||||
/* Calculate latitude */
|
||||
double nLat = phif + x2frac * x2poly * (x * x)
|
||||
+ x4frac * x4poly * Math.Pow(x, 4.0)
|
||||
+ x6frac * x6poly * Math.Pow(x, 6.0)
|
||||
+ x8frac * x8poly * Math.Pow(x, 8.0);
|
||||
|
||||
/* Calculate longitude */
|
||||
double nLong = zone + x1frac * x
|
||||
+ x3frac * x3poly * Math.Pow(x, 3.0)
|
||||
+ x5frac * x5poly * Math.Pow(x, 5.0)
|
||||
+ x7frac * x7poly * Math.Pow(x, 7.0);
|
||||
|
||||
double dLat = RadToDeg(nLat);
|
||||
double dLong = RadToDeg(nLong);
|
||||
if (dLat > 90) { dLat = 90; }
|
||||
if (dLat < -90) { dLat = -90; }
|
||||
if (dLong > 180) { dLong = 180; }
|
||||
if (dLong < -180) { dLong = -180; }
|
||||
|
||||
Coordinate c = new Coordinate(equatorialRadius,flattening, true);
|
||||
CoordinatePart cLat = new CoordinatePart(dLat, CoordinateType.Lat);
|
||||
CoordinatePart cLng = new CoordinatePart(dLong, CoordinateType.Long);
|
||||
|
||||
c.Latitude = cLat;
|
||||
c.Longitude = cLng;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
private static double RadToDeg(double rad)
|
||||
{
|
||||
double pi = 3.14159265358979;
|
||||
return (rad / pi * 180.0);
|
||||
}
|
||||
private static double DegToRad(double deg)
|
||||
{
|
||||
double pi = 3.14159265358979;
|
||||
return (deg / 180.0 * pi);
|
||||
}
|
||||
private static double FootpointLatitude(double y, double equatorialRadius, double flattening)
|
||||
{
|
||||
double y_, alpha_, beta_, gamma_, delta_, epsilon_, n;
|
||||
double result;
|
||||
|
||||
|
||||
/* Ellipsoid model constants (actual values here are for WGS84) */
|
||||
double sm_a = equatorialRadius;
|
||||
double sm_b = equatorialRadius * (1 - (1.0 / flattening));
|
||||
|
||||
|
||||
/* Precalculate n (Eq. 10.18) */
|
||||
n = (sm_a - sm_b) / (sm_a + sm_b);
|
||||
|
||||
/* Precalculate alpha_ (Eq. 10.22) */
|
||||
/* (Same as alpha in Eq. 10.17) */
|
||||
alpha_ = ((sm_a + sm_b) / 2.0) * (1 + (Math.Pow(n, 2.0) / 4) + (Math.Pow(n, 4.0) / 64));
|
||||
|
||||
/* Precalculate y_ (Eq. 10.23) */
|
||||
y_ = y / alpha_;
|
||||
|
||||
/* Precalculate beta_ (Eq. 10.22) */
|
||||
beta_ = (3.0 * n / 2.0) + (-27.0 * Math.Pow(n, 3.0) / 32.0)
|
||||
+ (269.0 * Math.Pow(n, 5.0) / 512.0);
|
||||
|
||||
/* Precalculate gamma_ (Eq. 10.22) */
|
||||
gamma_ = (21.0 * Math.Pow(n, 2.0) / 16.0)
|
||||
+ (-55.0 * Math.Pow(n, 4.0) / 32.0);
|
||||
|
||||
/* Precalculate delta_ (Eq. 10.22) */
|
||||
delta_ = (151.0 * Math.Pow(n, 3.0) / 96.0)
|
||||
+ (-417.0 * Math.Pow(n, 5.0) / 128.0);
|
||||
|
||||
/* Precalculate epsilon_ (Eq. 10.22) */
|
||||
epsilon_ = (1097.0 * Math.Pow(n, 4.0) / 512.0);
|
||||
|
||||
/* Now calculate the sum of the series (Eq. 10.21) */
|
||||
result = y_ + (beta_ * Math.Sin(2.0 * y_))
|
||||
+ (gamma_ * Math.Sin(4.0 * y_))
|
||||
+ (delta_ * Math.Sin(6.0 * y_))
|
||||
+ (epsilon_ * Math.Sin(8.0 * y_));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts UTM coordinate to Lat/Long
|
||||
/// </summary>
|
||||
/// <param name="utm">utm</param>
|
||||
/// <returns>Coordinate object</returns>
|
||||
public static Coordinate ConvertUTMtoLatLong(UniversalTransverseMercator utm)
|
||||
{
|
||||
|
||||
bool southhemi = false;
|
||||
if (utm.latZone == "A" || utm.latZone == "B" || utm.latZone == "C" || utm.latZone == "D" || utm.latZone == "E" || utm.latZone == "F" || utm.latZone == "G" || utm.latZone == "H" || utm.latZone == "J" ||
|
||||
utm.latZone == "K" || utm.latZone == "L" || utm.latZone == "M")
|
||||
{
|
||||
southhemi = true;
|
||||
}
|
||||
|
||||
double cmeridian;
|
||||
|
||||
double x = utm.Easting - 500000.0;
|
||||
double UTMScaleFactor = 0.9996;
|
||||
x /= UTMScaleFactor;
|
||||
|
||||
/* If in southern hemisphere, adjust y accordingly. */
|
||||
double y = utm.Northing;
|
||||
if (southhemi)
|
||||
{
|
||||
y -= 10000000.0;
|
||||
}
|
||||
|
||||
y /= UTMScaleFactor;
|
||||
|
||||
cmeridian = UTMCentralMeridian(utm.LongZone);
|
||||
|
||||
Coordinate c = UTMtoLatLong(x, y, cmeridian, utm.equatorial_radius, utm.inverse_flattening);
|
||||
|
||||
if (c.Latitude.ToDouble() > 85 || c.Latitude.ToDouble() < -85)
|
||||
{
|
||||
Debug.WriteLine("UTM conversions greater than 85 degrees or less than -85 degree latitude contain major deviations and should be used with caution.");
|
||||
}
|
||||
return c;
|
||||
|
||||
|
||||
}
|
||||
|
||||
private static double UTMCentralMeridian(double zone)
|
||||
{
|
||||
double cmeridian;
|
||||
|
||||
cmeridian = DegToRad(-183.0 + (zone * 6.0));
|
||||
|
||||
return cmeridian;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property changed event
|
||||
/// </summary>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
/// <summary>
|
||||
/// Notify property changed
|
||||
/// </summary>
|
||||
/// <param name="propName">Property name</param>
|
||||
public void NotifyPropertyChanged(string propName)
|
||||
{
|
||||
if (this.PropertyChanged != null)
|
||||
{
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(propName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,436 +0,0 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains distance values between two coordinates.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class Distance
|
||||
{
|
||||
private double kilometers;
|
||||
private double miles;
|
||||
private double feet;
|
||||
private double meters;
|
||||
private double bearing;
|
||||
private double nauticalMiles;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a distance object using Haversine (Spherical Earth).
|
||||
/// </summary>
|
||||
/// <param name="c1">Coordinate 1</param>
|
||||
/// <param name="c2">Coordinate 2</param>
|
||||
public Distance(Coordinate c1, Coordinate c2)
|
||||
{
|
||||
Haversine(c1, c2);
|
||||
}
|
||||
/// <summary>
|
||||
/// Initializes a distance object using Haversine (Spherical Earth) or Vincenty (Elliptical Earth).
|
||||
/// </summary>
|
||||
/// <param name="c1">Coordinate 1</param>
|
||||
/// <param name="c2">Coordinate 2</param>
|
||||
/// <param name="shape">Shape of earth</param>
|
||||
public Distance(Coordinate c1, Coordinate c2, Shape shape)
|
||||
{
|
||||
if (shape == Shape.Sphere)
|
||||
{
|
||||
Haversine(c1, c2);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vincenty(c1, c2);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Initializes distance object based on distance in KM
|
||||
/// </summary>
|
||||
/// <param name="km">Kilometers</param>
|
||||
public Distance(double km)
|
||||
{
|
||||
kilometers = km;
|
||||
meters = km * 1000;
|
||||
feet = meters * 3.28084;
|
||||
miles = meters * 0.000621371;
|
||||
nauticalMiles = meters * 0.0005399565;
|
||||
bearing = 0;//None specified
|
||||
}
|
||||
/// <summary>
|
||||
/// Initializaes distance object based on specified distance and measurement type
|
||||
/// </summary>
|
||||
/// <param name="distance">Distance</param>
|
||||
/// <param name="type">Measurement type</param>
|
||||
public Distance(double distance, DistanceType type)
|
||||
{
|
||||
bearing = 0;
|
||||
switch (type)
|
||||
{
|
||||
case DistanceType.Feet:
|
||||
feet = distance;
|
||||
meters = feet * 0.3048;
|
||||
kilometers = meters / 1000;
|
||||
miles = meters * 0.000621371;
|
||||
nauticalMiles = meters * 0.0005399565;
|
||||
break;
|
||||
case DistanceType.Kilometers:
|
||||
kilometers = distance;
|
||||
meters = kilometers * 1000;
|
||||
feet = meters * 3.28084;
|
||||
miles = meters * 0.000621371;
|
||||
nauticalMiles = meters * 0.0005399565;
|
||||
break;
|
||||
case DistanceType.Meters:
|
||||
meters = distance;
|
||||
kilometers = meters / 1000;
|
||||
feet = meters * 3.28084;
|
||||
miles = meters * 0.000621371;
|
||||
nauticalMiles = meters * 0.0005399565;
|
||||
break;
|
||||
case DistanceType.Miles:
|
||||
miles = distance;
|
||||
meters = miles * 1609.344;
|
||||
feet = meters * 3.28084;
|
||||
kilometers = meters / 1000;
|
||||
nauticalMiles = meters * 0.0005399565;
|
||||
break;
|
||||
case DistanceType.NauticalMiles:
|
||||
nauticalMiles = distance;
|
||||
meters = nauticalMiles * 1852.001;
|
||||
feet = meters * 3.28084;
|
||||
kilometers = meters / 1000;
|
||||
miles = meters * 0.000621371;
|
||||
break;
|
||||
default:
|
||||
kilometers = distance;
|
||||
meters = distance * 1000;
|
||||
feet = meters * 3.28084;
|
||||
miles = meters * 0.000621371;
|
||||
nauticalMiles = meters * 0.0005399565;
|
||||
break;
|
||||
}
|
||||
}
|
||||
private void Vincenty(Coordinate c1, Coordinate c2)
|
||||
{
|
||||
double lat1, lat2, lon1, lon2;
|
||||
double d, crs12, crs21;
|
||||
|
||||
lat1 = c1.Latitude.ToRadians();
|
||||
lat2 = c2.Latitude.ToRadians();
|
||||
lon1 = c1.Longitude.ToRadians();
|
||||
lon2 = c2.Longitude.ToRadians();
|
||||
//Ensure datums match between coords
|
||||
if ((c1.equatorial_radius != c2.equatorial_radius) || (c1.inverse_flattening != c2.inverse_flattening))
|
||||
{
|
||||
throw new InvalidOperationException("The datum set does not match between Coordinate objects.");
|
||||
}
|
||||
double[] ellipse = new double[] { c1.equatorial_radius, c1.inverse_flattening };
|
||||
|
||||
|
||||
// elliptic code
|
||||
double[] cde = Distance_Assistant.Dist_Ell(lat1, -lon1, lat2, -lon2, ellipse); // ellipse uses East negative
|
||||
crs12 = cde[1] * (180 / Math.PI); //Bearing
|
||||
crs21 = cde[2] * (180 / Math.PI); //Reverse Bearing
|
||||
d = cde[0]; //Distance
|
||||
|
||||
bearing = crs21;
|
||||
//reverseBearing = crs12;
|
||||
meters = d;
|
||||
kilometers = d / 1000;
|
||||
feet = d * 3.28084;
|
||||
miles = d * 0.000621371;
|
||||
nauticalMiles = d * 0.0005399565;
|
||||
|
||||
}
|
||||
|
||||
private void Haversine(Coordinate c1, Coordinate c2)
|
||||
{
|
||||
////RADIANS
|
||||
double nLat = c1.Latitude.ToDouble() * Math.PI / 180;
|
||||
double nLong = c1.Longitude.ToDouble() * Math.PI / 180;
|
||||
double cLat = c2.Latitude.ToDouble() * Math.PI / 180;
|
||||
double cLong = c2.Longitude.ToDouble() * Math.PI / 180;
|
||||
|
||||
//Calcs
|
||||
double R = 6371e3; //meters
|
||||
double v1 = nLat;
|
||||
double v2 = cLat;
|
||||
double latRad = (c2.Latitude.ToDouble() - c1.Latitude.ToDouble()) * Math.PI / 180;
|
||||
double longRad = (c2.Longitude.ToDouble() - c1.Longitude.ToDouble()) * Math.PI / 180;
|
||||
|
||||
double a = Math.Sin(latRad / 2.0) * Math.Sin(latRad / 2.0) +
|
||||
Math.Cos(nLat) * Math.Cos(cLat) * Math.Sin(longRad / 2.0) * Math.Sin(longRad / 2.0);
|
||||
double cl = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
|
||||
double dist = R * cl;
|
||||
|
||||
//Get bearing
|
||||
double y = Math.Sin(cLong - nLong) * Math.Cos(cLat);
|
||||
double x = Math.Cos(nLat) * Math.Sin(cLat) -
|
||||
Math.Sin(nLat) * Math.Cos(cLat) * Math.Cos(cLong - nLong);
|
||||
double brng = Math.Atan2(y, x) * (180 / Math.PI); //Convert bearing back to degrees.
|
||||
if (brng < 0) { brng -= 180; brng = Math.Abs(brng); }
|
||||
kilometers = dist / 1000;
|
||||
meters = dist;
|
||||
feet = dist * 3.28084;
|
||||
miles = dist * 0.000621371;
|
||||
nauticalMiles = dist * 0.0005399565;
|
||||
bearing = brng;
|
||||
}
|
||||
/// <summary>
|
||||
/// Distance in Kilometers
|
||||
/// </summary>
|
||||
public double Kilometers
|
||||
{
|
||||
get { return kilometers; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Distance in Statute Miles
|
||||
/// </summary>
|
||||
public double Miles
|
||||
{
|
||||
get { return miles; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Distance in Nautical Miles
|
||||
/// </summary>
|
||||
public double NauticalMiles
|
||||
{
|
||||
get { return nauticalMiles; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Distance in Meters
|
||||
/// </summary>
|
||||
public double Meters
|
||||
{
|
||||
get { return meters; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Distance in Feet
|
||||
/// </summary>
|
||||
public double Feet
|
||||
{
|
||||
get { return feet; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Initial Bearing from Coordinate 1 to Coordinate 2
|
||||
/// </summary>
|
||||
public double Bearing
|
||||
{
|
||||
get { return bearing; }
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Distance measurement type
|
||||
/// </summary>
|
||||
public enum DistanceType
|
||||
{
|
||||
/// <summary>
|
||||
/// Distance in Meters
|
||||
/// </summary>
|
||||
Meters,
|
||||
/// <summary>
|
||||
/// Distance in Kilometers
|
||||
/// </summary>
|
||||
Kilometers,
|
||||
/// <summary>
|
||||
/// Distance in Feet
|
||||
/// </summary>
|
||||
Feet,
|
||||
/// <summary>
|
||||
/// Distance in Statute Miles
|
||||
/// </summary>
|
||||
Miles,
|
||||
/// <summary>
|
||||
/// Distance in Nautical Miles
|
||||
/// </summary>
|
||||
NauticalMiles
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal class Distance_Assistant
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns new geodetic coordinate in radians
|
||||
/// </summary>
|
||||
/// <param name="glat1">Latitude in Radians</param>
|
||||
/// <param name="glon1">Longitude in Radians</param>
|
||||
/// <param name="faz">Bearing</param>
|
||||
/// <param name="s">Distance</param>
|
||||
/// <param name="ellipse">Earth Ellipse Values</param>
|
||||
/// <returns>double[]</returns>
|
||||
public static double[] Direct_Ell(double glat1, double glon1, double faz, double s, double[] ellipse)
|
||||
{
|
||||
double EPS = 0.00000000005;//Used to determine if starting at pole.
|
||||
double r, tu, sf, cf, b, cu, su, sa, c2a, x, c, d, y, sy = 0, cy = 0, cz = 0, e = 0;
|
||||
double glat2, glon2, f;
|
||||
|
||||
//Determine if near pole
|
||||
if ((Math.Abs(Math.Cos(glat1)) < EPS) && !(Math.Abs(Math.Sin(faz)) < EPS))
|
||||
{
|
||||
Debug.WriteLine("Warning: Location is at earth's pole. Only N-S courses are meaningful at this location.");
|
||||
}
|
||||
|
||||
|
||||
double a = ellipse[0];//Equitorial Radius
|
||||
f = 1 / ellipse[1];//Flattening
|
||||
r = 1 - f;
|
||||
tu = r * Math.Tan(glat1);
|
||||
sf = Math.Sin(faz);
|
||||
cf = Math.Cos(faz);
|
||||
if (cf == 0)
|
||||
{
|
||||
b = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
b = 2.0 * Math.Atan2(tu, cf);
|
||||
}
|
||||
cu = 1.0 / Math.Sqrt(1 + tu * tu);
|
||||
su = tu * cu;
|
||||
sa = cu * sf;
|
||||
c2a = 1 - sa * sa;
|
||||
x = 1.0 + Math.Sqrt(1.0 + c2a * (1.0 / (r * r) - 1.0));
|
||||
x = (x - 2.0) / x;
|
||||
c = 1.0 - x;
|
||||
c = (x * x / 4.0 + 1.0) / c;
|
||||
d = (0.375 * x * x - 1.0) * x;
|
||||
tu = s / (r * a * c);
|
||||
y = tu;
|
||||
c = y + 1;
|
||||
while (Math.Abs(y - c) > EPS)
|
||||
{
|
||||
sy = Math.Sin(y);
|
||||
cy = Math.Cos(y);
|
||||
cz = Math.Cos(b + y);
|
||||
e = 2.0 * cz * cz - 1.0;
|
||||
c = y;
|
||||
x = e * cy;
|
||||
y = e + e - 1.0;
|
||||
y = (((sy * sy * 4.0 - 3.0) * y * cz * d / 6.0 + x) *
|
||||
d / 4.0 - cz) * sy * d + tu;
|
||||
}
|
||||
|
||||
b = cu * cy * cf - su * sy;
|
||||
c = r * Math.Sqrt(sa * sa + b * b);
|
||||
d = su * cy + cu * sy * cf;
|
||||
|
||||
glat2 = ModM.ModLat(Math.Atan2(d, c));
|
||||
c = cu * cy - su * sy * cf;
|
||||
x = Math.Atan2(sy * sf, c);
|
||||
c = ((-3.0 * c2a + 4.0) * f + 4.0) * c2a * f / 16.0;
|
||||
d = ((e * cy * c + cz) * sy * c + y) * sa;
|
||||
glon2 = ModM.ModLon(glon1 + x - (1.0 - c) * d * f); //Adjust for IDL
|
||||
//baz = ModM.ModCrs(Math.Atan2(sa, b) + Math.PI);
|
||||
return new double[] { glat2, glon2 };
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns new geodetic coordinate in radians
|
||||
/// </summary>
|
||||
/// <param name="lat1">Latitude in radians</param>
|
||||
/// <param name="lon1">Longitude in radians</param>
|
||||
/// <param name="crs12">Bearing</param>
|
||||
/// <param name="d12">Distance</param>
|
||||
/// <returns>double[]</returns>
|
||||
public static double[] Direct(double lat1, double lon1, double crs12, double d12)
|
||||
{
|
||||
var EPS = 0.00000000005;//Used to determine if near pole.
|
||||
double dlon, lat, lon;
|
||||
d12 = d12 * 0.0005399565; //convert meter to nm
|
||||
d12 = d12 / (180 * 60 / Math.PI);//Convert to Radian
|
||||
//Determine if near pole
|
||||
if ((Math.Abs(Math.Cos(lat1)) < EPS) && !(Math.Abs(Math.Sin(crs12)) < EPS))
|
||||
{
|
||||
Debug.WriteLine("Warning: Location is at earth's pole. Only N-S courses are meaningful at this location.");
|
||||
}
|
||||
|
||||
lat = Math.Asin(Math.Sin(lat1) * Math.Cos(d12) +
|
||||
Math.Cos(lat1) * Math.Sin(d12) * Math.Cos(crs12));
|
||||
if (Math.Abs(Math.Cos(lat)) < EPS)
|
||||
{
|
||||
lon = 0.0; //endpoint a pole
|
||||
}
|
||||
else
|
||||
{
|
||||
dlon = Math.Atan2(Math.Sin(crs12) * Math.Sin(d12) * Math.Cos(lat1),
|
||||
Math.Cos(d12) - Math.Sin(lat1) * Math.Sin(lat));
|
||||
lon = ModM.Mod(lon1 - dlon + Math.PI, 2 * Math.PI) - Math.PI;
|
||||
}
|
||||
|
||||
return new double[] { lat, lon };
|
||||
}
|
||||
public static double[] Dist_Ell(double glat1, double glon1, double glat2, double glon2, double[] ellipse)
|
||||
{
|
||||
double a = ellipse[0]; //Equitorial Radius
|
||||
double f = 1 / ellipse[1]; //Flattening
|
||||
|
||||
double r, tu1, tu2, cu1, su1, cu2, s1, b1, f1;
|
||||
double x = 0, sx = 0, cx = 0, sy = 0, cy = 0, y = 0, sa = 0, c2a = 0, cz = 0, e = 0, c = 0, d = 0;
|
||||
double EPS = 0.00000000005;
|
||||
double faz, baz, s;
|
||||
double iter = 1;
|
||||
double MAXITER = 100;
|
||||
if ((glat1 + glat2 == 0.0) && (Math.Abs(glon1 - glon2) == Math.PI))
|
||||
{
|
||||
Debug.WriteLine("Warning: Course and distance between antipodal points is undefined");
|
||||
glat1 = glat1 + 0.00001; // allow algorithm to complete
|
||||
}
|
||||
if (glat1 == glat2 && (glon1 == glon2 || Math.Abs(Math.Abs(glon1 - glon2) - 2 * Math.PI) < EPS))
|
||||
{
|
||||
Debug.WriteLine("Warning: Points 1 and 2 are identical- course undefined");
|
||||
//D
|
||||
//crs12
|
||||
//crs21
|
||||
return new double[] { 0, 0, Math.PI };
|
||||
}
|
||||
r = 1 - f;
|
||||
tu1 = r * Math.Tan(glat1);
|
||||
tu2 = r * Math.Tan(glat2);
|
||||
cu1 = 1.0 / Math.Sqrt(1.0 + tu1 * tu1);
|
||||
su1 = cu1 * tu1;
|
||||
cu2 = 1.0 / Math.Sqrt(1.0 + tu2 * tu2);
|
||||
s1 = cu1 * cu2;
|
||||
b1 = s1 * tu2;
|
||||
f1 = b1 * tu1;
|
||||
x = glon2 - glon1;
|
||||
d = x + 1; // force one pass
|
||||
while ((Math.Abs(d - x) > EPS) && (iter < MAXITER))
|
||||
{
|
||||
iter = iter + 1;
|
||||
sx = Math.Sin(x);
|
||||
cx = Math.Cos(x);
|
||||
tu1 = cu2 * sx;
|
||||
tu2 = b1 - su1 * cu2 * cx;
|
||||
sy = Math.Sqrt(tu1 * tu1 + tu2 * tu2);
|
||||
cy = s1 * cx + f1;
|
||||
y = Math.Atan2(sy, cy);
|
||||
sa = s1 * sx / sy;
|
||||
c2a = 1 - sa * sa;
|
||||
cz = f1 + f1;
|
||||
if (c2a > 0.0)
|
||||
{
|
||||
cz = cy - cz / c2a;
|
||||
}
|
||||
e = cz * cz * 2.0 - 1.0;
|
||||
c = ((-3.0 * c2a + 4.0) * f + 4.0) * c2a * f / 16.0;
|
||||
d = x;
|
||||
x = ((e * cy * c + cz) * sy * c + y) * sa;
|
||||
x = (1.0 - c) * x * f + glon2 - glon1;
|
||||
}
|
||||
faz = ModM.ModCrs(Math.Atan2(tu1, tu2));
|
||||
baz = ModM.ModCrs(Math.Atan2(cu1 * sx, b1 * cx - su1 * cu2) + Math.PI);
|
||||
x = Math.Sqrt((1 / (r * r) - 1) * c2a + 1);
|
||||
x += 1;
|
||||
x = (x - 2.0) / x;
|
||||
c = 1.0 - x;
|
||||
c = (x * x / 4.0 + 1.0) / c;
|
||||
d = (0.375 * x * x - 1.0) * x;
|
||||
x = e * cy;
|
||||
s = ((((sy * sy * 4.0 - 3.0) * (1.0 - e - e) * cz * d / 6.0 - x) * d / 4.0 + cz) * sy * d + y) * c * a * r;
|
||||
|
||||
if (Math.Abs(iter - MAXITER) < EPS)
|
||||
{
|
||||
Debug.WriteLine("Warning: Distance algorithm did not converge");
|
||||
}
|
||||
|
||||
return new double[] { s, faz, baz };
|
||||
}
|
||||
}
|
||||
}
|
@ -1,161 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace CoordinateSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Geo Fence class. It helps to check if points/coordinates are inside a polygon,
|
||||
/// Next to a polyline, and counting...
|
||||
/// </summary>
|
||||
public class GeoFence
|
||||
{
|
||||
#region Fields
|
||||
private List<Point> _points = new List<Point>();
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Prepare GeoFence with a list of points
|
||||
/// </summary>
|
||||
/// <param name="points">List of points</param>
|
||||
public GeoFence(List<Point> points)
|
||||
{
|
||||
_points = points;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prepare Geofence with a list of coordinates
|
||||
/// </summary>
|
||||
/// <param name="coordinates">List of coordinates</param>
|
||||
public GeoFence(List<Coordinate> coordinates)
|
||||
{
|
||||
foreach (var c in coordinates)
|
||||
{
|
||||
_points.Add(new Point { Latitude = c.Latitude.ToDouble(), Longitude = c.Longitude.ToDouble() });
|
||||
}
|
||||
}
|
||||
|
||||
#region Utils
|
||||
private Coordinate ClosestPointOnSegment(Point a, Point b, Coordinate p)
|
||||
{
|
||||
var d = new Point
|
||||
{
|
||||
Longitude = b.Longitude - a.Longitude,
|
||||
Latitude = b.Latitude - a.Latitude,
|
||||
};
|
||||
|
||||
double number = (p.Longitude.ToDouble() - a.Longitude) * d.Longitude + (p.Latitude.ToDouble() - a.Latitude) * d.Latitude;
|
||||
|
||||
if (number <= 0.0)
|
||||
return new Coordinate(a.Latitude, a.Longitude);
|
||||
|
||||
double denom = d.Longitude * d.Longitude + d.Latitude * d.Latitude;
|
||||
|
||||
if (number >= denom)
|
||||
return new Coordinate(b.Latitude, b.Longitude);
|
||||
|
||||
return new Coordinate(a.Latitude + (number / denom) * d.Latitude, a.Longitude + (number / denom) * d.Longitude);
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// The function will return true if the point x,y is inside the polygon, or
|
||||
/// false if it is not. If the point is exactly on the edge of the polygon,
|
||||
/// then the function may return true or false.
|
||||
/// </summary>
|
||||
/// <param name="point">The point to test</param>
|
||||
/// <returns>bool</returns>
|
||||
public bool IsPointInPolygon(Coordinate point)
|
||||
{
|
||||
if (point == null)
|
||||
return false;
|
||||
|
||||
double latitude = point.Latitude.ToDouble();
|
||||
double longitude = point.Longitude.ToDouble();
|
||||
int sides = _points.Count;
|
||||
int j = sides - 1;
|
||||
bool pointStatus = false;
|
||||
for (int i = 0; i < sides; i++)
|
||||
{
|
||||
if (_points[i].Latitude < latitude && _points[j].Latitude >= latitude || _points[j].Latitude < latitude && _points[i].Latitude >= latitude)
|
||||
{
|
||||
if (_points[i].Longitude + (latitude - _points[i].Latitude) / (_points[j].Latitude - _points[i].Latitude) * (_points[j].Longitude - _points[i].Longitude) < longitude)
|
||||
{
|
||||
pointStatus = !pointStatus;
|
||||
}
|
||||
}
|
||||
j = i;
|
||||
}
|
||||
return pointStatus;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The function will return true if the point x,y is next the given range of
|
||||
/// the polyline, or false if it is not.
|
||||
/// </summary>
|
||||
/// <param name="point">The point to test</param>
|
||||
/// <param name="range">The range in meters</param>
|
||||
/// <returns>bool</returns>
|
||||
public bool IsPointInRangeOfLine(Coordinate point, double range)
|
||||
{
|
||||
if (point == null)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < _points.Count - 1; i++)
|
||||
{
|
||||
Coordinate c = ClosestPointOnSegment(_points[i], _points[i + 1], point);
|
||||
if (c.Get_Distance_From_Coordinate(point).Meters <= range)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The function will return true if the point x,y is next the given range of
|
||||
/// the polyline, or false if it is not.
|
||||
/// </summary>
|
||||
/// <param name="point">The point to test</param>
|
||||
/// <param name="range">The range is a distance object</param>
|
||||
/// <returns>bool</returns>
|
||||
public bool IsPointInRangeOfLine(Coordinate point, Distance range)
|
||||
{
|
||||
if (point == null || range == null)
|
||||
return false;
|
||||
|
||||
return IsPointInRangeOfLine(point, range.Meters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class is a help class to simplify GeoFence calculus
|
||||
/// </summary>
|
||||
public class Point
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Initialize empty point
|
||||
/// </summary>
|
||||
public Point()
|
||||
{
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Initialize point with defined Latitude and Longitude
|
||||
/// </summary>
|
||||
/// <param name="lat">Latitude (signed)</param>
|
||||
/// <param name="lng">Longitude (signed)</param>
|
||||
public Point(double lat, double lng)
|
||||
{
|
||||
Latitude = lat;
|
||||
Longitude = lng;
|
||||
}
|
||||
/// <summary>
|
||||
/// The longitude in degrees
|
||||
/// </summary>
|
||||
public double Longitude;
|
||||
/// <summary>
|
||||
/// The latitude in degrees
|
||||
/// </summary>
|
||||
public double Latitude;
|
||||
}
|
||||
}
|
||||
}
|
62
Lora-Map/Lib/WebRequests.cs
Normal file
@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
using BlubbFish.Utils;
|
||||
|
||||
using LitJson;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Lib {
|
||||
public class WebRequests {
|
||||
private static readonly Object getLock = new Object();
|
||||
public JsonData GetJson(String url) {
|
||||
String text = null;
|
||||
for(Int32 i = 0; i < 3; i++) {
|
||||
try {
|
||||
text = this.GetString(url);
|
||||
break;
|
||||
} catch(Exception e) {
|
||||
Helper.WriteError(e.Message);
|
||||
if(i == 2) {
|
||||
throw;
|
||||
}
|
||||
System.Threading.Thread.Sleep(30000);
|
||||
}
|
||||
}
|
||||
if(text == null) {
|
||||
return new JsonData();
|
||||
}
|
||||
try {
|
||||
return JsonMapper.ToObject(text);
|
||||
} catch(Exception) {
|
||||
return new JsonData();
|
||||
}
|
||||
}
|
||||
|
||||
private String GetString(String url, Boolean withoutput = true) {
|
||||
String ret = null;
|
||||
lock(getLock) {
|
||||
HttpWebRequest request = WebRequest.CreateHttp(url);
|
||||
request.Timeout = 10000;
|
||||
//request.Headers.Add(HttpRequestHeader.Authorization, this.auth);
|
||||
try {
|
||||
using(HttpWebResponse response = (HttpWebResponse)request.GetResponse()) {
|
||||
if(response.StatusCode == HttpStatusCode.Unauthorized) {
|
||||
Console.Error.WriteLine("Benutzer oder Passwort falsch!");
|
||||
throw new Exception("Benutzer oder Passwort falsch!");
|
||||
}
|
||||
if(withoutput) {
|
||||
StreamReader reader = new StreamReader(response.GetResponseStream());
|
||||
ret = reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
//Helper.WriteError("Konnte keine Verbindung zum Razzbery Server herstellen. Resource: \"" + this.server + v + "\" Fehler: " + e.Message);
|
||||
//return null;
|
||||
throw new Exception("Konnte keine Verbindung zum Server herstellen: " + e.Message);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,255 +1,217 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{95D6F48A-9488-42A6-A973-941B45B26DB8}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<RootNamespace>Fraunhofer.Fit.IoT.LoraMap</RootNamespace>
|
||||
<AssemblyName>Lora-Map</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationManifest>Adminrights.manifest</ApplicationManifest>
|
||||
<Product>Lora-Map</Product>
|
||||
<Description>Displays Items with Coordinates from Mqtt on a Map</Description>
|
||||
<Company>Fraunhofer FIT</Company>
|
||||
<PackageId>LoraMap.IoT.Fit.Fraunhofer</PackageId>
|
||||
<Copyright>Copyright © Fraunhofer FIT, BlubbFish 2018 - 10.04.2021</Copyright>
|
||||
<Authors>BlubbFish</Authors>
|
||||
<Version>1.3.1</Version>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<PackageProjectUrl>https://github.com/MONICA-Project/lora-map</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/MONICA-Project/lora-map.git</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<NeutralLanguage>de-DE</NeutralLanguage>
|
||||
<PackageReleaseNotes>
|
||||
1.3.1 Refactory is the king
|
||||
1.3.0 New Gateway
|
||||
1.2.10 Refactoring is the thing
|
||||
1.2.9 The PüMa Release
|
||||
1.2.8 Improving the UI
|
||||
1.2.7 Reorganise a lot of things, add Support for Cameradata
|
||||
1.2.6 New Types of marker for person
|
||||
1.2.5 Set textsize for every zoomlevel
|
||||
1.2.4 Can draw Textmarkers on the Map, use MGRS (UTM) on the Map
|
||||
1.2.3 #9 display polygons and marker on the map
|
||||
1.2.2 Bugfix, if only recieve panic packet with gps data, update the marker on the map also
|
||||
1.2.1 #6 Load the map from the Device
|
||||
1.2.0 #4 Possible to Ex and Import Setting
|
||||
1.1.7 #8 Editor for Names
|
||||
1.1.6 #5 Create admin area
|
||||
1.1.5 Add support for alert button
|
||||
1.1.4 #3 Create icons for devices
|
||||
1.1.3 #1 Click on icon and show details
|
||||
1.1.2 #2 Show versions number in Site
|
||||
1.1.1 Add Debian package config</PackageReleaseNotes>
|
||||
<PackageTags>lora mqtt map lagekarte</PackageTags>
|
||||
<StartupObject>Fraunhofer.Fit.IoT.LoraMap.Program</StartupObject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<ProjectReference Include="..\..\Librarys\Coordinates\CoordinateSharp\CoordinateSharp.csproj" />
|
||||
<ProjectReference Include="..\..\Librarys\litjson\litjson\litjson.csproj" />
|
||||
<ProjectReference Include="..\..\Librarys\mqtt\M2Mqtt\M2Mqtt.csproj" />
|
||||
<ProjectReference Include="..\..\Utils\Bot-Utils\Bot-Utils\Bot-Utils.csproj" />
|
||||
<ProjectReference Include="..\..\Utils\ConnectorDataMqtt\ConnectorDataMqtt\ConnectorDataMqtt.csproj" />
|
||||
<ProjectReference Include="..\..\Utils\Utils-IoT\Utils-IoT\Utils-IoT.csproj" />
|
||||
<ProjectReference Include="..\..\Utils\Utils\Utils\Utils.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Helper\Celestial.Assistant.cs" />
|
||||
<Compile Include="Helper\Celestial.cs" />
|
||||
<Compile Include="Helper\Celestial.LunarEclipseCalc.cs" />
|
||||
<Compile Include="Helper\Celestial.MeeusTables.cs" />
|
||||
<Compile Include="Helper\Celestial.MoonCalculations.cs" />
|
||||
<Compile Include="Helper\Celestial.SolarEclipseCalc.cs" />
|
||||
<Compile Include="Helper\Celestial.SunCalculations.cs" />
|
||||
<Compile Include="Helper\Coordinate.Assistant.cs" />
|
||||
<Compile Include="Helper\Coordinate.Cartesian.cs" />
|
||||
<Compile Include="Helper\Coordinate.cs" />
|
||||
<Compile Include="Helper\Coordinate.EagerLoad.cs" />
|
||||
<Compile Include="Helper\Coordinate.ECEF.cs" />
|
||||
<Compile Include="Helper\Coordinate.Formatting.cs" />
|
||||
<Compile Include="Helper\Coordinate.MGRS.cs" />
|
||||
<Compile Include="Helper\Coordinate.Parser.cs" />
|
||||
<Compile Include="Helper\Coordinate.UTM.cs" />
|
||||
<Compile Include="Helper\Distance.cs" />
|
||||
<Compile Include="Helper\Eclipse\LunarData.cs" />
|
||||
<Compile Include="Helper\Eclipse\SolarData.cs" />
|
||||
<Compile Include="Helper\GeoFence.cs" />
|
||||
<Compile Include="Model\Admin\AdminModel.cs" />
|
||||
<Compile Include="Model\Admin\AdminSession.cs" />
|
||||
<Compile Include="Model\Camera.cs" />
|
||||
<Compile Include="Model\Crowd.cs" />
|
||||
<Compile Include="Model\Marker.cs" />
|
||||
<Compile Include="Model\AlarmItem.cs" />
|
||||
<Compile Include="Model\UTMData.cs" />
|
||||
<Compile Include="Server.cs" />
|
||||
<Compile Include="Model\PositionItem.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Content Include="../CHANGELOG.md" />
|
||||
<Content Include="../CONTRIBUTING.md" />
|
||||
<Content Include="../LICENSE" />
|
||||
<Content Include="../README.md" />
|
||||
<Content Include="../map-swagger.yml" />
|
||||
<Content Include="../.github/workflows/dotnetcore.yml" />
|
||||
<Content Include="../doc/Manual.md" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="Adminrights.manifest" />
|
||||
<None Include="config-example\settings.conf.example">
|
||||
<None Update="config-example\settings.conf.example">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="dpkg\control" />
|
||||
<None Include="dpkg\create-Builds.bat" />
|
||||
<None Include="dpkg\loramap-logrotate" />
|
||||
<None Include="dpkg\loramap.service" />
|
||||
<None Include="dpkg\make-deb.sh" />
|
||||
<None Include="dpkg\postinst" />
|
||||
<None Include="dpkg\preinst" />
|
||||
<None Include="dpkg\prerm" />
|
||||
<None Include="resources\icons\marker\din1451m.woff">
|
||||
<None Update="resources\admin\css\global.css">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="resources\js\leaflet\leaflet-src.js.map" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="resources\admin\css\global.css">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\admin\index.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\admin\login.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\css\global.css">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\css\icons\admin-with-cogwheels.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\css\icons\cctv.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\css\icons\failtile.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\css\icons\information.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\css\icons\placeholder.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\icons\akku\0-4.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\icons\akku\1-4.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\icons\akku\2-4.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\icons\akku\3-4.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\icons\akku\4-4.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\icons\general\add.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\icons\general\bullet_add.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\icons\general\bullet_delete.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\icons\general\bullet_star.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\icons\general\edit.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\icons\general\icon_edit.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\icons\general\remove.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\icons\general\save.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\icons\marker\map-marker.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\icons\marker\Marker.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\icons\marker\Person.svg">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<Content Include="resources\js\functions.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\js\leaflet\images\layers-2x.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\js\leaflet\images\layers.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\js\leaflet\images\marker-icon-2x.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\js\leaflet\images\marker-icon.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\js\leaflet\images\marker-shadow.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\js\leaflet\leaflet-src.js" />
|
||||
<Content Include="resources\js\leaflet\leaflet.css">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\js\leaflet\leaflet.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\js\menu.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\js\map.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\js\marker.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<None Include="config-example\requests.conf.example">
|
||||
<None Update="resources\admin\index.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<Content Include="resources\favicon.ico">
|
||||
<None Update="resources\admin\js\adminmenu.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="resources\index.html">
|
||||
</None>
|
||||
<None Update="resources\admin\js\eximport.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Librarys\litjson\litjson\litjson_4.7.1.csproj">
|
||||
<Project>{91a14cd2-2940-4500-8193-56d37edddbaa}</Project>
|
||||
<Name>litjson_4.7.1</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Librarys\mqtt\M2Mqtt\M2Mqtt_4.7.1.csproj">
|
||||
<Project>{a11aef5a-b246-4fe8-8330-06db73cc8074}</Project>
|
||||
<Name>M2Mqtt_4.7.1</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Utils\Bot-Utils\Bot-Utils\Bot-Utils.csproj">
|
||||
<Project>{bb7bfcb5-3db0-49e1-802a-3ce3eecc59f9}</Project>
|
||||
<Name>Bot-Utils</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Utils\ConnectorDataMqtt\ConnectorDataMqtt\ConnectorDataMqtt.csproj">
|
||||
<Project>{ee6c8f68-ed46-4c1c-abdd-cfcdf75104f2}</Project>
|
||||
<Name>ConnectorDataMqtt</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Utils\Utils-IoT\Utils-IoT\Utils-IoT.csproj">
|
||||
<Project>{b870e4d5-6806-4a0b-b233-8907eedc5afc}</Project>
|
||||
<Name>Utils-IoT</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Utils\Utils\Utils\Utils.csproj">
|
||||
<Project>{fac8ce64-bf13-4ece-8097-aeb5dd060098}</Project>
|
||||
<Name>Utils</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="resources\admin\js\menu.js">
|
||||
</None>
|
||||
<None Update="resources\admin\js\nameseditor.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="resources\js\overlays.js">
|
||||
</None>
|
||||
<None Update="resources\admin\js\settings.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</None>
|
||||
<None Update="resources\admin\login.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\css\global.css">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\css\icons\admin-with-cogwheels.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\css\icons\cctv.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\css\icons\failtile.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\css\icons\filter.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\css\icons\information.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\css\icons\placeholder.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\css\icons\search.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\css\icons\storm-ac.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\css\icons\storm-in.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\favicon.ico">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\icons\akku\0-4.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\icons\akku\1-4.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\icons\akku\2-4.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\icons\akku\3-4.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\icons\akku\4-4.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\icons\general\add.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\icons\general\bullet_add.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\icons\general\bullet_delete.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\icons\general\bullet_star.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\icons\general\edit.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\icons\general\icon_edit.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\icons\general\remove.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\icons\general\save.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\icons\marker\din1451m.woff">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\icons\marker\map-marker.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\icons\marker\Marker.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\index.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\js\functions.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\js\leaflet\images\layers-2x.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\js\leaflet\images\layers.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\js\leaflet\images\marker-icon-2x.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\js\leaflet\images\marker-icon.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\js\leaflet\images\marker-shadow.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\js\leaflet\leaflet.css">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\js\leaflet\leaflet.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\js\map.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\js\marker.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\js\menu.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="resources\js\overlays.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\LICENSE">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
|
||||
</Project>
|
||||
|
@ -1,157 +1,146 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using BlubbFish.Utils;
|
||||
using BlubbFish.Utils.IoT.Bots;
|
||||
using LitJson;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Admin {
|
||||
class AdminModel {
|
||||
public delegate void AdminEvent(Object sender, EventArgs e);
|
||||
public event AdminEvent NamesUpdate;
|
||||
|
||||
private readonly Dictionary<Int64, AdminSession> session = new Dictionary<Int64, AdminSession>();
|
||||
private readonly Dictionary<String, String> settings;
|
||||
|
||||
public AdminModel(Dictionary<String, String> settings) {
|
||||
this.settings = settings;
|
||||
if(!settings.ContainsKey("admin_user") || !settings.ContainsKey("admin_pass")) {
|
||||
Helper.WriteError("Kann die Einstellungen [webserver] admin_user und admin_pass nicht laden!");
|
||||
throw new FileNotFoundException("Kann die Einstellungen [webserver] admin_user und admin_pass nicht laden!");
|
||||
}
|
||||
}
|
||||
|
||||
public Boolean ParseReuqest(HttpListenerContext cont) {
|
||||
if(cont.Request.Url.PathAndQuery == "/admin/login") {
|
||||
return this.Login(cont);
|
||||
}
|
||||
if(!this.CheckAuth(cont)) {
|
||||
return false;
|
||||
}
|
||||
if(cont.Request.Url.PathAndQuery.StartsWith("/admin/get_json_")) {
|
||||
return this.SendJson(cont);
|
||||
}
|
||||
if(cont.Request.Url.PathAndQuery.StartsWith("/admin/set_json_")) {
|
||||
return this.GetJson(cont);
|
||||
}
|
||||
return Webserver.SendFileResponse(cont);
|
||||
}
|
||||
|
||||
private Boolean GetJson(HttpListenerContext cont) {
|
||||
if(cont.Request.Url.PathAndQuery == "/admin/set_json_names") {
|
||||
StreamReader reader = new StreamReader(cont.Request.InputStream, cont.Request.ContentEncoding);
|
||||
String rawData = reader.ReadToEnd();
|
||||
cont.Request.InputStream.Close();
|
||||
reader.Close();
|
||||
try {
|
||||
JsonMapper.ToObject(rawData);
|
||||
} catch(Exception) {
|
||||
Helper.WriteError("501 - Error recieving names.json " + cont.Request.Url.PathAndQuery);
|
||||
cont.Response.StatusCode = 501;
|
||||
return false;
|
||||
}
|
||||
File.WriteAllText("json/names.json", rawData);
|
||||
Console.WriteLine("200 - Post names.json " + cont.Request.Url.PathAndQuery);
|
||||
this.NamesUpdate?.Invoke(this, new EventArgs());
|
||||
return true;
|
||||
} else if(cont.Request.Url.PathAndQuery == "/admin/set_json_geo") {
|
||||
StreamReader reader = new StreamReader(cont.Request.InputStream, cont.Request.ContentEncoding);
|
||||
String rawData = reader.ReadToEnd();
|
||||
cont.Request.InputStream.Close();
|
||||
reader.Close();
|
||||
try {
|
||||
JsonMapper.ToObject(rawData);
|
||||
} catch(Exception) {
|
||||
Helper.WriteError("501 - Error recieving geo.json " + cont.Request.Url.PathAndQuery);
|
||||
cont.Response.StatusCode = 501;
|
||||
return false;
|
||||
}
|
||||
File.WriteAllText("json/geo.json", rawData);
|
||||
Console.WriteLine("200 - Post geo.json " + cont.Request.Url.PathAndQuery);
|
||||
this.NamesUpdate?.Invoke(this, new EventArgs());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Boolean SendJson(HttpListenerContext cont) {
|
||||
if(cont.Request.Url.PathAndQuery == "/admin/get_json_names") {
|
||||
String file = File.ReadAllText("json/names.json");
|
||||
Byte[] buf = Encoding.UTF8.GetBytes(file);
|
||||
cont.Response.ContentLength64 = buf.Length;
|
||||
cont.Response.OutputStream.Write(buf, 0, buf.Length);
|
||||
Console.WriteLine("200 - Send names.json " + cont.Request.Url.PathAndQuery);
|
||||
return true;
|
||||
} else if(cont.Request.Url.PathAndQuery == "/admin/get_json_geo") {
|
||||
String file = File.ReadAllText("json/geo.json");
|
||||
Byte[] buf = Encoding.UTF8.GetBytes(file);
|
||||
cont.Response.ContentLength64 = buf.Length;
|
||||
cont.Response.OutputStream.Write(buf, 0, buf.Length);
|
||||
Console.WriteLine("200 - Send geo.json " + cont.Request.Url.PathAndQuery);
|
||||
return true;
|
||||
}
|
||||
Helper.WriteError("404 - Section in get_json not found " + cont.Request.Url.PathAndQuery + "!");
|
||||
cont.Response.StatusCode = 404;
|
||||
return false;
|
||||
}
|
||||
|
||||
private Boolean Login(HttpListenerContext cont) {
|
||||
Dictionary<String, String> POST = Webserver.GetPostParams(cont.Request);
|
||||
if(POST.ContainsKey("user") && POST["user"] == this.settings["admin_user"] && POST.ContainsKey("pass") && POST["pass"] == this.settings["admin_pass"]) {
|
||||
Int64 sessionid = 0;
|
||||
while(true) {
|
||||
sessionid = AdminSession.GetRandomSessionid();
|
||||
if(!this.session.ContainsKey(sessionid)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(cont.Request.Cookies["loramapsession"] != null) {
|
||||
if(Int64.TryParse(cont.Request.Cookies["loramapsession"].Value, out Int64 cookiesessionid)) {
|
||||
if(this.session.ContainsKey(cookiesessionid)) {
|
||||
if(!this.session[sessionid].IsLoggedin) {
|
||||
sessionid = cookiesessionid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!this.session.ContainsKey(sessionid)) {
|
||||
this.session.Add(sessionid, new AdminSession());
|
||||
}
|
||||
this.session[sessionid].IsLoggedin = true;
|
||||
cont.Response.AppendCookie(new Cookie("loramapsession", sessionid.ToString()) {
|
||||
Expires = DateTime.Now.AddYears(1)
|
||||
});
|
||||
cont.Response.AddHeader("Location", "/admin");
|
||||
cont.Response.StatusCode = 307;
|
||||
Console.WriteLine("200 - Login OK! " + cont.Request.Url.PathAndQuery);
|
||||
return true;
|
||||
}
|
||||
cont.Response.AddHeader("Location", "/admin/login.html");
|
||||
cont.Response.StatusCode = 307;
|
||||
Helper.WriteError("307 - Login WRONG! " + cont.Request.Url.PathAndQuery);
|
||||
return false;
|
||||
}
|
||||
|
||||
private Boolean CheckAuth(HttpListenerContext cont) {
|
||||
#if DEBUG
|
||||
return true;
|
||||
#endif
|
||||
if(cont.Request.Url.PathAndQuery.StartsWith("/admin/login.html")) {
|
||||
return true;
|
||||
} else {
|
||||
if(cont.Request.Cookies["loramapsession"] != null) {
|
||||
if(Int64.TryParse(cont.Request.Cookies["loramapsession"].Value, out Int64 sessionid)) {
|
||||
if(this.session.ContainsKey(sessionid)) {
|
||||
return this.session[sessionid].IsLoggedin;
|
||||
}
|
||||
}
|
||||
}
|
||||
cont.Response.StatusCode = 403;
|
||||
Helper.WriteError("403 - " + cont.Request.Url.PathAndQuery);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
using BlubbFish.Utils;
|
||||
using BlubbFish.Utils.IoT.Bots;
|
||||
|
||||
using LitJson;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Admin {
|
||||
class AdminModel {
|
||||
public delegate void AdminEvent(Object sender, EventArgs e);
|
||||
#pragma warning disable 0067
|
||||
public event AdminEvent NamesUpdate;
|
||||
public event AdminEvent GeoUpdate;
|
||||
public event AdminEvent SettingsUpdate;
|
||||
#pragma warning restore 0067
|
||||
|
||||
private readonly SortedDictionary<String, Tuple<String, String>> datastorage = new SortedDictionary<String, Tuple<String, String>>() {
|
||||
{ "name", new Tuple<String, String>("names", "NamesUpdate") },
|
||||
{ "geo", new Tuple<String, String>("geo", "GeoUpdate") },
|
||||
{ "setting", new Tuple<String, String>("settings", "SettingsUpdate") }
|
||||
};
|
||||
|
||||
private readonly Dictionary<Int64, AdminSession> session = new Dictionary<Int64, AdminSession>();
|
||||
private readonly Dictionary<String, String> settings;
|
||||
|
||||
public AdminModel(Dictionary<String, String> settings) {
|
||||
this.settings = settings;
|
||||
if(!settings.ContainsKey("admin_user") || !settings.ContainsKey("admin_pass")) {
|
||||
Helper.WriteError("Kann die Einstellungen [webserver] admin_user und admin_pass nicht laden!");
|
||||
throw new FileNotFoundException("Kann die Einstellungen [webserver] admin_user und admin_pass nicht laden!");
|
||||
}
|
||||
}
|
||||
|
||||
public Boolean ParseReuqest(HttpListenerContext cont) {
|
||||
if(cont.Request.Url.PathAndQuery == "/admin/login") {
|
||||
return this.Login(cont);
|
||||
}
|
||||
if(!this.CheckAuth(cont)) {
|
||||
return false;
|
||||
}
|
||||
if(cont.Request.Url.PathAndQuery.StartsWith("/admin/api/json/")) {
|
||||
if(cont.Request.HttpMethod == "GET") {
|
||||
if(cont.Request.Url.AbsolutePath.Length > 16) {
|
||||
String parts = cont.Request.Url.AbsolutePath[16..];
|
||||
Dictionary<String, JsonData> ret = new Dictionary<String, JsonData>();
|
||||
foreach(String part in parts.Split(",")) {
|
||||
if(this.datastorage.ContainsKey(part)) {
|
||||
ret.Add(part, JsonMapper.ToObject(File.ReadAllText("json/" + this.datastorage[part].Item1 + ".json")));
|
||||
}
|
||||
}
|
||||
Console.WriteLine("200 - Send names.json " + cont.Request.Url.PathAndQuery);
|
||||
return Webserver.SendJsonResponse(ret, cont);
|
||||
}
|
||||
} else if(cont.Request.HttpMethod == "PUT") {
|
||||
if(cont.Request.Url.AbsolutePath.Length > 16) {
|
||||
String part = cont.Request.Url.AbsolutePath[16..];
|
||||
if(this.datastorage.ContainsKey(part)) {
|
||||
return this.SetJsonFile(cont, "json/" + this.datastorage[part].Item1 + ".json", this.datastorage[part].Item2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Webserver.SendFileResponse(cont);
|
||||
}
|
||||
|
||||
private Boolean SetJsonFile(HttpListenerContext cont, String filename, String updatenotifier) {
|
||||
StreamReader reader = new StreamReader(cont.Request.InputStream, cont.Request.ContentEncoding);
|
||||
String rawData = reader.ReadToEnd();
|
||||
cont.Request.InputStream.Close();
|
||||
reader.Close();
|
||||
try {
|
||||
_ = JsonMapper.ToObject(rawData);
|
||||
} catch (Exception) {
|
||||
Helper.WriteError("501 - Error recieving " + filename + ", no valid json " + cont.Request.Url.PathAndQuery);
|
||||
cont.Response.StatusCode = 501;
|
||||
return false;
|
||||
}
|
||||
File.WriteAllText(filename, rawData);
|
||||
Console.WriteLine("200 - PUT " + filename + " " + cont.Request.Url.PathAndQuery);
|
||||
this.GetEvent<AdminEvent>(updatenotifier)?.Invoke(this, new EventArgs());
|
||||
return true;
|
||||
}
|
||||
|
||||
private Boolean Login(HttpListenerContext cont) {
|
||||
Dictionary<String, String> POST = Webserver.GetPostParams(cont.Request);
|
||||
if(POST.ContainsKey("user") && POST["user"] == this.settings["admin_user"] && POST.ContainsKey("pass") && POST["pass"] == this.settings["admin_pass"]) {
|
||||
Int64 sessionid;
|
||||
while(true) {
|
||||
sessionid = AdminSession.GetRandomSessionid();
|
||||
if(!this.session.ContainsKey(sessionid)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(cont.Request.Cookies["loramapsession"] != null) {
|
||||
if(Int64.TryParse(cont.Request.Cookies["loramapsession"].Value, out Int64 cookiesessionid)) {
|
||||
if(this.session.ContainsKey(cookiesessionid)) {
|
||||
if(!this.session[sessionid].IsLoggedin) {
|
||||
sessionid = cookiesessionid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!this.session.ContainsKey(sessionid)) {
|
||||
this.session.Add(sessionid, new AdminSession());
|
||||
}
|
||||
this.session[sessionid].IsLoggedin = true;
|
||||
cont.Response.AppendCookie(new Cookie("loramapsession", sessionid.ToString()) {
|
||||
Expires = DateTime.Now.AddYears(1)
|
||||
});
|
||||
cont.Response.AddHeader("Location", "/admin");
|
||||
cont.Response.StatusCode = 307;
|
||||
Console.WriteLine("200 - Login OK! " + cont.Request.Url.PathAndQuery);
|
||||
return true;
|
||||
}
|
||||
cont.Response.AddHeader("Location", "/admin/login.html");
|
||||
cont.Response.StatusCode = 307;
|
||||
Helper.WriteError("307 - Login WRONG! " + cont.Request.Url.PathAndQuery);
|
||||
return false;
|
||||
}
|
||||
|
||||
private Boolean CheckAuth(HttpListenerContext cont) {
|
||||
#if DEBUG
|
||||
Helper.WriteError("200 - AUTH-Bypassed!");
|
||||
return true;
|
||||
#else
|
||||
if(cont.Request.Url.PathAndQuery.StartsWith("/admin/login.html")) {
|
||||
return true;
|
||||
} else {
|
||||
if(cont.Request.Cookies["loramapsession"] != null) {
|
||||
if(Int64.TryParse(cont.Request.Cookies["loramapsession"].Value, out Int64 sessionid)) {
|
||||
if(this.session.ContainsKey(sessionid)) {
|
||||
return this.session[sessionid].IsLoggedin;
|
||||
}
|
||||
}
|
||||
}
|
||||
cont.Response.StatusCode = 403;
|
||||
Helper.WriteError("403 - " + cont.Request.Url.PathAndQuery);
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Admin {
|
||||
class AdminSession {
|
||||
|
@ -1,54 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using LitJson;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Model {
|
||||
class AlarmItem {
|
||||
public Double Rssi { get; private set; }
|
||||
public Double Snr { get; private set; }
|
||||
public DateTime Lorarecievedtime { get; private set; }
|
||||
public DateTime Recievedtime { get; private set; }
|
||||
public Double Latitude { get; private set; }
|
||||
public Double Longitude { get; private set; }
|
||||
public UTMData UTM { get; private set; }
|
||||
public Double Hdop { get; private set; }
|
||||
public Boolean Fix { get; private set; }
|
||||
public Double Height { get; private set; }
|
||||
|
||||
public AlarmItem(JsonData json) => this.Update(json);
|
||||
|
||||
public void Update(JsonData json) {
|
||||
this.Rssi = (Double)json["Rssi"];
|
||||
this.Snr = (Double)json["Snr"];
|
||||
if(DateTime.TryParse((String)json["Receivedtime"], DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal, out DateTime updatetime)) {
|
||||
this.Lorarecievedtime = updatetime.ToUniversalTime();
|
||||
}
|
||||
this.Recievedtime = DateTime.UtcNow;
|
||||
this.Latitude = (Double)json["Gps"]["Latitude"];
|
||||
this.Longitude = (Double)json["Gps"]["Longitude"];
|
||||
this.Fix = (Boolean)json["Gps"]["Fix"];
|
||||
if(!this.Fix) {
|
||||
this.Latitude = (Double)json["Gps"]["LastLatitude"];
|
||||
this.Longitude = (Double)json["Gps"]["LastLongitude"];
|
||||
}
|
||||
this.UTM = new UTMData(this.Latitude, this.Longitude);
|
||||
this.Hdop = (Double)json["Gps"]["Hdop"];
|
||||
this.Height = (Double)json["Gps"]["Height"];
|
||||
}
|
||||
|
||||
public static String GetId(JsonData json) => (String)json["Name"];
|
||||
|
||||
public static Boolean CheckJson(JsonData json) => json.ContainsKey("Rssi") && json["Rssi"].IsDouble
|
||||
&& json.ContainsKey("Snr") && json["Snr"].IsDouble
|
||||
&& json.ContainsKey("Receivedtime") && json["Receivedtime"].IsString
|
||||
&& json.ContainsKey("Gps") && json["Gps"].IsObject
|
||||
&& json["Gps"].ContainsKey("Latitude") && json["Gps"]["Latitude"].IsDouble
|
||||
&& json["Gps"].ContainsKey("Longitude") && json["Gps"]["Longitude"].IsDouble
|
||||
&& json["Gps"].ContainsKey("LastLatitude") && json["Gps"]["LastLatitude"].IsDouble
|
||||
&& json["Gps"].ContainsKey("LastLongitude") && json["Gps"]["LastLongitude"].IsDouble
|
||||
&& json["Gps"].ContainsKey("Hdop") && json["Gps"]["Hdop"].IsDouble
|
||||
&& json["Gps"].ContainsKey("Fix") && json["Gps"]["Fix"].IsBoolean
|
||||
&& json["Gps"].ContainsKey("Height") && json["Gps"]["Height"].IsDouble
|
||||
&& json.ContainsKey("Name") && json["Name"].IsString;
|
||||
}
|
||||
}
|
@ -2,17 +2,15 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Model
|
||||
{
|
||||
class Camera
|
||||
{
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Camera {
|
||||
public class CameraCounter {
|
||||
public DateTime Lastcameradata { get; private set; }
|
||||
public String Name { get; private set; }
|
||||
public Int32 Total { get; private set; }
|
||||
public Int32 Incoming { get; private set; }
|
||||
public Int32 Outgoing { get; private set; }
|
||||
|
||||
public Camera(JsonData json) => this.Update(json);
|
||||
public CameraCounter(JsonData json) => this.Update(json);
|
||||
|
||||
internal static String GetId(JsonData json) => (String)json["camera_id"];
|
||||
|
@ -1,63 +1,49 @@
|
||||
using LitJson;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Model
|
||||
{
|
||||
public class Crowd
|
||||
{
|
||||
public Int32 DensityCount { get; private set; }
|
||||
public DateTime LastUpdate { get; private set; }
|
||||
public Double AverageFlowMagnitude { get; private set; }
|
||||
public Double AverageFlowDirection { get; private set; }
|
||||
public Double Cofidence { get; private set; }
|
||||
public String Situation { get; private set; }
|
||||
|
||||
public Crowd(JsonData json) => this.Update(json);
|
||||
|
||||
public static Boolean CheckJsonCrowdDensityLocal(JsonData json) => json.ContainsKey("camera_ids") && json["camera_ids"].IsArray && json["camera_ids"].Count == 1 &&
|
||||
json.ContainsKey("density_map") && json["density_map"].IsArray &&
|
||||
json.ContainsKey("type_module") && json["type_module"].IsString && json["type_module"].ToString() == "crowd_density_local" &&
|
||||
json.ContainsKey("density_count") && json["density_count"].IsInt &&
|
||||
json.ContainsKey("timestamp1") && json["timestamp1"].IsString;
|
||||
|
||||
public static Boolean CheckJsonFlow(JsonData json) => json.ContainsKey("camera_ids") && json["camera_ids"].IsArray && json["camera_ids"].Count == 1 &&
|
||||
json.ContainsKey("average_flow_magnitude") && json["average_flow_magnitude"].IsArray &&
|
||||
json.ContainsKey("type_module") && json["type_module"].IsString && json["type_module"].ToString() == "flow" &&
|
||||
json.ContainsKey("average_flow_direction") && json["average_flow_direction"].IsArray &&
|
||||
json.ContainsKey("timestamp") && json["timestamp"].IsString;
|
||||
|
||||
public static Boolean CheckJsonFightingDetection(JsonData json) => json.ContainsKey("camera_ids") && json["camera_ids"].IsArray && json["camera_ids"].Count == 1 &&
|
||||
json.ContainsKey("confidence") && json["confidence"].IsDouble &&
|
||||
json.ContainsKey("type_module") && json["type_module"].IsString && json["type_module"].ToString() == "fighting_detection" &&
|
||||
json.ContainsKey("situation") && json["situation"].IsString &&
|
||||
json.ContainsKey("timestamp") && json["timestamp"].IsString;
|
||||
|
||||
public static String GetId(JsonData json) => (String)json["camera_ids"][0];
|
||||
|
||||
public void Update(JsonData json) {
|
||||
if(CheckJsonCrowdDensityLocal(json)) {
|
||||
this.DensityCount = (Int32)json["density_count"];
|
||||
if (DateTime.TryParse((String)json["timestamp1"], DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal, out DateTime updatetime)) {
|
||||
this.LastUpdate = updatetime.ToUniversalTime();
|
||||
}
|
||||
} else if(CheckJsonFlow(json)) {
|
||||
if (json["average_flow_magnitude"].Count == 1) {
|
||||
this.AverageFlowMagnitude = (Double)json["average_flow_magnitude"][0];
|
||||
}
|
||||
if (json["average_flow_direction"].Count == 1) {
|
||||
this.AverageFlowDirection = (Double)json["average_flow_direction"][0];
|
||||
}
|
||||
if (DateTime.TryParse((String)json["timestamp"], DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal, out DateTime updatetime)) {
|
||||
this.LastUpdate = updatetime.ToUniversalTime();
|
||||
}
|
||||
} else if(CheckJsonFightingDetection(json)) {
|
||||
this.Cofidence = (Double)json["confidence"];
|
||||
this.Situation = (String)json["situation"];
|
||||
if (DateTime.TryParse((String)json["timestamp"], DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal, out DateTime updatetime)) {
|
||||
this.LastUpdate = updatetime.ToUniversalTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using LitJson;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Camera {
|
||||
public class CameraDensity {
|
||||
public Int32 DensityCount { get; private set; }
|
||||
public DateTime TimeStamp { get; private set; }
|
||||
public Double AverageFlowMagnitude { get; private set; }
|
||||
public Double AverageFlowDirection { get; private set; }
|
||||
public DateTime LastUpdate { get; private set; }
|
||||
|
||||
public CameraDensity(JsonData json) => this.Update(json);
|
||||
|
||||
public static Boolean CheckJsonCrowdDensityLocal(JsonData json) => json.ContainsKey("camera_ids") && json["camera_ids"].IsArray && json["camera_ids"].Count == 1 &&
|
||||
json.ContainsKey("density_map") && json["density_map"].IsArray &&
|
||||
json.ContainsKey("type_module") && json["type_module"].IsString && json["type_module"].ToString() == "crowd_density_local" &&
|
||||
json.ContainsKey("density_count") && json["density_count"].IsInt &&
|
||||
json.ContainsKey("timestamp_1") && json["timestamp_1"].IsString;
|
||||
|
||||
public static Boolean CheckJsonFlow(JsonData json) => json.ContainsKey("camera_ids") && json["camera_ids"].IsArray && json["camera_ids"].Count == 1 &&
|
||||
json.ContainsKey("average_flow_magnitude") && json["average_flow_magnitude"].IsArray &&
|
||||
json.ContainsKey("type_module") && json["type_module"].IsString && json["type_module"].ToString() == "flow" &&
|
||||
json.ContainsKey("average_flow_direction") && json["average_flow_direction"].IsArray &&
|
||||
json.ContainsKey("timestamp") && json["timestamp"].IsString;
|
||||
|
||||
public static String GetId(JsonData json) => (String)json["camera_ids"][0];
|
||||
|
||||
public void Update(JsonData json) {
|
||||
if(CheckJsonCrowdDensityLocal(json)) {
|
||||
this.DensityCount = (Int32)json["density_count"];
|
||||
if (DateTime.TryParse((String)json["timestamp_1"], DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal, out DateTime updatetime)) {
|
||||
this.TimeStamp = updatetime.ToUniversalTime();
|
||||
}
|
||||
} else if(CheckJsonFlow(json)) {
|
||||
if (json["average_flow_magnitude"].Count == 1) {
|
||||
this.AverageFlowMagnitude = (Double)json["average_flow_magnitude"][0];
|
||||
}
|
||||
if (json["average_flow_direction"].Count == 1) {
|
||||
this.AverageFlowDirection = (Double)json["average_flow_direction"][0];
|
||||
}
|
||||
if (DateTime.TryParse((String)json["timestamp"], DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal, out DateTime updatetime)) {
|
||||
this.TimeStamp = updatetime.ToUniversalTime();
|
||||
}
|
||||
}
|
||||
this.LastUpdate = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
}
|
35
Lora-Map/Model/Camera/CameraFights.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using LitJson;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Camera {
|
||||
public class CameraFights {
|
||||
public CameraFights(JsonData json) => this.Update(json);
|
||||
|
||||
public DateTime LastUpdate { get; private set; }
|
||||
public DateTime TimeStamp { get; private set; }
|
||||
public String Situation { get; private set; }
|
||||
public Double FightProbability { get; private set; }
|
||||
|
||||
public static Boolean CheckJsonFightingDetection(JsonData json) => json.ContainsKey("camera_ids") && json["camera_ids"].IsArray && json["camera_ids"].Count == 1 &&
|
||||
json.ContainsKey("confidence") && json["confidence"].IsString &&
|
||||
json.ContainsKey("type_module") && json["type_module"].IsString && json["type_module"].ToString() == "fighting_detection" &&
|
||||
json.ContainsKey("situation") && json["situation"].IsString &&
|
||||
json.ContainsKey("timestamp") && json["timestamp"].IsString;
|
||||
|
||||
public static String GetId(JsonData json) => (String)json["camera_ids"][0];
|
||||
|
||||
public void Update(JsonData json) {
|
||||
if (CheckJsonFightingDetection(json)) {
|
||||
if (Double.TryParse((String)json["confidence"], NumberStyles.Float, CultureInfo.InvariantCulture, out Double cofidence)) {
|
||||
this.FightProbability = cofidence;
|
||||
}
|
||||
this.Situation = (String)json["situation"];
|
||||
if (DateTime.TryParse((String)json["timestamp"], DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal, out DateTime updatetime)) {
|
||||
this.TimeStamp = updatetime.ToUniversalTime();
|
||||
}
|
||||
this.LastUpdate = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
62
Lora-Map/Model/Camera/CameraModel.cs
Normal file
@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using BlubbFish.Utils;
|
||||
|
||||
using LitJson;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Camera {
|
||||
public class CameraModel : OwnSingeton<CameraModel> {
|
||||
private readonly Object lockFight = new Object();
|
||||
private readonly Object lockCount = new Object();
|
||||
private readonly Object lockDensy = new Object();
|
||||
|
||||
public SortedDictionary<String, CameraCounter> Counter {
|
||||
get; private set;
|
||||
}
|
||||
public SortedDictionary<String, CameraDensity> Density {
|
||||
get; private set;
|
||||
}
|
||||
public SortedDictionary<String, CameraFights> Fights {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
protected CameraModel() {
|
||||
this.Counter = new SortedDictionary<String, CameraCounter>();
|
||||
this.Density = new SortedDictionary<String, CameraDensity>();
|
||||
this.Fights = new SortedDictionary<String, CameraFights>();
|
||||
}
|
||||
|
||||
public void ParseMqttJson(JsonData mqtt, String from) {
|
||||
if(from.Contains("camera/count") && CameraCounter.CheckJson(mqtt)) {
|
||||
String cameraid = CameraCounter.GetId(mqtt);
|
||||
lock(this.lockCount) {
|
||||
if(this.Counter.ContainsKey(cameraid)) {
|
||||
this.Counter[cameraid].Update(mqtt);
|
||||
} else {
|
||||
this.Counter.Add(cameraid, new CameraCounter(mqtt));
|
||||
}
|
||||
}
|
||||
} else if((from.Contains("sfn/crowd_density_local") || from.Contains("camera/crowd")) && CameraDensity.CheckJsonCrowdDensityLocal(mqtt) || from.Contains("sfn/flow") && CameraDensity.CheckJsonFlow(mqtt)) {
|
||||
String cameraid = CameraDensity.GetId(mqtt);
|
||||
lock(this.lockDensy) {
|
||||
if(this.Density.ContainsKey(cameraid)) {
|
||||
this.Density[cameraid].Update(mqtt);
|
||||
} else {
|
||||
this.Density.Add(cameraid, new CameraDensity(mqtt));
|
||||
}
|
||||
}
|
||||
} else if((from.Contains("camera/fighting_detection") || from.Contains("sfn/fighting_detection")) && CameraFights.CheckJsonFightingDetection(mqtt)) {
|
||||
String cameraid = CameraFights.GetId(mqtt);
|
||||
lock(this.lockFight) {
|
||||
if(this.Fights.ContainsKey(cameraid)) {
|
||||
this.Fights[cameraid].Update(mqtt);
|
||||
} else {
|
||||
this.Fights.Add(cameraid, new CameraFights(mqtt));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using LitJson;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Model
|
||||
{
|
||||
class Marker {
|
||||
private readonly XmlDocument svg = new XmlDocument();
|
||||
|
||||
public Marker(String hash) {
|
||||
this.svg.LoadXml(File.ReadAllText("resources/icons/marker/Marker.svg"));
|
||||
this.ParseParams(hash);
|
||||
}
|
||||
|
||||
public static String ParseMarkerConfig(JsonData json, String name) {
|
||||
String ret = "icons/marker/Marker.svg";
|
||||
if(json.ContainsKey("person") && json["person"].IsObject) {
|
||||
ret += "?icon=person";
|
||||
if(json["person"].ContainsKey("org") && json["person"]["org"].IsString) {
|
||||
ret += "&person-org=" + (String)json["person"]["org"];
|
||||
}
|
||||
if(json["person"].ContainsKey("funct") && json["person"]["funct"].IsString) {
|
||||
ret += "&person-funct=" + (String)json["person"]["funct"];
|
||||
}
|
||||
if(json["person"].ContainsKey("rang") && json["person"]["rang"].IsString) {
|
||||
ret += "&person-rang=" + (String)json["person"]["rang"];
|
||||
}
|
||||
if(json["person"].ContainsKey("text") && json["person"]["text"].IsString) {
|
||||
ret += "&person-text=" + (String)json["person"]["text"];
|
||||
}
|
||||
if(json["person"].ContainsKey("typ") && json["person"]["typ"].IsArray) {
|
||||
foreach(JsonData item in json["person"]["typ"]) {
|
||||
if(item.IsString) {
|
||||
ret += "&person-typ=" + (String)item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ret += (ret.Contains("?")) ? "&name=" + name : "?name=" + name;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void ParseParams(String hash) {
|
||||
String[] parts = hash.Split('&');
|
||||
foreach(String part in parts) {
|
||||
String[] keyvalue = part.Split('=');
|
||||
if(keyvalue.Length == 2) {
|
||||
switch(keyvalue[0].ToLower()) {
|
||||
case "name":
|
||||
XmlNodeList xmlname = this.svg.DocumentElement.SelectNodes("//*[local-name()='tspan'][@id='marker-name-text']");
|
||||
if(xmlname.Count == 1) {
|
||||
xmlname.Item(0).InnerText = keyvalue[1];
|
||||
}
|
||||
break;
|
||||
case "marker-bg":
|
||||
if(keyvalue[1].ToLower() == "hidden") {
|
||||
XmlNodeList markerbg = this.svg.DocumentElement.SelectNodes("//*[local-name()='defs'][@id='global-def']");
|
||||
if(markerbg.Count == 1) {
|
||||
markerbg[0].InnerXml += "<style type=\"text/css\">#marker-bg {display: none;}#marker-name {display: none;}</style>";
|
||||
}
|
||||
XmlNodeList root = this.svg.DocumentElement.SelectNodes("//*[local-name()='svg']");
|
||||
if(root.Count == 1) {
|
||||
foreach(XmlAttribute item in root[0].Attributes) {
|
||||
if(item.Name.ToLower() == "height") {
|
||||
item.Value = "38px";
|
||||
}
|
||||
if(item.Name.ToLower() == "width") {
|
||||
item.Value = "40px";
|
||||
}
|
||||
if(item.Name.ToLower() == "viewbox") {
|
||||
item.Value = "8 35 70 100";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "icon":
|
||||
if(keyvalue[1].ToLower() == "person") {
|
||||
XmlNodeList xmlicon = this.svg.DocumentElement.SelectNodes("//*[local-name()='defs'][@id='global-def']");
|
||||
if (xmlicon.Count == 1) {
|
||||
xmlicon.Item(0).InnerXml += "<style type=\"text/css\">#marker-icon #person { display: inline; }</style>";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "person-org":
|
||||
XmlNodeList xmlpersonorg = this.svg.DocumentElement.SelectNodes("//*[local-name()='defs'][@id='people-def']");
|
||||
if (xmlpersonorg.Count == 1) {
|
||||
xmlpersonorg.Item(0).InnerXml += "<style type=\"text/css\">#person-layer-org #person-layer-org-"+ keyvalue[1] + " { display: inline; }</style>";
|
||||
}
|
||||
break;
|
||||
case "person-funct":
|
||||
XmlNodeList xmlpersonfunct = this.svg.DocumentElement.SelectNodes("//*[local-name()='defs'][@id='people-def']");
|
||||
if (xmlpersonfunct.Count == 1) {
|
||||
xmlpersonfunct.Item(0).InnerXml += "<style type=\"text/css\">#person-layer-funct #person-layer-funct-" + keyvalue[1] + " { display: inline; }</style>";
|
||||
}
|
||||
break;
|
||||
case "person-rang":
|
||||
XmlNodeList xmlpersonrang = this.svg.DocumentElement.SelectNodes("//*[local-name()='defs'][@id='people-def']");
|
||||
if (xmlpersonrang.Count == 1) {
|
||||
xmlpersonrang.Item(0).InnerXml += "<style type=\"text/css\">#person-layer-rang #person-layer-rang-" + keyvalue[1] + " { display: inline; }</style>";
|
||||
}
|
||||
break;
|
||||
case "person-text":
|
||||
XmlNodeList xmlpersontext = this.svg.DocumentElement.SelectNodes("//*[local-name()='tspan'][@id='person-layer-typ-text']");
|
||||
if (xmlpersontext.Count == 1) {
|
||||
xmlpersontext.Item(0).InnerText = keyvalue[1];
|
||||
}
|
||||
break;
|
||||
case "person-typ":
|
||||
XmlNodeList xmlpersontyp = this.svg.DocumentElement.SelectNodes("//*[local-name()='defs'][@id='people-def']");
|
||||
if(xmlpersontyp.Count == 1) {
|
||||
xmlpersontyp.Item(0).InnerXml += "<style type=\"text/css\">#person-layer-typ #person-layer-typ-" + keyvalue[1] + " { display: inline; }</style>";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override String ToString() => this.svg.OuterXml;
|
||||
}
|
||||
}
|
32
Lora-Map/Model/Position/PositionAlarm.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LitJson;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Position {
|
||||
public class PositionAlarm : PositionItem {
|
||||
private readonly SortedDictionary<DateTime, String> buttonhistory = new SortedDictionary<DateTime, String>();
|
||||
|
||||
public List<DateTime> ButtonPressed => this.buttonhistory.Keys.ToList();
|
||||
|
||||
public PositionAlarm(JsonData json) : base(json, null) {
|
||||
}
|
||||
|
||||
public override void Update(JsonData json) {
|
||||
base.Update(json);
|
||||
this.SetHistory(json);
|
||||
}
|
||||
|
||||
private void SetHistory(JsonData json) {
|
||||
if(json.ContainsKey("Hash") && json["Hash"].IsString) {
|
||||
String key = json["Hash"].ToString();
|
||||
if(!this.buttonhistory.ContainsValue(key)) {
|
||||
this.buttonhistory.Add(DateTime.UtcNow, key);
|
||||
if(this.buttonhistory.Count > 10) {
|
||||
_ = this.buttonhistory.Remove(this.buttonhistory.Keys.ToList().First());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
102
Lora-Map/Model/Position/PositionItem.cs
Normal file
@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
using Fraunhofer.Fit.IoT.LoraMap.Model.Svg;
|
||||
|
||||
using LitJson;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Position {
|
||||
public class PositionItem {
|
||||
private Double _lastLat = 0;
|
||||
private Double _lastLon = 0;
|
||||
|
||||
public Double Rssi { get; private set; }
|
||||
public Double Snr { get; private set; }
|
||||
public DateTime Lorarecievedtime { get; private set; }
|
||||
public DateTime Recievedtime { get; private set; }
|
||||
public Double Latitude { get; private set; }
|
||||
public Double Longitude { get; private set; }
|
||||
public UTMData UTM { get; private set; }
|
||||
public Double Hdop { get; private set; }
|
||||
public DateTime Lastgpspostime { get; private set; }
|
||||
public Double Battery { get; private set; }
|
||||
public Int32 Batterysimple { get; private set; }
|
||||
public Boolean Fix { get; private set; }
|
||||
public Double Height { get; private set; }
|
||||
public String Name { get; private set; }
|
||||
public String Icon { get; private set; }
|
||||
public String MenuIcon { get; private set; }
|
||||
public String Group { get; private set; }
|
||||
|
||||
public PositionItem(JsonData json, JsonData marker) {
|
||||
this.Update(json);
|
||||
this.UpdateMarker(marker, GetId(json));
|
||||
}
|
||||
|
||||
public void UpdateMarker(JsonData marker, String id) {
|
||||
if(marker != null && marker.ContainsKey(id)) {
|
||||
this.Name = marker[id].ContainsKey("name") && marker[id]["name"].IsString ? (String)marker[id]["name"] : id;
|
||||
Tuple<String, String> icons = this.ParseIconConfig(marker[id]);
|
||||
this.Icon = icons.Item1;
|
||||
this.MenuIcon = icons.Item2;
|
||||
this.Group = marker[id].ContainsKey("Group") && marker[id]["Group"].IsString ? (String)marker[id]["Group"] : "no";
|
||||
} else {
|
||||
this.Name = id;
|
||||
this.Icon = null;
|
||||
this.Group = null;
|
||||
}
|
||||
}
|
||||
|
||||
private Tuple<String, String> ParseIconConfig(JsonData marker) {
|
||||
String icon = null;
|
||||
String menu = null;
|
||||
if(marker.ContainsKey("marker.svg") && marker["marker.svg"].IsObject) {
|
||||
icon = SVGMarker.ParseConfig(marker["marker.svg"], this.Name);
|
||||
if(marker["marker.svg"].ContainsKey("person") && marker["marker.svg"]["person"].IsObject) {
|
||||
menu = SVGPerson.ParseConfig(marker["marker.svg"]["person"]);
|
||||
}
|
||||
} else if(marker.ContainsKey("icon") && marker["icon"].IsString) {
|
||||
icon = (String)marker["icon"];
|
||||
}
|
||||
return new Tuple<String, String>(icon, menu);
|
||||
}
|
||||
|
||||
public static Boolean CheckJson(JsonData json) =>
|
||||
json.ContainsKey("BatteryLevel") && (json["BatteryLevel"].IsDouble || json["BatteryLevel"].IsInt)
|
||||
&& json.ContainsKey("Gps") && json["Gps"].IsObject
|
||||
&& json["Gps"].ContainsKey("Latitude") && (json["Gps"]["Latitude"].IsDouble || json["Gps"]["Latitude"].IsInt)
|
||||
&& json["Gps"].ContainsKey("Longitude") && (json["Gps"]["Longitude"].IsDouble || json["Gps"]["Longitude"].IsInt)
|
||||
&& json["Gps"].ContainsKey("Fix") && json["Gps"]["Fix"].IsBoolean
|
||||
&& json["Gps"].ContainsKey("Height") && (json["Gps"]["Height"].IsDouble || json["Gps"]["Height"].IsInt)
|
||||
&& json.ContainsKey("Name") && json["Name"].IsString;
|
||||
|
||||
public static String GetId(JsonData json) => (String)json["Name"];
|
||||
|
||||
public virtual void Update(JsonData json) {
|
||||
this.Rssi = json.ContainsKey("Rssi") && (json["Rssi"].IsDouble || json["Rssi"].IsInt) && Double.TryParse(json["Rssi"].ToString(), out Double rssi) ? rssi : 0;
|
||||
this.Snr = json.ContainsKey("Snr") && (json["Snr"].IsDouble || json["Snr"].IsInt) && Double.TryParse(json["Snr"].ToString(), out Double snr) ? snr : 0;
|
||||
this.Lorarecievedtime = json.ContainsKey("Receivedtime") && json["Receivedtime"].IsString && DateTime.TryParse((String)json["Receivedtime"], DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal, out DateTime updatetime) ? updatetime.ToUniversalTime() : DateTime.UtcNow;
|
||||
this.Recievedtime = DateTime.UtcNow;
|
||||
this.Battery = Math.Round(json["BatteryLevel"].IsInt ? (Int32)json["BatteryLevel"] : (Double)json["BatteryLevel"], 2);
|
||||
this.Batterysimple = this.Battery < 3.44 ? 0 : this.Battery < 3.53 ? 1 : this.Battery < 3.6525 ? 2 : this.Battery < 3.8825 ? 3 : 4;
|
||||
|
||||
this.Latitude = json["Gps"]["Latitude"].IsInt ? (Int32)json["Gps"]["Latitude"] : (Double)json["Gps"]["Latitude"];
|
||||
this.Longitude = json["Gps"]["Longitude"].IsInt ? (Int32)json["Gps"]["Longitude"] : (Double)json["Gps"]["Longitude"];
|
||||
this.Fix = (Boolean)json["Gps"]["Fix"];
|
||||
this.Height = json["Gps"]["Height"].IsInt ? (Int32)json["Gps"]["Height"] : (Double)json["Gps"]["Height"];
|
||||
this.Hdop = json["Gps"].ContainsKey("Hdop") && (json["Gps"]["Hdop"].IsDouble || json["Gps"]["Hdop"].IsInt) && Double.TryParse(json["Gps"]["Hdop"].ToString(), out Double hdop) ? hdop : 0;
|
||||
|
||||
if(!this.Fix) {
|
||||
this.Latitude = this._lastLat;
|
||||
this.Longitude = this._lastLon;
|
||||
} else {
|
||||
this._lastLat = this.Latitude;
|
||||
this._lastLon = this.Longitude;
|
||||
this.Lastgpspostime = DateTime.UtcNow;
|
||||
}
|
||||
this.UTM = new UTMData(this.Latitude, this.Longitude);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
73
Lora-Map/Model/Position/PositionModel.cs
Normal file
@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using BlubbFish.Utils;
|
||||
|
||||
using LitJson;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Position {
|
||||
public class PositionModel : OwnSingeton<PositionModel> {
|
||||
private readonly Object lockData = new Object();
|
||||
private readonly Object lockPanic = new Object();
|
||||
private JsonData marker;
|
||||
|
||||
public SortedDictionary<String, PositionItem> Positions {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public SortedDictionary<String, PositionAlarm> Alarms {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
protected PositionModel() {
|
||||
this.Positions = new SortedDictionary<String, PositionItem>();
|
||||
this.Alarms = new SortedDictionary<String, PositionAlarm>();
|
||||
this.CheckJsonFile();
|
||||
this.marker = JsonMapper.ToObject(File.ReadAllText("json/names.json"));
|
||||
|
||||
}
|
||||
|
||||
public void ParseMqttJson(JsonData mqtt, String from) {
|
||||
if((from.Contains("lora/data") || from.Contains("lora/panic")) && PositionItem.CheckJson(mqtt)) {
|
||||
String name = PositionItem.GetId(mqtt);
|
||||
lock(this.lockData) {
|
||||
if(this.Positions.ContainsKey(name)) {
|
||||
this.Positions[name].Update(mqtt);
|
||||
} else {
|
||||
this.Positions.Add(name, new PositionItem(mqtt, this.marker));
|
||||
}
|
||||
}
|
||||
if(from.Contains("lora/panic")) {
|
||||
lock(this.lockPanic) {
|
||||
if(this.Alarms.ContainsKey(name)) {
|
||||
this.Alarms[name].Update(mqtt);
|
||||
} else {
|
||||
this.Alarms.Add(name, new PositionAlarm(mqtt));
|
||||
}
|
||||
}
|
||||
Console.WriteLine("PANIC erhalten!");
|
||||
}
|
||||
Console.WriteLine("Koordinate erhalten!");
|
||||
}
|
||||
}
|
||||
|
||||
public void ReloadNames(Object sender, EventArgs e) {
|
||||
this.CheckJsonFile();
|
||||
this.marker = JsonMapper.ToObject(File.ReadAllText("json/names.json"));
|
||||
foreach(KeyValuePair<String, PositionItem> item in this.Positions) {
|
||||
item.Value.UpdateMarker(this.marker, item.Key);
|
||||
}
|
||||
Console.WriteLine("Namen und Icons aktualisiert!");
|
||||
}
|
||||
|
||||
private void CheckJsonFile() {
|
||||
if(!Directory.Exists("json")) {
|
||||
_ = Directory.CreateDirectory("json");
|
||||
}
|
||||
if(!File.Exists("json/names.json")) {
|
||||
File.WriteAllText("json/names.json", "{}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using LitJson;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Model {
|
||||
class PositionItem {
|
||||
public Double Rssi { get; private set; }
|
||||
public Double Snr { get; private set; }
|
||||
public DateTime Lorarecievedtime { get; private set; }
|
||||
public DateTime Recievedtime { get; private set; }
|
||||
public Double Latitude { get; private set; }
|
||||
public Double Longitude { get; private set; }
|
||||
public UTMData UTM { get; private set; }
|
||||
public Double Hdop { get; private set; }
|
||||
public DateTime Lastgpspostime { get; private set; }
|
||||
public Double Battery { get; private set; }
|
||||
public Int32 Batterysimple { get; private set; }
|
||||
public Boolean Fix { get; private set; }
|
||||
public Double Height { get; private set; }
|
||||
public String Name { get; private set; }
|
||||
public String Icon { get; private set; }
|
||||
|
||||
|
||||
|
||||
public PositionItem(JsonData json, JsonData marker) {
|
||||
this.Update(json);
|
||||
this.UpdateMarker(marker, GetId(json));
|
||||
}
|
||||
|
||||
public void UpdateMarker(JsonData marker, String id) {
|
||||
if(marker.ContainsKey(id)) {
|
||||
if(marker[id].ContainsKey("name") && marker[id]["name"].IsString) {
|
||||
this.Name = (String)marker[id]["name"];
|
||||
} else {
|
||||
this.Name = id;
|
||||
}
|
||||
if(marker[id].ContainsKey("marker.svg") && marker[id]["marker.svg"].IsObject) {
|
||||
this.Icon = Marker.ParseMarkerConfig(marker[id]["marker.svg"], this.Name);
|
||||
} else if(marker[id].ContainsKey("icon") && marker[id]["icon"].IsString) {
|
||||
this.Icon = (String)marker[id]["icon"];
|
||||
} else {
|
||||
this.Icon = null;
|
||||
}
|
||||
} else {
|
||||
this.Name = id;
|
||||
this.Icon = null;
|
||||
}
|
||||
}
|
||||
public static Boolean CheckJson(JsonData json) => json.ContainsKey("Rssi") && json["Rssi"].IsDouble
|
||||
&& json.ContainsKey("Snr") && json["Snr"].IsDouble
|
||||
&& json.ContainsKey("Receivedtime") && json["Receivedtime"].IsString
|
||||
&& json.ContainsKey("BatteryLevel") && json["BatteryLevel"].IsDouble
|
||||
&& json.ContainsKey("Gps") && json["Gps"].IsObject
|
||||
&& json["Gps"].ContainsKey("Latitude") && json["Gps"]["Latitude"].IsDouble
|
||||
&& json["Gps"].ContainsKey("Longitude") && json["Gps"]["Longitude"].IsDouble
|
||||
&& json["Gps"].ContainsKey("LastLatitude") && json["Gps"]["LastLatitude"].IsDouble
|
||||
&& json["Gps"].ContainsKey("LastLongitude") && json["Gps"]["LastLongitude"].IsDouble
|
||||
&& json["Gps"].ContainsKey("LastGPSPos") && json["Gps"]["LastGPSPos"].IsString
|
||||
&& json["Gps"].ContainsKey("Hdop") && json["Gps"]["Hdop"].IsDouble
|
||||
&& json["Gps"].ContainsKey("Fix") && json["Gps"]["Fix"].IsBoolean
|
||||
&& json["Gps"].ContainsKey("Height") && json["Gps"]["Height"].IsDouble
|
||||
&& json.ContainsKey("Name") && json["Name"].IsString;
|
||||
|
||||
public static String GetId(JsonData json) => (String)json["Name"];
|
||||
|
||||
public void Update(JsonData json) {
|
||||
this.Rssi = (Double)json["Rssi"];
|
||||
this.Snr = (Double)json["Snr"];
|
||||
if(DateTime.TryParse((String)json["Receivedtime"], DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal, out DateTime updatetime)) {
|
||||
this.Lorarecievedtime = updatetime.ToUniversalTime();
|
||||
}
|
||||
this.Recievedtime = DateTime.UtcNow;
|
||||
this.Battery = Math.Round((Double)json["BatteryLevel"], 2);
|
||||
if(this.Battery < 3.44) {
|
||||
this.Batterysimple = 0;
|
||||
} else if(this.Battery < 3.53) {
|
||||
this.Batterysimple = 1;
|
||||
} else if(this.Battery < 3.6525) {
|
||||
this.Batterysimple = 2;
|
||||
} else if(this.Battery < 3.8825) {
|
||||
this.Batterysimple = 3;
|
||||
} else {
|
||||
this.Batterysimple = 4;
|
||||
}
|
||||
this.Latitude = (Double)json["Gps"]["Latitude"];
|
||||
this.Longitude = (Double)json["Gps"]["Longitude"];
|
||||
this.Fix = (Boolean)json["Gps"]["Fix"];
|
||||
if(!this.Fix) {
|
||||
this.Latitude = (Double)json["Gps"]["LastLatitude"];
|
||||
this.Longitude = (Double)json["Gps"]["LastLongitude"];
|
||||
}
|
||||
this.UTM = new UTMData(this.Latitude, this.Longitude);
|
||||
if(DateTime.TryParse((String)json["Gps"]["LastGPSPos"], DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal, out DateTime lastgpstime)) {
|
||||
this.Lastgpspostime = lastgpstime.ToUniversalTime();
|
||||
}
|
||||
this.Hdop = (Double)json["Gps"]["Hdop"];
|
||||
this.Height = (Double)json["Gps"]["Height"];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
41
Lora-Map/Model/Sensor/SensorEnviromentData.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
using LitJson;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Sensor {
|
||||
public class SensorEnviromentData {
|
||||
public String Name { get; private set; }
|
||||
public Double Rssi { get; private set; }
|
||||
public Double Snr { get; private set; }
|
||||
public Double Temperature { get; private set; }
|
||||
public Double Humidity { get; private set; }
|
||||
public Double Windspeed { get; private set; }
|
||||
public DateTime Lorarecievedtime { get; private set; }
|
||||
|
||||
public SensorEnviromentData(JsonData json) => this.Update(json);
|
||||
|
||||
public void Update(JsonData json) {
|
||||
this.Name = GetId(json);
|
||||
this.Rssi = json["Rssi"].IsInt ? (Int32)json["Rssi"] : (Double)json["Rssi"];
|
||||
this.Snr = json["Snr"].IsInt ? (Int32)json["Snr"] : (Double)json["Snr"];
|
||||
this.Temperature = json["Temperature"].IsInt ? (Int32)json["Temperature"] : (Double)json["Temperature"];
|
||||
this.Humidity = json["Humidity"].IsInt ? (Int32)json["Humidity"] : (Double)json["Humidity"];
|
||||
this.Windspeed = json["Windspeed"].IsInt ? (Int32)json["Windspeed"] : (Double)json["Windspeed"];
|
||||
if(DateTime.TryParse((String)json["Receivedtime"], DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal, out DateTime updatetime)) {
|
||||
this.Lorarecievedtime = updatetime.ToUniversalTime();
|
||||
}
|
||||
}
|
||||
|
||||
public static Boolean CheckJson(JsonData json) =>
|
||||
json.ContainsKey("Name") && json["Name"].IsString &&
|
||||
json.ContainsKey("Rssi") && (json["Rssi"].IsDouble || json["Rssi"].IsInt) &&
|
||||
json.ContainsKey("Snr") && (json["Snr"].IsDouble || json["Snr"].IsInt) &&
|
||||
json.ContainsKey("Temperature") && (json["Temperature"].IsDouble || json["Temperature"].IsInt) &&
|
||||
json.ContainsKey("Humidity") && (json["Humidity"].IsDouble || json["Humidity"].IsInt) &&
|
||||
json.ContainsKey("Windspeed") && (json["Windspeed"].IsDouble || json["Windspeed"].IsInt) &&
|
||||
json.ContainsKey("Receivedtime") && json["Receivedtime"].IsString;
|
||||
|
||||
public static String GetId(JsonData json) => (String)json["Name"];
|
||||
}
|
||||
}
|
41
Lora-Map/Model/Sensor/SensorModel.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using BlubbFish.Utils;
|
||||
|
||||
using LitJson;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Sensor {
|
||||
public class SensorModel : OwnSingeton<SensorModel> {
|
||||
private readonly Object lockSensor = new Object();
|
||||
|
||||
public SortedDictionary<String, SensorEnviromentData> Enviroments {
|
||||
get; private set;
|
||||
}
|
||||
public SensorWeather Weather {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
protected SensorModel() {
|
||||
this.Enviroments = new SortedDictionary<String, SensorEnviromentData>();
|
||||
this.Weather = new SensorWeather();
|
||||
}
|
||||
|
||||
public void ParseMqttJson(JsonData mqtt, String from) {
|
||||
if(from.Contains("lora/sensor") && SensorEnviromentData.CheckJson(mqtt)) {
|
||||
String sensorid = SensorEnviromentData.GetId(mqtt);
|
||||
lock(this.lockSensor) {
|
||||
if(this.Enviroments.ContainsKey(sensorid)) {
|
||||
this.Enviroments[sensorid].Update(mqtt);
|
||||
} else {
|
||||
this.Enviroments.Add(sensorid, new SensorEnviromentData(mqtt));
|
||||
}
|
||||
}
|
||||
Console.WriteLine("Umweltdaten erhalten!");
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() => this.Weather.Dispose();
|
||||
}
|
||||
}
|
177
Lora-Map/Model/Sensor/SensorWeather.cs
Normal file
@ -0,0 +1,177 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
using Fraunhofer.Fit.IoT.LoraMap.Lib;
|
||||
|
||||
using LitJson;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Sensor {
|
||||
public class SensorWeather {
|
||||
private Thread bgthread;
|
||||
private Boolean backgroundrunnerAlive;
|
||||
private readonly WebRequests webrequests = new WebRequests();
|
||||
|
||||
public List<Warning> Warnungen { get; private set; }
|
||||
|
||||
public SensorWeather() => this.StartBackgroundThread();
|
||||
|
||||
private void StartBackgroundThread() {
|
||||
this.Warnungen = new List<Warning>();
|
||||
this.bgthread = new Thread(this.BackGroundRunner);
|
||||
this.backgroundrunnerAlive = true;
|
||||
this.bgthread.Start();
|
||||
}
|
||||
|
||||
private void BackGroundRunner() {
|
||||
while(this.backgroundrunnerAlive) {
|
||||
List<Warning> ret = new List<Warning>();
|
||||
foreach(Int32 item in Settings.Instance.Internal.WeatherCellIDs) {
|
||||
try {
|
||||
JsonData json = this.webrequests.GetJson("https://maps.dwd.de/geoserver/wfs?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&typeName=dwd:Warnungen_Gemeinden&outputFormat=application/json&cql_filter=WARNCELLID=" + item);
|
||||
if (json.ContainsKey("features") && json["features"].IsArray && json["features"].Count > 0) {
|
||||
foreach (JsonData warning in json["features"]) {
|
||||
try {
|
||||
ret.Add(new Warning(warning));
|
||||
} catch { }
|
||||
}
|
||||
}
|
||||
} catch { }
|
||||
}
|
||||
this.Warnungen = ret;
|
||||
for (Int32 i = 0; i < 1000; i++) {
|
||||
if (this.backgroundrunnerAlive) {
|
||||
Thread.Sleep(60);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
try {
|
||||
this.backgroundrunnerAlive = false;
|
||||
while (this.bgthread != null && this.bgthread.IsAlive) {
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
this.bgthread = null;
|
||||
} catch { }
|
||||
}
|
||||
|
||||
public class Warning {
|
||||
public Warning(JsonData warning) {
|
||||
this.Id = warning["id"].ToString();
|
||||
this.From = warning["properties"]["SENT"].ToString();
|
||||
this.To = warning["properties"]["EXPIRES"].ToString();
|
||||
this.Location = warning["properties"]["NAME"].ToString();
|
||||
this.Type = warning["properties"]["EVENT"].ToString().ToLower();
|
||||
this.Level = warning["properties"]["SEVERITY"].ToString().ToLower();
|
||||
this.Headline = warning["properties"]["HEADLINE"].ToString();
|
||||
this.Body = warning["properties"]["DESCRIPTION"].ToString();
|
||||
this.Instructions = warning["properties"]["INSTRUCTION"] != null ? warning["properties"]["INSTRUCTION"].ToString() : "";
|
||||
}
|
||||
|
||||
public String Id { get; }
|
||||
public String From { get; }
|
||||
public String To { get; }
|
||||
public String Location { get; }
|
||||
public String Type { get; }
|
||||
public String Level { get; }
|
||||
public String Headline { get; }
|
||||
public String Body { get; }
|
||||
public String Instructions { get; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* https://maps.dwd.de/geoserver/wfs?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&typeName=dwd:Warnungen_Gemeinden&outputFormat=application/json&cql_filter=WARNCELLID=805314000
|
||||
* {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "Warnungen_Gemeinden.805314000.2.49.0.1.276.0.DWD.PVW.1565627520000.4edfa973-5fef-4b97-8990-7489828dbe5b.DEU",
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[
|
||||
[ 7.2072, 50.7395 ],
|
||||
[ 7.1534, 50.7599 ],
|
||||
[ 7.1255, 50.7744 ],
|
||||
[ 7.105, 50.7622 ],
|
||||
[ 7.0768, 50.7679 ],
|
||||
[ 7.0666, 50.7705 ],
|
||||
[ 7.0378, 50.7558 ],
|
||||
[ 7.0256, 50.7054 ],
|
||||
[ 7.0385, 50.6886 ],
|
||||
[ 7.0255, 50.665 ],
|
||||
[ 7.0473, 50.6391 ],
|
||||
[ 7.0639, 50.6309 ],
|
||||
[ 7.1054, 50.6595 ],
|
||||
[ 7.1278, 50.6472 ],
|
||||
[ 7.1564, 50.6547 ],
|
||||
[ 7.1954, 50.6434 ],
|
||||
[ 7.2119, 50.649 ],
|
||||
[ 7.1972, 50.6648 ],
|
||||
[ 7.1679, 50.7035 ],
|
||||
[ 7.1969, 50.7138 ],
|
||||
[ 7.2072, 50.7395 ]
|
||||
]
|
||||
]
|
||||
]
|
||||
},
|
||||
"geometry_name": "THE_GEOM",
|
||||
"properties": {
|
||||
"AREADESC": "Bonn",
|
||||
"NAME": "Stadt Bonn",
|
||||
"WARNCELLID": 805314000,
|
||||
"IDENTIFIER": "2.49.0.1.276.0.DWD.PVW.1565627520000.4edfa973-5fef-4b97-8990-7489828dbe5b.DEU",
|
||||
"SENDER": "CAP@dwd.de",
|
||||
"SENT": "2019-08-12T16:32:00Z",
|
||||
"STATUS": "Actual",
|
||||
"MSGTYPE": "Update",
|
||||
"SOURCE": "PVW",
|
||||
"SCOPE": "Public",
|
||||
"CODE": "id:2.49.0.1.276.0.DWD.PVW.1565627520000.4edfa973-5fef-4b97-8990-7489828dbe5b",
|
||||
"LANGUAGE": "de-DE",
|
||||
"CATEGORY": "Met",
|
||||
"EVENT": "GEWITTER",
|
||||
"RESPONSETYPE": "Prepare",
|
||||
"URGENCY": "Immediate",
|
||||
"SEVERITY": "Minor",
|
||||
"CERTAINTY": "Likely",
|
||||
"EC_PROFILE": "2.1",
|
||||
"EC_LICENSE": "Geobasisdaten: Copyright Bundesamt für Kartographie und Geodäsie, Frankfurt am Main, 2017",
|
||||
"EC_II": "31",
|
||||
"EC_GROUP": "THUNDERSTORM;WIND",
|
||||
"EC_AREA_COLOR": "255 255 0",
|
||||
"EFFECTIVE": "2019-08-12T16:32:00Z",
|
||||
"ONSET": "2019-08-12T16:32:00Z",
|
||||
"EXPIRES": "2019-08-12T17:00:00Z",
|
||||
"SENDERNAME": "DWD / Nationales Warnzentrum Offenbach",
|
||||
"HEADLINE": "Amtliche WARNUNG vor GEWITTER",
|
||||
"DESCRIPTION": "Von Südwesten ziehen einzelne Gewitter auf. Dabei gibt es Windböen mit Geschwindigkeiten um 60 km/h (17m/s, 33kn, Bft 7).",
|
||||
"INSTRUCTION": "ACHTUNG! Hinweis auf mögliche Gefahren: Örtlich kann es Blitzschlag geben. Bei Blitzschlag besteht Lebensgefahr!",
|
||||
"WEB": "http://www.wettergefahren.de",
|
||||
"CONTACT": "Deutscher Wetterdienst",
|
||||
"PARAMETERNAME": "Böen;Gewitter;Gewitteraufzugsrichtung",
|
||||
"PARAMETERVALUE": "~60 [km/h];einzelne;SW",
|
||||
"ALTITUDE": 0,
|
||||
"CEILING": 9842.5197,
|
||||
"bbox": [ 7.0255, 50.6309, 7.2119, 50.7744 ]
|
||||
}
|
||||
}
|
||||
],
|
||||
"totalFeatures": 1,
|
||||
"numberMatched": 1,
|
||||
"numberReturned": 1,
|
||||
"timeStamp": "2019-08-12T16:42:20.743Z",
|
||||
"crs": {
|
||||
"type": "name",
|
||||
"properties": { "name": "urn:ogc:def:crs:EPSG::4326" }
|
||||
},
|
||||
"bbox": [ 50.6309, 7.0255, 50.7744, 7.2119 ]
|
||||
}
|
||||
*/
|
328
Lora-Map/Model/Settings.cs
Normal file
@ -0,0 +1,328 @@
|
||||
using BlubbFish.Utils;
|
||||
|
||||
using CoordinateSharp;
|
||||
using LitJson;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Model {
|
||||
public class Settings : OwnSingeton<Settings> {
|
||||
|
||||
private Int32 gridradius;
|
||||
|
||||
public PublicSettings External {
|
||||
get; set;
|
||||
}
|
||||
|
||||
public PrivateSettings Internal {
|
||||
get; set;
|
||||
}
|
||||
|
||||
protected Settings() {
|
||||
this.External = new PublicSettings();
|
||||
this.Internal = new PrivateSettings();
|
||||
this.ParseSettingsJson();
|
||||
this.ParseGeoJson();
|
||||
}
|
||||
|
||||
public void ReloadSettings(Object sender, EventArgs e) => this.ParseSettingsJson();
|
||||
public void ReloadGeo(Object sender, EventArgs e) => this.ParseGeoJson();
|
||||
|
||||
private void ParseSettingsJson() {
|
||||
this.CheckJsonFiles();
|
||||
JsonData json = JsonMapper.ToObject(File.ReadAllText("json/settings.json"));
|
||||
if(json.ContainsKey("StartPos") && json["StartPos"].IsObject && json["StartPos"].ContainsKey("lat") && (json["StartPos"]["lat"].IsDouble || json["StartPos"]["lat"].IsInt) && json["StartPos"].ContainsKey("lon") && (json["StartPos"]["lon"].IsDouble || json["StartPos"]["lon"].IsInt)) {
|
||||
this.External.Startloclat = Double.Parse(json["StartPos"]["lat"].ToString());
|
||||
this.External.Startloclon = Double.Parse(json["StartPos"]["lon"].ToString());
|
||||
} else {
|
||||
this.External.Startloclat = 0;
|
||||
this.External.Startloclon = 0;
|
||||
}
|
||||
this.Internal.WeatherCellIDs.Clear();
|
||||
if(json.ContainsKey("CellIds") && json["CellIds"].IsArray && json["CellIds"].Count > 0) {
|
||||
foreach(JsonData item in json["CellIds"]) {
|
||||
if(Int32.TryParse(item.ToString(), out Int32 cellid)) {
|
||||
this.Internal.WeatherCellIDs.Add(cellid);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(json.ContainsKey("FightDedection") && json["FightDedection"].IsObject) {
|
||||
Dictionary<String, Fight> fights = new Dictionary<String, Fight>();
|
||||
foreach(KeyValuePair<String, JsonData> entry in json["FightDedection"]) {
|
||||
Fight fight = new Fight {
|
||||
Polygon = new List<List<Double>>()
|
||||
};
|
||||
if(entry.Value.ContainsKey("Poly") && entry.Value["Poly"].IsArray) {
|
||||
foreach(JsonData coord in entry.Value["Poly"]) {
|
||||
List<Double> coords = new List<Double>();
|
||||
if(coord.ContainsKey("Lat") && coord["Lat"].IsDouble && coord.ContainsKey("Lon") && coord["Lon"].IsDouble) {
|
||||
coords.Add((Double)coord["Lat"]);
|
||||
coords.Add((Double)coord["Lon"]);
|
||||
}
|
||||
fight.Polygon.Add(coords);
|
||||
}
|
||||
}
|
||||
if(entry.Value.ContainsKey("Level") && entry.Value["Level"].IsDouble) {
|
||||
fight.Level = (Double)entry.Value["Level"];
|
||||
}
|
||||
if(entry.Value.ContainsKey("Alias") && entry.Value["Alias"].IsString) {
|
||||
fight.Alias = (String)entry.Value["Alias"];
|
||||
}
|
||||
fights.Add(entry.Key, fight);
|
||||
}
|
||||
this.External.FightDedection = fights;
|
||||
}
|
||||
if(json.ContainsKey("CrwodDensity") && json["CrwodDensity"].IsObject) {
|
||||
Dictionary<String, Density> densitys = new Dictionary<String, Density>();
|
||||
foreach(KeyValuePair<String, JsonData> entry in json["CrwodDensity"]) {
|
||||
Density density = new Density {
|
||||
Polygon = new List<List<Double>>()
|
||||
};
|
||||
if(entry.Value.ContainsKey("Poly") && entry.Value["Poly"].IsArray) {
|
||||
foreach(JsonData coord in entry.Value["Poly"]) {
|
||||
List<Double> coords = new List<Double>();
|
||||
if(coord.ContainsKey("Lat") && coord["Lat"].IsDouble && coord.ContainsKey("Lon") && coord["Lon"].IsDouble) {
|
||||
coords.Add((Double)coord["Lat"]);
|
||||
coords.Add((Double)coord["Lon"]);
|
||||
}
|
||||
density.Polygon.Add(coords);
|
||||
}
|
||||
}
|
||||
if(entry.Value.ContainsKey("Count") && (entry.Value["Count"].IsInt || entry.Value["Count"].IsDouble)) {
|
||||
density.Maximum = (Int32)entry.Value["Count"];
|
||||
}
|
||||
if(entry.Value.ContainsKey("Alias") && entry.Value["Alias"].IsString) {
|
||||
density.Alias = (String)entry.Value["Alias"];
|
||||
}
|
||||
densitys.Add(entry.Key, density);
|
||||
}
|
||||
this.External.DensityArea = densitys;
|
||||
}
|
||||
if(json.ContainsKey("Sensors") && json["Sensors"].IsObject) {
|
||||
Dictionary<String, Sensor> sensors = new Dictionary<String, Sensor>();
|
||||
foreach(KeyValuePair<String, JsonData> entry in json["Sensors"]) {
|
||||
Sensor sensor = new Sensor {
|
||||
Coordinates = new List<Double>()
|
||||
};
|
||||
if(entry.Value.ContainsKey("Poly") && entry.Value["Poly"].IsObject) {
|
||||
JsonData coord = entry.Value["Poly"];
|
||||
List<Double> coords = new List<Double>();
|
||||
if(coord.ContainsKey("Lat") && coord["Lat"].IsDouble && coord.ContainsKey("Lon") && coord["Lon"].IsDouble) {
|
||||
coords.Add((Double)coord["Lat"]);
|
||||
coords.Add((Double)coord["Lon"]);
|
||||
}
|
||||
sensor.Coordinates = coords;
|
||||
if(entry.Value.ContainsKey("Level") && (entry.Value["Level"].IsInt || entry.Value["Level"].IsDouble)) {
|
||||
sensor.Level = entry.Value["Level"].IsInt ? (Int32)entry.Value["Level"] : (Double)entry.Value["Level"];
|
||||
}
|
||||
if(entry.Value.ContainsKey("Alias") && entry.Value["Alias"].IsString) {
|
||||
sensor.Alias = (String)entry.Value["Alias"];
|
||||
}
|
||||
sensors.Add(entry.Key, sensor);
|
||||
}
|
||||
}
|
||||
this.External.Sensors = sensors;
|
||||
}
|
||||
this.gridradius = json.ContainsKey("GridRadius") && json["GridRadius"].IsInt && this.External.Startloclat != 0 && this.External.Startloclon != 0 ? (Int32)json["GridRadius"] : 0;
|
||||
this.GenerateGrid();
|
||||
this.FindMapLayer();
|
||||
}
|
||||
|
||||
private void ParseGeoJson() {
|
||||
this.CheckJsonFiles();
|
||||
this.External.GeoLayer = JsonMapper.ToObject(File.ReadAllText("json/geo.json"));
|
||||
}
|
||||
|
||||
private void GenerateGrid() {
|
||||
this.External.Grid = new Dictionary<String, List<Dictionary<String, List<Double>>>> {
|
||||
{ "Major", new List<Dictionary<String, List<Double>>>() },
|
||||
{ "Minor", new List<Dictionary<String, List<Double>>>() }
|
||||
};
|
||||
if(this.External.Startloclat == 0 || this.External.Startloclon == 0 || this.gridradius == 0) {
|
||||
return;
|
||||
}
|
||||
MilitaryGridReferenceSystem start = new Coordinate(this.External.Startloclat, this.External.Startloclon).MGRS;
|
||||
|
||||
Double left = start.Easting - this.gridradius - (start.Easting - this.gridradius) % 100;
|
||||
Double bottom = start.Northing - this.gridradius - (start.Northing - this.gridradius) % 100;
|
||||
Double right = start.Easting + this.gridradius + (100 - (start.Easting + this.gridradius) % 100);
|
||||
Double top = start.Northing + this.gridradius + (100 - (start.Northing + this.gridradius) % 100);
|
||||
for(Double i = left; i <= right; i += 50) {
|
||||
Coordinate TopLeft = MilitaryGridReferenceSystem.MGRStoLatLong(new MilitaryGridReferenceSystem(start.LatZone, start.LongZone, start.Digraph, i, top));
|
||||
Coordinate BottomLeft = MilitaryGridReferenceSystem.MGRStoLatLong(new MilitaryGridReferenceSystem(start.LatZone, start.LongZone, start.Digraph, i, bottom));
|
||||
if(i % 100 == 0) {
|
||||
this.External.Grid["Major"].Add(new Dictionary<String, List<Double>> {
|
||||
{ "from", new List<Double> {
|
||||
TopLeft.Latitude.DecimalDegree,
|
||||
TopLeft.Longitude.DecimalDegree
|
||||
}
|
||||
},
|
||||
{ "to", new List<Double> {
|
||||
BottomLeft.Latitude.DecimalDegree,
|
||||
BottomLeft.Longitude.DecimalDegree
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.External.Grid["Minor"].Add(new Dictionary<String, List<Double>> {
|
||||
{ "from", new List<Double> {
|
||||
TopLeft.Latitude.DecimalDegree,
|
||||
TopLeft.Longitude.DecimalDegree
|
||||
}
|
||||
},
|
||||
{ "to", new List<Double> {
|
||||
BottomLeft.Latitude.DecimalDegree,
|
||||
BottomLeft.Longitude.DecimalDegree
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
for(Double i = bottom; i <= top; i += 50) {
|
||||
Coordinate BottomLeft = MilitaryGridReferenceSystem.MGRStoLatLong(new MilitaryGridReferenceSystem(start.LatZone, start.LongZone, start.Digraph, left, i));
|
||||
Coordinate BottomRight = MilitaryGridReferenceSystem.MGRStoLatLong(new MilitaryGridReferenceSystem(start.LatZone, start.LongZone, start.Digraph, right, i));
|
||||
if(i % 100 == 0) {
|
||||
this.External.Grid["Major"].Add(new Dictionary<String, List<Double>> {
|
||||
{ "from", new List<Double> {
|
||||
BottomLeft.Latitude.DecimalDegree,
|
||||
BottomLeft.Longitude.DecimalDegree
|
||||
}
|
||||
},
|
||||
{ "to", new List<Double> {
|
||||
BottomRight.Latitude.DecimalDegree,
|
||||
BottomRight.Longitude.DecimalDegree
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.External.Grid["Minor"].Add(new Dictionary<String, List<Double>> {
|
||||
{ "from", new List<Double> {
|
||||
BottomLeft.Latitude.DecimalDegree,
|
||||
BottomLeft.Longitude.DecimalDegree
|
||||
}
|
||||
},
|
||||
{ "to", new List<Double> {
|
||||
BottomRight.Latitude.DecimalDegree,
|
||||
BottomRight.Longitude.DecimalDegree
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void FindMapLayer() {
|
||||
this.External.Layers = new Dictionary<String, Dictionary<String, Object>> {
|
||||
{ "online", new Dictionary<String, Object>() {
|
||||
{ "title", "Online Map" },
|
||||
{ "url", "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" },
|
||||
{ "attribution", "© <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors" },
|
||||
{ "minZoom", 1 },
|
||||
{ "maxZoom", 19 }
|
||||
} }
|
||||
};
|
||||
if(Directory.Exists("resources" + Path.DirectorySeparatorChar + "maps")) {
|
||||
String[] dirs = Directory.GetDirectories("resources" + Path.DirectorySeparatorChar + "maps");
|
||||
foreach(String dir in dirs) {
|
||||
if(File.Exists(dir + Path.DirectorySeparatorChar + "tiles.json")) {
|
||||
try {
|
||||
JsonData map = JsonMapper.ToObject(File.ReadAllText(dir + Path.DirectorySeparatorChar + "tiles.json"));
|
||||
Dictionary<String, Object> entry = new Dictionary<String, Object> {
|
||||
{ "title", (String)map["name"] },
|
||||
{ "url", (String)map["tiles"][0] },
|
||||
{ "attribution", (String)map["attribution"] },
|
||||
{ "minZoom", (Int32)map["minzoom"] },
|
||||
{ "maxZoom", (Int32)map["maxzoom"] },
|
||||
{ "bounds", new Dictionary<String, Object>() {
|
||||
{ "corner1", new Double[] { (Double)map["bounds"][0], (Double)map["bounds"][1] } },
|
||||
{ "corner2", new Double[] { (Double)map["bounds"][2], (Double)map["bounds"][3] } }
|
||||
} }
|
||||
};
|
||||
this.External.Layers.Add(dir[(("resources" + Path.DirectorySeparatorChar + "maps").Length + 1)..], entry);
|
||||
} catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckJsonFiles() {
|
||||
if(!Directory.Exists("json")) {
|
||||
_ = Directory.CreateDirectory("json");
|
||||
}
|
||||
if(!File.Exists("json/settings.json")) {
|
||||
File.WriteAllText("json/settings.json", "{}");
|
||||
}
|
||||
if(!File.Exists("json/geo.json")) {
|
||||
File.WriteAllText("json/geo.json", "{}");
|
||||
}
|
||||
}
|
||||
|
||||
public struct Density {
|
||||
public List<List<Double>> Polygon {
|
||||
get; set;
|
||||
}
|
||||
public Int32 Maximum {
|
||||
get; set;
|
||||
}
|
||||
public String Alias {
|
||||
get; set;
|
||||
}
|
||||
}
|
||||
|
||||
public struct Fight {
|
||||
public List<List<Double>> Polygon {
|
||||
get; set;
|
||||
}
|
||||
public Double Level {
|
||||
get; set;
|
||||
}
|
||||
public String Alias {
|
||||
get; set;
|
||||
}
|
||||
}
|
||||
|
||||
public struct Sensor {
|
||||
public List<Double> Coordinates {
|
||||
get; set;
|
||||
}
|
||||
public Double Level {
|
||||
get; set;
|
||||
}
|
||||
public String Alias {
|
||||
get; set;
|
||||
}
|
||||
}
|
||||
|
||||
public class PublicSettings {
|
||||
public Double Startloclat {
|
||||
get; set;
|
||||
} = 0;
|
||||
public Double Startloclon {
|
||||
get; set;
|
||||
} = 0;
|
||||
public Dictionary<String, List<Dictionary<String, List<Double>>>> Grid {
|
||||
get; set;
|
||||
} = new Dictionary<String, List<Dictionary<String, List<Double>>>>();
|
||||
public Dictionary<String, Fight> FightDedection {
|
||||
get; set;
|
||||
} = new Dictionary<String, Fight>();
|
||||
public Dictionary<String, Density> DensityArea {
|
||||
get; set;
|
||||
} = new Dictionary<String, Density>();
|
||||
public Dictionary<String, Sensor> Sensors {
|
||||
get; set;
|
||||
} = new Dictionary<String, Sensor>();
|
||||
public Dictionary<String, Dictionary<String, Object>> Layers {
|
||||
get; set;
|
||||
} = new Dictionary<String, Dictionary<String, Object>>();
|
||||
public JsonData GeoLayer {
|
||||
get; set;
|
||||
}
|
||||
}
|
||||
|
||||
public class PrivateSettings {
|
||||
public List<Int32> WeatherCellIDs { get; set; } = new List<Int32>();
|
||||
}
|
||||
}
|
||||
}
|
116
Lora-Map/Model/Svg/SVGFile.cs
Normal file
@ -0,0 +1,116 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Web;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Svg {
|
||||
public abstract class SVGFile {
|
||||
protected String query;
|
||||
protected Double width;
|
||||
protected Double height;
|
||||
protected List<Double> viewbox;
|
||||
private readonly Boolean withSvgHeader;
|
||||
protected List<String> css = new List<String>();
|
||||
|
||||
public SVGFile(String query, Double width, Double heigt, List<Double> viewbox, Boolean withSvGHeader = true) {
|
||||
this.query = query;
|
||||
this.width = width;
|
||||
this.height = heigt;
|
||||
this.viewbox = viewbox;
|
||||
this.withSvgHeader = withSvGHeader;
|
||||
this.ParseParams();
|
||||
#region add css font
|
||||
if(withSvGHeader) {
|
||||
this.css.Add("@font-face {\nfont-family: DIN1451;\nsrc: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAC2UAA0AAAAAQoQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAAtfAAAABUAAAAc1BgWEkdERUYAAC1cAAAAHQAAAB4AJwCoT1MvMgAAAZgAAAAzAAAAVhQYMm1jbWFwAAADmAAAAXwAAAIKS0qCl2dhc3AAAC1UAAAACAAAAAj//wADZ2x5ZgAABlwAACTqAAA3PEjM+G9oZWFkAAABMAAAA" +
|
||||
"CkAAAA2ZvZKqGhoZWEAAAFcAAAAIAAAACQPWgX3aG10eAAAAcwAAAHMAAACiHnVMb1sb2NhAAAFFAAAAUYAAAFG8KHj6G1heHAAAAF8AAAAGgAAACAAqABqbmFtZQAAK0gAAADUAAAB48UOolxwb3N0AAAsHAAAATUAAAGUFigoJnicY2BkAAO7BpH/8fw2Xxm4ORjQwf8n/3TYv7DXA5kcDEwgEQDaEggdAAAAeJxjYGRgYK//p8PAwMHw/8l/DfYvDEARFLAIAI0JBmJ4nGNgZGBgWMQQycDKAAIgngADEgAAG1oBEwAAeJxjYGQOY5zAwMqAAzBxszGzMjM" +
|
||||
"xMbFglXZgUFBUYq//p8PAwF7PeAUowggSBgCK/ATIAHicNZFPSFRRFMZ/797znkMrcRFRIwSZRKER1NRYQjYVydCIklNJm5lSxIWEbaKIKIga6N9Ggqa91LY2QQVtWrVwZ0EbsVZBtLBIiMbv3pwHH9+553z33POdlwNj40u+g+vkrhvnnF8iJ3RZLzPpXsZUe+SK3BD2uEXK9pF6yPkhZmPtOV3Sj7iX3BOXhLywVTjtVxgVzwj7Qhz0AbZCLfSxt9T8KwazKUbsL86Wadqc3t0UuWllYTnO0dR8Tf8Za9cyndOr/+v2boPD/SfkZSzobkln2QJbbLj1w2h9l" +
|
||||
"aeSfMy79+wW91mVo9ImyS+6/Scqqjf8A4qBla9KM6T4kuZoRK+drdVQ0yyNbJH5kA+6qJfO53V/ic2xdzn0av1OP5CFnOJV9T7hzlNIKpwVtplnMLnMAb/AsP9HxX/jkF3kcKj7afZnY0xqv71+lgF5qbg3nIy52+xy19lpFxhwN+lxT+mJHp5R9l84khToTtaUe80xd58dvk5/+pBq2hTWtPNJjusfWFrTfurU24g7zFGMuytzR94O2k+y6PGK9hP86pxNMxcxwZnAfjsFm6DU8Yf+5DFTbbgXnHLzjAa07/g+Su244xrj6wZKjbN4nGNgYGBmgGAZBkYgycD" +
|
||||
"IAuQxgvksDC+AtBmDApAlxlDHsJxhP8NRhlMM1xnuMNxneMLwnuE7wx+Gf4xBjAmMk5iOMd1REFGQUpBTUFIwULBUVFKS/P8fqF+BYSHDSoYjDCcYrsH1fUPTJ6wgoSCjoIDQ9//x/4P/D/zf83/X//X/V/9f+X/p/9n/p/6f+H/Cf9v/Bv/+/z3zd/uDxgd1D2of1DzIf5B+v/5eHMT95ABGNga4ZkYmIMGErgAYRCysbOwcnFzcPLx8/AKCQsIiomLiEpJS0jKycvIKikrKKqpq6hqaWto6unr6BoZGxiamZuYWllbWNrZ29g6OTs4urm7uHp5e3j6+fv4Bg" +
|
||||
"UHBIaFh4RGRUdExsXHxCYkMDY0MzQyt7UDLOhH2doGIbhDRO6cgOSVjXllHXubCErBcIQNDWimYlVUFJOqTchgmMjBkV4OF+hmmTJ05a9r0HjBvARDPLZ8xez5DCwNDE7LHJk3OB5IVQAwA3UV6TwAAAB4AHgAeAB4ANABIAIAAygEWAWgBdgGSAa4B0AHoAfQCAgIOAh4CTAJeAoYCwgLeAxIDSANeA6ID2APqA/wEEAQkBDgEagTSBPgFMAVsBZoFsgXIBgoGIgYwBkwGbAZ8BpwGtgcCBy4HgAewB/AIBAgkCDoIXgh+CJYIrAi+CM4I4Aj2CQIJEglWCYo" +
|
||||
"JsgnoChYKMgqICqgKvArWCvQLCAs6C1oLngvUDAgMJAxcDHoMmgywDNIM8A0QDSYNdA2CDc4OCA4cDlIOqA7wDxwPMA+4ECYQbBCIEJgQphEOERwRVBF0EaIR7BH8EiISQBJcEooSnBLiEv4TLBNuE9YUEhQ+FHwUyhU4FaQV/BYeFkoWgBa+Ft4XLhdoF5QXtBf+GGwYthkyGWYZdBmCGZAZnhmqGb4Z0hnkGigaihqqGvobdBueAAB4nJV7CUBTV/b3O/e9JO4aQgjKGgIJ+xZCWMIiArILiKCiCIgIiCK4geCuILbWVkWs1Iq4b53qWKU6trbFtmpd4m47O" +
|
||||
"F2m/dd2utpNIDffve8lip2ZTwd4yUveXc76O+eee2EQw5nN3Gei1xmWGcwwINM6AKtkVaAF2H6du/76XNPt6vvIphPJ0EC0xLTK9Bsk4NOioz3jGMQ0mc2wnu8rYRgZqxwMOq38ZgaIM18xwkwuufck3nr1KkN+EDORGwvmR22lWv534raaNvJ9OW6lF99ugNnMXuPbuVB6VKwDqFiVTKXT8peW5S+5ir9QpN95v/rY87E7Yv520e/MxZj2mA/p/QW/v12MQfGgwXdNp+EtHAdvNYGmSbjDcU34bhOOo3SxjI3Zjm0Vp5HZ1Iwfw8SAMyik/qALCdUTZuwUErV" +
|
||||
"G6gxyW7FErtKJ1SAdRj7YyaTRpInaZkPIyqKzu9/eU/bmzoVFq84du3ygbMGnMMEwMebM1OT4N1oNmQPhQ7+r24/ek2/YwDa15Q7CaZrPXj30tX13N1ShPmgbWF6eNBX/gDPt6iYnVFGaREyF+QF7VnSGGcgoGA8mgNESSchttcFREKJykxDStMF2TmArVrmp4YlP+ketWKJBdDwtNTVtwcLU5EWLklMXYh/r3QL6/Uz01yZTBkRUlZRUlXz23KzCwlnPVRYUcHaW22nT7vOPek7y2qayyjY/EGkJXYMYLyaY0GSr4KWgchODZhio3BCVmr+FJLmtBKJBrxgGE" +
|
||||
"tlAEBOhaYNDYX/ljPTsqOgs1NKU/+GCy/jFRl388c2bjj8AvW+k/SllYdRveBBuv75z9phtXN2kIvVUfXh2dm/6pvh8GHJ8xReJkRtSVn/44eobNXhdWF1cctahWPx38IW98w7MbzUwwGzgkqCQtx9GptNLNxi5JGMr3kroB2aJ2R/ZkGdDiZBVakKtjV4rRnJbG2ST3bFzZ0f21LKya8fh1PVrcPr4u3javX/gQtrPx+wPZ4V+Mq2djdwWSVShNroQ5JO9s6NjZ3Z+ebno9eM44dp1nHj8XWj/xz3YSfulstmomfSTkg86iUav0SuITekVEoVEIwe/3dEHD0b" +
|
||||
"vrt9F33ax2R8UFJSVFxS8/35BQXlZQcEHDE9zMfHPOdxg3juJxyjlSqlKqtQh+3Y4gVPacQrKgZM4eQdOgRM7KP/mMihkrlD+FVKtfINxK8y8Sr6fA5fQbfSqIBelfA4qh0tGozDHBuLH1j462geo1wLxjQeojeibfk/syQbut2PFUNGFnlDBp8cRO32OPB/KOFDqeEuQS3lFe0gFI5DydolOVU+ZOnfu1CnVppa+jp0m086OPuhAs8oXLiw3tVQsWFCAVp3/5JPzpiXnP/5YoGmtuQ95E9mJia6kEp1eK4WJV69e47jbW++19qTxbcYQrFhJ5ldQusFqixJVN" +
|
||||
"FjsTykfgyKUtpVTJ9RJjPDjnhMP8rAP8oUudN47UZm2qrr46INfj2yuNB3n+XUk/Mwn43lSfREm+o9nQyGAAgFH+NFoncHyHCqSyuqW5sUtlBqHfPPKe9/GTZ6SaWZObf7OyehUPDmvcc0UtLFzweRJiydO3PZ/2LwjZ0dE5OGJH/389snU/PrK2fV03lGED2pfwxhGryOCVlJwlKsI4IyCr+9jGTQYFyww3j7H2fb+C3bjKefu3OH5Tyf0UvxVUkSllkFFrhDQivqju0ZrZ2VDUsYOMJ0pWTO+2dOg9wnw65i9HvcojB6HXw7JXlE3Br3C2hrxycxYn9Evv7F" +
|
||||
"pgyG8+LWPDl6bWddeR/ScZf6ebRW9xsj4mQiBWjKRgkqYKFej1oV4uEnEFHr0ZC6NuhnW3seXOP/Ra2dVNDbualu6FHZNMkRdS0qIj4pCr7IjTK2youIbfZWzFi68uqYqIqruR33oqsWGCMpTBZHFPsLTAIEnUBElVrBRWPYNfI+XcENhl7HXlfv0GsWjIML/AaKvwYQuP4pHj7gVsyH9gEgsseP15q7v1wIcV2RmrqDXt4dHZ/109OhP2TGH8MM3TuAe4/qCqRs2TC1YzznMrKiYWTprlklzc17E+sLXf/vt9cL1EfNvvPvgQVfJqlUlJatX8/LpIfI5LchnI" +
|
||||
"CFZZZGL3iInES8ZFS8lhR07Ddd+AyFccNTzZeVrGndvXb4MT82LijImxydEGdhBfT+icllR4a3eytm1tZfXzIkIW/KTPmxlQ3gEmYv3VdRuiaPEW1neY41GuGI04kDiuEjAAGsbigLWNhQL4Cpxe2CKGOBmc/7Uv2Q6kA8EeRE3pO8IOx4ub4JLh/EW3HKY+ngx8zU3h1Va5yMaIVcxN6T3F24IWtHejme2tzNPjqfXDQQyZBGb03eYGwKHYRZUHMbaTTxmRBH9phKdOfDxnWgoBiwKIeZuDRys2AkozTBF5nZCO9+QXmX8v1e2Phh92o3wOXONYVKgKWFMTvG" +
|
||||
"MxV67v7j11yWTzUxg1oLHuQbBJfEo3i5iLVZhw0+BQK9leUMlnxmVKyO3ZZTBoSQIcOSDdASj5F+J7lTUfYgCGaI/NGp6+prTBUkvvYl0I5t22wbkncFXH+BufBrGg+vJXyc2zcTbbuNTOA06IRHUsA//ZeULdpx3VfnyXTDs77vHoKKcWeBbm1CNvwBRmen7aJ9I8Nh0HsR4z1d/4NeKpu7phF2QAnHQhvfjB9iMu1YFZZ9cfhFKd1B+EMNwn4qOEQ3YMAzxPpIRKVmZ0p/VDGMRsj2BbL8medr8N2Cvv07jqVR5a7SiYz0ZkIxPoiFNLy9cXFa5onazkO+0k" +
|
||||
"XjSSvxrOGNPrVUhVQoeIudhgwxMvqAKeXTThnQ3P5m4rHbhT7tD8WHIqZ83bwM+C7GL5s8H0dFPDk/eG845nqs68ylqwslrcnMbUSkuWJyXs0TAcZLLcDVEF+7kA5UzAU9/kI4I1VNQ5RQqf6AQyydVCgqqbPN9H/zV6cP3te6Oju7a+4evwHC3+w6byjNqlD4uLj7KmoxO2PLR7T2FsVtBApKtsdP2m4/mLI31Dmv89LPGUN8YwQYon7v4mD2K59L1MS4C4UzPRwuNWtUGGHxeCrVXBo3+ogN/BwNPTHSXyX3zDxDmfp3a8eVve9JKn+M+7f1xmX7Zxa4thsW" +
|
||||
"EJzp2DBl7MD8ywV3hamN3m8JRgakDfUA6G3HROZzDxxVr+4H92z9qzbcdf8608ZG8FhN5eVHvUEptmadKLDQK0Hwkxtc+/v8JbekRlGnEt+/iG/9dcofXpTJWelsF/kRSmm+QvINc7CnTW93dKK4bUINpteio6UU0l2SGfHuoFXIugjbStm6wpIzkGUcwOkuIbTHAoy9pwQdR7lj80vEHuvG915eePbpi+oIW9naf7JNfyxkrDaIhpN8QYUwSFAfSPzK4COWBBPshDvfgGjND5jJJ0Q+md/peQB/iX3D8o/68zEVCf6Kdbl4tvS5XH41fK9BFng8ELWFTRaFb2" +
|
||||
"maEDnjZ2M3hK534ioj06UthT/SMY9ebxqAzffMej/+Z1QaIT5I5hM5oE3fPaJpN+1GM7BlHsVKwSatuFSSnZ2QWjVIlSkcIAZtqWmZVq8VErequ4BV76L5O5eio0t0/xCu7m9ftYy3zd+i2oNz902K34of44dbYwj2C0nktx/iGNn72aWOYdyzVvNVXXuLtU0HzON7viWvQOyGdQCqlFGohqb5uWlSh6QsknbB9QtyU+5/i17l/YO/NeaujvXpdRUfd47R/XfgK/sr0gZXfeyIx4deeX8GQ7De0P0NW+xVprKxL+4uE+KqCtTu16qDtn3gsgGOdow9VPjZ2XiY" +
|
||||
"K53cAbW5tSvz2EWuCUf+0KSyxv8kLUvmuI3zbI5x4n+d95J95tyAGKIHnPqOhISV6uulDFHF6dtSE1tWQTQzwOv6S+xdOXDe1Su/XKxMdLdS1F6+/62eqQ3OoQ/M5JZcs+DNdW/LpB2FVY81OFBJeHoIwFEKC6eq4MfvWgqZtbwXnhp95/+HnTd+X1Gd2Fpa+UFjllK376D38zTf45Om9cZlz8w+PFA8ZMOqzHad+zI07ERxdVhZdKRUNFo/8reX8PYv/mVm67pbwvqyjyAObcDXbi6uB+66rq1cm2PMKQud6Ya1CV+e2j1yVABCzovvQ0qWHuvG1O3fxdfgX2" +
|
||||
"9U3oXXHjlb2UJ/hn/hbkAvzEJwX5qEZIq0gfIld7kMaB2n3sQt1h0PcBB4v7M1m8SY+BtG2Mr41eaXuB2vwpm++5MBhBzhwX36DN3Xi+xz+xuJMFoca1fsVpdn8PZmz0IJTJO0iTsz/saX4HXz2IVnpF/SQId16cAG8DcjZ9Dn6Fr2PJfDQFGEiNJv/Sfq7CrmmSMp3Bim8jFO/hlDQ3ScrKpTHTiaqbOrbazpgWW/8nwXHdUCFya8wtpjWsM2mMrQVOjld197ec3S91ULWmiMEeVDMJxgqb4H69967Jl7Z1PN8Ey9zb/MPqF30N4qbVGZIhD3a4BOp6FKPln/" +
|
||||
"uR9ad+61jqEg0UOp+eBfq8ZpU0fymh0ubaJtYFMu5CeskmpkTIcTC66vgL/vwCXwCxbJz+15EXSYDPx6YbTgw1wnrPEI8x3w/cyb53ol7Ce4JdBCQlYEefwWDT5AvffBN6iMZ5h/YOs6RcWa8CaU6lZjk/Wohv9UrdaESktdKNKGKUIWdQsqSxwqS5Grt9KHoL5xTRHTJ4YmF48d3wEi4mhQYYN8+/7Mz86rRhQfHkL/vjOUhgaIpofajuIkTm1dOnIjmrONGyH2XtnEobdwZUzjMThPVhai9kFJJ6GgmsYT6qlzIXLRSK1hYFzwauczNUmkgSNNsjFiRNW2dH" +
|
||||
"8UNv3XT2isvbYqI2LQpMpKGjO/18ekRYS1vnW3VR6bWVrLJ16pqrl1YvOgCkUc4mWcNN5LMw4CCX0hJR7jzvqpWuUpHKIPRt9viTy88jrtBdXzh6fhtE+vxzzCsAQLXZcz4FZzA6ffSjOZKfAa/xWPME3SLdGIB7WixRGCAcAL96Ea/zt5RuM7X19nZ13ddYebKCCOevjkycvNLhPLK2tRIfevZt1rCItLj9ciGhKXkC4sWX7hWU3WNnyuXzHWE0C6jeQ8o6Zj6fjxwci/gAYc9Ylr8XOWK6a3p75S34xsgbz0EjGkxnBAtnjK1Hk4uX16yYnL6FWJNAV9/d35" +
|
||||
"BQwORy2izGaUSPmwEe9QSDiJBrnJzArJalR4sL29f3LQwn6To7Jz25peau3Kb2/s2EppK8Dh2J6HJlQljGOWf+VfoLAmBRs/jI/yXAIiuzt5R2qzyUyr9VM2lW+cb8Q9HS84mdKjLDWVr8IyhjvLsmKgsO4ehQx3ssqJisuWOQ2fVZvlFrLxzZ2Wk7/j6qr5B39wrzFihDpuPqpdkqxxDQhxV2UuWZLs76HQO7tkCDjYTH6e6klnyDqGKobIWN5qNXNGRus+MC/ImL+DNqL7zdVMGquArGVus6zNrnZOO8Gh9xg3r/Zn7VKi5IPMvOB/mk3aDLBkIiXc+tOggJ" +
|
||||
"c13GQ+tzoqcb6zmlvZWr9x5TvQ27cXTxtn3z4kIZClBQomCDT14G7SSiPSv3TRjWQBf4wrTWvjyNL5l5Qt+4Odj9HQ2XnHERTLGTqnZ2sOd6M1P6qriccssjiG6EjxMzvOv+JMQHt20GLnph2YvD6u/RESykIjkKn0hnFbVZ4Q39ZfMIwk9kjFvo4/n+G8ypmM9IeJ+Nq5gfAjqhTxOGqw4QI3Gg0/v3SyJBnWDaMgNMfi0Lq7d6mMIIXdbaxe3kjvUpHDUV8/TOcvlzrp51XpHBZLs2x0XkJsbELd738HdcYE5OYFxu/dXT/FOS/OeUlUz1SstzWsK9Wucz/M" +
|
||||
"hFyowWnnon8mQyqzlBkJEs3H2jsdwlLUi4hLBok0Ek3C+6NjsOgpHZ9/eQuAoLsz0PSq7UFt78Vp1tWAvxIfyeR+yJV5E8pT/4EPQbyp0ddn6xxDy6hyCIAQ9XiIogvORzWKCIVvePksxpG52TwYqM1ZXX7tYW3vBopsEMs/wx7qhsPdILzUzW+MT05fwesk8rp1ZY3qR16kdrUWRfu6P8vyQAPj3JMcFhHWmq93GtW9Pmr+sc8XBe3vWvpu+Inp1TklGxLjDO5/vOY5Nh19cMyYuf7B00JbGVzvSY7d6h44NdYsQDxl8tP7lvZbYaAYsSqJYJBPKZVab1hFoa" +
|
||||
"jFu3ZqSMXv2hjJuKETic+2m3Rldq+tRVbtgfwSPuaHU/p7IdVQ6WrghTrFgct4CI+H2UP1nkI+O8SXKCjSr9+c5i0+SKPobkVEb6S+x5C8kd4EavLr7AfdLN15FRGPyQrd7f+bpFJN1RhdpS3MdVkV3VmSWX2DP3uXuduLj3R9w3279lvugGx8HdMvkLfTvN4YdmY+OMZjGZ60DdXvVYJLZ1OLDPVeu9JBVeXFPd3cPkkIffh0yMWf6HibhfXyORHCG3S7M72GhdRjwSKOHMvz833/jfuvGcb7bpiVGF7ho2K/4aR1qJ5ybLOBhAq3XkP5P5DwJaACWo/umP9A" +
|
||||
"A2INef3OvaUoXaRtq9kFRBGO0tFIUTJIDIlXyQtVCUga51JbkCWKJnHgj/SWfyRtRHPFTjZQk3aGeTi5SDUTqsg4UB8hlMhunKLfhTg72TjYymW1g8YFMMpJGg7yb5FL3pBngUWmIbERBwYn497iAAGW0hGOHSV1cgnTx+GG8fwjXiAxRM8FtVkIS5SPP/APzs5DjUOzMa7OmWeSZA6FbTegO4uvfPNk0tQnV6yhpNNOh5GlIxAumKQ4h2wV4hig7DkUBtnK5jWO4s+0IewcnqVwuDyjcnx2hQ97qVFG6pw/ShY2/2cjqAuNg4JjgYBeDmBs0aKirS1BQIkgSt" +
|
||||
"EGoMTK6At8rS0wUN3EJCeX449JoA6J0RUEpex1t59FFQ+kJFiRHSdQr6ORuAn0acr8mySXKUBgapg/3jw71jPTxVI51DQ8v1YaO1gZF6LwjvAOhdNkYkpTJ5I6KUSMh0Dt8eUJwOMhHyUaOlHOsdziPMzqcCyHcYCF+EVOT0fily5iR9s8LOJdL6z3OfcnXGJPNIWw9d53hGCdiWVIxayOj0mJt9P02zngq5fDNLYBbBxYtB1heuz/jRtXm6Orq6M1VN95GaxX4Gr6Jp54eunQZDIQhy5cNPn3ataU528FUN3J8c4vLaSoHmn9eJrrT8xVPNa8aakAqNbErOwV" +
|
||||
"Z09gp6A0FeUEwvE25SXS0Jb/cypibgmD2zL2XSoovDD1yBkES8ZPPVQgZDLrYEN+wwKAVY7JyolMWLssYXzg205UbNlA6EE1v3P3Se1UVCNUsOP2p6O7+5sbi8XPniAcMlw5Vd4QRqQ2XIc8uDZqU621wCHem8gsDCXuC6yBSISs+mV5N9EYXvoRevUJCyVRINILeJDJbgWId8uDCilIAUorKiye+2jKteGZxOsumTJtZXLAlJSbeq3hsWmp9Q0rKAPwH/gVqSvM7dhSWVMxIFaGUolklRdt3Tp0xa8Y4sLd3nQGXm8ZlZWWsBReJmLftSHMv509s296y/tNpl" +
|
||||
"DqtsNbRypUSOb8gvIlvgbcD/ukKfuc2uIHqNn7nKv7Rgeb/IkhqWqdvQq+aFqFmU3GTfl0T7iR8PvYna57De1VbmxT5mG6yHfSVyiOErDVjRKeYWGYiaael9ktZDtWoA4AoSU+1KWiUGreKrr3FQpmcxwg7Ca9YOTV20hxIQ02IYPS0HWkppu2mHZP4emcm+viCh1dD6i59OMt6aeqfF0HB5LXPT52GjqnVaSlKd//gOXszM0GpaZiicuVKZ25rLpoBk+e5u6MBgxUylVo709N+wCDkMcLbfWRGQDDy8UxP8XD3cNDnZrc1Zo3Tjt+5sWAiypl0PN3fn1NrguK" +
|
||||
"c1W5+OTkfLk7NiFEnjJ1wsLiI46YXoRHcWF1Fmov7SEcbqSjCwU0TX6l1sLen9dcZ5h/EIiI3FyaAiaE1USSyLqV4Aaj7CYAIyoP4kwensJMhiVjkrlHLbMj3RAgyJHg9F/BCHP744rz51bMvbywpsX1huMGQt2psSnrKiomR4X3xnPE8BEPwpY9Eoo8u4o/wRx8YW2HnK7//8ep2hLa/+sfvr+xEOfgQB80rrtxevoIdn3UoJyQE5Rc0ry4shTDt38Fw4wbL3riO38PvXrolEt26DFH44a4DAAd2gQSGdOxBaE+HkKOo2ShUKXqPrBN9afXy8S5IJOiEZIyuE" +
|
||||
"/WhWneFVKNTqSW8lqkLgFGkrn3BEB0WXPwP5K0JSXB1HlHmE66bAkpJ2465MHSQjdq3wGUkmxgxJkKflBcR4RE+dNCAIQ6T9bYjJNdx7sdqSBw+dKhkmK1coCWCaWETWCMjolFTBnKJQs7yrxHQcu2aC31BWnjVeOnyVXhVeOf9JYO5wxlYV1o39KD+ImV39h1hv78D+3aaOsnzRLiI2lCbdR81EU2Ai8K+A/dIt4OIt3nStQ7I6TJYrxYKSu58vJCRJEAKT1ErOj598ugYjtPrMvD3EA2uKHL0xB/3/pxlOvoMGuXkv3F2iqy0UXYmFTudxb3LIsMH4VegELf" +
|
||||
"Ddoi49aRCr4DhPyoUGE/uLioRTbPy6okM3N3GRkG+HmwNmkp4HU73cWQWRFZY3FRvQTa9JTZ5QHb2ovrMcQiNy6xflJ09PTwoY5wuGKHg0IyMoHCudUlONkLZ45c05EwAmJBTnxkSHq4blxmmRUgbKuiT4JiGG0i0OZyv0+mUlt1wuh8F/yRR6+A2OIDzTH9jvwM78G4HL3y7Hd/CXwr7U+4oCRURekfx+11CkU8sUYVYCKepCUls3KHc31mpmz1ob1ZK/fKsDDRE6o6vQA1K2girvcMCnZzQ0qWpYxFKSKvw9fDR4Lc28mNHoXoydiAfnyy7oLy1q6yhyvYxj" +
|
||||
"qnEGi3v27xd9MSO9vZwcQ/21bgP3zckNaVu07g02UhDlLM9ysp68eegfc7lER5uCGm8otjzjW6jdAHOTiNHhdckJCCUnDo9xD/Awy0kOGxxSjL7RyHr5qyP8FAyT9Z0HMgi0ekkDMJfWUs69GwCzmXnkjhvZ8mBLaHoURaskaZeDA/PywsLu3CBK9kZPwbnit4wbS43REYaylFl749zFjvhFCF/MuDl7BHRUXo+AqRU5TYiumtAzPze6bkLiVF1wd5tbXg558VWzdwD6+CPq+KDD3P5vk5wHjzRJ1Srskf7pcK+spPGIzxcrdF4RES4a1B2pIb8RIZrvLw0VOb" +
|
||||
"YFz4z99GTBwqtxLIhLUR+PZUu1YBaovl2xkTO3iU7wA8lJpYWlqvGJlSJHB18PNX+XP0AP7/R0/2DUECuE8rzGiFD9hqBnziUBLNEx/mamnD24NyqVXuJAZ3NPzK5bzNvjyqCdbOJfC1rUBrB+OxQUDVPP/EDscUP+ICn4QOWathgTc7GDbkewwcPHq7OffGl8eohw9pEKlVysrutmAMXj8QUdzmScA2TQ4I8J032CgiZlB8Y5JWf7xESNLnQMyjI0dE+rNArAKEAe0cHSos/wbpwK9Z56PQaugFLXgF2X7gALX2/0teWq5cvGXExLhbeaSzKNd8RpYqu01NQt" +
|
||||
"PpNz3h40PMHWpLACecPQGD/GDtpdd9e2Ae6ffja3b1xcXv7Fq5atc9T1Nsj6tiIck2Hvvhi07JlcNkqIWHsPH5sZ8bj0dj/ze8s8yxnJz3XtxPJocLP2SWscuC+7JTFy7PT0ZARauKF83pXWidVbYSVPmGBzo5oaUN6EkKJqRU+xDDw2xtR+mMaiggNRy38jRFqrB6aJ/n7X90VMtmCVUQUswFC9mPj3X2jR+/rq4od7aUmPuyn8RhGfDi1blNGuu3IyGjHkSgre8MD4sMVxCtZVqOJtoosz3SQFxk7rtHNIcTfxWmko17w6bTioKBAd5U2KLwulfh0EbL6NGL" +
|
||||
"icQprID7ryu+mEiYImcNBLLckVXqtNU3ShOhlofwG+vSLA4YoT4ZAuM6QodOii2hO5Stb5i1Acac8yAe/hY36wIBA89jY8YFBSBtS57W3qhqhill/XZ4HoIPJNLKxwhlB8S/MMCJHO7qOJSnkYJo+0uXsQEoIlSj7+1z80+Vb1z/Cv1qODPZVdD/XDZBwjp4cPCccGxQr7pEfIV7y40qW8WcPFYzqifOHA8F6eIOea+t/buNP5xL73mrIy2ugV3ZqaGgqvf58VFF8RGjQkCc8TyVzF5uxWM7vQbgwGlrXBleFnXSERKx01ailI0hK4qoPlY7QqJWuErF0BAnVW" +
|
||||
"lBplBIVpS8SvO/cuXkdX8Y3bt2+dRP8QfLmqVNv4oe45xT56dwOM/Ym49qkfXBsE5CV5a3b+AZtevM2+JGut3sOn+okyx3a6RTuwQ9PneLi+/acPIkO47XEi/vTFsxEMolPp45VWoBTYgVQpV4bTA3b57GN+8DTKI+DtgUGg6NLcmZwcEzsDly6/cF6L9/o77rGuLs7qVK7nokVv+jojHFqT9cIw4TpSWPXzg93dVw6amRk8Eg7oun+vI15Ol8gtqKp9TSNkCJbjtLw4Po0ptBqp3EZ0dFJpxfMn1fz9ovTpnl1OIZpM5YkJiaMWZEVEe74LFwBXh0TI5fX13e" +
|
||||
"9V7949OhlBleX/PyGhvx8H69Masv83q74Z35vV8uvVP/H/V3qRsSv5M++zwvV3aZT9/6n3V5U0E1+aIwLJxncbfZzGjH0A4H8KQi7AyEcSvArc6AICqvwizC3CrfjHa0wC+bU4JegqgZvxC01UI038GdJ+D1DwrOUkdP48e/7hlaentg/RKndptPd/2EXUTSUJw6YNWYze8FyZkQnWDERkIRWiC0HhPiDhbxl66QhKjRsyRzX8IaaSazx9zPH/tHSsmPFiuSmGlbeVZfp4s+yo2N6t3AVhw6c2X4gxrAPr198uGs2VNbxGKQ3P2AXi54jelOSOOUl7G/xZ39Ct" +
|
||||
"Ur+zJZGKE+zOpWbsEXDWrhCB0Ux77x29uB+UN7cHLR79k9nf7za80Z+xcqy6TyHU8reWFvfWblmXMPWLWdNBqhMW6LLiGDPCCoQaoPc55Z9UIKpBPf4U8309DX7x1wcCWuucdfdS+byQGdDgLSL4lqX5fw1J9TBedp9hFPC/0st3MrFM9bEt1CWnqkwzo4SGGSZDPNVLooLIXcyiu786bE/5XjSfp9p5MpgfzCt8vQIi1Cr1R6R4e6elnt1RJiHJxxrb4eHEZ4ajWcEzQM9+76iSaHaEKHWkAxZTecU9tqeIzMqaG74n+q7Vqt8ss57lzrTv1V7Oc5ik3/SlZb" +
|
||||
"XlfKRrr65RVR1Gf/8X3TFMjUMiEeJ9vO45/kM0YaISgMkRWETQX3n1vUb+Dq+S7DtOviCqLOz803ch01vvvlm50DkjAvmwcQvG0T7b9zCt2mrG7fAGzS3b/aQhiACrpM0xCbc92Yn56HpuxiFdiXz/tufpvhnoMmyWH+cLhEqlZIn9Kl5Gr0xvh7u3gkBfgEBqQGuTsGepVCBf9H4B82NTxifszZdFxb6LHzA/nBbu8CQxCRtkHSwGj5qODYkLWlBY+4EF+VoIYfPMT8UDxUd4c+F8rsPnEQpUdKgQd7sOIq/cuoejEal19LgQt5CGWUwJx4alfH79nO4O5DdH" +
|
||||
"dO3hOPYsTEmuzDw+mj9T+PG9a7vw0vCv4tpIUvomNfCYQ1wLeDKXV9eUPvlgdWhw6X+q0/dmTvtWEwxOD1c7aD2dFj9B4xayPybvLOfQd79ZC1X9XeUx0dvtY9KKHzLp0n/ZGpIkMpNr3d2ahidUDszdrSLa9hzKanzFsWNaZBIZJ7BBg+NLjTzWVSAzrg4jQ30UCnddHPi42JHl8T7BbgaNs6LGxMZWe1sYytVqtwM6W5Kui/A7UE9ona+UqB6tFASzgjotY/r2ITPI4tGGMKneCp9HNzcnJxdHEYOXjRMqyvRqDQe6QZbV1duz+y4mEFDh44YPAzZ2oQWxif" +
|
||||
"DsEHD3NEIO3o+A4ycB2qx1ivGsJ+DsatLsAd/MEp+efzMX/L+42el3FgIfPw/A6UXuLHXWvn/R3nymVQrp8+g3HJuvtQ8HQKZi9az9qUXtkMZrY0ncWNRpnUPmKzEpEpyQeMF0x+WkfnREZNF2k3q9z8xcjpK1oV5F/k5tlrmoeeLp6NJ/DyW87zWdnS+rXTOJ23L4xlsi5i79KnmcnF/xq1nwhX2QEPf8X+zccMz5HcEiWlR9z/Y+XB4GnkITP8C/0B7hZvKkOTu0hA/ZuWi+NS2554JQXLqXaEsNCgkKNLT0zcwuTktLT5u7pbj7bwdlbESLo6vSfypsjUGy" +
|
||||
"qe3tJbMQGjG9K1bisvRzbaZ5QiVl217eWYFy1aU0pyivwy8eQR6KtrrwHLkX8pqn8b2Q9wK+6LnzGl4991n4nSDH6o1vVd2Ao3BnzB/pi+SSX0GLbHR8GTc1gkbZKF6Gdsfpejp9qdQDx2fD7UfbKeojIvLyl5SHz9WxA0bJLOz+VdIpMrdTRU12sXd3f2ZYhmL32Y5lk2Ir6pPThmXvlTl5uI8SqWxh/EmqbfH6Ghvb2+vmBhPL96HJqDpEhf+LJUdrVKpdPRMltJy5FMlpbuqUkj9Da39ndvB4YeluJfb9vM/v/oZTUenN240JaDXTNn0YtPpsde+vzL/Dyy" +
|
||||
"zUD4AAHicrY0xigJBEEVf6+iyIEaLGHZoIIMDCnsANzDQQNDMQGTUhkFhZjzF5h7AE3kLr+EfKQMTI7uh+/H4VR9occZRHUeH2LjGFwvjuvy/cSS+GjdoOWfc5Mf9Kumib5n+Y6riGm3+jOvyK+NIfDFu0OVm3KTn2oyZMMOTMGSk1zMlUOqmZBRs2JPLbGUYT2Y+GY4SPw1lmWbFZp+Hrfxc4R0nDawVZp7uTtla8JHlH1myVDhXOHDk8FgWM9DPMs2LcDz4JB74Z9ez6X1PVfPacgcnT02VeJx9z81PzwEAx/HXt4ffLz0oRSGUVJ7zqzxUHqqfVJI85PkhZ" +
|
||||
"FZtzVya2VxSInSy1akOmI2T5akLhx6szT8gh04dnMyBzmx19rm89jm+xfj/nhHEBLFixYkXEpZgiURJkqVYKlWaZdJlWG6FTFlWWmW1bGustU6OXOvl2SBfgUIbbbLZFltts12RHSKKlSi10y677VGmXIW99tnvgEpVqkUdVOOQWnXqHdbgiEZHNTnmuBNOanbKaWecdc55F1x0yWUtrrjqmud63ffJoB/6PDbslRdBnEe+6/E0iA9CBgx5aMJsEDbitT9+m//X3+q6r26Y1uaXdv063XbXmG4/vTHnpW9mjHrrg48mvfPelHvGPfDFZ09CbZ13brUXL1AS7rr" +
|
||||
"ZEYlU1ywYXfzR0kXL/wIjEkhHAAAAAAAAAf//AAJ4nGNgZGBg4AFiMSBmYmAEwoVAzALmMQAACokA0AAAAHicY2BgYGQAgisSYoIMaAAAFToBFQAAAA==) format('woff');\n}");
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
protected static String DictionaryConfigToString(Dictionary<String, String> config) {
|
||||
String query = "";
|
||||
if(config.Count > 0) {
|
||||
query += "?";
|
||||
List<String> queryparts = new List<String>();
|
||||
foreach(KeyValuePair<String, String> item in config) {
|
||||
queryparts.Add(HttpUtility.UrlEncode(item.Key) + "=" + HttpUtility.UrlEncode(item.Value));
|
||||
}
|
||||
query += String.Join("&", queryparts);
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
protected abstract void ParseParams();
|
||||
|
||||
protected abstract String DrawSvgContent();
|
||||
|
||||
public override String ToString() {
|
||||
String svg = "";
|
||||
if(this.withSvgHeader) {
|
||||
svg += "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
|
||||
svg += $"<svg width=\"{this.width.ToString(CultureInfo.InvariantCulture)}mm\" height=\"{this.height.ToString(CultureInfo.InvariantCulture)}mm\" viewBox=\"";
|
||||
foreach(Double item in this.viewbox) {
|
||||
svg += item.ToString(CultureInfo.InvariantCulture) + " ";
|
||||
}
|
||||
svg += "\" preserveAspectRatio=\"xMinYMin slice\" xmlns:svg=\"http://www.w3.org/2000/svg\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n";
|
||||
}
|
||||
if(this.css.Count > 0) {
|
||||
svg += "<defs><style type=\"text/css\">\n";
|
||||
foreach(String item in this.css) {
|
||||
svg += item + "\n";
|
||||
}
|
||||
svg += "</style></defs>\n";
|
||||
}
|
||||
svg += this.DrawSvgContent();
|
||||
if(this.withSvgHeader) {
|
||||
svg += "</svg>\n";
|
||||
}
|
||||
return svg;
|
||||
}
|
||||
}
|
||||
}
|
66
Lora-Map/Model/Svg/SVGMarker.cs
Normal file
@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using LitJson;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Svg {
|
||||
public class SVGMarker : SVGFile {
|
||||
private String name;
|
||||
private String icon;
|
||||
|
||||
public SVGMarker(String query) : base(query, 86, 121.25, new List<Double>() { 0, 0, 86, 121.25 }) => this.css.Add("#marker-name tspan {\n font-size: 20px;\n font-family: DIN1451;\n}");
|
||||
|
||||
public static String ParseConfig(JsonData json, String name) => "api/svg/marker.svg" + DictionaryConfigToString(GenerateConfig(json, name));
|
||||
|
||||
protected override void ParseParams() {
|
||||
String[] parts = this.query.Split('&');
|
||||
foreach(String part in parts) {
|
||||
String[] keyvalue = part.Split('=');
|
||||
if(keyvalue.Length == 2) {
|
||||
switch(keyvalue[0].ToLower()) {
|
||||
case "name":
|
||||
this.name = keyvalue[1];
|
||||
break;
|
||||
case "icon":
|
||||
this.icon = keyvalue[1].ToLower();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Dictionary<String, String> GenerateConfig(JsonData json, String name) {
|
||||
Dictionary<String, String> config = new Dictionary<String, String>();
|
||||
if(name != "") {
|
||||
config.Add("name", name);
|
||||
}
|
||||
if(json.ContainsKey("person") && json["person"].IsObject) {
|
||||
config.Add("icon", "person");
|
||||
Dictionary<String, String> personconfig = SVGPerson.GenerateConfig(json["person"]);
|
||||
personconfig.ToList().ForEach(x => config.Add(x.Key, x.Value));
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
protected override String DrawSvgContent() {
|
||||
String svg = "<g inkscape:groupmode=\"layer\" id=\"marker-bg\" inkscape:label=\"Marker\">\n";
|
||||
svg += "<rect style=\"fill:#ffffff;stroke:#000000;stroke-width:1.5px;\" width=\"82.5\" height=\"110\" x=\"2\" y=\"0.75\" />\n";
|
||||
svg += "<path style=\"stroke:#000000;stroke-width:1.5px;\" d=\"m 2,110.75 0,8.5\" />\n";
|
||||
svg += "<circle style=\"fill:#000000;\" cx=\"2\" cy=\"119.25\" r=\"2\" />\n";
|
||||
svg += "</g>\n";
|
||||
|
||||
svg += "<g inkscape:groupmode=\"layer\" id=\"marker-name\" inkscape:label=\"Name\">\n";
|
||||
svg += $"<text><tspan x=\"5\" y=\"20\" id=\"marker-name-text\">{this.name}</tspan></text>\n";
|
||||
svg += "</g>\n";
|
||||
|
||||
if(this.icon == "person") {
|
||||
svg += "<g inkscape:groupmode=\"layer\" id=\"marker-icon\" inkscape:label=\"Icon\" transform=\"translate(42.5 45) scale(0.8)\">\n";
|
||||
svg += new SVGPerson(this.query, false);
|
||||
svg += "</g>\n";
|
||||
}
|
||||
return svg;
|
||||
}
|
||||
}
|
||||
}
|
198
Lora-Map/Model/Svg/SVGPerson.cs
Normal file
@ -0,0 +1,198 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
using LitJson;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Svg {
|
||||
public class SVGPerson : SVGFile {
|
||||
private String organisation;
|
||||
private String function;
|
||||
private String rang;
|
||||
private String text;
|
||||
private String[] typs;
|
||||
|
||||
|
||||
|
||||
public SVGPerson(String query, Boolean withOutline = true) : base(query, 74.953316, 84.703323, new List<Double>() { -37.5, -12, 74.953316, 84.703323 }, withOutline) {
|
||||
this.css.Add("#person-layer-org rect {\n stroke: black;\n stroke-width: 3px;\n}");
|
||||
this.css.Add("#person-layer-funct path {\n stroke: #000000;\n stroke-width: 3px;\n fill: #000000;\n}");
|
||||
this.css.Add("#person-layer-rang circle {\n fill: #000000;\n}");
|
||||
this.css.Add("#person-layer-typ tspan {\n font-size: 20px;\n font-family: DIN1451;\n text-align: center;\n text-anchor: middle;\n fill: #000000;\n}");
|
||||
this.css.Add("#person-layer-typ line {\n stroke-width: 3px;\n stroke: black;\n}");
|
||||
}
|
||||
|
||||
public static String ParseConfig(JsonData json) => "api/svg/person.svg" + DictionaryConfigToString(GenerateConfig(json));
|
||||
|
||||
protected override void ParseParams() {
|
||||
String[] parts = this.query.Split('&');
|
||||
foreach(String part in parts) {
|
||||
String[] keyvalue = part.Split('=');
|
||||
if(keyvalue.Length == 2) {
|
||||
switch(keyvalue[0].ToLower()) {
|
||||
case "person-org":
|
||||
this.organisation = keyvalue[1].ToLower();
|
||||
break;
|
||||
case "person-funct":
|
||||
this.function = keyvalue[1].ToLower();
|
||||
break;
|
||||
case "person-rang":
|
||||
this.rang = keyvalue[1].ToLower();
|
||||
break;
|
||||
case "person-text":
|
||||
this.text = keyvalue[1];
|
||||
break;
|
||||
case "person-typ":
|
||||
this.typs = keyvalue[1].ToLower().Split(",");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Dictionary<String, String> GenerateConfig(JsonData json) {
|
||||
Dictionary<String, String> config = new Dictionary<String, String>();
|
||||
if(json.ContainsKey("org") && json["org"].IsString) {
|
||||
config.Add("person-org", json["org"].ToString());
|
||||
}
|
||||
if(json.ContainsKey("funct") && json["funct"].IsString) {
|
||||
config.Add("person-funct", json["funct"].ToString());
|
||||
}
|
||||
if(json.ContainsKey("rang") && json["rang"].IsString) {
|
||||
config.Add("person-rang", json["rang"].ToString());
|
||||
}
|
||||
if(json.ContainsKey("text") && json["text"].IsString) {
|
||||
config.Add("person-text", json["text"].ToString());
|
||||
}
|
||||
if(json.ContainsKey("typ") && json["typ"].IsArray) {
|
||||
List<String> typs = new List<String>();
|
||||
foreach(JsonData item in json["person"]["typ"]) {
|
||||
if(item.IsString) {
|
||||
typs.Add(item.ToString());
|
||||
}
|
||||
}
|
||||
config.Add("person-typ", String.Join(",", typs));
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
protected override String DrawSvgContent() {
|
||||
String svg = "";
|
||||
if(this.organisation != null && this.orglookup.ContainsKey(this.organisation)) {
|
||||
svg += "<g inkscape:groupmode=\"layer\" id=\"person-layer-org\" inkscape:label=\"Organisation\">\n";
|
||||
svg += $"<g inkscape:groupmode=\"layer\" id=\"person-layer-org-{this.organisation}\" inkscape:label=\"{this.orglookup[this.organisation].Name}\">\n";
|
||||
svg += $"<rect style=\"fill: {this.orglookup[this.organisation].Color}\" height=\"50\" width=\"50\" transform=\"rotate(45)\"/>\n";
|
||||
svg += "</g>\n";
|
||||
svg += "</g>\n";
|
||||
}
|
||||
if(this.function != null && this.funclookup.ContainsKey(this.function)) {
|
||||
svg += "<g inkscape:groupmode=\"layer\" id=\"person-layer-funct\" inkscape:label=\"Funktion\">\n";
|
||||
svg += $"<g inkscape:groupmode=\"layer\" id=\"person-layer-funct-{this.function}\" inkscape:label=\"{this.funclookup[this.function].Name}\">\n";
|
||||
svg += $"<path d=\"{this.funclookup[this.function].Path}\" />\n";
|
||||
svg += "</g>\n";
|
||||
svg += "</g>\n";
|
||||
}
|
||||
if(this.rang != null && this.ranglookup.ContainsKey(this.rang)) {
|
||||
svg += "<g inkscape:groupmode=\"layer\" id=\"person-layer-rang\" inkscape:label=\"Rang\">\n";
|
||||
svg += $"<g inkscape:groupmode=\"layer\" id=\"person-layer-rang-{this.rang}\" inkscape:label=\"{this.ranglookup[this.rang].Name}\">\n";
|
||||
svg += "<g style=\"display: inline;\">\n";
|
||||
foreach(Double item in this.ranglookup[this.rang].Circles) {
|
||||
svg += $"<circle cx=\"{item.ToString(CultureInfo.InvariantCulture)}\" cy=\"-8\" r=\"3\" />\n";
|
||||
}
|
||||
svg += "</g>\n";
|
||||
svg += "</g>\n";
|
||||
svg += "</g>\n";
|
||||
}
|
||||
if(this.text != null || this.typs != null && this.typs.All(x => this.typlookup.ContainsKey(x))) {
|
||||
svg += "<g inkscape:groupmode=\"layer\" id=\"person-layer-typ\" inkscape:label=\"Typ\">\n";
|
||||
if(this.text != null && this.typs == null) {
|
||||
svg += $"<text><tspan y=\"42\" x=\"0\" id=\"person-layer-typ-text\">{this.text}</tspan></text>\n";
|
||||
}
|
||||
if(this.text == null && this.typs != null && this.typs.All(x => this.typlookup.ContainsKey(x))) {
|
||||
foreach(String typ in this.typs) {
|
||||
svg += $"<g id=\"person-layer-typ-{typ}\" inkscape:label=\"{this.typlookup[typ].Name}\">\n";
|
||||
foreach(Tuple<Double, Double, Double, Double> item in this.typlookup[typ].Lines) {
|
||||
svg += $"<line x1=\"{item.Item1.ToString(CultureInfo.InvariantCulture)}\" y1=\"{item.Item2.ToString(CultureInfo.InvariantCulture)}\" x2=\"{item.Item3.ToString(CultureInfo.InvariantCulture)}\" y2=\"{item.Item4.ToString(CultureInfo.InvariantCulture)}\" />\n";
|
||||
}
|
||||
svg += "</g>\n";
|
||||
}
|
||||
}
|
||||
svg += "</g>\n";
|
||||
}
|
||||
return svg;
|
||||
}
|
||||
|
||||
private readonly Dictionary<String, Organistaion> orglookup = new Dictionary<String, Organistaion>() {
|
||||
{ "thw", new Organistaion("THW", "#0069b4") },
|
||||
{ "fw", new Organistaion("Feuerwehr", "#e30613") },
|
||||
{ "hilo", new Organistaion("Hilo", "#ffffff") },
|
||||
{ "pol", new Organistaion("Polizei", "#13a538") },
|
||||
{ "fueh", new Organistaion("Führung", "#ffed00") },
|
||||
{ "sonst", new Organistaion("Sonstig", "#ec6725") }
|
||||
};
|
||||
private readonly Dictionary<String, Funktion> funclookup = new Dictionary<String, Funktion>() {
|
||||
{ "sonder", new Funktion("Sonder", "M -10,10 H 10") },
|
||||
{ "fueh", new Funktion("Führungskraft", "M -10,10 H 10 L 0,0 Z") }
|
||||
};
|
||||
private readonly Dictionary<String, Rang> ranglookup = new Dictionary<String, Rang>() {
|
||||
{ "trupp", new Rang("Truppführer", new List<Double>() { 0 }) },
|
||||
{ "grupp", new Rang("Gruppenführer", new List<Double>() { -4.5, 4.5 }) },
|
||||
{ "zug", new Rang("Zugführer", new List<Double>() { -9, 0, 9 }) }
|
||||
};
|
||||
private readonly Dictionary<String, Typ> typlookup = new Dictionary<String, Typ>() {
|
||||
{ "loesch", new Typ("Brandbekämpfung/Löscheinsatz", new List<Tuple<Double, Double, Double, Double>>() { new Tuple<Double, Double, Double, Double>(-35, 35.5, 35, 35.5), new Tuple<Double, Double, Double, Double>(17.5, 35.5, 25, 26), new Tuple<Double, Double, Double, Double>(17.5, 35.5, 25, 44) }) },
|
||||
{ "sani", new Typ("Rettungswesen, Sanitätswesen, Gesundheitswesen", new List<Tuple<Double, Double, Double, Double>>() { new Tuple<Double, Double, Double, Double>(0, 0, 0, 70), new Tuple<Double, Double, Double, Double>(-35, 35.5, 35, 35.5) }) },
|
||||
{ "betreu", new Typ("Betreuung", new List<Tuple<Double, Double, Double, Double>>() { new Tuple<Double, Double, Double, Double>(-17, 53, 0, 35.5), new Tuple<Double, Double, Double, Double>(17, 53, 0, 35.5) }) }
|
||||
};
|
||||
|
||||
private struct Organistaion {
|
||||
public String Name {
|
||||
get;
|
||||
}
|
||||
public String Color {
|
||||
get;
|
||||
}
|
||||
public Organistaion(String name, String color) {
|
||||
this.Name = name;
|
||||
this.Color = color;
|
||||
}
|
||||
}
|
||||
private struct Funktion {
|
||||
public String Name {
|
||||
get;
|
||||
}
|
||||
public String Path {
|
||||
get;
|
||||
}
|
||||
public Funktion(String name, String path) {
|
||||
this.Name = name;
|
||||
this.Path = path;
|
||||
}
|
||||
}
|
||||
private struct Rang {
|
||||
public String Name {
|
||||
get;
|
||||
}
|
||||
public List<Double> Circles {
|
||||
get;
|
||||
}
|
||||
public Rang(String name, List<Double> circles) {
|
||||
this.Name = name;
|
||||
this.Circles = circles;
|
||||
}
|
||||
}
|
||||
private struct Typ {
|
||||
public String Name {
|
||||
get;
|
||||
}
|
||||
public List<Tuple<Double, Double, Double, Double>> Lines {
|
||||
get;
|
||||
}
|
||||
public Typ(String name, List<Tuple<Double, Double, Double, Double>> lines) {
|
||||
this.Name = name;
|
||||
this.Lines = lines;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
42
Lora-Map/Model/Svg/SvgModel.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
using BlubbFish.Utils;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Svg {
|
||||
public class SvgModel : OwnSingeton<SvgModel> {
|
||||
private readonly Dictionary<String, SVGFile> svgtable = new Dictionary<String, SVGFile>();
|
||||
public Boolean ParseRequest(HttpListenerContext cont) {
|
||||
Byte[] svg = this.GetSvg(cont.Request.Url.PathAndQuery);
|
||||
if(svg.Length > 0) {
|
||||
cont.Response.ContentType = "image/svg+xml";
|
||||
cont.Response.ContentLength64 = svg.Length;
|
||||
cont.Response.OutputStream.Write(svg, 0, svg.Length);
|
||||
Console.WriteLine("200 - " + cont.Request.Url.PathAndQuery);
|
||||
return true;
|
||||
}
|
||||
cont.Response.StatusCode = 404;
|
||||
Helper.WriteError("404 - " + cont.Request.Url.PathAndQuery + " not found!");
|
||||
return false;
|
||||
}
|
||||
|
||||
private Byte[] GetSvg(String pathAndQuery) {
|
||||
if(this.svgtable.ContainsKey(pathAndQuery)) {
|
||||
return Encoding.UTF8.GetBytes(this.svgtable[pathAndQuery].ToString());
|
||||
} else {
|
||||
if(pathAndQuery.StartsWith("/api/svg/marker.svg") && pathAndQuery.Contains("?")) {
|
||||
String query = pathAndQuery[(pathAndQuery.IndexOf('?') + 1)..];
|
||||
this.svgtable.Add(pathAndQuery, new SVGMarker(query));
|
||||
return Encoding.UTF8.GetBytes(this.svgtable[pathAndQuery].ToString());
|
||||
} else if(pathAndQuery.StartsWith("/api/svg/person.svg") && pathAndQuery.Contains("?")) {
|
||||
String query = pathAndQuery[(pathAndQuery.IndexOf('?') + 1)..];
|
||||
this.svgtable.Add(pathAndQuery, new SVGPerson(query));
|
||||
return Encoding.UTF8.GetBytes(this.svgtable[pathAndQuery].ToString());
|
||||
}
|
||||
}
|
||||
return new Byte[0];
|
||||
}
|
||||
}
|
||||
}
|
@ -5,26 +5,18 @@ using BlubbFish.Utils.IoT.Connector;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap {
|
||||
class Program {
|
||||
static void Main(String[] args) {
|
||||
static void Main(String[] _1) {
|
||||
InIReader.SetSearchPath(new List<String>() { "/etc/loramap", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\loramap" });
|
||||
if (!InIReader.ConfigExist("settings")) {
|
||||
Helper.WriteError("settings.ini not found!");
|
||||
Console.ReadLine();
|
||||
return;
|
||||
}
|
||||
if(!InIReader.ConfigExist("requests")) {
|
||||
Helper.WriteError("requests.ini not found!");
|
||||
Console.ReadLine();
|
||||
_ = Console.ReadLine();
|
||||
return;
|
||||
}
|
||||
InIReader ini = InIReader.GetInstance("settings");
|
||||
Dictionary<String, String> backenddata = ini.GetSection("mqtt");
|
||||
backenddata.Add("topic", "lora/#;camera/#");
|
||||
backenddata.Add("topic", "lora/#;camera/#;sfn/#");
|
||||
ADataBackend b = (ADataBackend)ABackend.GetInstance(backenddata, ABackend.BackendType.Data);
|
||||
new Server(b, ini.GetSection("webserver"), InIReader.GetInstance("requests"));
|
||||
while(true) {
|
||||
System.Threading.Thread.Sleep(1000);
|
||||
}
|
||||
_ = new Server(b, ini.GetSection("webserver"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,55 +0,0 @@
|
||||
using System.Resources;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// Allgemeine Informationen über eine Assembly werden über die folgenden
|
||||
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
|
||||
// die einer Assembly zugeordnet sind.
|
||||
[assembly: AssemblyTitle("Lora-Map")]
|
||||
[assembly: AssemblyDescription("Displays Items with Coordinates from Mqtt on a Map")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Fraunhofer FIT")]
|
||||
[assembly: AssemblyProduct("Lora-Map")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018 - 24.06.2019")]
|
||||
[assembly: AssemblyTrademark("Fraunhofer FIT, BlubbFish")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: NeutralResourcesLanguage("de-DE")]
|
||||
|
||||
// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly
|
||||
// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von
|
||||
// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
|
||||
[assembly: Guid("95d6f48a-9488-42a6-a973-941b45b26db8")]
|
||||
|
||||
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
|
||||
//
|
||||
// Hauptversion
|
||||
// Nebenversion
|
||||
// Buildnummer
|
||||
// Revision
|
||||
//
|
||||
// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
|
||||
// übernehmen, indem Sie "*" eingeben:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.2.7")]
|
||||
[assembly: AssemblyFileVersion("1.2.7")]
|
||||
|
||||
/*
|
||||
* 1.1.1 Add Debian package config
|
||||
* 1.1.2 #2 Show versions number in Site
|
||||
* 1.1.3 #1 Click on icon and show details
|
||||
* 1.1.4 #3 Create icons for devices
|
||||
* 1.1.5 Add support for alert button
|
||||
* 1.1.6 #5 Create admin area
|
||||
* 1.1.7 #8 Editor for Names
|
||||
* 1.2.0 #4 Possible to Ex and Import Setting
|
||||
* 1.2.1 #6 Load the map from the Device
|
||||
* 1.2.2 Bugfix, if only recieve panic packet with gps data, update the marker on the map also
|
||||
* 1.2.3 #9 display polygons and marker on the map
|
||||
* 1.2.4 Can draw Textmarkers on the Map, use MGRS (UTM) on the Map
|
||||
* 1.2.5 #10 text Letzer Datenempfang is too long when scrollbar is there and #11 set textsize for every zoomlevel
|
||||
* 1.2.6 New Types of marker for person
|
||||
* 1.2.7 Reorganise a lot of things, add Support for Cameradata
|
||||
*/
|
@ -1,176 +1,86 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
using BlubbFish.Utils;
|
||||
using BlubbFish.Utils.IoT.Bots;
|
||||
using BlubbFish.Utils.IoT.Connector;
|
||||
using BlubbFish.Utils.IoT.Events;
|
||||
|
||||
using Fraunhofer.Fit.IoT.LoraMap.Model;
|
||||
using Fraunhofer.Fit.IoT.LoraMap.Model.Admin;
|
||||
using Fraunhofer.Fit.IoT.LoraMap.Model.Camera;
|
||||
using Fraunhofer.Fit.IoT.LoraMap.Model.Position;
|
||||
using Fraunhofer.Fit.IoT.LoraMap.Model.Sensor;
|
||||
using Fraunhofer.Fit.IoT.LoraMap.Model.Svg;
|
||||
|
||||
using LitJson;
|
||||
|
||||
namespace Fraunhofer.Fit.IoT.LoraMap {
|
||||
class Server : Webserver {
|
||||
private readonly SortedDictionary<String, PositionItem> positions = new SortedDictionary<String, PositionItem>();
|
||||
private readonly SortedDictionary<String, AlarmItem> alarms = new SortedDictionary<String, AlarmItem>();
|
||||
private readonly SortedDictionary<String, Camera> cameras = new SortedDictionary<String, Camera>();
|
||||
private readonly SortedDictionary<String, Crowd> crowds = new SortedDictionary<String, Crowd>();
|
||||
private JsonData marker;
|
||||
private readonly Dictionary<String, Marker> markertable = new Dictionary<String, Marker>();
|
||||
private readonly SortedDictionary<String, Object> jsonapi = new SortedDictionary<String, Object>() {
|
||||
{ "camera", CameraModel.Instance },
|
||||
{ "position", PositionModel.Instance },
|
||||
{ "sensor", SensorModel.Instance },
|
||||
{ "settings", Settings.Instance.External },
|
||||
};
|
||||
private readonly AdminModel admin;
|
||||
|
||||
public Server(ADataBackend backend, Dictionary<String, String> settings, InIReader requests) : base(backend, settings, requests) {
|
||||
public Server(ADataBackend backend, Dictionary<String, String> settings) : base(backend, settings, null) {
|
||||
this.logger.SetPath(settings["loggingpath"]);
|
||||
this.CheckJsonFiles();
|
||||
this.admin = new AdminModel(settings);
|
||||
this.marker = JsonMapper.ToObject(File.ReadAllText("json/names.json"));
|
||||
this.admin.NamesUpdate += this.AdminModelUpdateNames;
|
||||
this.admin.SettingsUpdate += Settings.Instance.ReloadSettings;
|
||||
this.admin.GeoUpdate += Settings.Instance.ReloadGeo;
|
||||
this.admin.NamesUpdate += PositionModel.Instance.ReloadNames;
|
||||
this.StartListen();
|
||||
this.WaitForShutdown();
|
||||
this.Dispose();
|
||||
}
|
||||
|
||||
private void AdminModelUpdateNames(Object sender, EventArgs e) {
|
||||
this.marker = JsonMapper.ToObject(File.ReadAllText("json/names.json"));
|
||||
foreach(KeyValuePair<String, PositionItem> item in this.positions) {
|
||||
item.Value.UpdateMarker(this.marker, item.Key);
|
||||
}
|
||||
Console.WriteLine("Namen und Icons aktualisiert!");
|
||||
}
|
||||
|
||||
private void CheckJsonFiles() {
|
||||
if(!Directory.Exists("json")) {
|
||||
Directory.CreateDirectory("json");
|
||||
}
|
||||
if(!File.Exists("json/names.json")) {
|
||||
File.WriteAllText("json/names.json", "{}");
|
||||
}
|
||||
if(!File.Exists("json/geo.json")) {
|
||||
File.WriteAllText("json/geo.json", "{}");
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Backend_MessageIncomming(Object sender, BackendEvent e) {
|
||||
protected override void Backend_MessageIncomming(Object sender, BackendEvent mqtt) {
|
||||
try {
|
||||
JsonData d = JsonMapper.ToObject(e.Message);
|
||||
if(PositionItem.CheckJson(d) && ((String)e.From).Contains("lora/data")) {
|
||||
String name = PositionItem.GetId(d);
|
||||
if(this.positions.ContainsKey(name)) {
|
||||
this.positions[name].Update(d);
|
||||
} else {
|
||||
this.positions.Add(name, new PositionItem(d, this.marker));
|
||||
}
|
||||
Console.WriteLine("Koordinate erhalten!");
|
||||
} else if(AlarmItem.CheckJson(d) && ((String)e.From).Contains("lora/panic")) {
|
||||
String name = AlarmItem.GetId(d);
|
||||
if(this.alarms.ContainsKey(name)) {
|
||||
this.alarms[name].Update(d);
|
||||
} else {
|
||||
this.alarms.Add(name, new AlarmItem(d));
|
||||
}
|
||||
if(this.positions.ContainsKey(name)) {
|
||||
this.positions[name].Update(d);
|
||||
} else {
|
||||
this.positions.Add(name, new PositionItem(d, this.marker));
|
||||
}
|
||||
Console.WriteLine("PANIC erhalten!");
|
||||
} else if(Camera.CheckJson(d) && ((String)e.From).Contains("camera/count")) {
|
||||
String cameraid = Camera.GetId(d);
|
||||
if(this.cameras.ContainsKey(cameraid)) {
|
||||
this.cameras[cameraid].Update(d);
|
||||
} else {
|
||||
this.cameras.Add(cameraid, new Camera(d));
|
||||
}
|
||||
} else if((Crowd.CheckJsonCrowdDensityLocal(d) || Crowd.CheckJsonFightingDetection(d) || Crowd.CheckJsonFlow(d)) && ((String)e.From).Contains("camera/crowd")) {
|
||||
String cameraid = Crowd.GetId(d);
|
||||
if(this.crowds.ContainsKey(cameraid)) {
|
||||
this.crowds[cameraid].Update(d);
|
||||
} else {
|
||||
this.crowds.Add(cameraid, new Crowd(d));
|
||||
}
|
||||
}
|
||||
} catch(Exception ex) {
|
||||
Helper.WriteError(ex.Message);
|
||||
JsonData d = JsonMapper.ToObject(mqtt.Message);
|
||||
PositionModel.Instance.ParseMqttJson(d, (String)mqtt.From);
|
||||
CameraModel.Instance.ParseMqttJson(d, (String)mqtt.From);
|
||||
SensorModel.Instance.ParseMqttJson(d, (String)mqtt.From);
|
||||
} catch(Exception e) {
|
||||
Helper.WriteError("Backend_MessageIncomming(): "+e.Message + "\n\n" + e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
protected override Boolean SendWebserverResponse(HttpListenerContext cont) {
|
||||
try {
|
||||
if(cont.Request.Url.PathAndQuery.StartsWith("/loc")) {
|
||||
return SendJsonResponse(this.positions, cont);
|
||||
} else if(cont.Request.Url.PathAndQuery.StartsWith("/panic")) {
|
||||
return SendJsonResponse(this.alarms, cont);
|
||||
} else if(cont.Request.Url.PathAndQuery.StartsWith("/icons/marker/Marker.svg") && cont.Request.Url.PathAndQuery.Contains("?")) {
|
||||
String hash = cont.Request.Url.PathAndQuery.Substring(cont.Request.Url.PathAndQuery.IndexOf('?') + 1);
|
||||
if(!this.markertable.ContainsKey(hash)) {
|
||||
this.markertable.Add(hash, new Marker(hash));
|
||||
if(cont.Request.Url.AbsolutePath.StartsWith("/api/json/")) {
|
||||
if(cont.Request.Url.AbsolutePath.Length > 10) {
|
||||
String parts = cont.Request.Url.AbsolutePath[10..];
|
||||
Dictionary<String, Object> ret = new Dictionary<String, Object>();
|
||||
foreach(String part in parts.Split(",")) {
|
||||
if(this.jsonapi.ContainsKey(part)) {
|
||||
ret.Add(part, this.jsonapi[part]);
|
||||
}
|
||||
}
|
||||
return SendJsonResponse(ret, cont);
|
||||
}
|
||||
cont.Response.ContentType = "image/svg+xml";
|
||||
Byte[] buf = Encoding.UTF8.GetBytes(this.markertable[hash].ToString());
|
||||
cont.Response.ContentLength64 = buf.Length;
|
||||
cont.Response.OutputStream.Write(buf, 0, buf.Length);
|
||||
Console.WriteLine("200 - " + cont.Request.Url.PathAndQuery);
|
||||
return true;
|
||||
} else if(cont.Request.Url.PathAndQuery.StartsWith("/currenttime")) {
|
||||
} else if(cont.Request.Url.AbsolutePath.StartsWith("/api/time")) {
|
||||
return SendJsonResponse(new Dictionary<String, DateTime>() { { "utc", DateTime.UtcNow } }, cont);
|
||||
} else if(cont.Request.Url.PathAndQuery.StartsWith("/admin")) {
|
||||
} else if(cont.Request.Url.AbsolutePath.StartsWith("/api/svg/")) {
|
||||
return SvgModel.Instance.ParseRequest(cont);
|
||||
} else if(cont.Request.Url.PathAndQuery.StartsWith("/admin/")) {
|
||||
return this.admin.ParseReuqest(cont);
|
||||
} else if(cont.Request.Url.PathAndQuery.StartsWith("/getlayer")) {
|
||||
return SendJsonResponse(this.FindMapLayer(cont.Request), cont);
|
||||
} else if(cont.Request.Url.PathAndQuery.StartsWith("/maps/")) {
|
||||
return SendFileResponse(cont, "resources", false);
|
||||
} else if(cont.Request.Url.PathAndQuery.StartsWith("/getgeo")) {
|
||||
Byte[] buf = Encoding.UTF8.GetBytes(File.ReadAllText("json/geo.json"));
|
||||
cont.Response.ContentLength64 = buf.Length;
|
||||
cont.Response.OutputStream.Write(buf, 0, buf.Length);
|
||||
Console.WriteLine("200 - " + cont.Request.Url.PathAndQuery);
|
||||
return true;
|
||||
} else if(cont.Request.Url.PathAndQuery.StartsWith("/cameracount")) {
|
||||
return SendJsonResponse(this.cameras, cont);
|
||||
} else if (cont.Request.Url.PathAndQuery.StartsWith("/crowdcount")) {
|
||||
return SendJsonResponse(this.crowds, cont);
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
Helper.WriteError("500 - " + e.Message);
|
||||
Helper.WriteError("SendWebserverResponse(): 500 - " + e.Message + "\n\n" + e.StackTrace);
|
||||
cont.Response.StatusCode = 500;
|
||||
return false;
|
||||
}
|
||||
return SendFileResponse(cont);
|
||||
}
|
||||
|
||||
private Dictionary<String, Dictionary<String, Object>> FindMapLayer(HttpListenerRequest request) {
|
||||
Dictionary<String, Dictionary<String, Object>> ret = new Dictionary<String, Dictionary<String, Object>> {
|
||||
{ "online", new Dictionary<String, Object>() {
|
||||
{ "title", "Online Map" },
|
||||
{ "url", "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" },
|
||||
{ "attribution", "© <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors" },
|
||||
{ "minZoom", 1 },
|
||||
{ "maxZoom", 18 }
|
||||
} }
|
||||
};
|
||||
if(Directory.Exists("resources" + Path.DirectorySeparatorChar + "maps")) {
|
||||
String[] dirs = Directory.GetDirectories("resources" + Path.DirectorySeparatorChar + "maps");
|
||||
foreach(String dir in dirs) {
|
||||
if(File.Exists(dir + Path.DirectorySeparatorChar + "tiles.json")) {
|
||||
try {
|
||||
JsonData map = JsonMapper.ToObject(File.ReadAllText(dir + Path.DirectorySeparatorChar + "tiles.json"));
|
||||
Dictionary<String, Object> entry = new Dictionary<String, Object> {
|
||||
{ "title", (String)map["name"] },
|
||||
{ "url", (String)map["tiles"][0] },
|
||||
{ "attribution", (String)map["attribution"] },
|
||||
{ "minZoom", (Int32)map["minzoom"] },
|
||||
{ "maxZoom", (Int32)map["maxzoom"] },
|
||||
{ "bounds", new Dictionary<String, Object>() {
|
||||
{ "corner1", new Double[] { (Double)map["bounds"][0], (Double)map["bounds"][1] } },
|
||||
{ "corner2", new Double[] { (Double)map["bounds"][2], (Double)map["bounds"][3] } }
|
||||
} }
|
||||
};
|
||||
ret.Add(dir.Substring(("resources" + Path.DirectorySeparatorChar + "maps").Length+1), entry);
|
||||
} catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
public override void Dispose() {
|
||||
SensorModel.Instance.Dispose();
|
||||
base.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
[js/map.js]
|
||||
start_location=50.7, 7.2
|
@ -3,7 +3,7 @@ Version: x.x-x
|
||||
Section: base
|
||||
Priority: optional
|
||||
Architecture: any
|
||||
Depends: mono-runtime (>= 5.18), libmono-posix4.0-cil (>= 5.18), libmono-system-web4.0-cil (>= 5.18)
|
||||
Depends: dotnet-runtime-3.0 (>= 3.0.1)
|
||||
Maintainer: BlubbFish <dev@blubbfish.net>
|
||||
Description: Lora-Map
|
||||
Lora-Map shows a Map to control the Lora Tracker
|
||||
|
@ -2,26 +2,35 @@
|
||||
|
||||
HOMEDIR=$HOME
|
||||
ROOT="$HOMEDIR/deb"
|
||||
OUTPUT="../bin/Release"
|
||||
OUTPUT="../bin/Release/netcoreapp3.1"
|
||||
|
||||
EXEC="$ROOT/usr/local/bin/loramap"
|
||||
CONFIG="$ROOT/etc/loramap"
|
||||
DEBNAME="loramap"
|
||||
CSPROJFILE="Lora-Map.csproj"
|
||||
|
||||
EXEC="$ROOT/usr/local/bin/$DEBNAME"
|
||||
CONFIG="$ROOT/etc/$DEBNAME"
|
||||
SYSTEMD="$ROOT/lib/systemd/system"
|
||||
LOGROTATE="$ROOT/etc/logrotate.d"
|
||||
|
||||
echo "Catch all paths together for $DEBNAME."
|
||||
|
||||
DEBIAN="$ROOT/DEBIAN"
|
||||
VMAJOR=$(grep -e "^\[assembly: AssemblyVersion(\"" ../Properties/AssemblyInfo.cs | cut -d'"' -f 2 | cut -d'.' -f 1)
|
||||
VMINOR=$(grep -e "^\[assembly: AssemblyVersion(\"" ../Properties/AssemblyInfo.cs | cut -d'"' -f 2 | cut -d'.' -f 2)
|
||||
VBUILD=$(grep -e "^\[assembly: AssemblyVersion(\"" ../Properties/AssemblyInfo.cs | cut -d'"' -f 2 | cut -d'.' -f 3)
|
||||
VMAJOR=$(grep -e "<Version>" ../$CSPROJFILE | cut -d'>' -f 2 | cut -d'<' -f 1 | cut -d'.' -f 1)
|
||||
VMINOR=$(grep -e "<Version>" ../$CSPROJFILE | cut -d'>' -f 2 | cut -d'<' -f 1 | cut -d'.' -f 2)
|
||||
VBUILD=$(grep -e "<Version>" ../$CSPROJFILE | cut -d'>' -f 2 | cut -d'<' -f 1 | cut -d'.' -f 3)
|
||||
ARCHT=$1
|
||||
|
||||
echo "Versionsumber parsed: $VMAJOR.$VMINOR-$VBUILD."
|
||||
|
||||
mkdir -p $EXEC
|
||||
mkdir -p $CONFIG
|
||||
mkdir -p $DEBIAN
|
||||
mkdir -p $SYSTEMD
|
||||
mkdir -p $LOGROTATE
|
||||
|
||||
cp control $DEBIAN
|
||||
echo "Created directorys."
|
||||
|
||||
cp control $DEBIAN/control
|
||||
cp preinst $DEBIAN
|
||||
cp postinst $DEBIAN
|
||||
cp prerm $DEBIAN
|
||||
@ -29,26 +38,49 @@ sed -i s/Version:\ x\.x-x/"Version: $VMAJOR.$VMINOR-$VBUILD"/ $DEBIAN/control
|
||||
sed -i s/Architecture:\ any/"Architecture: $ARCHT"/ $DEBIAN/control
|
||||
chmod 755 $DEBIAN -R
|
||||
|
||||
cp loramap.service $SYSTEMD
|
||||
chmod 644 $SYSTEMD/loramap.service
|
||||
echo "Copy deb control files."
|
||||
|
||||
cp $OUTPUT/*.exe $EXEC/
|
||||
#cp $OUTPUT/gpio.2.44 $EXEC/
|
||||
#cp $OUTPUT/libwiringPi.so.2.44 $EXEC/
|
||||
cp "service-$DEBNAME" "$SYSTEMD/$DEBNAME.service"
|
||||
chmod 644 $SYSTEMD/"$DEBNAME.service"
|
||||
|
||||
echo "Copy $DEBNAME.service to $SYSTEMD."
|
||||
|
||||
cp $OUTPUT/*.runtimeconfig.json $EXEC/
|
||||
find $OUTPUT -name \*.dll -exec cp {} $EXEC/ \;
|
||||
chmod 644 $EXEC/*
|
||||
chmod 755 $EXEC
|
||||
|
||||
echo "Copy programm files to $EXEC."
|
||||
|
||||
cp $OUTPUT/resources $EXEC -r
|
||||
sed -i s/"<div id=\"version\">vx.x.x"/"<div id=\"version\">$VMAJOR.$VMINOR.$VBUILD"/ $EXEC/resources/index.html
|
||||
|
||||
echo "Change Versionnumber in index.html"
|
||||
|
||||
cp $OUTPUT/config-example/* $CONFIG
|
||||
chmod 644 $CONFIG/*
|
||||
chmod 755 $CONFIG
|
||||
|
||||
cp loramap-logrotate $LOGROTATE/loramap
|
||||
echo "Copy example-conf to $CONFIG."
|
||||
|
||||
cp "logrotate-$DEBNAME" "$LOGROTATE/$DEBNAME.conf"
|
||||
chmod 644 $LOGROTATE/*
|
||||
|
||||
echo "Copy $DEBNAME.conf to $LOGROTATE."
|
||||
|
||||
dpkg-deb --build $ROOT
|
||||
mv $HOMEDIR/deb.deb ../../../Builds/"$ARCHT-loramap_$VMAJOR.$VMINOR-$VBUILD.deb"
|
||||
rm $HOMEDIR/deb -r
|
||||
|
||||
echo "Build deb packet."
|
||||
|
||||
|
||||
TARGETFILE="$DEBNAME""_$VMAJOR.$VMINOR-$VBUILD.deb"
|
||||
mv $HOMEDIR/deb.deb "../../../Builds/$ARCHT-$TARGETFILE"
|
||||
|
||||
echo "Move $ARCHT-$TARGETFILE to Builds."
|
||||
|
||||
rm $HOMEDIR/deb -r
|
||||
|
||||
echo "Remove $HOMEDIR/deb."
|
||||
|
||||
echo "##[set-output name=debuilderfile;]$TARGETFILE"
|
||||
echo "##[set-output name=builddaterelease;]$(date +"%F_%H%M%S")"
|
@ -1,9 +1,17 @@
|
||||
#!/bin/bash
|
||||
|
||||
systemctl enable loramap
|
||||
DEBNAME="loramap"
|
||||
|
||||
systemctl enable $DEBNAME
|
||||
systemctl daemon-reload
|
||||
|
||||
if [ -f /tmp/loramap_service_runner ]; then
|
||||
service loramap start
|
||||
rm /tmp/loramap_service_runner
|
||||
touch /var/log/loramap.log
|
||||
chown loramapbot:loramapbot /var/log/loramap.log
|
||||
chmod 644 /var/log/loramap.log
|
||||
|
||||
chown -R loramapbot:loramapbot /usr/local/bin/$DEBNAME
|
||||
|
||||
if [ -f /tmp/$DEBNAME_service_runner ]; then
|
||||
service $DEBNAME start
|
||||
rm /tmp/$DEBNAME_service_runner
|
||||
fi
|
@ -1,2 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
useradd -M loramapbot
|
||||
usermod -L loramapbot
|
||||
groupadd loramapbot
|
||||
usermod -G loramapbot,adm loramapbot
|
@ -1,7 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ $(systemctl is-active loramap || true) == "active" ]]
|
||||
DEBNAME="loramap"
|
||||
|
||||
if [[ $(systemctl is-active $DEBNAME || true) == "active" ]]
|
||||
then
|
||||
touch /tmp/loramap_service_runner
|
||||
service loramap stop
|
||||
touch /tmp/$DEBNAME_service_runner
|
||||
service $DEBNAME stop
|
||||
fi
|
@ -5,10 +5,12 @@ Description=Lora-Map
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
User=root
|
||||
Group=root
|
||||
User=loramapbot
|
||||
Group=loramapbot
|
||||
WorkingDirectory=/usr/local/bin/loramap
|
||||
ExecStart=/usr/bin/mono /usr/local/bin/loramap/Lora-Map.exe
|
||||
PermissionsStartOnly=true
|
||||
ExecStartPre=setcap 'cap_net_bind_service=+ep' /usr/share/dotnet/dotnet
|
||||
ExecStart=/usr/bin/dotnet /usr/local/bin/loramap/Lora-Map.dll
|
||||
KillMode=control-group
|
||||
TimeoutStopSec=5
|
||||
Restart=on-failure
|
@ -30,54 +30,42 @@
|
||||
margin-left: 210px;
|
||||
border-left: 1px solid black;
|
||||
}
|
||||
#content #nameeditor .title {
|
||||
margin-bottom: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
#content #nameeditor #nametable {
|
||||
|
||||
#content .settingstable {
|
||||
margin-left: 15px;
|
||||
border-collapse: collapse;
|
||||
border-collapse: separate;
|
||||
}
|
||||
#content #nameeditor #nametable thead {
|
||||
#content .settingstable thead {
|
||||
background-color: #CCCCCC;
|
||||
background-color: rgba(0,0,0,0.2);
|
||||
}
|
||||
#content #nameeditor #nametable thead th {
|
||||
#content .settingstable thead th {
|
||||
text-align: left;
|
||||
}
|
||||
#content #nameeditor #nametable thead .rowid {
|
||||
width: 60px;
|
||||
}
|
||||
#content #nameeditor #nametable thead .rowicon {
|
||||
width: 65px;
|
||||
}
|
||||
#content #nameeditor #nametable thead .rowedit {
|
||||
width: 50px;
|
||||
}
|
||||
#content #nameeditor #nametable thead .rowname {
|
||||
width: 250px;
|
||||
}
|
||||
#content #nameeditor #nametable tbody tr:nth-child(odd) {
|
||||
#content .settingstable tbody tr:nth-child(odd) {
|
||||
background-color: #f39d9d;
|
||||
background-color: rgba(20,0,250,0.1);
|
||||
}
|
||||
#content #nameeditor #nametable tbody tr:nth-child(even) {
|
||||
#content .settingstable tbody tr:nth-child(even) {
|
||||
background-color: #9c9eee;
|
||||
background-color: rgba(250,59,0,0.1);
|
||||
}
|
||||
#content #nameeditor #nametable tbody tr:hover {
|
||||
#content .settingstable tbody tr:hover {
|
||||
background-color: #e4e1e1;
|
||||
background-color: rgba(0,0,0,0.1);
|
||||
}
|
||||
#content #nameeditor #nametable tfoot {
|
||||
#content .settingstable tfoot {
|
||||
background-color: #e4e1e1;
|
||||
background-color: rgba(0,0,0,0.1);
|
||||
}
|
||||
#content #nameeditor .pointer {
|
||||
|
||||
#content .pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
#content #nameeditor #nametable tbody .name {
|
||||
width: 55px;
|
||||
|
||||
#content #nameeditor .title {
|
||||
margin-bottom: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#iconeditor {
|
||||
@ -113,4 +101,22 @@
|
||||
#content #eximport .names textarea {
|
||||
height: 120px;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
#content #settingseditor .title {
|
||||
margin-bottom: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#content #settingseditor .startloc,
|
||||
#content #settingseditor .wetterwarnings,
|
||||
#content #settingseditor .savesettings,
|
||||
#content #settingseditor .gridradius {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
#content #settingseditor .fightdedection,
|
||||
#content #settingseditor .crowddensity {
|
||||
margin-left: 15px;
|
||||
margin-top: 20px;
|
||||
}
|
@ -5,17 +5,21 @@
|
||||
<meta charset="utf-8" />
|
||||
<title>Adminpannel Lora-Map</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/global.css" />
|
||||
<script type="text/javascript" src="js/menu.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header">Adminpannel Lora-Map</div>
|
||||
<div id="menu">
|
||||
<ul>
|
||||
<li><a onclick="menu_names(); return false;" href="#">Namen und Icons</a></li>
|
||||
<li><a onclick="menu_overlay(); return false;" href="#">Karteneditor</a></li>
|
||||
<li><a onclick="menu_eximport(); return false;" href="#">Ex- und Import</a></li>
|
||||
<li><a onclick="return AdminMenu.Names();" href="#">Namen und Icons</a></li>
|
||||
<!-- <li><a onclick="return AdminMenu.Overlay();" href="#">Karteneditor</a></li> -->
|
||||
<li><a onclick="return AdminMenu.Settings();" href="#">Einstellungen</a></li>
|
||||
<li><a onclick="return AdminMenu.ExImport();" href="#">Ex- und Import</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="content">Wilkommen im Adminbereich</div>
|
||||
<script type="text/javascript" src="js/adminmenu.js"></script>
|
||||
<script type="text/javascript" src="js/eximport.js"></script>
|
||||
<script type="text/javascript" src="js/nameseditor.js"></script>
|
||||
<script type="text/javascript" src="js/settings.js"></script>
|
||||
</body>
|
||||
</html>
|
42
Lora-Map/resources/admin/js/adminmenu.js
Normal file
@ -0,0 +1,42 @@
|
||||
var AdminMenu = {
|
||||
//public functions
|
||||
ExImport: function () {
|
||||
var ajaxrequest = new XMLHttpRequest();
|
||||
ajaxrequest.onreadystatechange = function () {
|
||||
if (ajaxrequest.readyState === 4 && ajaxrequest.status === 200) {
|
||||
var json = JSON.parse(ajaxrequest.responseText);
|
||||
ExImport.ParseJson(json.name, json.geo, json.setting);
|
||||
}
|
||||
};
|
||||
ajaxrequest.open("GET", "/admin/api/json/name,geo,setting", true);
|
||||
ajaxrequest.send();
|
||||
return false;
|
||||
},
|
||||
Names: function () {
|
||||
var ajaxrequest = new XMLHttpRequest();
|
||||
ajaxrequest.onreadystatechange = function () {
|
||||
if (ajaxrequest.readyState === 4 && ajaxrequest.status === 200) {
|
||||
var json = JSON.parse(ajaxrequest.responseText);
|
||||
NamesEditor.ParseJson(json.name);
|
||||
}
|
||||
};
|
||||
ajaxrequest.open("GET", "/admin/api/json/name", true);
|
||||
ajaxrequest.send();
|
||||
return false;
|
||||
},
|
||||
Overlay: function () {
|
||||
return false;
|
||||
},
|
||||
Settings: function () {
|
||||
var ajaxrequest = new XMLHttpRequest();
|
||||
ajaxrequest.onreadystatechange = function () {
|
||||
if (ajaxrequest.readyState === 4 && ajaxrequest.status === 200) {
|
||||
var json = JSON.parse(ajaxrequest.responseText);
|
||||
Settings.ParseJson(json.setting);
|
||||
}
|
||||
};
|
||||
ajaxrequest.open("GET", "/admin/api/json/setting", true);
|
||||
ajaxrequest.send();
|
||||
return false;
|
||||
}
|
||||
};
|
56
Lora-Map/resources/admin/js/eximport.js
Normal file
@ -0,0 +1,56 @@
|
||||
var ExImport = {
|
||||
//public functions
|
||||
ParseJson: function (jsonnames, jsongeo, jsonsettings) {
|
||||
html = "<div id='eximport'><div class='title'>Ex- und Import der Einstellungen</div>";
|
||||
html += "<div class='names'>names.json (Namen und Icons)<br/><textarea id='ex_names'></textarea> <img src='../icons/general/save.png' onclick='ExImport.SaveNames()' class='pointer'></div>";
|
||||
html += "<div class='names'>geo.json (Layer on the MAP) <a href='https://mapbox.github.io/togeojson/'>Kml Konverter</a><br/><textarea id='ex_geo'></textarea> <img src='../icons/general/save.png' onclick='ExImport.SaveGeo()' class='pointer'></div>";
|
||||
html += "<div class='names'>settings.json (Settings of the Map)<br/><textarea id='ex_settings'></textarea> <img src='../icons/general/save.png' onclick='ExImport.SaveSettings()' class='pointer'></div>";
|
||||
html += "</div>";
|
||||
document.getElementById("content").innerHTML = html;
|
||||
document.getElementById("ex_names").value = JSON.stringify(jsonnames);
|
||||
document.getElementById("ex_geo").value = JSON.stringify(jsongeo);
|
||||
document.getElementById("ex_settings").value = JSON.stringify(jsonsettings);
|
||||
},
|
||||
SaveNames: function () {
|
||||
var savenames = new XMLHttpRequest();
|
||||
savenames.onreadystatechange = function () {
|
||||
if (savenames.readyState === 4) {
|
||||
if (savenames.status === 200) {
|
||||
alert("Änderungen an names.json gespeichert!");
|
||||
} else if (savenames.status === 501) {
|
||||
alert("Ein Fehler ist aufgetreten (invalid JSON)!");
|
||||
}
|
||||
}
|
||||
};
|
||||
savenames.open("PUT", "/admin/api/json/name", true);
|
||||
savenames.send(document.getElementById("ex_names").value);
|
||||
},
|
||||
SaveGeo: function () {
|
||||
var savegeo = new XMLHttpRequest();
|
||||
savegeo.onreadystatechange = function () {
|
||||
if (savegeo.readyState === 4) {
|
||||
if (savegeo.status === 200) {
|
||||
alert("Änderungen an geo.json gespeichert!");
|
||||
} else if (savegeo.status === 501) {
|
||||
alert("Ein Fehler ist aufgetreten (invalid JSON)!");
|
||||
}
|
||||
}
|
||||
};
|
||||
savegeo.open("PUT", "/admin/api/json/geo", true);
|
||||
savegeo.send(document.getElementById("ex_geo").value);
|
||||
},
|
||||
SaveSettings: function () {
|
||||
var savesettings = new XMLHttpRequest();
|
||||
savesettings.onreadystatechange = function () {
|
||||
if (savesettings.readyState === 4) {
|
||||
if (savesettings.status === 200) {
|
||||
alert("Änderungen an settings.json gespeichert!");
|
||||
} else if (savesettings.status === 501) {
|
||||
alert("Ein Fehler ist aufgetreten (invalid JSON)!");
|
||||
}
|
||||
}
|
||||
};
|
||||
savesettings.open("PUT", "/admin/api/json/setting", true);
|
||||
savesettings.send(document.getElementById("ex_settings").value);
|
||||
}
|
||||
};
|
@ -1,109 +1,38 @@
|
||||
function menu_names() {
|
||||
var ajaxnames = new XMLHttpRequest();
|
||||
ajaxnames.onreadystatechange = function() {
|
||||
if(ajaxnames.readyState === 4 && ajaxnames.status === 200) {
|
||||
NamesEditor.ParseJson(ajaxnames.responseText);
|
||||
}
|
||||
};
|
||||
ajaxnames.open("GET", "http://{%REQUEST_URL_HOST%}/admin/get_json_names", true);
|
||||
ajaxnames.send();
|
||||
}
|
||||
|
||||
function menu_overlay() {
|
||||
|
||||
}
|
||||
|
||||
function menu_eximport() {
|
||||
var ajaxnames = new XMLHttpRequest();
|
||||
ajaxnames.onreadystatechange = function () {
|
||||
if (ajaxnames.readyState === 4 && ajaxnames.status === 200) {
|
||||
var ajaxgeo = new XMLHttpRequest();
|
||||
ajaxgeo.onreadystatechange = function () {
|
||||
if (ajaxgeo.readyState === 4 && ajaxgeo.status === 200) {
|
||||
ExImport.ParseJson(ajaxnames.responseText, ajaxgeo.responseText);
|
||||
}
|
||||
};
|
||||
ajaxgeo.open("GET", "http://{%REQUEST_URL_HOST%}/admin/get_json_geo", true);
|
||||
ajaxgeo.send();
|
||||
}
|
||||
};
|
||||
ajaxnames.open("GET", "http://{%REQUEST_URL_HOST%}/admin/get_json_names", true);
|
||||
ajaxnames.send();
|
||||
}
|
||||
|
||||
var NamesEditor = {
|
||||
var NamesEditor = {
|
||||
//public variables
|
||||
iconeditorcounter: 0,
|
||||
ParseJson: function (jsontext) {
|
||||
document.getElementById("content").innerHTML = "";
|
||||
var namesconfig = JSON.parse(jsontext);
|
||||
var html = "<div id='nameeditor'><div class='title'>Namenseinträge in den Einstellungen</div>";
|
||||
html += "<table id='nametable'>";
|
||||
html += "<thead><tr><th class='rowid'>ID</th><th class='rowname'>Name</th><th class='rowicon'>Icon</th><th class='rowedit'></th></tr></thead>";
|
||||
html += "<tbody>";
|
||||
for (var id in namesconfig) {
|
||||
if (namesconfig.hasOwnProperty(id)) {
|
||||
var nameentry = namesconfig[id];
|
||||
html += "<tr>" +
|
||||
"<td>" + id + "</td>" +
|
||||
"<td>" + nameentry["name"] + "</td>";
|
||||
if (nameentry.hasOwnProperty("marker.svg")) {
|
||||
html += "<td>" + this.ParseIcon(nameentry["marker.svg"]) + "</td>";
|
||||
} else if (nameentry.hasOwnProperty("icon")) {
|
||||
html += "<td><img src='"+nameentry["icon"]+"'></td>";
|
||||
} else {
|
||||
html += "<td><img src='../js/leaflet/images/marker-icon.png'></td>";
|
||||
}
|
||||
html += "<td><img src='../icons/general/edit.png' onclick='NamesEditor.Edit(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='NamesEditor.Delete(this.parentNode.parentNode)' class='pointer'></td>" +
|
||||
"</tr>";
|
||||
}
|
||||
}
|
||||
html += "</tbody>";
|
||||
html += "<tfoot><tr><td></td><td></td><td></td><td><img src='../icons/general/add.png' onclick='NamesEditor.Add()' class='pointer'> <img src='../icons/general/save.png' onclick='NamesEditor.Save()' class='pointer'></td></tr></tfoot>";
|
||||
html += "</table>";
|
||||
document.getElementById("content").innerHTML = html + "</div>";
|
||||
filterGropus: { no: "immer Sichtbar", fw: "Feuerwehr", sani: "Sanitäter", pol: "Polizei", oa: "Ordnungsamt", si: "Sicherheitsdienst", thw: "Technisches Hilfswerk", crew: "Veranstalter", dev: "Entwickler" },
|
||||
//public functions
|
||||
Abort: function (el) {
|
||||
el.parentNode.removeChild(el);
|
||||
},
|
||||
ParseIcon: function (markerobj) {
|
||||
var url = "../icons/marker/Marker.svg";
|
||||
if (markerobj.hasOwnProperty("person")) {
|
||||
url += "?icon=person&marker-bg=hidden";
|
||||
if (markerobj["person"].hasOwnProperty("org")) {
|
||||
url += "&person-org=" + markerobj["person"]["org"];
|
||||
}
|
||||
if(markerobj["person"].hasOwnProperty("funct")) {
|
||||
url += "&person-funct=" + markerobj["person"]["funct"];
|
||||
}
|
||||
if(markerobj["person"].hasOwnProperty("rang")) {
|
||||
url += "&person-rang=" + markerobj["person"]["rang"];
|
||||
}
|
||||
if(markerobj["person"].hasOwnProperty("text")) {
|
||||
url += "&person-text=" + markerobj["person"]["text"];
|
||||
}
|
||||
if (markerobj["person"].hasOwnProperty("typ") && Array.isArray(markerobj["person"]["typ"])) {
|
||||
for (i in markerobj["person"]["typ"]) {
|
||||
url += "&person-typ=" + markerobj["person"]["typ"][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return "<object data='"+url+"' type='image/svg+xml' style='height:50px; width:50px;'></object>";
|
||||
Add: function () {
|
||||
var newrow = document.createElement("tr");
|
||||
newrow.innerHTML = "<td><input style='width: 55px;'/></td>";
|
||||
newrow.innerHTML += "<td><input style='width: 245px;'/></td>";
|
||||
newrow.innerHTML += "<td><img src='../icons/general/icon_edit.png' onclick='NamesEditor.IconEditor(this.parentNode)' class='pointer'> wähle Icon</td>";
|
||||
newrow.innerHTML += "<td>" + this.CreateSelectBox("", "item", { item: "" }, this.filterGropus, null, null, true);
|
||||
newrow.innerHTML += "<td><img src='../icons/general/save.png' onclick='NamesEditor.SaveRow(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='NamesEditor.Abort(this.parentNode.parentNode)' class='pointer'></td>";
|
||||
document.getElementById("nametable").children[1].appendChild(newrow);
|
||||
},
|
||||
BuildIconJson: function (url) {
|
||||
var query = this.SplitQueryIntoObject(this.SplitUrlIntoParts(url).query);
|
||||
var markerobj = {};
|
||||
if (query.hasOwnProperty("icon") && query["icon"] === "person") {
|
||||
if (Object.prototype.hasOwnProperty.call(query, "icon") && query["icon"] === "person") {
|
||||
markerobj["person"] = {};
|
||||
if (query.hasOwnProperty("person-org")) {
|
||||
if (Object.prototype.hasOwnProperty.call(query, "person-org")) {
|
||||
markerobj["person"]["org"] = query["person-org"];
|
||||
}
|
||||
if (query.hasOwnProperty("person-funct")) {
|
||||
if (Object.prototype.hasOwnProperty.call(query, "person-funct")) {
|
||||
markerobj["person"]["funct"] = query["person-funct"];
|
||||
}
|
||||
if (query.hasOwnProperty("person-rang")) {
|
||||
if (Object.prototype.hasOwnProperty.call(query, "person-rang")) {
|
||||
markerobj["person"]["rang"] = query["person-rang"];
|
||||
}
|
||||
if (query.hasOwnProperty("person-text")) {
|
||||
if (Object.prototype.hasOwnProperty.call(query, "person-text")) {
|
||||
markerobj["person"]["text"] = query["person-text"];
|
||||
}
|
||||
if (query.hasOwnProperty("person-typ")) {
|
||||
if (Object.prototype.hasOwnProperty.call(query, "person-typ")) {
|
||||
if (Array.isArray(query["person-typ"])) {
|
||||
markerobj["person"]["typ"] = new Array();
|
||||
for (var i in query["person-typ"]) {
|
||||
@ -117,186 +46,6 @@ var NamesEditor = {
|
||||
}
|
||||
return markerobj;
|
||||
},
|
||||
Add: function () {
|
||||
var newrow = document.createElement("tr");
|
||||
newrow.innerHTML = "<td><input class='name'/></td>";
|
||||
newrow.innerHTML += "<td><input /></td>";
|
||||
newrow.innerHTML += "<td><img src='../icons/general/icon_edit.png' onclick='NamesEditor.IconEditor(this.parentNode)' class='pointer'> wähle Icon</td>";
|
||||
newrow.innerHTML += "<td><img src='../icons/general/save.png' onclick='NamesEditor.SaveRow(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='NamesEditor.Abort(this.parentNode.parentNode)' class='pointer'></td>";
|
||||
document.getElementById("nametable").children[1].appendChild(newrow);
|
||||
},
|
||||
Save: function () {
|
||||
var rows = document.getElementById("nametable").children[1].children;
|
||||
var namejson = {};
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
if (rows[i].children[0].children.length === 1) {
|
||||
alert("Bitte zuerst alle Zeilen speichern oder Löschen!");
|
||||
return;
|
||||
}
|
||||
var id = rows[i].children[0].innerText;
|
||||
var name = rows[i].children[1].innerText;
|
||||
namejson[id] = { "name": name };
|
||||
if (rows[i].children[2].children[0].hasAttribute("data")) {
|
||||
namejson[id]["marker.svg"] = this.BuildIconJson(rows[i].children[2].children[0].data);
|
||||
}
|
||||
}
|
||||
var savenames = new XMLHttpRequest();
|
||||
savenames.onreadystatechange = function () {
|
||||
if (savenames.readyState === 4) {
|
||||
if (savenames.status === 200) {
|
||||
alert("Änderungen gespeichert!");
|
||||
} else if (savenames.status === 501) {
|
||||
alert("Ein Fehler ist aufgetreten (invalid JSON)!");
|
||||
}
|
||||
}
|
||||
};
|
||||
savenames.open("POST", "http://{%REQUEST_URL_HOST%}/admin/set_json_names", true);
|
||||
savenames.send(JSON.stringify(namejson));
|
||||
},
|
||||
Delete: function (el) {
|
||||
var name = el.firstChild.innerHTML;
|
||||
var answ = window.prompt("Wollen sie den Eintrag für \"" + name + "\" wirklich löschen?", "");
|
||||
if (answ !== null) {
|
||||
el.parentNode.removeChild(el);
|
||||
}
|
||||
},
|
||||
Edit: function (el) {
|
||||
var id = el.children[0].innerText;
|
||||
var name = el.children[1].innerText;
|
||||
var url = null;
|
||||
if (el.children[2].children[0].hasAttribute("data")) {
|
||||
url = el.children[2].children[0].data;
|
||||
}
|
||||
el.innerHTML = "<td><input class='name' value='" + id + "'/></td>";
|
||||
el.innerHTML += "<td><input value='" + name + "'/></td>";
|
||||
if (url === null) {
|
||||
el.innerHTML += "<td><img src='../icons/general/icon_edit.png' onclick='NamesEditor.IconEditor(this.parentNode)' class='pointer'> wähle Icon</td>";
|
||||
} else {
|
||||
el.innerHTML += "<td><img src='../icons/general/icon_edit.png' onclick='NamesEditor.IconEditor(this.parentNode)' class='pointer'> <object data='" + url + "' type='image/svg+xml' style='height:50px; width:50px;'></object></td>";
|
||||
}
|
||||
el.innerHTML += "<td><img src='../icons/general/save.png' onclick='NamesEditor.SaveRow(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='NamesEditor.Abort(this.parentNode.parentNode)' class='pointer'></td>";
|
||||
},
|
||||
Abort: function (el) {
|
||||
el.parentNode.removeChild(el);
|
||||
},
|
||||
SaveRow: function (el) {
|
||||
var id = el.children[0].children[0].value;
|
||||
var name = el.children[1].children[0].value;
|
||||
var url = null;
|
||||
if (el.children[2].children.length === 2) {
|
||||
url = el.children[2].children[1].data;
|
||||
}
|
||||
el.innerHTML = "<td>" + id + "</td>" +
|
||||
"<td>" + name + "</td>";
|
||||
if (url === null) {
|
||||
el.innerHTML += "<td><img src='../js/leaflet/images/marker-icon.png'></td>";
|
||||
} else {
|
||||
el.innerHTML += "<td><object data='" + url +"' type='image/svg+xml' style='height:50px; width:50px;'></object></td>";
|
||||
}
|
||||
el.innerHTML += "<td><img src='../icons/general/edit.png' onclick='NamesEditor.Edit(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='NamesEditor.Delete(this.parentNode.parentNode)' class='pointer'></td>";
|
||||
},
|
||||
IconEditor: function (el) {
|
||||
var url = "../icons/marker/Marker.svg?marker-bg=hidden";
|
||||
el.id = "icon_edit_" + this.iconeditorcounter++;
|
||||
if (el.children.length === 2) {
|
||||
url = el.children[1].data;
|
||||
}
|
||||
var query = this.SplitQueryIntoObject(this.SplitUrlIntoParts(url).query);
|
||||
var ie = document.createElement("div");
|
||||
ie.id = "iconeditor";
|
||||
ie.innerHTML = "<div class='innerbox'>" +
|
||||
"<div class='preview'><object id='markerprev' data='" + url + "' type='image/svg+xml' style='height:200px; width:200px;'></object></div>" +
|
||||
"<div class='controls'>" +
|
||||
this.CreateSelectBox("Typ", "icon", query, { "person": "Person" }, null, "iconeditor-type-") + "<br>" +
|
||||
"<div id='iconeditor-type-person' style='display: " + (query.hasOwnProperty("icon") && query["icon"] === "person" ? "block" : "none") + ";'>" +
|
||||
this.CreateSelectBox("Organisation", "person-org", query, { "fw": "Feuerwehr", "thw": "Technisches Hilfswerk", "hilo": "Hilfsorganisationen, Bundeswehr", "fueh": "Einrichtungen der Führung", "pol": "Polizei, Bundespolizei, Zoll", "sonst": "Sonstige Einrichtungen der Gefahrenabwehr" }) + "<br>" +
|
||||
this.CreateSelectBox("Funktion", "person-funct", query, { "sonder": "Sonder", "fueh": "Führung" }) + "<br>" +
|
||||
this.CreateSelectBox("Rang", "person-rang", query, { "trupp": "Trupp", "grupp": "Gruppe", "zug":"Zug" }) + "<br>" +
|
||||
"Text: <input onchange='NamesEditor.ChangeLinkPreview(\"person-text\",this.value);' value='" + (query.hasOwnProperty("person-text") ? query["person-text"] : "") + "'><br>" +
|
||||
this.CreateSelectBox("Typ", "person-typ", query, { "loesch": "Brandbekämpfung/Löscheinsatz", "sani": "Rettungswesen, Sanitätswesen, Gesundheitswesen", "betreu": "Betreuung" }, true) + "<br>" +
|
||||
"</div>" +
|
||||
"</div>" +
|
||||
"<div class='save'><button onclick='NamesEditor.SaveIconEditor(\"" + el.id + "\"); '>Schließen</botton></div>" +
|
||||
"</div>";
|
||||
document.getElementsByTagName("body")[0].appendChild(ie);
|
||||
},
|
||||
CreateSelectBox: function (title, key, query, options, muliple, group) {
|
||||
var html = title + ": ";
|
||||
var eventtext = "NamesEditor.ChangeLinkPreview(\"" + key + "\",this.selectedOptions);";
|
||||
if (typeof group !== "undefined") {
|
||||
eventtext += " document.getElementById(\"" + group + "\"+this.value).style.display = \"block\";'";
|
||||
}
|
||||
html += "<select onchange='" + eventtext + "'" + (typeof muliple !== "undefined" && muliple !== null ? " multiple" : "") + ">";
|
||||
if (typeof muliple === "undefined" || muliple === null) {
|
||||
html += "<option>---</option>";
|
||||
}
|
||||
for (var value in options) {
|
||||
if (query.hasOwnProperty(key) && query[key] === value) {
|
||||
html += "<option value='" + value + "' selected>" + options[value] + "</option>";
|
||||
} else if (query.hasOwnProperty(key) && Array.isArray(query[key])) {
|
||||
var notinqueryarray = true;
|
||||
for (var i in query[key]) {
|
||||
if (query[key][i] === value) {
|
||||
notinqueryarray = false;
|
||||
html += "<option value='" + value + "' selected>" + options[value] + "</option>";
|
||||
}
|
||||
}
|
||||
if (notinqueryarray) {
|
||||
html += "<option value='" + value + "'>" + options[value] + "</option>";
|
||||
}
|
||||
} else {
|
||||
html += "<option value='" + value + "'>" + options[value] + "</option>";
|
||||
}
|
||||
}
|
||||
html += "</select>";
|
||||
return html;
|
||||
},
|
||||
SaveIconEditor: function (id) {
|
||||
var cell = document.getElementById(id);
|
||||
cell.innerHTML = "<img src='../icons/general/icon_edit.png' onclick='NamesEditor.IconEditor(this.parentNode)' class='pointer'> <object data='" + document.getElementById("markerprev").data + "' type='image/svg+xml' style='height:50px; width:50px;'></object>";
|
||||
cell.removeAttribute("id");
|
||||
document.getElementById("iconeditor").remove();
|
||||
},
|
||||
SplitQueryIntoObject: function (query) {
|
||||
if (query.indexOf("?") !== -1) {
|
||||
query = query.split("?")[1];
|
||||
}
|
||||
var queryobj = {};
|
||||
var pairs = query.split("&");
|
||||
for (var i = 0; i < pairs.length; i++) {
|
||||
var pair = pairs[i].split("=");
|
||||
if (queryobj.hasOwnProperty(decodeURIComponent(pair[0]))) {
|
||||
if (Array.isArray(queryobj[decodeURIComponent(pair[0])])) {
|
||||
queryobj[decodeURIComponent(pair[0])].push(decodeURIComponent(pair[1] || ""));
|
||||
} else {
|
||||
var tmp = queryobj[decodeURIComponent(pair[0])];
|
||||
queryobj[decodeURIComponent(pair[0])] = new Array();
|
||||
queryobj[decodeURIComponent(pair[0])].push(tmp);
|
||||
queryobj[decodeURIComponent(pair[0])].push(decodeURIComponent(pair[1] || ""));
|
||||
}
|
||||
} else {
|
||||
queryobj[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || "");
|
||||
}
|
||||
}
|
||||
return queryobj;
|
||||
},
|
||||
JoinObjectIntoQuery: function (queryobj) {
|
||||
var query = new Array();
|
||||
for (var id in queryobj) {
|
||||
if (Array.isArray(queryobj[id])) {
|
||||
for (var i in queryobj[id]) {
|
||||
query.push(encodeURIComponent(id) + "=" + encodeURIComponent(queryobj[id][i]));
|
||||
}
|
||||
} else {
|
||||
query.push(encodeURIComponent(id) + "=" + encodeURIComponent(queryobj[id]));
|
||||
}
|
||||
}
|
||||
return query.join("&");
|
||||
},
|
||||
SplitUrlIntoParts: function (url) {
|
||||
var parts = url.split("?");
|
||||
return { "file": parts[0], "query": parts[1] || "" };
|
||||
},
|
||||
ChangeLinkPreview: function (key, val) {
|
||||
var cur = this.SplitUrlIntoParts(document.getElementById("markerprev").data);
|
||||
var query = this.SplitQueryIntoObject(cur.query);
|
||||
@ -317,45 +66,239 @@ var NamesEditor = {
|
||||
}
|
||||
}
|
||||
document.getElementById("markerprev").data = cur.file + "?" + this.JoinObjectIntoQuery(query);
|
||||
}
|
||||
};
|
||||
|
||||
var ExImport = {
|
||||
ParseJson: function (jsonnames, jsongeo) {
|
||||
html = "<div id='eximport'><div class='title'>Ex- und Import der Einstellungen</div>";
|
||||
html += "<div class='names'>names.json (Namen und Icons)<br/><textarea id='ex_names'></textarea> <img src='../icons/general/save.png' onclick='ExImport.SaveNames()' class='pointer'></div>";
|
||||
html += "<div class='names'>geo.json (Layer on the MAP) <a href='https://mapbox.github.io/togeojson/'>Kml Konverter</a><br/><textarea id='ex_geo'></textarea> <img src='../icons/general/save.png' onclick='ExImport.SaveGeo()' class='pointer'></div>";
|
||||
html += "</div>";
|
||||
document.getElementById("content").innerHTML = html;
|
||||
document.getElementById("ex_names").value = jsonnames;
|
||||
document.getElementById("ex_geo").value = jsongeo;
|
||||
},
|
||||
SaveNames: function () {
|
||||
CreateSelectBox: function (title, key, query, options, muliple, group, noonchange) {
|
||||
var html = title !== "" ? title + ": " : "";
|
||||
var onchange = "";
|
||||
if (!(typeof noonchange !== "undefined" && noonchange === true)) {
|
||||
var eventtext = "NamesEditor.ChangeLinkPreview(\"" + key + "\",this.selectedOptions);";
|
||||
if (typeof group !== "undefined" && group !== null) {
|
||||
eventtext += " document.getElementById(\"" + group + "\"+this.value).style.display = \"block\";'";
|
||||
}
|
||||
onchange = " onchange='" + eventtext + "'";
|
||||
}
|
||||
html += "<select" + onchange + (typeof muliple !== "undefined" && muliple !== null ? " multiple" : "") + ">";
|
||||
if (typeof muliple === "undefined" || muliple === null) {
|
||||
html += "<option>---</option>";
|
||||
}
|
||||
for (var value in options) {
|
||||
if (Object.prototype.hasOwnProperty.call(query, key) && query[key] === value) {
|
||||
html += "<option value='" + value + "' selected>" + options[value] + "</option>";
|
||||
} else if (Object.prototype.hasOwnProperty.call(query, key) && Array.isArray(query[key])) {
|
||||
var notinqueryarray = true;
|
||||
for (var i in query[key]) {
|
||||
if (query[key][i] === value) {
|
||||
notinqueryarray = false;
|
||||
html += "<option value='" + value + "' selected>" + options[value] + "</option>";
|
||||
}
|
||||
}
|
||||
if (notinqueryarray) {
|
||||
html += "<option value='" + value + "'>" + options[value] + "</option>";
|
||||
}
|
||||
} else {
|
||||
html += "<option value='" + value + "'>" + options[value] + "</option>";
|
||||
}
|
||||
}
|
||||
html += "</select>";
|
||||
return html;
|
||||
},
|
||||
Delete: function (el) {
|
||||
var name = el.firstChild.innerHTML;
|
||||
var answ = window.prompt("Wollen sie den Eintrag für \"" + name + "\" wirklich löschen?", "");
|
||||
if (answ !== null) {
|
||||
el.parentNode.removeChild(el);
|
||||
}
|
||||
},
|
||||
Edit: function (el) {
|
||||
var id = el.children[0].innerText;
|
||||
var name = el.children[1].innerText;
|
||||
var url = null;
|
||||
var gfilter = el.children[3].attributes.rel.nodeValue;
|
||||
if (el.children[2].children[0].hasAttribute("data")) {
|
||||
url = el.children[2].children[0].data;
|
||||
}
|
||||
el.innerHTML = "<td><input style='width: 55px;' value='" + id + "'/></td>";
|
||||
el.innerHTML += "<td><input style='width: 245px;' value='" + name + "'/></td>";
|
||||
if (url === null) {
|
||||
el.innerHTML += "<td><img src='../icons/general/icon_edit.png' onclick='NamesEditor.IconEditor(this.parentNode)' class='pointer'> wähle Icon</td>";
|
||||
} else {
|
||||
el.innerHTML += "<td><img src='../icons/general/icon_edit.png' onclick='NamesEditor.IconEditor(this.parentNode)' class='pointer'> <object data='" + url + "' type='image/svg+xml' style='height:50px; width:50px;'></object></td>";
|
||||
}
|
||||
el.innerHTML += "<td>" + this.CreateSelectBox("", "item", { item: gfilter }, this.filterGropus, null, null, true);
|
||||
el.innerHTML += "<td><img src='../icons/general/save.png' onclick='NamesEditor.SaveRow(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='NamesEditor.Abort(this.parentNode.parentNode)' class='pointer'></td>";
|
||||
},
|
||||
IconEditor: function (el) {
|
||||
var url = "../api/svg/person.svg?";
|
||||
el.id = "icon_edit_" + this.iconeditorcounter++;
|
||||
if (el.children.length === 2) {
|
||||
url = el.children[1].data;
|
||||
}
|
||||
var query = this.SplitQueryIntoObject(this.SplitUrlIntoParts(url).query);
|
||||
var ie = document.createElement("div");
|
||||
ie.id = "iconeditor";
|
||||
ie.innerHTML = "<div class='innerbox'>" +
|
||||
"<div class='preview'><object id='markerprev' data='" + url + "' type='image/svg+xml' style='height:200px; width:200px;'></object></div>" +
|
||||
"<div class='controls'>" +
|
||||
this.CreateSelectBox("Typ", "icon", query, { "person": "Person" }, null, "iconeditor-type-") + "<br>" +
|
||||
"<div id='iconeditor-type-person' style='display: " + (Object.prototype.hasOwnProperty.call(query, "icon") && query["icon"] === "person" ? "block" : "none") + ";'>" +
|
||||
this.CreateSelectBox("Organisation", "person-org", query, { "fw": "Feuerwehr", "thw": "Technisches Hilfswerk", "hilo": "Hilfsorganisationen, Bundeswehr", "fueh": "Einrichtungen der Führung", "pol": "Polizei, Bundespolizei, Zoll", "sonst": "Sonstige Einrichtungen der Gefahrenabwehr" }) + "<br>" +
|
||||
this.CreateSelectBox("Funktion", "person-funct", query, { "sonder": "Sonder", "fueh": "Führung" }) + "<br>" +
|
||||
this.CreateSelectBox("Rang", "person-rang", query, { "trupp": "Trupp", "grupp": "Gruppe", "zug": "Zug" }) + "<br>" +
|
||||
"Text: <input onchange='NamesEditor.ChangeLinkPreview(\"person-text\",this.value);' value='" + (Object.prototype.hasOwnProperty.call(query, "person-text") ? query["person-text"] : "") + "'><br>" +
|
||||
this.CreateSelectBox("Typ", "person-typ", query, { "loesch": "Brandbekämpfung/Löscheinsatz", "sani": "Rettungswesen, Sanitätswesen, Gesundheitswesen", "betreu": "Betreuung" }, true) + "<br>" +
|
||||
"</div>" +
|
||||
"</div>" +
|
||||
"<div class='save'><button onclick='NamesEditor.SaveIconEditor(\"" + el.id + "\"); '>Schließen</botton></div>" +
|
||||
"</div>";
|
||||
document.getElementsByTagName("body")[0].appendChild(ie);
|
||||
},
|
||||
JoinObjectIntoQuery: function (queryobj) {
|
||||
var query = new Array();
|
||||
for (var id in queryobj) {
|
||||
if (Array.isArray(queryobj[id])) {
|
||||
for (var i in queryobj[id]) {
|
||||
query.push(encodeURIComponent(id) + "=" + encodeURIComponent(queryobj[id][i]));
|
||||
}
|
||||
} else {
|
||||
query.push(encodeURIComponent(id) + "=" + encodeURIComponent(queryobj[id]));
|
||||
}
|
||||
}
|
||||
return query.join("&");
|
||||
},
|
||||
ParseIcon: function (markerobj) {
|
||||
var url = "../api/svg/person.svg";
|
||||
if (Object.prototype.hasOwnProperty.call(markerobj, "person")) {
|
||||
url += "?icon=person";
|
||||
if (Object.prototype.hasOwnProperty.call(markerobj["person"], "org")) {
|
||||
url += "&person-org=" + markerobj["person"]["org"];
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(markerobj["person"], "funct")) {
|
||||
url += "&person-funct=" + markerobj["person"]["funct"];
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(markerobj["person"], "rang")) {
|
||||
url += "&person-rang=" + markerobj["person"]["rang"];
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(markerobj["person"], "text")) {
|
||||
url += "&person-text=" + markerobj["person"]["text"];
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(markerobj["person"], "typ") && Array.isArray(markerobj["person"]["typ"])) {
|
||||
for (i in markerobj["person"]["typ"]) {
|
||||
url += "&person-typ=" + markerobj["person"]["typ"][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return "<object data='" + url + "' type='image/svg+xml' style='height:50px; width:50px;'></object>";
|
||||
},
|
||||
ParseJson: function (namesconfig) {
|
||||
document.getElementById("content").innerHTML = "";
|
||||
var html = "<div id='nameeditor'><div class='title'>Namenseinträge in den Einstellungen</div>";
|
||||
html += "<table id='nametable' class='settingstable'>";
|
||||
html += "<thead><tr><th width='60'>ID</th><th width='250'>Name</th><th width='65'>Icon</th><th width='150'>Filter Gruppe</th><th width='50'></th></tr></thead>";
|
||||
html += "<tbody>";
|
||||
for (var id in namesconfig) {
|
||||
if (Object.prototype.hasOwnProperty.call(namesconfig, id)) {
|
||||
var nameentry = namesconfig[id];
|
||||
html += "<tr>" +
|
||||
"<td>" + id + "</td>" +
|
||||
"<td>" + nameentry["name"] + "</td>";
|
||||
if (Object.prototype.hasOwnProperty.call(nameentry, "marker.svg")) {
|
||||
html += "<td>" + this.ParseIcon(nameentry["marker.svg"]) + "</td>";
|
||||
} else if (Object.prototype.hasOwnProperty.call(nameentry, "icon")) {
|
||||
html += "<td><img src='" + nameentry["icon"] + "'></td>";
|
||||
} else {
|
||||
html += "<td><img src='../js/leaflet/images/marker-icon.png'></td>";
|
||||
}
|
||||
var gfilter = typeof nameentry.Group === "undefined" ? "no" : nameentry.Group;
|
||||
html += "<td rel='" + gfilter + "'>" + this.filterGropus[gfilter] + "</td>";
|
||||
html += "<td><img src='../icons/general/edit.png' onclick='NamesEditor.Edit(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='NamesEditor.Delete(this.parentNode.parentNode)' class='pointer'></td>" +
|
||||
"</tr>";
|
||||
}
|
||||
}
|
||||
html += "</tbody>";
|
||||
html += "<tfoot><tr><td></td><td></td><td></td><td></td><td><img src='../icons/general/add.png' onclick='NamesEditor.Add()' class='pointer'> <img src='../icons/general/save.png' onclick='NamesEditor.Save()' class='pointer'></td></tr></tfoot>";
|
||||
html += "</table>";
|
||||
document.getElementById("content").innerHTML = html + "</div>";
|
||||
},
|
||||
Save: function () {
|
||||
var rows = document.getElementById("nametable").children[1].children;
|
||||
var namejson = {};
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
if (rows[i].children[0].children.length === 1) {
|
||||
alert("Bitte zuerst alle Zeilen speichern oder Löschen!");
|
||||
return;
|
||||
}
|
||||
var id = rows[i].children[0].innerText;
|
||||
var name = rows[i].children[1].innerText;
|
||||
namejson[id] = { "name": name, "Group": rows[i].children[3].attributes.rel.nodeValue };
|
||||
if (rows[i].children[2].children[0].hasAttribute("data")) {
|
||||
namejson[id]["marker.svg"] = this.BuildIconJson(rows[i].children[2].children[0].data);
|
||||
}
|
||||
}
|
||||
var savenames = new XMLHttpRequest();
|
||||
savenames.onreadystatechange = function () {
|
||||
if (savenames.readyState === 4) {
|
||||
if (savenames.status === 200) {
|
||||
alert("Änderungen an names.json gespeichert!");
|
||||
alert("Änderungen gespeichert!");
|
||||
} else if (savenames.status === 501) {
|
||||
alert("Ein Fehler ist aufgetreten (invalid JSON)!");
|
||||
}
|
||||
}
|
||||
};
|
||||
savenames.open("POST", "http://{%REQUEST_URL_HOST%}/admin/set_json_names", true);
|
||||
savenames.send(document.getElementById("ex_names").value);
|
||||
savenames.open("PUT", "/admin/api/json/name", true);
|
||||
savenames.send(JSON.stringify(namejson));
|
||||
},
|
||||
SaveGeo: function () {
|
||||
var savegeo = new XMLHttpRequest();
|
||||
savegeo.onreadystatechange = function () {
|
||||
if (savegeo.readyState === 4) {
|
||||
if (savegeo.status === 200) {
|
||||
alert("Änderungen an geo.json gespeichert!");
|
||||
} else if (savegeo.status === 501) {
|
||||
alert("Ein Fehler ist aufgetreten (invalid JSON)!");
|
||||
SaveIconEditor: function (id) {
|
||||
var cell = document.getElementById(id);
|
||||
cell.innerHTML = "<img src='../icons/general/icon_edit.png' onclick='NamesEditor.IconEditor(this.parentNode)' class='pointer'> <object data='" + document.getElementById("markerprev").data + "' type='image/svg+xml' style='height:50px; width:50px;'></object>";
|
||||
cell.removeAttribute("id");
|
||||
document.getElementById("iconeditor").remove();
|
||||
},
|
||||
SaveRow: function (el) {
|
||||
var id = el.children[0].children[0].value;
|
||||
var name = el.children[1].children[0].value;
|
||||
var url = null;
|
||||
var gfilter = el.children[3].children[0].selectedOptions[0].value;
|
||||
if (gfilter === "---") {
|
||||
gfilter = "no";
|
||||
}
|
||||
if (el.children[2].children.length === 2) {
|
||||
url = el.children[2].children[1].data;
|
||||
}
|
||||
el.innerHTML = "<td>" + id + "</td>" +
|
||||
"<td>" + name + "</td>";
|
||||
if (url === null) {
|
||||
el.innerHTML += "<td><img src='../js/leaflet/images/marker-icon.png'></td>";
|
||||
} else {
|
||||
el.innerHTML += "<td><object data='" + url + "' type='image/svg+xml' style='height:50px; width:50px;'></object></td>";
|
||||
}
|
||||
el.innerHTML += "<td rel='" + gfilter + "'>" + this.filterGropus[gfilter] + "</td>";
|
||||
el.innerHTML += "<td><img src='../icons/general/edit.png' onclick='NamesEditor.Edit(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='NamesEditor.Delete(this.parentNode.parentNode)' class='pointer'></td>";
|
||||
},
|
||||
SplitQueryIntoObject: function (query) {
|
||||
if (query.indexOf("?") !== -1) {
|
||||
query = query.split("?")[1];
|
||||
}
|
||||
var queryobj = {};
|
||||
var pairs = query.split("&");
|
||||
for (var i = 0; i < pairs.length; i++) {
|
||||
var pair = pairs[i].split("=");
|
||||
if (Object.prototype.hasOwnProperty.call(queryobj, decodeURIComponent(pair[0]))) {
|
||||
if (Array.isArray(queryobj[decodeURIComponent(pair[0])])) {
|
||||
queryobj[decodeURIComponent(pair[0])].push(decodeURIComponent(pair[1] || ""));
|
||||
} else {
|
||||
var tmp = queryobj[decodeURIComponent(pair[0])];
|
||||
queryobj[decodeURIComponent(pair[0])] = new Array();
|
||||
queryobj[decodeURIComponent(pair[0])].push(tmp);
|
||||
queryobj[decodeURIComponent(pair[0])].push(decodeURIComponent(pair[1] || ""));
|
||||
}
|
||||
} else {
|
||||
queryobj[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || "");
|
||||
}
|
||||
};
|
||||
savegeo.open("POST", "http://{%REQUEST_URL_HOST%}/admin/set_json_geo", true);
|
||||
savegeo.send(document.getElementById("ex_geo").value);
|
||||
}
|
||||
return queryobj;
|
||||
},
|
||||
SplitUrlIntoParts: function (url) {
|
||||
var parts = url.split("?");
|
||||
return { "file": parts[0], "query": parts[1] || "" };
|
||||
}
|
||||
};
|
330
Lora-Map/resources/admin/js/settings.js
Normal file
@ -0,0 +1,330 @@
|
||||
var Settings = {
|
||||
//public functions
|
||||
Abort: function (el) {
|
||||
el.parentNode.removeChild(el);
|
||||
},
|
||||
AddDensity: function () {
|
||||
var newrow = document.createElement("tr");
|
||||
newrow.innerHTML = "<td><input style='width: 145px;'/></td>";
|
||||
newrow.innerHTML += "<td><input style='width: 195px;'/></td>";
|
||||
newrow.innerHTML += "<td><textarea style='width: 240px;height: 60px;'></textarea></td>";
|
||||
newrow.innerHTML += "<td><input style='width: 145px;'/></td>";
|
||||
newrow.innerHTML += "<td><img src='../icons/general/save.png' onclick='Settings.SaveRowdensity(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='Settings.Abort(this.parentNode.parentNode)' class='pointer'></td>";
|
||||
document.getElementById("crowdtable").children[1].appendChild(newrow);
|
||||
},
|
||||
AddFight: function () {
|
||||
var newrow = document.createElement("tr");
|
||||
newrow.innerHTML = "<td><input style='width: 145px;'/></td>";
|
||||
newrow.innerHTML += "<td><textarea style='width: 240px;height: 60px;'></textarea></td>";
|
||||
newrow.innerHTML += "<td><input style='width: 145px;'/></td>";
|
||||
newrow.innerHTML += "<td><input style='width: 145px;'/></td>";
|
||||
newrow.innerHTML += "<td><img src='../icons/general/save.png' onclick='Settings.SaveRowfight(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='Settings.Abort(this.parentNode.parentNode)' class='pointer'></td>";
|
||||
document.getElementById("fighttable").children[1].appendChild(newrow);
|
||||
},
|
||||
AddSensor: function () {
|
||||
var newrow = document.createElement("tr");
|
||||
newrow.innerHTML = "<td><input style='width: 145px;'/></td>";
|
||||
newrow.innerHTML += "<td><input style='width: 145px;'/></td>";
|
||||
newrow.innerHTML += "<td><input style='width: 250px;'/></td>";
|
||||
newrow.innerHTML += "<td><input style='width: 145px;'/></td>";
|
||||
newrow.innerHTML += "<td><img src='../icons/general/save.png' onclick='Settings.SaveRowSensor(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='Settings.Abort(this.parentNode.parentNode)' class='pointer'></td>";
|
||||
document.getElementById("sensortable").children[1].appendChild(newrow);
|
||||
},
|
||||
Delete: function (el) {
|
||||
var answ = window.prompt("Wollen sie den Eintrag für \"" + el.firstChild.innerHTML + "\" wirklich löschen?", "");
|
||||
if (answ !== null) {
|
||||
el.parentNode.removeChild(el);
|
||||
}
|
||||
},
|
||||
EditDensity: function (el) {
|
||||
el.innerHTML = "<td><input style='width: 145px;' value='" + el.children[0].innerText + "'/></td>" +
|
||||
"<td><input style='width: 195px;' value='" + el.children[1].innerText + "'/></td>" +
|
||||
"<td><textarea style='width: 240px;height: 60px;'>" + el.children[2].innerText + "</textarea></td>" +
|
||||
"<td><input style='width: 145px;' value='" + el.children[3].innerText + "'/></td>" +
|
||||
"<td><img src='../icons/general/save.png' onclick='Settings.SaveRowdensity(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='Settings.Abort(this.parentNode.parentNode)' class='pointer'></td>";
|
||||
},
|
||||
EditFight: function (el) {
|
||||
el.innerHTML = "<td><input style='width: 145px;' value='" + el.children[0].innerText + "'/></td>" +
|
||||
"<td><textarea style='width: 240px;height: 60px;'>" + el.children[1].innerText + "</textarea></td>" +
|
||||
"<td><input style='width: 145px;' value='" + el.children[2].innerText + "'/></td>" +
|
||||
"<td><input style='width: 145px;' value='" + el.children[3].innerText + "'/></td>" +
|
||||
"<td><img src='../icons/general/save.png' onclick='Settings.SaveRowfight(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='Settings.Abort(this.parentNode.parentNode)' class='pointer'></td>";
|
||||
},
|
||||
EditSensor: function (el) {
|
||||
el.innerHTML = "<td><input style='width: 145px;' value='" + el.children[0].innerText + "'/></td>" +
|
||||
"<td><input style='width: 145px;' value='" + el.children[1].innerText + "'/></td>" +
|
||||
"<td><input style='width: 250px;' value='" + el.children[2].innerText + "'/></td>" +
|
||||
"<td><input style='width: 145px;' value='" + el.children[3].innerText + "'/></td>" +
|
||||
"<td><img src='../icons/general/save.png' onclick='Settings.SaveRowSensor(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='Settings.Abort(this.parentNode.parentNode)' class='pointer'></td>";
|
||||
},
|
||||
ParseJson: function (jsonsettings) {
|
||||
if (typeof jsonsettings.StartPos === "undefined") {
|
||||
jsonsettings.StartPos = { lat: 0, lon: 0 };
|
||||
}
|
||||
if (typeof jsonsettings.CellIds === "undefined") {
|
||||
jsonsettings.CellIds = [];
|
||||
}
|
||||
if (typeof jsonsettings.GridRadius === "undefined") {
|
||||
jsonsettings.GridRadius = 1000;
|
||||
}
|
||||
if (typeof jsonsettings.FightDedection === "undefined") {
|
||||
jsonsettings.FightDedection = [];
|
||||
}
|
||||
if (typeof jsonsettings.CrwodDensity === "undefined") {
|
||||
jsonsettings.CrwodDensity = [];
|
||||
}
|
||||
if (typeof jsonsettings.Counting === "undefined") {
|
||||
jsonsettings.Counting = [];
|
||||
}
|
||||
if (typeof jsonsettings.Sensors === "undefined") {
|
||||
jsonsettings.Sensors = [];
|
||||
}
|
||||
var html = "<div id='settingseditor'><div class='title'>Einstellungen</div>";
|
||||
html += "<div class='startloc'>Startpunkt: <input value='" + jsonsettings.StartPos.lat + "' id='startlat'> Lat, <input value='" + jsonsettings.StartPos.lon + "' id='startlon'> Lon</div>";
|
||||
html += "<div class='wetterwarnings'>CellId's für DWD-Wetterwarnungen: <input value='" + jsonsettings.CellIds.join(";") + "' id='wetterids'> (Trennen durch \";\", <a href='https://www.dwd.de/DE/leistungen/opendata/help/warnungen/cap_warncellids_csv.html'>cap_warncellids_csv</a>)</div>";
|
||||
html += "<div class='gridradius'>Radius für das Grid um den Startpunkt: <input value='" + jsonsettings.GridRadius + "' id='gridrad'>m</div>";
|
||||
html += "<div class='fightdedection'>Fight Dedection Kameras: <br>" + this._renderFightDedection(jsonsettings.FightDedection) + "</div>";
|
||||
html += "<div class='crowddensity'>Crowd Density Kameras: <br>" + this._renderCrowdDensity(jsonsettings.CrwodDensity) + "</div>";
|
||||
html += "<div class='sensorsettings'>Sensors: <br>" + this._renderSensorSettings(jsonsettings.Sensors) + "</div>";
|
||||
html += "<div class='savesettings'><img src='../icons/general/save.png' onclick='Settings.Save()' class='pointer'></div>";
|
||||
document.getElementById("content").innerHTML = html + "</div>";
|
||||
},
|
||||
Save: function () {
|
||||
var ret = {};
|
||||
ret.StartPos = {};
|
||||
ret.StartPos.lat = parseFloat(document.getElementById("startlat").value.replace(",", "."));
|
||||
ret.StartPos.lon = parseFloat(document.getElementById("startlon").value.replace(",", "."));
|
||||
ret.CellIds = document.getElementById("wetterids").value.split(";");
|
||||
ret.GridRadius = parseInt(document.getElementById("gridrad").value);
|
||||
|
||||
var rowsf = document.getElementById("fighttable").children[1].children;
|
||||
var fightjson = {};
|
||||
for (var i = 0; i < rowsf.length; i++) {
|
||||
if (rowsf[i].children[0].children.length === 1) {
|
||||
alert("Bitte zuerst alle Zeilen speichern oder Löschen!");
|
||||
return;
|
||||
}
|
||||
var id = rowsf[i].children[0].innerText;
|
||||
var coords = rowsf[i].children[1].innerHTML.split("<br>");
|
||||
var polyjson = [];
|
||||
for (var j = 0; j < coords.length; j++) {
|
||||
var coord = coords[j].split(";");
|
||||
polyjson[j] = { "Lat": this._filterFloat(coord[0]), "Lon": this._filterFloat(coord[1]) };
|
||||
}
|
||||
fightjson[id] = { "Poly": polyjson, "Alias": rowsf[i].children[2].innerText, "Level": this._filterFloat(rowsf[i].children[3].innerText) };
|
||||
}
|
||||
ret.FightDedection = fightjson;
|
||||
|
||||
var rowsc = document.getElementById("crowdtable").children[1].children;
|
||||
var crowdjson = {};
|
||||
for (i = 0; i < rowsc.length; i++) {
|
||||
if (rowsc[i].children[0].children.length === 1) {
|
||||
alert("Bitte zuerst alle Zeilen speichern oder Löschen!");
|
||||
return;
|
||||
}
|
||||
id = rowsc[i].children[0].innerText;
|
||||
var num = this._filterFloat(rowsc[i].children[1].innerText);
|
||||
coords = rowsc[i].children[2].innerHTML.split("<br>");
|
||||
|
||||
polyjson = [];
|
||||
for (j = 0; j < coords.length; j++) {
|
||||
coord = coords[j].split(";");
|
||||
polyjson[j] = { "Lat": this._filterFloat(coord[0]), "Lon": this._filterFloat(coord[1]) };
|
||||
}
|
||||
crowdjson[id] = {
|
||||
"Poly": polyjson,
|
||||
"Count": num,
|
||||
"Alias": rowsc[i].children[3].innerText
|
||||
};
|
||||
}
|
||||
ret.CrwodDensity = crowdjson;
|
||||
|
||||
var rowss = document.getElementById("sensortable").children[1].children;
|
||||
var sensorjson = {};
|
||||
for (i = 0; i < rowss.length; i++) {
|
||||
if (rowss[i].children[0].children.length === 1) {
|
||||
alert("Bitte zuerst alle Zeilen speichern oder Löschen!");
|
||||
return;
|
||||
}
|
||||
id = rowss[i].children[0].innerText;
|
||||
coord = rowss[i].children[2].innerHTML.split(";");
|
||||
sensorjson[id] = {
|
||||
"Poly": {
|
||||
"Lat": this._filterFloat(coord[0]),
|
||||
"Lon": this._filterFloat(coord[1])
|
||||
},
|
||||
"Level": this._filterFloat(rowss[i].children[3].innerText),
|
||||
"Alias": rowss[i].children[1].innerText
|
||||
};
|
||||
}
|
||||
ret.Sensors = sensorjson;
|
||||
|
||||
var savesettings = new XMLHttpRequest();
|
||||
savesettings.onreadystatechange = function () {
|
||||
if (savesettings.readyState === 4) {
|
||||
if (savesettings.status === 200) {
|
||||
alert("Änderungen gespeichert!");
|
||||
} else if (savesettings.status === 501) {
|
||||
alert("Ein Fehler ist aufgetreten (invalid JSON)!");
|
||||
}
|
||||
}
|
||||
};
|
||||
savesettings.open("PUT", "/admin/api/json/setting", true);
|
||||
savesettings.send(JSON.stringify(ret));
|
||||
},
|
||||
SaveRowdensity: function (el) {
|
||||
var coords = el.children[2].children[0].value.replace(/\n/gi, "<br>");
|
||||
var coordscheck = coords.split("<br>");
|
||||
var fail = false;
|
||||
for (var i = 0; i < coordscheck.length; i++) {
|
||||
var coord = coordscheck[i].split(";");
|
||||
if (coord.length !== 2) {
|
||||
fail = true;
|
||||
break;
|
||||
}
|
||||
if (isNaN(this._filterFloat(coord[0])) || isNaN(this._filterFloat(coord[1]))) {
|
||||
fail = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fail) {
|
||||
alert("Die Eingabe der Koordinaten ist nicht Korrekt!\n\nBeispiel:\n50.7;7.8\n50.6;7.9");
|
||||
return;
|
||||
}
|
||||
if (isNaN(this._filterFloat(el.children[1].children[0].value))) {
|
||||
alert("Die Eingabe der Maximalen Anzahl der Personen ist nicht Korrekt, erwarte eine Zahl.");
|
||||
return;
|
||||
}
|
||||
el.innerHTML = "<td>" + el.children[0].children[0].value + "</td>" +
|
||||
"<td>" + el.children[1].children[0].value + "</td>" +
|
||||
"<td>" + coords + "</td>" +
|
||||
"<td>" + el.children[3].children[0].value + "</td>" +
|
||||
"<td><img src='../icons/general/edit.png' onclick='Settings.EditDensity(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='Settings.Delete(this.parentNode.parentNode)' class='pointer'></td>";
|
||||
},
|
||||
SaveRowfight: function (el) {
|
||||
var coords = el.children[1].children[0].value.replace(/\n/gi, "<br>");
|
||||
var coordscheck = coords.split("<br>");
|
||||
var fail = false;
|
||||
for (var i = 0; i < coordscheck.length; i++) {
|
||||
var coord = coordscheck[i].split(";");
|
||||
if (coord.length !== 2) {
|
||||
fail = true;
|
||||
break;
|
||||
}
|
||||
if (isNaN(this._filterFloat(coord[0])) || isNaN(this._filterFloat(coord[1]))) {
|
||||
fail = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isNaN(this._filterFloat(el.children[3].children[0].value))) {
|
||||
alert("Die Eingabe des Alertlevel erwartet einen Float");
|
||||
return;
|
||||
}
|
||||
if (fail) {
|
||||
alert("Die Eingabe der Koordinaten ist nicht Korrekt!\n\nBeispiel:\n50.7;7.8\n50.6;7.9");
|
||||
return;
|
||||
}
|
||||
el.innerHTML = "<td>" + el.children[0].children[0].value + "</td>" +
|
||||
"<td>" + coords + "</td>" +
|
||||
"<td>" + el.children[2].children[0].value + "</td>" +
|
||||
"<td>" + this._filterFloat(el.children[3].children[0].value) + "</td>" +
|
||||
"<td><img src='../icons/general/edit.png' onclick='Settings.EditFight(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='Settings.Delete(this.parentNode.parentNode)' class='pointer'></td>";
|
||||
},
|
||||
SaveRowSensor: function (el) {
|
||||
var coords = el.children[2].children[0].value;
|
||||
var coord = coords.split(";");
|
||||
var fail = false;
|
||||
if (coord.length !== 2) {
|
||||
fail = true;
|
||||
} else if (isNaN(this._filterFloat(coord[0])) || isNaN(this._filterFloat(coord[1]))) {
|
||||
fail = true;
|
||||
}
|
||||
if (isNaN(this._filterFloat(el.children[3].children[0].value))) {
|
||||
alert("Die Eingabe des Alertlevel erwartet einen Float");
|
||||
return;
|
||||
}
|
||||
if (fail) {
|
||||
alert("Die Eingabe der Koordinaten ist nicht Korrekt!\n\nBeispiel:\n50.7;7.8");
|
||||
return;
|
||||
}
|
||||
el.innerHTML = "<td>" + el.children[0].children[0].value + "</td>" +
|
||||
"<td>" + el.children[1].children[0].value + "</td>" +
|
||||
"<td>" + coords + "</td>" +
|
||||
"<td>" + this._filterFloat(el.children[3].children[0].value) + "</td>" +
|
||||
"<td><img src='../icons/general/edit.png' onclick='Settings.EditSensor(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='Settings.Delete(this.parentNode.parentNode)' class='pointer'></td>";
|
||||
},
|
||||
//private functions
|
||||
_filterFloat: function (value) {
|
||||
if (/^(-|\+)?([0-9]+(\.[0-9]+)?|Infinity)$/.test(value)) {
|
||||
return Number(value);
|
||||
}
|
||||
return NaN;
|
||||
},
|
||||
_renderCrowdDensity: function (json) {
|
||||
var ret = "";
|
||||
ret += "<table id='crowdtable' class='settingstable'>";
|
||||
ret += "<thead><tr><th width='150'>ID</th><th width='200'>Personenanzahl</th><th width='250'>Koordinaten</th><th width='150'>Alias</th><th width='50'></th></tr></thead>";
|
||||
ret += "<tbody>";
|
||||
for (var id in json) {
|
||||
var coords = [];
|
||||
for (var i = 0; i < json[id].Poly.length; i++) {
|
||||
coords[i] = json[id].Poly[i].Lat + ";" + json[id].Poly[i].Lon;
|
||||
}
|
||||
ret += "<tr>" +
|
||||
"<td>" + id + "</td>" +
|
||||
"<td>" + json[id].Count + "</td>" +
|
||||
"<td>" + coords.join("<br>") + "</td>" +
|
||||
"<td>" + json[id].Alias + "</td>" +
|
||||
"<td><img src='../icons/general/edit.png' onclick='Settings.EditDensity(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='Settings.Delete(this.parentNode.parentNode)' class='pointer'></td>" +
|
||||
"</tr>";
|
||||
}
|
||||
ret += "</tbody>";
|
||||
ret += "<tfoot><tr><td></td><td></td><td></td><td></td><td><img src='../icons/general/add.png' onclick='Settings.AddDensity()' class='pointer'></td></tr></tfoot>";
|
||||
ret += "</table>";
|
||||
return ret;
|
||||
},
|
||||
_renderFightDedection: function (json) {
|
||||
var ret = "";
|
||||
ret += "<table id='fighttable' class='settingstable'>";
|
||||
ret += "<thead><tr><th width='150'>ID</th><th width='250'>Koordinaten</th><th width='150'>Alias</th><th width='150'>Alertlimit</th><th width='50'></th></tr></thead>";
|
||||
ret += "<tbody>";
|
||||
for (var id in json) {
|
||||
var coords = [];
|
||||
for (var i = 0; i < json[id].Poly.length; i++) {
|
||||
coords[i] = json[id].Poly[i].Lat + ";" + json[id].Poly[i].Lon;
|
||||
}
|
||||
ret += "<tr>" +
|
||||
"<td>" + id + "</td>" +
|
||||
"<td>" + coords.join("<br>") + "</td>" +
|
||||
"<td>" + json[id].Alias + "</td>" +
|
||||
"<td>" + json[id].Level + "</td>" +
|
||||
"<td><img src='../icons/general/edit.png' onclick='Settings.EditFight(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='Settings.Delete(this.parentNode.parentNode)' class='pointer'></td>" +
|
||||
"</tr>";
|
||||
}
|
||||
ret += "</tbody>";
|
||||
ret += "<tfoot><tr><td></td><td></td><td></td><td></td><td><img src='../icons/general/add.png' onclick='Settings.AddFight()' class='pointer'></td></tr></tfoot>";
|
||||
ret += "</table>";
|
||||
return ret;
|
||||
},
|
||||
_renderSensorSettings: function (json) {
|
||||
var ret = "";
|
||||
ret += "<table id='sensortable' class='settingstable'>";
|
||||
ret += "<thead><tr><th width='150'>ID</th><th width='150'>Alias</th><th width='250'>Koordinaten</th><th width='150'>Warn above</th><th width='50'></th></tr></thead>";
|
||||
|
||||
ret += "<tbody>";
|
||||
for (var id in json) {
|
||||
ret += "<tr>" +
|
||||
"<td>" + id + "</td>" +
|
||||
"<td>" + json[id].Alias + "</td>" +
|
||||
"<td>" + json[id].Poly.Lat + ";" + json[id].Poly.Lon + "</td>" +
|
||||
"<td>" + json[id].Level + "</td>" +
|
||||
"<td><img src='../icons/general/edit.png' onclick='Settings.EditSensor(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='Settings.Delete(this.parentNode.parentNode)' class='pointer'></td>" +
|
||||
"</tr>";
|
||||
}
|
||||
ret += "</tbody>";
|
||||
|
||||
ret += "<tfoot><tr><td></td><td></td><td></td><td></td><td><img src='../icons/general/add.png' onclick='Settings.AddSensor()' class='pointer'></td></tr></tfoot>";
|
||||
ret += "</table>";
|
||||
return ret;
|
||||
},
|
||||
};
|
@ -13,6 +13,7 @@
|
||||
#bigmap .leaflet-map-pane .leaflet-marker-pane .snumber-icon {
|
||||
font-weight: bold;
|
||||
font-size: 5px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
#bigmap .leaflet-map-pane .leaflet-marker-pane .coord-icon {
|
||||
font-size: 13px;
|
||||
@ -20,6 +21,28 @@
|
||||
color: #ffffff;
|
||||
font-weight: bold;
|
||||
}
|
||||
#bigmap .leaflet-map-pane .leaflet-marker-pane .mapsensor {
|
||||
background-color: white;
|
||||
border: 2px solid black;
|
||||
padding: 5px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
#bigmap .leaflet-map-pane .leaflet-marker-pane .mapsensor.alert {
|
||||
border: 2px solid red;
|
||||
}
|
||||
#bigmap .leaflet-map-pane .leaflet-marker-pane .mapsensor span {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
#bigmap .leaflet-map-pane .leaflet-marker-pane .mapsensor .name {
|
||||
font-weight: bold;
|
||||
}
|
||||
#bigmap .leaflet-map-pane .leaflet-marker-pane .mapsensor .wind {
|
||||
font-size: 18px;
|
||||
}
|
||||
#bigmap .leaflet-map-pane .leaflet-marker-pane .mapsensor.alert .wind {
|
||||
color: red;
|
||||
}
|
||||
|
||||
/* Optional: Makes the sample page fill the window. */
|
||||
html, body {
|
||||
@ -59,12 +82,24 @@ object {
|
||||
#menucollumn .pos {
|
||||
background-image: url("icons/placeholder.png");
|
||||
}
|
||||
#menucollumn .filter {
|
||||
background-image: url("icons/filter.png");
|
||||
}
|
||||
#menucollumn .admin {
|
||||
background-image: url("icons/admin-with-cogwheels.png");
|
||||
}
|
||||
#menucollumn .info {
|
||||
background-image: url("icons/information.png");
|
||||
}
|
||||
#menucollumn .weather {
|
||||
background-image: url("icons/storm-in.png");
|
||||
}
|
||||
#menucollumn .weather.ac {
|
||||
background-image: url("icons/storm-ac.png");
|
||||
}
|
||||
#menucollumn .suche {
|
||||
background-image: url("icons/search.png");
|
||||
}
|
||||
|
||||
#pannels {
|
||||
position: absolute;
|
||||
@ -89,6 +124,10 @@ object {
|
||||
#pannels #pannels_pos .item {
|
||||
margin: 4px;
|
||||
}
|
||||
#pannels #pannels_pos .item.filter {
|
||||
opacity: 0.4;
|
||||
background-color: rgba(1,1,1,0.2);
|
||||
}
|
||||
#pannels #pannels_pos .item .color {
|
||||
float: left;
|
||||
width: 2px;
|
||||
@ -101,10 +140,10 @@ object {
|
||||
margin-right: 5px;
|
||||
}
|
||||
#pannels #pannels_pos .item .icon img {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
margin-left: 3px;
|
||||
}
|
||||
height: 40px;
|
||||
width: 35px;
|
||||
margin-left: 3px;
|
||||
}
|
||||
#pannels #pannels_pos .item .line1 .name {
|
||||
font-weight: bold;
|
||||
}
|
||||
@ -143,6 +182,12 @@ object {
|
||||
#pannels #pannels_info .update {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
#pannels #pannels_info .alerts {
|
||||
margin-top: 10px;
|
||||
}
|
||||
#pannels #pannels_info .alerts .panicitem {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#pannels #pannels_version {
|
||||
padding: 5px;
|
||||
@ -197,6 +242,103 @@ object {
|
||||
margin-left: 70px;
|
||||
}
|
||||
|
||||
#pannels #pannels_weather {
|
||||
margin: 5px;
|
||||
display: none;
|
||||
}
|
||||
#pannels #pannels_weather h1 {
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
#pannels #pannels_weather .alertitem {
|
||||
padding: 5px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
#pannels #pannels_weather .alertitem.minor {
|
||||
background-color: #ffeb3b;
|
||||
}
|
||||
#pannels #pannels_weather .alertitem.moderate {
|
||||
background-color: #fb8c00;
|
||||
}
|
||||
#pannels #pannels_weather .alertitem.severe {
|
||||
background-color: #e53935;
|
||||
}
|
||||
#pannels #pannels_weather .alertitem.extreme {
|
||||
background-color: #880e4f;
|
||||
}
|
||||
#pannels #pannels_weather .alertitem.hitze {
|
||||
background-color: #c9f;
|
||||
}
|
||||
#pannels #pannels_weather .alertitem .head {
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
}
|
||||
#pannels #pannels_weather .alertitem .ort {
|
||||
display: block;
|
||||
text-align: right;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
#pannels #pannels_weather .alertitem .text {
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#pannels #pannels_filter {
|
||||
margin: 5px;
|
||||
display: none;
|
||||
}
|
||||
#pannels #pannels_filter h1 {
|
||||
font-size: 16px;
|
||||
}
|
||||
#pannels #pannels_filter select {
|
||||
height: 140px;
|
||||
width: 235px;
|
||||
}
|
||||
|
||||
#pannels #pannels_suche {
|
||||
display: none;
|
||||
padding: 5px;
|
||||
}
|
||||
#pannels #pannels_suche .searchtitle {
|
||||
font-weight: bold;
|
||||
font-size: 13px;
|
||||
}
|
||||
#pannels #pannels_suche input {
|
||||
width: 220px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
#pannels #pannels_suche #search_results {
|
||||
border-top: 1px solid black;
|
||||
margin-top: 10px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
#pannels #pannels_suche #search_results .result {
|
||||
background-color: rgba(0,0,0,0.2);
|
||||
margin-bottom: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#pannels #pannels_suche #search_results .result .text {
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
}
|
||||
#pannels #pannels_suche #search_results .result .text .title {
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
}
|
||||
#pannels #pannels_suche #search_results .result .text .desc {
|
||||
display: block;
|
||||
}
|
||||
#pannels #pannels_suche #search_results .result .box {
|
||||
display: inline-block;
|
||||
height: 25px;
|
||||
width: 15px;
|
||||
border-style: solid;
|
||||
border-width: 2px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
#overlays #cameracount {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
@ -205,12 +347,14 @@ object {
|
||||
font-size: 11px;
|
||||
font-family: "Verdana";
|
||||
padding: 3px;
|
||||
display: inline-flex;
|
||||
}
|
||||
#overlays #cameracount .camera {
|
||||
background-color: white;
|
||||
border: rgba(0,0,0,0.3) solid 2px;
|
||||
border-radius: 5px;
|
||||
padding: 4px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
#overlays #cameracount .camera span {
|
||||
display: block;
|
||||
|
BIN
Lora-Map/resources/css/icons/filter.png
Normal file
After Width: | Height: | Size: 848 B |
BIN
Lora-Map/resources/css/icons/search.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Lora-Map/resources/css/icons/storm-ac.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
Lora-Map/resources/css/icons/storm-in.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 21 KiB |
@ -10,15 +10,36 @@
|
||||
<body>
|
||||
<div id="bigmap"></div>
|
||||
<div id="menucollumn">
|
||||
<span class="pos" onclick="showHidePanel('pannels_pos');"></span>
|
||||
<span class="admin" onclick="showHidePanel('pannels_admin');"></span>
|
||||
<span class="info" onclick="showHidePanel('pannels_version');"></span>
|
||||
<span class="pos" onclick="MenuObject.ShowHidePanel('pannels_pos');"></span>
|
||||
<span class="filter" onclick="MenuObject.ShowHidePanel('pannels_filter');"></span>
|
||||
<span class="suche" onclick="MenuObject.ShowHidePanel('pannels_suche');"></span>
|
||||
<span class="weather" onclick="MenuObject.ShowHidePanel('pannels_weather');" id="menucol_weather_icon"></span>
|
||||
<span class="admin" onclick="MenuObject.ShowHidePanel('pannels_admin');"></span>
|
||||
<span class="info" onclick="MenuObject.ShowHidePanel('pannels_version');"></span>
|
||||
</div>
|
||||
<div id="pannels">
|
||||
<div id="pannels_pos"></div>
|
||||
<div id="pannels_info">
|
||||
<!-- Shows infos about selected device here, this will be cleand by js -->
|
||||
</div>
|
||||
<div id="pannels_filter">
|
||||
<h1>Angezeigte Gruppen</h1>
|
||||
<select multiple onchange="MarkerObject.ChangeFilter(this);">
|
||||
<option value="fw">Feuerwehr</option>
|
||||
<option value="sani">Rettungsdienst</option>
|
||||
<option value="pol">Polizei</option>
|
||||
<option value="oa">Ordnungsamt</option>
|
||||
<option value="si">Sicherheitsdienst</option>
|
||||
<option value="thw">Technisches Hilfswerk</option>
|
||||
<option value="crew">Veranstalter</option>
|
||||
<option value="dev">Entwickler</option>
|
||||
</select><br />
|
||||
<span>(Klicken Sie mit <strong>STRG</strong> in das Formular um mehrere Gruppen auszuwählen)</span><br /><br />
|
||||
<span>Sind keine Gruppen ausgewählt, werden alle Icons angezeigt, egal welcher Gruppe sie angehören.</span>
|
||||
</div>
|
||||
<div id="pannels_weather">
|
||||
<h1>Keine Gefahren</h1>
|
||||
</div>
|
||||
<div id="pannels_admin">
|
||||
Teste Login...
|
||||
</div>
|
||||
@ -34,9 +55,16 @@
|
||||
<li><a href="https://www.freepik.com/" title="Freepik">Freepik</a> licensed <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a></li>
|
||||
<li><a href="http://www.famfamfam.com/about/" title="Silk Iconset">Silk Iconset</a> licensed <a href="http://creativecommons.org/licenses/by/2.5/" title="Creative Commons BY 2.5" target="_blank">CC 2.5 BY</a></li>
|
||||
<li><a href="https://www.flaticon.com/authors/those-icons" title="Those Icons">Those Icons</a> licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a></li>
|
||||
<li><a href="https://www.flaticon.com/authors/freepik" title="Freepik">Freepik</a> licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a></li>
|
||||
<li><a href="https://www.flaticon.com/authors/dimitry-miroliubov" title="Dimitry Miroliubov">Dimitry Miroliubov</a> from <a href="https://www.flaticon.com/" title="Flaticon">flaticon.com</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="pannels_suche">
|
||||
<span class="searchtitle">Standnummer:</span><br />
|
||||
<input onkeyup="MenuObject.SearchInGeoJson(this.value);"/>
|
||||
<div id="search_results"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="overlays">
|
||||
<div id="cameracount"></div>
|
||||
|
@ -1,43 +1,93 @@
|
||||
setInterval(timecorrectionrunner, 60000);
|
||||
timecorrectionrunner();
|
||||
|
||||
function timecorrectionrunner() {
|
||||
var timecorrection = new XMLHttpRequest();
|
||||
timecorrection.onreadystatechange = parseAjaxTimecorrection;
|
||||
timecorrection.open("GET", "http://{%REQUEST_URL_HOST%}/currenttime", true);
|
||||
timecorrection.send();
|
||||
}
|
||||
|
||||
var timeOffset = 0;
|
||||
|
||||
function parseAjaxTimecorrection() {
|
||||
if (this.readyState === 4 && this.status === 200) {
|
||||
utcobject = JSON.parse(this.responseText);
|
||||
if (utcobject.hasOwnProperty("utc")) {
|
||||
timeOffset = Date.now() - Date.parse(utcobject["utc"]);
|
||||
var FunctionsObject = {
|
||||
/// private variables
|
||||
_internalTimeOffset: 0,
|
||||
/// public functions
|
||||
Start: function () {
|
||||
setInterval(this._QueryJsonEveryMinute, 60000);
|
||||
setInterval(this._QueryJsonEverySecond, 1000);
|
||||
this._QueryJsonEveryMinute();
|
||||
this._QueryJsonEverySecond();
|
||||
this._QueryJsonStartup();
|
||||
return this;
|
||||
},
|
||||
TimeCalculation: function (timestr, type) {
|
||||
if (type === "diffraw" || type === "difftext" || type === "difftextn") {
|
||||
var diff = Math.round((Date.now() - Date.parse(timestr) - this._internalTimeOffset) / 1000);
|
||||
if (type === "diffraw") {
|
||||
return diff;
|
||||
}
|
||||
if (type === "difftextn" && diff < 0) {
|
||||
diff = diff * -1;
|
||||
}
|
||||
var isneg = false;
|
||||
if (diff < 0) {
|
||||
isneg = true;
|
||||
diff = diff * -1;
|
||||
}
|
||||
if (diff < 60) {
|
||||
return (isneg ? "-" : "") + diff + " s";
|
||||
}
|
||||
if (diff < 60 * 60) {
|
||||
return (isneg ? "-" : "") + Math.floor(diff / 60) + " m";
|
||||
}
|
||||
if (diff < 60 * 60 * 24) {
|
||||
return (isneg ? "-" : "") + Math.floor(diff / (60 * 60)) + " h";
|
||||
}
|
||||
return (isneg ? "-" : "") + Math.floor(diff / (60 * 60 * 24)) + " d";
|
||||
} else if (type === "str") {
|
||||
var date = new Date(Date.parse(timestr) + this._internalTimeOffset);
|
||||
var str = date.toLocaleString();
|
||||
return str;
|
||||
}
|
||||
},
|
||||
/// private functions
|
||||
_ParseAJAX: function (utcobject) {
|
||||
if (Object.prototype.hasOwnProperty.call(utcobject, "utc")) {
|
||||
this._internalTimeOffset = Date.now() - Date.parse(utcobject["utc"]);
|
||||
}
|
||||
},
|
||||
_QueryJsonEveryMinute: function () {
|
||||
var get60000 = new XMLHttpRequest();
|
||||
get60000.onreadystatechange = function () {
|
||||
if (get60000.readyState === 4 && get60000.status === 200) {
|
||||
var json = JSON.parse(get60000.responseText);
|
||||
FunctionsObject._ParseAJAX(json);
|
||||
}
|
||||
};
|
||||
get60000.open("GET", "/api/time", true);
|
||||
get60000.send();
|
||||
},
|
||||
_QueryJsonEverySecond: function () {
|
||||
var get1000 = new XMLHttpRequest();
|
||||
get1000.onreadystatechange = function () {
|
||||
if (get1000.readyState === 4 && get1000.status === 200) {
|
||||
var json = JSON.parse(get1000.responseText);
|
||||
MarkerObject.ParseAJAXPositionModel(json.position);
|
||||
MarkerObject.ParseAJAXSensorModel(json.sensor);
|
||||
|
||||
OverlayObject.ParseAJAXCameraModel(json.camera);
|
||||
|
||||
MapObject.ParseAJAXCameraModel(json.camera);
|
||||
|
||||
MenuObject.ParseAJAXSensorModel(json.sensor);
|
||||
}
|
||||
};
|
||||
get1000.open("GET", "/api/json/position,camera,sensor", true);
|
||||
get1000.send();
|
||||
},
|
||||
_QueryJsonStartup: function () {
|
||||
var getonce = new XMLHttpRequest();
|
||||
getonce.onreadystatechange = function () {
|
||||
if (getonce.readyState === 4 && getonce.status === 200) {
|
||||
var json = JSON.parse(getonce.responseText);
|
||||
MarkerObject.ParseAJAXSettings(json.settings);
|
||||
|
||||
OverlayObject.ParseAJAXSettings(json.settings);
|
||||
|
||||
MapObject.ParseAJAXSettings(json.settings);
|
||||
}
|
||||
};
|
||||
getonce.open("GET", "/api/json/settings", true);
|
||||
getonce.send();
|
||||
}
|
||||
}
|
||||
|
||||
function timeCalculation(timestr, type) {
|
||||
if (type === "diffraw" || type === "difftext") {
|
||||
var diff = Math.round((Date.now() - Date.parse(timestr) - timeOffset) / 1000);
|
||||
if (type === "diffraw") {
|
||||
return diff;
|
||||
}
|
||||
if (diff < 60) {
|
||||
return diff + " s";
|
||||
}
|
||||
if (diff < 60 * 60) {
|
||||
return Math.floor(diff / 60) + " m";
|
||||
}
|
||||
if (diff < 60 * 60 * 24) {
|
||||
return Math.floor(diff / (60 * 60)) + " h";
|
||||
}
|
||||
return Math.floor(diff / (60 * 60 * 24)) + " d";
|
||||
} else if (type === "str") {
|
||||
var date = new Date(Date.parse(timestr) + timeOffset);
|
||||
var str = date.toLocaleString();
|
||||
return str;
|
||||
}
|
||||
}
|
||||
}.Start();
|
@ -1,193 +1,280 @@
|
||||
var mymap = L.map('bigmap').setView(["{%START_LOCATION%}"], 16);
|
||||
|
||||
GetMapLayers();
|
||||
function GetMapLayers() {
|
||||
var layergetter = new XMLHttpRequest();
|
||||
layergetter.onreadystatechange = function () {
|
||||
if (layergetter.readyState === 4 && layergetter.status === 200) {
|
||||
var maps = JSON.parse(layergetter.responseText);
|
||||
var i = 0;
|
||||
for (var key in maps) {
|
||||
i++;
|
||||
}
|
||||
if (i === 1) {
|
||||
L.tileLayer(maps["online"]["url"], {
|
||||
attribution: maps["online"]["attribution"],
|
||||
minZoom: maps["online"]["minZoom"],
|
||||
maxZoom: maps["online"]["maxZoom"]
|
||||
}).addTo(mymap);
|
||||
} else {
|
||||
var baseMaps = {};
|
||||
for (key in maps) {
|
||||
if (key !== "online") {
|
||||
var basemap = L.tileLayer(maps[key]["url"], {
|
||||
attribution: maps[key]["attribution"],
|
||||
minZoom: maps[key]["minZoom"],
|
||||
maxZoom: maps[key]["maxZoom"],
|
||||
errorTileUrl: "css/icons/failtile.png"
|
||||
});
|
||||
basemap.addTo(mymap);
|
||||
baseMaps[maps[key]["title"]] = basemap;
|
||||
break;
|
||||
}
|
||||
var MapObject = {
|
||||
/// public variables
|
||||
GeoJson: {},
|
||||
Map: {},
|
||||
/// private variables
|
||||
_DensityAreas: {},
|
||||
_FightDedection: {},
|
||||
_SpecialMarkers: new Array(),
|
||||
/// public functions
|
||||
JumpTo: function (lat, lon) {
|
||||
this.Map.flyTo([lat, lon], 19);
|
||||
},
|
||||
ParseAJAXCameraModel: function (json) {
|
||||
this._ParseAJAXFightDedection(json.Fights);
|
||||
this._ParseAJAXDensity(json.Density);
|
||||
},
|
||||
ParseAJAXSettings: function (settings) {
|
||||
this._ParseAJAXLayers(settings.Layers);
|
||||
this._ParseAJAXGeo(settings.GeoLayer);
|
||||
this.Map.panTo([settings.Startloclat, settings.Startloclon]);
|
||||
this._GenerateGrid(settings.Grid);
|
||||
this._GenerateFightBoxes(settings.FightDedection);
|
||||
this._GenerateDensityBoxes(settings.DensityArea);
|
||||
},
|
||||
Start: function () {
|
||||
this.Map = L.map('bigmap').setView([0, 0], 16);
|
||||
this._SetupMapZoomFontsize();
|
||||
this._SetupClickHandler();
|
||||
return this;
|
||||
},
|
||||
/// private functions
|
||||
_createRGB: function (current, max) {
|
||||
return "hsl(" + 120 * (1 - current / max) + ",100%,50%)";
|
||||
},
|
||||
_GenerateDensityBoxes: function (densityareas) {
|
||||
for (var cameraid in densityareas) {
|
||||
this._DensityAreas[cameraid] = { 'Poly': L.polygon(densityareas[cameraid].Polygon, { color: 'hsl(120,100%,50%)', weight: 1 }).addTo(this.Map), 'Maximum': densityareas[cameraid].Maximum };
|
||||
this._DensityAreas[cameraid].Poly.bindPopup("<strong>Besuchermenge:</strong><br>" +
|
||||
"Besucher <strong>(0/" + this._DensityAreas[cameraid].Maximum + ")</strong> Personen<br>" +
|
||||
"<progress value='0' max='" + this._DensityAreas[cameraid].Maximum + "'></progress>");
|
||||
}
|
||||
},
|
||||
_GenerateFightBoxes: function (fightdedection) {
|
||||
for (var cameraid in fightdedection) {
|
||||
this._FightDedection[cameraid] = {};
|
||||
this._FightDedection[cameraid].Box = L.polygon(fightdedection[cameraid].Polygon, { color: 'black', weight: 1 }).addTo(this.Map);
|
||||
this._FightDedection[cameraid].Box.bindPopup("Fightdedection " + fightdedection[cameraid].Alias);
|
||||
this._FightDedection[cameraid].Level = fightdedection[cameraid].Level;
|
||||
}
|
||||
},
|
||||
_GenerateGrid: function (grid) {
|
||||
for (var i = 0; i < grid.Major.length; i++) {
|
||||
var linemajor = grid.Major[i];
|
||||
L.polyline([[linemajor.from[0], linemajor.from[1]], [linemajor.to[0], linemajor.to[1]]], { color: "red", weight: 1, interactive: false }).addTo(this.Map);
|
||||
}
|
||||
for (var j = 0; j < grid.Minor.length; j++) {
|
||||
var lineminor = grid.Minor[j];
|
||||
L.polyline([[lineminor.from[0], lineminor.from[1]], [lineminor.to[0], lineminor.to[1]]], { color: "red", weight: 0.7, opacity: 0.5, interactive: false }).addTo(this.Map);
|
||||
}
|
||||
},
|
||||
_HidePanel: function (e) {
|
||||
MenuObject.ShowHidePanel(null);
|
||||
},
|
||||
_ParseAJAXDensity: function (json) {
|
||||
for (var cameraid in json) {
|
||||
if (Object.prototype.hasOwnProperty.call(this._DensityAreas, cameraid)) {
|
||||
var crowd = json[cameraid];
|
||||
var box = this._DensityAreas[cameraid].Poly;
|
||||
var max = this._DensityAreas[cameraid].Maximum;
|
||||
var cur = crowd.DensityCount;
|
||||
if (cur > max) {
|
||||
cur = max;
|
||||
}
|
||||
for (key in maps) {
|
||||
if (!baseMaps.hasOwnProperty(maps[key]["title"])) {
|
||||
baseMaps[maps[key]["title"]] = L.tileLayer(maps[key]["url"], {
|
||||
attribution: maps[key]["attribution"],
|
||||
minZoom: maps[key]["minZoom"],
|
||||
maxZoom: maps[key]["maxZoom"],
|
||||
errorTileUrl: "css/icons/failtile.png"
|
||||
});
|
||||
}
|
||||
}
|
||||
L.control.layers(baseMaps).addTo(mymap);
|
||||
box.setStyle({ color: this._createRGB(cur, max) });
|
||||
var p = box.getPopup().setContent("<strong>Besuchermenge:</strong><br>" +
|
||||
"Besucher <strong>(" + crowd.DensityCount + "/" + max + ")</strong> Personen<br>" +
|
||||
"<progress value='" + cur + "' max='" + max + "'></progress>").update();
|
||||
}
|
||||
}
|
||||
};
|
||||
layergetter.open("GET", "http://{%REQUEST_URL_HOST%}/getlayer", true);
|
||||
layergetter.send();
|
||||
}
|
||||
|
||||
var SpecialMarkers = new Array();
|
||||
GetGeoLayer();
|
||||
function GetGeoLayer() {
|
||||
var geogetter = new XMLHttpRequest();
|
||||
geogetter.onreadystatechange = function () {
|
||||
if (geogetter.readyState === 4 && geogetter.status === 200) {
|
||||
var geo = JSON.parse(geogetter.responseText);
|
||||
if (!(Object.keys(geo).length === 0 && geo.constructor === Object)) {
|
||||
L.geoJSON(geo, {
|
||||
style: function (features) {
|
||||
return {
|
||||
color: typeof features.properties["stroke"] === "undefined" ? '#000000' : features.properties["stroke"],
|
||||
weight: typeof features.properties["stroke-width"] === "undefined" ? 1 : features.properties["stroke-width"],
|
||||
opacity: typeof features.properties["stroke-opacity"] === "undefined" ? 1 : features.properties["stroke-opacity"],
|
||||
fillColor: typeof features.properties["fill"] === "undefined" ? '#ffffff' : features.properties["fill"],
|
||||
fillOpacity: typeof features.properties["fill-opacity"] === "undefined" ? 1 : features.properties["fill-opacity"]
|
||||
};
|
||||
},
|
||||
onEachFeature: function (feature, layer) {
|
||||
if (feature.geometry.type === "Polygon" || (feature.geometry.type === "Point" && feature.properties.hasOwnProperty("icon"))) {
|
||||
layer.bindPopup(feature.properties.name);
|
||||
}
|
||||
},
|
||||
pointToLayer: function (geoJsonPoint, latlng) {
|
||||
if (geoJsonPoint.properties.hasOwnProperty("description") && geoJsonPoint.properties["description"] === "snumber" && !geoJsonPoint.properties.hasOwnProperty("icon")) {
|
||||
var snumbericon = L.marker(latlng, {
|
||||
icon: new L.DivIcon({
|
||||
className: "snumber-icon",
|
||||
html: geoJsonPoint.properties["name"],
|
||||
iconSize: [8, 8]
|
||||
})
|
||||
});
|
||||
SpecialMarkers.push(snumbericon);
|
||||
return snumbericon;
|
||||
} else if (geoJsonPoint.properties.hasOwnProperty("description") && geoJsonPoint.properties["description"] === "coord" && !geoJsonPoint.properties.hasOwnProperty("icon")) {
|
||||
var coordicon = L.marker(latlng, {
|
||||
icon: new L.DivIcon({
|
||||
className: "coord-icon",
|
||||
html: geoJsonPoint.properties["name"]
|
||||
})
|
||||
});
|
||||
SpecialMarkers.push(coordicon);
|
||||
return coordicon;
|
||||
} else if (geoJsonPoint.properties.hasOwnProperty("icon")) {
|
||||
return L.marker(latlng, { icon: L.icon({ iconUrl: "css/icons/cctv.png", iconSize: [32, 32] }) });
|
||||
},
|
||||
_ParseAJAXFightDedection: function (json) {
|
||||
for (var cameraid in json) {
|
||||
if (Object.prototype.hasOwnProperty.call(this._FightDedection, cameraid)) {
|
||||
var fight = json[cameraid];
|
||||
var box = this._FightDedection[cameraid].Box;
|
||||
var diff = FunctionsObject.TimeCalculation(fight["LastUpdate"], "diffraw");
|
||||
if (fight["FightProbability"] > this._FightDedection[cameraid].Level) {
|
||||
if (diff <= 10 && box.options.color === "black") {
|
||||
box.setStyle({ color: 'rgb(' + fight["FightProbability"] * 255 + ',0,0)' });
|
||||
} else if (diff <= 10 && box.options.color !== "black") {
|
||||
if (diff % 2 === 0) {
|
||||
box.setStyle({ color: 'rgb(' + fight["FightProbability"] * 255 + ',0,0)' });
|
||||
} else {
|
||||
box.setStyle({ color: 'green' });
|
||||
}
|
||||
} else if (diff > 10 && box.options.color !== "black") {
|
||||
box.setStyle({ color: 'black' });
|
||||
}
|
||||
}).addTo(mymap);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
geogetter.open("GET", "http://{%REQUEST_URL_HOST%}/getgeo", true);
|
||||
geogetter.send();
|
||||
}
|
||||
|
||||
mymap.on('zoomend', function () {
|
||||
var currentZoom = mymap.getZoom();
|
||||
if (currentZoom < 14) {
|
||||
SpecialMarkers.forEach(function (elem, index) {
|
||||
if (elem.feature.properties["description"] === "snumber") {
|
||||
elem._icon.style.fontSize = "0px";
|
||||
elem._icon.style.marginLeft = "0px";
|
||||
elem._icon.style.marginTop = "0px";
|
||||
},
|
||||
_ParseAJAXGeo: function (geo) {
|
||||
if (!(Object.keys(geo).length === 0 && geo.constructor === Object)) {
|
||||
this.GeoJson = geo;
|
||||
L.geoJSON(geo, {
|
||||
style: function (features) {
|
||||
return {
|
||||
color: typeof features.properties["stroke"] === "undefined" ? '#000000' : features.properties["stroke"],
|
||||
weight: typeof features.properties["stroke-width"] === "undefined" ? 1 : features.properties["stroke-width"],
|
||||
opacity: typeof features.properties["stroke-opacity"] === "undefined" ? 1 : features.properties["stroke-opacity"],
|
||||
fillColor: typeof features.properties["fill"] === "undefined" ? '#ffffff' : features.properties["fill"],
|
||||
fillOpacity: typeof features.properties["fill-opacity"] === "undefined" ? 1 : features.properties["fill-opacity"]
|
||||
};
|
||||
},
|
||||
onEachFeature: function (feature, layer) {
|
||||
if (feature.geometry.type === "Polygon" || feature.geometry.type === "Point" && Object.prototype.hasOwnProperty.call(feature.properties, "icon")) {
|
||||
var text = "<b>" + feature.properties.name + "</b>";
|
||||
if (Object.prototype.hasOwnProperty.call(feature.properties, "description")) {
|
||||
text = text + "<br>" + feature.properties.description;
|
||||
}
|
||||
layer.bindPopup(text, { maxWidth: 485 });
|
||||
}
|
||||
},
|
||||
pointToLayer: function (geoJsonPoint, latlng) {
|
||||
if (Object.prototype.hasOwnProperty.call(geoJsonPoint.properties, "description") && geoJsonPoint.properties["description"] === "snumber" && !Object.prototype.hasOwnProperty.call(geoJsonPoint.properties, "icon")) {
|
||||
var snumbericon = L.marker(latlng, {
|
||||
icon: new L.DivIcon({
|
||||
className: "snumber-icon",
|
||||
html: geoJsonPoint.properties["name"],
|
||||
iconSize: [8, 8]
|
||||
}),
|
||||
interactive: false
|
||||
});
|
||||
MapObject._SpecialMarkers.push(snumbericon);
|
||||
return snumbericon;
|
||||
} else if (Object.prototype.hasOwnProperty.call(geoJsonPoint.properties, "description") && geoJsonPoint.properties["description"] === "coord" && !Object.prototype.hasOwnProperty.call(geoJsonPoint.properties, "icon")) {
|
||||
var coordicon = L.marker(latlng, {
|
||||
icon: new L.DivIcon({
|
||||
className: "coord-icon",
|
||||
html: geoJsonPoint.properties["name"]
|
||||
}),
|
||||
interactive: false
|
||||
});
|
||||
MapObject._SpecialMarkers.push(coordicon);
|
||||
return coordicon;
|
||||
} else if (Object.prototype.hasOwnProperty.call(geoJsonPoint.properties, "icon")) {
|
||||
return L.marker(latlng, { icon: L.icon({ iconUrl: "css/icons/cctv.png", iconSize: [32, 32] }) });
|
||||
}
|
||||
}
|
||||
}).addTo(this.Map);
|
||||
}
|
||||
},
|
||||
_ParseAJAXLayers: function (maps) {
|
||||
var i = 0;
|
||||
for (var key in maps) {
|
||||
i++;
|
||||
}
|
||||
if (i === 1) {
|
||||
L.tileLayer(maps["online"]["url"], {
|
||||
attribution: maps["online"]["attribution"],
|
||||
minZoom: maps["online"]["minZoom"],
|
||||
maxZoom: maps["online"]["maxZoom"]
|
||||
}).addTo(this.Map);
|
||||
} else {
|
||||
var baseMaps = {};
|
||||
for (key in maps) {
|
||||
if (key !== "online") {
|
||||
var basemap = L.tileLayer(maps[key]["url"], {
|
||||
attribution: maps[key]["attribution"],
|
||||
minZoom: maps[key]["minZoom"],
|
||||
maxZoom: maps[key]["maxZoom"],
|
||||
errorTileUrl: "css/icons/failtile.png"
|
||||
});
|
||||
basemap.addTo(this.Map);
|
||||
baseMaps[maps[key]["title"]] = basemap;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (elem.feature.properties["description"] === "coord") {
|
||||
elem._icon.style.fontSize = "0px";
|
||||
for (key in maps) {
|
||||
if (!Object.prototype.hasOwnProperty.call(baseMaps, maps[key]["title"])) {
|
||||
baseMaps[maps[key]["title"]] = L.tileLayer(maps[key]["url"], {
|
||||
attribution: maps[key]["attribution"],
|
||||
minZoom: maps[key]["minZoom"],
|
||||
maxZoom: maps[key]["maxZoom"],
|
||||
errorTileUrl: "css/icons/failtile.png"
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (currentZoom == 14) {
|
||||
SpecialMarkers.forEach(function (elem, index) {
|
||||
if (elem.feature.properties["description"] === "snumber") {
|
||||
elem._icon.style.fontSize = "0px";
|
||||
elem._icon.style.marginLeft = "0px";
|
||||
elem._icon.style.marginTop = "0px";
|
||||
}
|
||||
if (elem.feature.properties["description"] === "coord") {
|
||||
elem._icon.style.fontSize = "6px";
|
||||
}
|
||||
});
|
||||
} else if (currentZoom == 15) {
|
||||
SpecialMarkers.forEach(function (elem, index) {
|
||||
if (elem.feature.properties["description"] === "snumber") {
|
||||
elem._icon.style.fontSize = "0px";
|
||||
elem._icon.style.marginLeft = "0px";
|
||||
elem._icon.style.marginTop = "0px";
|
||||
}
|
||||
if (elem.feature.properties["description"] === "coord") {
|
||||
elem._icon.style.fontSize = "9px";
|
||||
}
|
||||
});
|
||||
} else if (currentZoom == 16) {
|
||||
SpecialMarkers.forEach(function (elem, index) {
|
||||
if (elem.feature.properties["description"] === "snumber") {
|
||||
elem._icon.style.fontSize = "5px";
|
||||
elem._icon.style.marginLeft = "-4px";
|
||||
elem._icon.style.marginTop = "-4px";
|
||||
}
|
||||
if (elem.feature.properties["description"] === "coord") {
|
||||
elem._icon.style.fontSize = "13px";
|
||||
}
|
||||
});
|
||||
} else if (currentZoom == 17) {
|
||||
SpecialMarkers.forEach(function (elem, index) {
|
||||
if (elem.feature.properties["description"] === "snumber") {
|
||||
elem._icon.style.fontSize = "5px";
|
||||
elem._icon.style.marginLeft = "-4px";
|
||||
elem._icon.style.marginTop = "-4px";
|
||||
}
|
||||
if (elem.feature.properties["description"] === "coord") {
|
||||
elem._icon.style.fontSize = "16px";
|
||||
}
|
||||
});
|
||||
} else if (currentZoom == 18) {
|
||||
SpecialMarkers.forEach(function (elem, index) {
|
||||
if (elem.feature.properties["description"] === "snumber") {
|
||||
elem._icon.style.fontSize = "8px";
|
||||
elem._icon.style.marginLeft = "-5px";
|
||||
elem._icon.style.marginTop = "-6px";
|
||||
}
|
||||
if (elem.feature.properties["description"] === "coord") {
|
||||
elem._icon.style.fontSize = "25px";
|
||||
}
|
||||
});
|
||||
} else if (currentZoom == 19) {
|
||||
SpecialMarkers.forEach(function (elem, index) {
|
||||
if (elem.feature.properties["description"] === "snumber") {
|
||||
elem._icon.style.fontSize = "14px";
|
||||
elem._icon.style.marginLeft = "-8px";
|
||||
elem._icon.style.marginTop = "-11px";
|
||||
}
|
||||
if (elem.feature.properties["description"] === "coord") {
|
||||
elem._icon.style.fontSize = "45px";
|
||||
L.control.layers(baseMaps).addTo(this.Map);
|
||||
}
|
||||
},
|
||||
_SetupClickHandler: function () {
|
||||
this.Map.on("click", this._HidePanel);
|
||||
},
|
||||
_SetupMapZoomFontsize: function () {
|
||||
this.Map.on('zoomend', function () {
|
||||
var currentZoom = MapObject.Map.getZoom();
|
||||
if (currentZoom < 14) {
|
||||
MapObject._SpecialMarkers.forEach(function (elem, index) {
|
||||
if (elem.feature.properties["description"] === "snumber") {
|
||||
elem._icon.style.fontSize = "0px";
|
||||
elem._icon.style.marginLeft = "0px";
|
||||
elem._icon.style.marginTop = "0px";
|
||||
}
|
||||
if (elem.feature.properties["description"] === "coord") {
|
||||
elem._icon.style.fontSize = "0px";
|
||||
}
|
||||
});
|
||||
} else if (currentZoom === 14) {
|
||||
MapObject._SpecialMarkers.forEach(function (elem, index) {
|
||||
if (elem.feature.properties["description"] === "snumber") {
|
||||
elem._icon.style.fontSize = "0px";
|
||||
elem._icon.style.marginLeft = "0px";
|
||||
elem._icon.style.marginTop = "0px";
|
||||
}
|
||||
if (elem.feature.properties["description"] === "coord") {
|
||||
elem._icon.style.fontSize = "6px";
|
||||
}
|
||||
});
|
||||
} else if (currentZoom === 15) {
|
||||
MapObject._SpecialMarkers.forEach(function (elem, index) {
|
||||
if (elem.feature.properties["description"] === "snumber") {
|
||||
elem._icon.style.fontSize = "0px";
|
||||
elem._icon.style.marginLeft = "0px";
|
||||
elem._icon.style.marginTop = "0px";
|
||||
}
|
||||
if (elem.feature.properties["description"] === "coord") {
|
||||
elem._icon.style.fontSize = "9px";
|
||||
}
|
||||
});
|
||||
} else if (currentZoom === 16) {
|
||||
MapObject._SpecialMarkers.forEach(function (elem, index) {
|
||||
if (elem.feature.properties["description"] === "snumber") {
|
||||
elem._icon.style.fontSize = "5px";
|
||||
elem._icon.style.marginLeft = "-4px";
|
||||
elem._icon.style.marginTop = "-4px";
|
||||
}
|
||||
if (elem.feature.properties["description"] === "coord") {
|
||||
elem._icon.style.fontSize = "13px";
|
||||
}
|
||||
});
|
||||
} else if (currentZoom === 17) {
|
||||
MapObject._SpecialMarkers.forEach(function (elem, index) {
|
||||
if (elem.feature.properties["description"] === "snumber") {
|
||||
elem._icon.style.fontSize = "5px";
|
||||
elem._icon.style.marginLeft = "-4px";
|
||||
elem._icon.style.marginTop = "-4px";
|
||||
}
|
||||
if (elem.feature.properties["description"] === "coord") {
|
||||
elem._icon.style.fontSize = "16px";
|
||||
}
|
||||
});
|
||||
} else if (currentZoom === 18) {
|
||||
MapObject._SpecialMarkers.forEach(function (elem, index) {
|
||||
if (elem.feature.properties["description"] === "snumber") {
|
||||
elem._icon.style.fontSize = "8px";
|
||||
elem._icon.style.marginLeft = "-5px";
|
||||
elem._icon.style.marginTop = "-6px";
|
||||
}
|
||||
if (elem.feature.properties["description"] === "coord") {
|
||||
elem._icon.style.fontSize = "25px";
|
||||
}
|
||||
});
|
||||
} else if (currentZoom === 19) {
|
||||
MapObject._SpecialMarkers.forEach(function (elem, index) {
|
||||
if (elem.feature.properties["description"] === "snumber") {
|
||||
elem._icon.style.fontSize = "14px";
|
||||
elem._icon.style.marginLeft = "-8px";
|
||||
elem._icon.style.marginTop = "-11px";
|
||||
}
|
||||
if (elem.feature.properties["description"] === "coord") {
|
||||
elem._icon.style.fontSize = "45px";
|
||||
}
|
||||
});
|
||||
}
|
||||
MarkerObject.ScaleSensors("zoom");
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
mymap.on("click", hidePanel);
|
||||
|
||||
function hidePanel(e) {
|
||||
showHidePanel(null);
|
||||
}
|
||||
}.Start();
|
@ -1,27 +1,65 @@
|
||||
setInterval(datarunner, 1000);
|
||||
function datarunner() {
|
||||
var loc = new XMLHttpRequest();
|
||||
loc.onreadystatechange = parseAjaxLoc;
|
||||
loc.open("GET", "http://{%REQUEST_URL_HOST%}/loc", true);
|
||||
loc.send();
|
||||
|
||||
var panic = new XMLHttpRequest();
|
||||
panic.onreadystatechange = parseAjaxPanic;
|
||||
panic.open("GET", "http://{%REQUEST_URL_HOST%}/panic", true);
|
||||
panic.send();
|
||||
}
|
||||
|
||||
var markers = {};
|
||||
var serverLocation = {};
|
||||
//https://leafletjs.com/reference-1.4.0.html#marker
|
||||
function parseAjaxLoc() {
|
||||
if (this.readyState === 4 && this.status === 200) {
|
||||
serverLocation = JSON.parse(this.responseText);
|
||||
for (var key in serverLocation) {
|
||||
if (serverLocation.hasOwnProperty(key)) {
|
||||
var positionItem = serverLocation[key];
|
||||
var MarkerObject = {
|
||||
/// public variables
|
||||
LocationData: {},
|
||||
PanicData: {},
|
||||
VisibleMarkers: {},
|
||||
/// private variables
|
||||
_Markers: {},
|
||||
_Sensors: {},
|
||||
_SensorSettings: {},
|
||||
/// public functions
|
||||
ChangeFilter: function (select) {
|
||||
this.VisibleMarkers = {};
|
||||
if (select.selectedOptions.length > 0) {
|
||||
for (var i = 0; i < select.selectedOptions.length; i++) {
|
||||
this.VisibleMarkers[select.selectedOptions[i].value] = true;
|
||||
}
|
||||
this.VisibleMarkers["no"] = true;
|
||||
this.VisibleMarkers["___isset"] = true;
|
||||
}
|
||||
this._ParseAJAXLoc(this.LocationData);
|
||||
},
|
||||
ParseAJAXPositionModel: function (json) {
|
||||
this._ParseAJAXLoc(json.Positions);
|
||||
this._ParseAJAXPanic(json.Alarms);
|
||||
},
|
||||
ParseAJAXSensorModel: function (json) {
|
||||
this._ParseAJAXSensors(json.Enviroments);
|
||||
},
|
||||
ParseAJAXSettings: function (json) {
|
||||
this._SensorSettings = json["Sensors"];
|
||||
},
|
||||
ScaleSensors: function (el) {
|
||||
if (el === "zoom") {
|
||||
for (var sensorid in this._Sensors) {
|
||||
this.ScaleSensors(document.getElementById('MapSensor_id_' + sensorid));
|
||||
}
|
||||
return;
|
||||
}
|
||||
var currentZoom = MapObject.Map.getZoom();
|
||||
var scale = 1;
|
||||
if (currentZoom < 14) {
|
||||
scale = 0;
|
||||
} else if (currentZoom === 14) {
|
||||
scale = 0.2;
|
||||
} else if (currentZoom === 15) {
|
||||
scale = 0.5;
|
||||
} else if (currentZoom >= 16) {
|
||||
scale = 1;
|
||||
}
|
||||
el.style.cssText = "transform: scale(" + scale + ");";
|
||||
},
|
||||
Start: function () {
|
||||
return this;
|
||||
},
|
||||
/// private functions
|
||||
_ParseAJAXLoc: function (serverLocation) {
|
||||
this.LocationData = serverLocation;
|
||||
for (var key in this.LocationData) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.LocationData, key)) {
|
||||
var positionItem = this.LocationData[key];
|
||||
if (positionItem['Latitude'] !== 0 || positionItem['Longitude'] !== 0) {
|
||||
if (!markers.hasOwnProperty(key)) {
|
||||
if (!Object.prototype.hasOwnProperty.call(this._Markers, key)) {
|
||||
var marker = null;
|
||||
if (positionItem['Icon'] === null) {
|
||||
marker = L.marker([positionItem['Latitude'], positionItem['Longitude']], { 'title': positionItem['Name'] });
|
||||
@ -30,58 +68,104 @@ function parseAjaxLoc() {
|
||||
className: 'pos-marker',
|
||||
iconSize: [56, 80],
|
||||
iconAnchor: [0, 80],
|
||||
html: '<object data="'+positionItem['Icon']+'" type="image/svg+xml" style="height:80px; width:56px;"></object>'
|
||||
html: '<img src="' + positionItem['Icon'] + '" height="80" width="56" />'
|
||||
});
|
||||
marker = L.marker([positionItem['Latitude'], positionItem['Longitude']], { 'title': positionItem['Name'], 'icon': myIcon });
|
||||
}
|
||||
markers[key] = marker.addTo(mymap).on("click", showMarkerInfo, key);
|
||||
this._Markers[key] = marker.addTo(MapObject.Map).on("click", function () { MenuObject.statusToDevice = this; MenuObject.ShowHidePanel("pannels_info"); }, key);
|
||||
} else {
|
||||
markers[key].setLatLng([positionItem['Latitude'], positionItem['Longitude']]);
|
||||
this._Markers[key].setLatLng([positionItem['Latitude'], positionItem['Longitude']]);
|
||||
if (positionItem['Icon'] !== null) {
|
||||
if (markers[key]._icon.children.length === 0) {
|
||||
markers[key].setIcon(L.divIcon({
|
||||
if (this._Markers[key]._icon.children.length === 0) {
|
||||
this._Markers[key].setIcon(L.divIcon({
|
||||
className: 'pos-marker',
|
||||
iconSize: [56, 80],
|
||||
iconAnchor: [0, 80],
|
||||
html: '<object data="' + positionItem['Icon'] + '" type="image/svg+xml" style="height:80px; width:56px;"></object>'
|
||||
html: '<img src="' + positionItem['Icon'] + '" height="80" width="56" />'
|
||||
}));
|
||||
} else if (markers[key]._icon.children[0].hasAttribute("data")) {
|
||||
var old = markers[key]._icon.children[0]["data"].substring(markers[key]._icon.children[0]["data"].indexOf("/", 7) + 1);
|
||||
} else if (this._Markers[key]._icon.children[0].hasAttribute("src")) {
|
||||
var old = this._Markers[key]._icon.children[0]["src"].substring(this._Markers[key]._icon.children[0]["src"].indexOf("/", 7) + 1);
|
||||
if (old !== positionItem['Icon']) {
|
||||
markers[key]._icon.children[0]["data"] = positionItem['Icon'];
|
||||
this._Markers[key]._icon.children[0]["src"] = positionItem['Icon'];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (markers[key]._icon.children.length === 1 && markers[key]._icon.children[0].hasAttribute("data")) {
|
||||
markers[key].removeFrom(mymap);
|
||||
markers[key] = L.marker([positionItem['Latitude'], positionItem['Longitude']], { 'title': positionItem['Name'] }).addTo(mymap).on("click", showMarkerInfo, key);
|
||||
if (this._Markers[key]._icon.children.length === 1 && this._Markers[key]._icon.children[0].hasAttribute("src")) {
|
||||
this._Markers[key].removeFrom(MapObject.Map);
|
||||
this._Markers[key] = L.marker([positionItem['Latitude'], positionItem['Longitude']], { 'title': positionItem['Name'] }).addTo(MapObject.Map).on("click", function () { MenuObject.statusToDevice = this; MenuObject.ShowHidePanel("pannels_info"); }, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (positionItem.Group !== null && Object.prototype.hasOwnProperty.call(this.VisibleMarkers, "___isset") && !Object.prototype.hasOwnProperty.call(this.VisibleMarkers, positionItem.Group)) {
|
||||
this._Markers[key]._icon.style.opacity = 0;
|
||||
} else {
|
||||
var lasttime = FunctionsObject.TimeCalculation(positionItem['Recievedtime'], "diffraw");
|
||||
if (lasttime <= 5 * 60) {
|
||||
this._Markers[key]._icon.style.opacity = 1;
|
||||
} else if (lasttime > 5 * 60 && lasttime <= 15 * 60) {
|
||||
this._Markers[key]._icon.style.opacity = 0.9 - (lasttime - 5 * 60) / (15 * 60 - 5 * 60) * (0.9 - 0.7);
|
||||
} else if (lasttime > 15 * 60 && lasttime <= 30 * 60) {
|
||||
this._Markers[key]._icon.style.opacity = 0.7 - (lasttime - 15 * 60) / (30 * 60 - 15 * 60) * (0.7 - 0.5);
|
||||
} else if (lasttime > 30 * 60 && lasttime <= 60 * 60) {
|
||||
this._Markers[key]._icon.style.opacity = 0.5 - (lasttime - 30 * 60) / (30 * 60 - 30 * 60) * (0.5 - 0.25);
|
||||
} else if (lasttime > 60 * 60) {
|
||||
this._Markers[key]._icon.style.opacity = 0.25;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
updateStatus();
|
||||
update_pannels_info();
|
||||
}
|
||||
}
|
||||
|
||||
function parseAjaxPanic() {
|
||||
if (this.readyState === 4 && this.status === 200) {
|
||||
var panics = JSON.parse(this.responseText);
|
||||
for (var id in panics) {
|
||||
if (panics.hasOwnProperty(id)) {
|
||||
var alertItem = panics[id];
|
||||
if (markers.hasOwnProperty(id)) {
|
||||
var marker = markers[id];
|
||||
if (timeCalculation(alertItem["Recievedtime"], "diffraw") <= 10 && marker._icon.className.indexOf(" marker-alert") === -1) {
|
||||
marker._icon.className += " marker-alert";
|
||||
showMarkerInfoPerId(id);
|
||||
} else if (timeCalculation(alertItem["Recievedtime"], "diffraw") > 10 && marker._icon.className.indexOf(" marker-alert") !== -1) {
|
||||
marker._icon.className = marker._icon.className.replace(" marker-alert", "");
|
||||
MenuObject.UpdateStatus();
|
||||
MenuObject._Update_pannels_info();
|
||||
},
|
||||
_ParseAJAXPanic: function (serverPanic) {
|
||||
this.PanicData = serverPanic;
|
||||
for (var id in this.PanicData) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.PanicData, id)) {
|
||||
var alertItem = this.PanicData[id];
|
||||
if (Object.prototype.hasOwnProperty.call(this._Markers, id)) {
|
||||
var marker = this._Markers[id];
|
||||
if (!(this.LocationData[id].Group !== null && Object.prototype.hasOwnProperty.call(this.VisibleMarkers, "___isset") /**/ && !Object.prototype.hasOwnProperty.call(this.VisibleMarkers, this.LocationData[id].Group))) {
|
||||
if (FunctionsObject.TimeCalculation(alertItem["Recievedtime"], "diffraw") <= 10 && marker._icon.className.indexOf(" marker-alert") === -1) {
|
||||
marker._icon.className += " marker-alert";
|
||||
MenuObject.ShowMarkerInfoPerId(id);
|
||||
} else if (FunctionsObject.TimeCalculation(alertItem["Recievedtime"], "diffraw") > 10 && marker._icon.className.indexOf(" marker-alert") !== -1) {
|
||||
marker._icon.className = marker._icon.className.replace(" marker-alert", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ParseAJAXSensors: function (sensorjson) {
|
||||
for (var sensorid in sensorjson) {
|
||||
if (Object.prototype.hasOwnProperty.call(sensorjson, sensorid)) {
|
||||
if (Object.prototype.hasOwnProperty.call(this._SensorSettings, sensorid)) {
|
||||
var sensordata = sensorjson[sensorid];
|
||||
var sensorsettings = this._SensorSettings[sensorid];
|
||||
if (!Object.prototype.hasOwnProperty.call(this._Sensors, sensorid)) { //Sensor is not drawn until now
|
||||
var sensor = null;
|
||||
var sensorIcon = L.divIcon({
|
||||
className: 'sensoricon',
|
||||
iconSize: [60, 120],
|
||||
iconAnchor: [30, 60],
|
||||
html: '<div class="mapsensor" id="MapSensor_id_' + sensorid + '"><span class="name">' + sensorsettings.Alias + '</span>' +
|
||||
'<span class="temp">' + sensordata.Temperature + ' °C</span>' +
|
||||
'<span class="wind">' + sensordata.Windspeed + ' m/s</span>' +
|
||||
'<span class="hum">' + sensordata.Humidity + ' %rl</span></div>'
|
||||
});
|
||||
sensor = L.marker(sensorsettings.Coordinates, { 'title': sensorsettings.Alias, 'icon': sensorIcon, interactive: false });
|
||||
this._Sensors[sensorid] = sensor.addTo(MapObject.Map);
|
||||
this.ScaleSensors(document.getElementById('MapSensor_id_' + sensorid));
|
||||
} else { //Sensor refresh!
|
||||
document.getElementById('MapSensor_id_' + sensorid).innerHTML = '<span class="name">' + sensorsettings.Alias + '</span>' +
|
||||
'<span class="temp">' + sensordata.Temperature + ' °C</span>' +
|
||||
'<span class="wind">' + sensordata.Windspeed + ' m/s</span>' +
|
||||
'<span class="hum">' + sensordata.Humidity + ' %rl</span>';
|
||||
}
|
||||
document.getElementById('MapSensor_id_' + sensorid).className = "mapsensor" + (sensordata.Windspeed > sensorsettings.Level ? ' alert' : '');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.Start();
|
@ -1,165 +1,230 @@
|
||||
var visiblePanel = null;
|
||||
function showHidePanel(name) {
|
||||
if (visiblePanel === null && name !== null) {
|
||||
document.getElementById("pannels").style.display = "block";
|
||||
document.getElementById(name).style.display = "block";
|
||||
visiblePanel = name;
|
||||
if (typeof window["update_" + name] === "function") {
|
||||
window["update_" + name]();
|
||||
var MenuObject = {
|
||||
/// public variables
|
||||
statusToDevice: null,
|
||||
/// private variables
|
||||
_overviewStatus: new Array(),
|
||||
_visiblePanel: null,
|
||||
/// public functions
|
||||
ParseAJAXSensorModel: function (json) {
|
||||
this._ParseAJAXWeatherAlerts(json.Weather.Warnungen);
|
||||
},
|
||||
SearchInGeoJson: function (searchtext) {
|
||||
var html = "";
|
||||
if (MapObject.GeoJson.features.length > 0) {
|
||||
for (var i = 0; i < MapObject.GeoJson.features.length; i++) {
|
||||
var feature = MapObject.GeoJson.features[i];
|
||||
if ((feature.properties.name.toLowerCase().indexOf(searchtext.toLowerCase()) !== -1 ||
|
||||
(typeof feature.properties.description !== "undefined" && feature.properties.description.toLowerCase().indexOf(searchtext.toLowerCase()) !== -1)) &&
|
||||
feature.geometry.type === "Polygon") {
|
||||
if (feature.geometry.coordinates.length > 0 && feature.geometry.coordinates[0].length > 0 && feature.geometry.coordinates[0][0].length > 0) {
|
||||
html += "<div class='result' onclick='MapObject.JumpTo(" + feature.geometry.coordinates[0][0][1] + "," + feature.geometry.coordinates[0][0][0] + ");'><span class='text'>" +
|
||||
"<span class='title'>" + feature.properties.name + "</span>" +
|
||||
"<span class='desc'>" + (typeof feature.properties.description !== "undefined" ? feature.properties.description : "") + "</span></span>" +
|
||||
"<span class='box' style='background-color: " + feature.properties.fill + "; border-color: " + feature.properties.stroke + "'></span>" +
|
||||
"</div>";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (visiblePanel === name && name !== "pannels_info" || name === null) {
|
||||
document.getElementById("pannels").style.display = "none";
|
||||
if (visiblePanel !== null) {
|
||||
document.getElementById(visiblePanel).style.display = "none";
|
||||
document.getElementById("search_results").innerHTML = html;
|
||||
},
|
||||
ShowHidePanel: function (name) {
|
||||
if (this._visiblePanel === null && name !== null) {
|
||||
document.getElementById("pannels").style.display = "block";
|
||||
document.getElementById(name).style.display = "block";
|
||||
this._visiblePanel = name;
|
||||
if (typeof MenuObject["_Update_" + name] === "function") {
|
||||
MenuObject["_Update_" + name]();
|
||||
}
|
||||
} else if (this._visiblePanel === name && name !== "pannels_info" || name === null) {
|
||||
document.getElementById("pannels").style.display = "none";
|
||||
if (this._visiblePanel !== null) {
|
||||
document.getElementById(this._visiblePanel).style.display = "none";
|
||||
}
|
||||
this._visiblePanel = null;
|
||||
} else {
|
||||
document.getElementById(this._visiblePanel).style.display = "none";
|
||||
document.getElementById(name).style.display = "block";
|
||||
this._visiblePanel = name;
|
||||
if (typeof MenuObject["_Update_" + name] === "function") {
|
||||
MenuObject["_Update_" + name]();
|
||||
}
|
||||
}
|
||||
visiblePanel = null;
|
||||
} else {
|
||||
document.getElementById(visiblePanel).style.display = "none";
|
||||
document.getElementById(name).style.display = "block";
|
||||
visiblePanel = name;
|
||||
if (typeof window["update_" + name] === "function") {
|
||||
window["update_" + name]();
|
||||
},
|
||||
ShowMarkerInfoPerId: function (id) {
|
||||
this.statusToDevice = id;
|
||||
this.ShowHidePanel("pannels_info");
|
||||
},
|
||||
Start: function () {
|
||||
return this;
|
||||
},
|
||||
SubmitLoginForm: function () {
|
||||
var adminlogin = new XMLHttpRequest();
|
||||
adminlogin.onreadystatechange = function () {
|
||||
if (adminlogin.readyState === 4 && adminlogin.status === 200) {
|
||||
MenuObject._Update_pannels_admin();
|
||||
}
|
||||
};
|
||||
adminlogin.open("POST", "/admin/login", true);
|
||||
adminlogin.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
||||
adminlogin.send("user=" + encodeURI(document.getElementById("pannels_admin_name").value) + "&pass=" + encodeURI(document.getElementById("pannels_admin_pass").value));
|
||||
},
|
||||
UpdateStatus: function () {
|
||||
for (var id in MarkerObject.LocationData) {
|
||||
if (Object.prototype.hasOwnProperty.call(MarkerObject.LocationData, id)) {
|
||||
var positionItem = MarkerObject.LocationData[id];
|
||||
if (typeof this._overviewStatus[id] === "undefined") {
|
||||
this._overviewStatus[id] = this._CreateOverviewElement(positionItem, id);
|
||||
document.getElementById("pannels_pos").appendChild(this._overviewStatus[id]);
|
||||
}
|
||||
if (positionItem.Group !== null && Object.prototype.hasOwnProperty.call(MarkerObject.VisibleMarkers, "___isset") && !Object.prototype.hasOwnProperty.call(MarkerObject.VisibleMarkers, positionItem.Group)) {
|
||||
if (this._overviewStatus[id].className.indexOf("filter") === -1) {
|
||||
this._overviewStatus[id].className = "item filter";
|
||||
}
|
||||
} else {
|
||||
if (this._overviewStatus[id].className.indexOf("filter") !== -1) {
|
||||
this._overviewStatus[id].className = "item";
|
||||
}
|
||||
}
|
||||
this._UpdateOverviewElement(positionItem, id);
|
||||
}
|
||||
}
|
||||
},
|
||||
/// private functions
|
||||
_UpdateOverviewElement: function (positionItem, id) {
|
||||
if (positionItem["Batterysimple"] === 0) {
|
||||
document.getElementById("overview-color-id-" + id).style.backgroundColor = "red";
|
||||
} else if (positionItem["Batterysimple"] === 1 || positionItem["Batterysimple"] === 2) {
|
||||
document.getElementById("overview-color-id-" + id).style.backgroundColor = "yellow";
|
||||
} else if (positionItem["Batterysimple"] === 3 || positionItem["Batterysimple"] === 4) {
|
||||
document.getElementById("overview-color-id-" + id).style.backgroundColor = "green";
|
||||
}
|
||||
document.getElementById("overview-name-id-" + id).innerText = positionItem["Name"];
|
||||
if (document.getElementById("overview-akkuimg-id-" + id).src.substring(document.getElementById("overview-akkuimg-id-" + id).src.indexOf("/", 7) + 1) !== "icons/akku/" + positionItem["Batterysimple"] + "-4.png") {
|
||||
document.getElementById("overview-akkuimg-id-" + id).src = "icons/akku/" + positionItem["Batterysimple"] + "-4.png";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var statusToDevice = null;
|
||||
function showMarkerInfo(e) {
|
||||
statusToDevice = this;
|
||||
showHidePanel("pannels_info");
|
||||
}
|
||||
|
||||
function showMarkerInfoPerId(id) {
|
||||
statusToDevice = id;
|
||||
showHidePanel("pannels_info");
|
||||
}
|
||||
|
||||
function showMarkerInfoMenu() {
|
||||
statusToDevice = this.getAttribute("rel");
|
||||
showHidePanel("pannels_info");
|
||||
}
|
||||
|
||||
function update_pannels_info() {
|
||||
document.getElementById("pannels_info").innerHTML = "";
|
||||
if (serverLocation.hasOwnProperty(statusToDevice)) {
|
||||
var positionItem = serverLocation[statusToDevice];
|
||||
var html = "<div class=\"name\">Name: <span class=\"bold\">" + positionItem["Name"] + "</span></div>";
|
||||
html += "<div class=\"batt\"><span class=\"bold\">Batterie:</span> " + positionItem["Battery"] + "V <img src=\"icons/akku/" + positionItem["Batterysimple"] + "-4.png\"></div>";
|
||||
if (positionItem["Fix"]) {
|
||||
html += "<div class=\"gps\" style=\"color: green;\">GPS-Empfang</div>";
|
||||
document.getElementById("overview-gps-id-" + id).innerText = "GPS-Empfang";
|
||||
document.getElementById("overview-gps-id-" + id).style.color = "green";
|
||||
} else {
|
||||
html += "<div class=\"gps\" style=\"color: red;\">kein GPS-Empfang</div>";
|
||||
document.getElementById("overview-gps-id-" + id).innerText = "kein GPS-Empfang";
|
||||
document.getElementById("overview-gps-id-" + id).style.color = "red";
|
||||
}
|
||||
html += "<div class=\"coord\">" + positionItem["UTM"]["Base"] + " <span style=\"color: #b1a831;\">" + positionItem["UTM"]["FieldWidth"] + "</span><span style=\"color: #218c00;\">" + positionItem["UTM"]["Width"] + "</span> <span style=\"color: #b1a831;\">" + positionItem["UTM"]["FieldHeight"] + "</span><span style=\"color: #218c00;\">" + positionItem["UTM"]["Height"] + "</span></div>";
|
||||
html += "<div class=\"height\"><span class=\"bold\">Höhe:</span> " + positionItem["Height"].toFixed(1) + " m</div>";
|
||||
html += "<div class=\"hdop\"><span class=\"bold\">HDOP:</span> " + positionItem["Hdop"].toFixed(1) + "</div>";
|
||||
html += "<div class=\"lanlot\"><span class=\"bold\">Dezimal:</span> " + positionItem["Latitude"].toFixed(5) + ", " + positionItem["Longitude"].toFixed(5) + "</div>";
|
||||
html += "<div class=\"lastgps\"><span class=\"bold\">Letzter Wert:</span> Vor: " + timeCalculation(positionItem["Lastgpspostime"], "difftext") + "</div>";
|
||||
html += "<div class=\"update\"><span class=\"bold\">Update:</span> " + timeCalculation(positionItem["Recievedtime"], "str") + "<br><span class=\"bold\">Vor:</span> " + timeCalculation(positionItem["Recievedtime"], "difftext") + "</div>";
|
||||
html += "<div><span class=\"bold\">RSSI:</span> " + positionItem["Rssi"] + ", <span class=\"bold\">SNR:</span> " + positionItem["Snr"] + "</div>";
|
||||
document.getElementById("pannels_info").innerHTML = html;
|
||||
}
|
||||
}
|
||||
|
||||
var overviewStatus = new Array();
|
||||
|
||||
function updateStatus() {
|
||||
for (var id in serverLocation) {
|
||||
if (serverLocation.hasOwnProperty(id)) {
|
||||
var positionItem = serverLocation[id];
|
||||
if (typeof overviewStatus[id] === "undefined") {
|
||||
overviewStatus[id] = createOverviewElement(positionItem, id);
|
||||
document.getElementById("pannels_pos").appendChild(overviewStatus[id]);
|
||||
}
|
||||
updateOverviewElement(positionItem, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateOverviewElement(positionItem, id) {
|
||||
if (positionItem["Batterysimple"] === 0) {
|
||||
document.getElementById("overview-color-id-" + id).style.backgroundColor = "red";
|
||||
} else if (positionItem["Batterysimple"] === 1 || positionItem["Batterysimple"] === 2) {
|
||||
document.getElementById("overview-color-id-" + id).style.backgroundColor = "yellow";
|
||||
} else if (positionItem["Batterysimple"] === 3 || positionItem["Batterysimple"] === 4) {
|
||||
document.getElementById("overview-color-id-" + id).style.backgroundColor = "green";
|
||||
}
|
||||
document.getElementById("overview-name-id-" + id).innerText = positionItem["Name"];
|
||||
document.getElementById("overview-akkuimg-id-" + id).src = "icons/akku/" + positionItem["Batterysimple"] + "-4.png";
|
||||
if (positionItem["Fix"]) {
|
||||
document.getElementById("overview-gps-id-" + id).innerText = "GPS-Empfang";
|
||||
document.getElementById("overview-gps-id-" + id).style.color = "green";
|
||||
} else {
|
||||
document.getElementById("overview-gps-id-" + id).innerText = "kein GPS-Empfang";
|
||||
document.getElementById("overview-gps-id-" + id).style.color = "red";
|
||||
}
|
||||
document.getElementById("overview-update-id-" + id).innerText = "Letzte Werte: vor " + timeCalculation(positionItem["Recievedtime"], "difftext");
|
||||
if (positionItem['Icon'] === null) {
|
||||
var icon = document.getElementById("overview-icon-id-" + id);
|
||||
if (icon.children[0].hasAttribute("data")) {
|
||||
document.getElementById("overview-icon-id-" + id).innerHTML = "<img src =\"icons/marker/map-marker.png\">";
|
||||
}
|
||||
} else {
|
||||
if (document.getElementById("overview-icon-id-" + id).children[0].hasAttribute("data")) {
|
||||
if (document.getElementById("overview-icon-id-" + id).children[0]["data"].substring(document.getElementById("overview-icon-id-" + id).children[0]["data"].indexOf("/", 7) + 1) !== positionItem['Icon'] + "&marker-bg=hidden") {
|
||||
document.getElementById("overview-icon-id-" + id).children[0]["data"] = positionItem['Icon'] + "&marker-bg=hidden";
|
||||
document.getElementById("overview-update-id-" + id).innerText = "Letzte Werte: vor " + FunctionsObject.TimeCalculation(positionItem["Recievedtime"], "difftext");
|
||||
if (positionItem['Icon'] === null) {
|
||||
var icon = document.getElementById("overview-icon-id-" + id);
|
||||
if (icon.children[0].hasAttribute("rel")) {
|
||||
document.getElementById("overview-icon-id-" + id).innerHTML = "<img src =\"icons/marker/map-marker.png\">";
|
||||
}
|
||||
} else {
|
||||
document.getElementById("overview-icon-id-" + id).innerHTML = "<object data=\"" + positionItem['Icon'] + "&marker-bg=hidden" + "\" type=\"image/svg+xml\"></object>";
|
||||
if (document.getElementById("overview-icon-id-" + id).children[0].hasAttribute("src")) {
|
||||
if (document.getElementById("overview-icon-id-" + id).children[0]["src"].substring(document.getElementById("overview-icon-id-" + id).children[0]["src"].indexOf("/", 7) + 1) !== positionItem['MenuIcon']) {
|
||||
document.getElementById("overview-icon-id-" + id).children[0]["src"] = positionItem['MenuIcon'];
|
||||
}
|
||||
} else {
|
||||
document.getElementById("overview-icon-id-" + id).innerHTML = "<img src=\"" + positionItem['MenuIcon'] + "\" rel='svg'/>";
|
||||
}
|
||||
}
|
||||
},
|
||||
_CreateOverviewElement: function (positionItem, id) {
|
||||
var divItem = document.createElement("div");
|
||||
divItem.className = "item";
|
||||
divItem.onclick = function showMarkerInfoMenu() {
|
||||
MenuObject.statusToDevice = this.getAttribute("rel");
|
||||
MenuObject.ShowHidePanel("pannels_info");
|
||||
};
|
||||
divItem.setAttribute("rel", id);
|
||||
divItem.innerHTML = "<span class=\"color\" id=\"overview-color-id-" + id + "\"></span>";
|
||||
if (positionItem['Icon'] !== null) {
|
||||
divItem.innerHTML += "<span class=\"icon\" id=\"overview-icon-id-" + id + "\"><img src=\"" + positionItem['MenuIcon'] + "\" rel='svg'/></span>";
|
||||
} else {
|
||||
divItem.innerHTML += "<span class=\"icon\" id=\"overview-icon-id-" + id + "\"><img src=\"icons/marker/map-marker.png\" /></span>";
|
||||
}
|
||||
divItem.innerHTML += "<div class=\"line1\">" +
|
||||
"<span class=\"name\" id=\"overview-name-id-" + id + "\"></span>" +
|
||||
"<span class=\"akku\"><img id=\"overview-akkuimg-id-" + id + "\" src=\"icons/akku/" + positionItem["Batterysimple"] + "-4.png\"></span>" +
|
||||
"</div>";
|
||||
divItem.innerHTML += "<div class=\"line2\" style=\"color: red;\" id=\"overview-gps-id-" + id + "\">kein GPS-Empfang</div>";
|
||||
divItem.innerHTML += "<div class=\"line3\" id=\"overview-update-id-" + id + "\">Letzte Werte: vor " + FunctionsObject.TimeCalculation(positionItem["Recievedtime"], "difftext") + "</div>";
|
||||
return divItem;
|
||||
},
|
||||
_ParseAJAXPannelAdmin: function (loggedin) {
|
||||
if (!loggedin) {
|
||||
var html = "<h3>Login to Adminpannel</h3><form onsubmit='MenuObject.SubmitLoginForm(); return false;'>";
|
||||
html += "<div><span class='label'>Username:</span><input id='pannels_admin_name'></div>";
|
||||
html += "<div><span class='label'>Passwort:</span><input type='password' id='pannels_admin_pass'></div>";
|
||||
html += "<div><span class='login'><input type='submit'></span></div></form>";
|
||||
document.getElementById("pannels_admin").innerHTML = html;
|
||||
} else {
|
||||
document.getElementById("pannels_admin").innerHTML = "<a href='/admin/' target='_blank'>Adminpannel</a>";
|
||||
}
|
||||
},
|
||||
_Update_pannels_info: function () {
|
||||
document.getElementById("pannels_info").innerHTML = "";
|
||||
if (Object.prototype.hasOwnProperty.call(MarkerObject.LocationData, this.statusToDevice)) {
|
||||
var positionItem = MarkerObject.LocationData[this.statusToDevice];
|
||||
var html = "<div class=\"name\">Name: <span class=\"bold\">" + positionItem["Name"] + "</span></div>";
|
||||
html += "<div class=\"batt\"><span class=\"bold\">Batterie:</span> " + positionItem["Battery"] + "V <img src=\"icons/akku/" + positionItem["Batterysimple"] + "-4.png\"></div>";
|
||||
if (positionItem["Fix"]) {
|
||||
html += "<div class=\"gps\" style=\"color: green;\">GPS-Empfang</div>";
|
||||
} else {
|
||||
html += "<div class=\"gps\" style=\"color: red;\">kein GPS-Empfang</div>";
|
||||
}
|
||||
html += "<div class=\"coord\">" + positionItem["UTM"]["Base"] + " <span style=\"color: #b1a831;\">" + positionItem["UTM"]["FieldWidth"] + "</span><span style=\"color: #218c00;\">" + positionItem["UTM"]["Width"] + "</span> <span style=\"color: #b1a831;\">" + positionItem["UTM"]["FieldHeight"] + "</span><span style=\"color: #218c00;\">" + positionItem["UTM"]["Height"] + "</span></div>";
|
||||
html += "<div class=\"height\"><span class=\"bold\">Höhe:</span> " + positionItem["Height"].toFixed(1) + " m</div>";
|
||||
html += "<div class=\"hdop\"><span class=\"bold\">HDOP:</span> " + positionItem["Hdop"].toFixed(1) + "</div>";
|
||||
html += "<div class=\"lanlot\"><span class=\"bold\">Dezimal:</span> " + positionItem["Latitude"].toFixed(5) + ", " + positionItem["Longitude"].toFixed(5) + "</div>";
|
||||
html += "<div class=\"lastgps\"><span class=\"bold\">Letzter Wert:</span> Vor: " + FunctionsObject.TimeCalculation(positionItem["Lastgpspostime"], "difftext") + "</div>";
|
||||
html += "<div class=\"update\"><span class=\"bold\">Update:</span> " + FunctionsObject.TimeCalculation(positionItem["Recievedtime"], "str") + "<br><span class=\"bold\">Vor:</span> " + FunctionsObject.TimeCalculation(positionItem["Recievedtime"], "difftext") + "</div>";
|
||||
html += "<div><span class=\"bold\">RSSI:</span> " + positionItem["Rssi"] + ", <span class=\"bold\">SNR:</span> " + positionItem["Snr"] + "</div>";
|
||||
if (Object.prototype.hasOwnProperty.call(MarkerObject.PanicData, this.statusToDevice)) {
|
||||
var panicData = MarkerObject.PanicData[this.statusToDevice];
|
||||
if (panicData["ButtonPressed"].length > 0) {
|
||||
html += "<div class='alerts'><span class=\"bold\">Alerts:</span>";
|
||||
for (var i = 0; i < panicData["ButtonPressed"].length; i++) {
|
||||
html += "<span class='panicitem'>" + FunctionsObject.TimeCalculation(panicData["ButtonPressed"][i], "str") + " (vor " + FunctionsObject.TimeCalculation(panicData["ButtonPressed"][i], "difftext") + ")</span>";
|
||||
}
|
||||
html += "</div>";
|
||||
}
|
||||
}
|
||||
document.getElementById("pannels_info").innerHTML = html;
|
||||
}
|
||||
},
|
||||
_Update_pannels_admin: function () {
|
||||
var testadmin = new XMLHttpRequest();
|
||||
testadmin.onreadystatechange = function () {
|
||||
if (testadmin.readyState === 4 && testadmin.status === 403) {
|
||||
MenuObject._ParseAJAXPannelAdmin(false);
|
||||
} else if (testadmin.readyState === 4 && testadmin.status === 200) {
|
||||
MenuObject._ParseAJAXPannelAdmin(true);
|
||||
}
|
||||
};
|
||||
testadmin.open("GET", "/admin", true);
|
||||
testadmin.send();
|
||||
},
|
||||
_ParseAJAXWeatherAlerts: function (json) {
|
||||
if (json.length > 0) {
|
||||
var html = "";
|
||||
for (var i = 0; i < json.length; i++) {
|
||||
var walert = json[i];
|
||||
html += "<div class='alertitem " + walert.Level +" "+ walert.Type + "'>" +
|
||||
"<span class='head'>" + walert.Headline + "</span>" +
|
||||
"<span class='ort'>" + walert.Location + "</span>" +
|
||||
"<span class='text'>" + walert.Body + (walert.Instructions !== "" ? "<br><br>" + walert.Instructions : "") + "</span>" +
|
||||
"<span class='time'><b>Von:</b> ";
|
||||
if (FunctionsObject.TimeCalculation(walert.From, "diffraw") < 0) {
|
||||
html += "in " + FunctionsObject.TimeCalculation(walert.From, "difftextn");
|
||||
} else {
|
||||
html += "seit " + FunctionsObject.TimeCalculation(walert.From, "difftext");
|
||||
}
|
||||
html += " <b>Bis:</b> in " + FunctionsObject.TimeCalculation(walert.To, "difftextn") + "</span>" +
|
||||
"</div>";
|
||||
}
|
||||
document.getElementById("pannels_weather").innerHTML = html;
|
||||
document.getElementById("menucol_weather_icon").className = "weather ac";
|
||||
} else {
|
||||
document.getElementById("pannels_weather").innerHTML = "<h1>Keine Gefahren</h1>";
|
||||
document.getElementById("menucol_weather_icon").className = "weather";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createOverviewElement(positionItem, id) {
|
||||
var divItem = document.createElement("div");
|
||||
divItem.className = "item";
|
||||
divItem.onclick = showMarkerInfoMenu;
|
||||
divItem.setAttribute("rel", id);
|
||||
divItem.innerHTML = "<span class=\"color\" id=\"overview-color-id-" + id + "\"></span>";
|
||||
if (positionItem['Icon'] !== null) {
|
||||
divItem.innerHTML += "<span class=\"icon\" id=\"overview-icon-id-" + id + "\"><object data=\"" + positionItem['Icon'] + "&marker-bg=hidden" + "\" type=\"image/svg+xml\"></object></span>";
|
||||
} else {
|
||||
divItem.innerHTML += "<span class=\"icon\" id=\"overview-icon-id-" + id + "\"><img src=\"icons/marker/map-marker.png\"></span>";
|
||||
}
|
||||
divItem.innerHTML += "<div class=\"line1\">" +
|
||||
"<span class=\"name\" id=\"overview-name-id-" + id + "\"></span>" +
|
||||
"<span class=\"akku\"><img id=\"overview-akkuimg-id-" + id + "\" src=\"icons/akku/" + positionItem["Batterysimple"] + "-4.png\"></span>" +
|
||||
"</div>";
|
||||
divItem.innerHTML += "<div class=\"line2\" style=\"color: red;\" id=\"overview-gps-id-" + id + "\">kein GPS-Empfang</div>";
|
||||
divItem.innerHTML += "<div class=\"line3\" id=\"overview-update-id-" + id + "\">Letzte Werte: vor " + timeCalculation(positionItem["Recievedtime"], "difftext") + "</div>";
|
||||
return divItem;
|
||||
}
|
||||
|
||||
|
||||
function update_pannels_admin() {
|
||||
var testadmin = new XMLHttpRequest();
|
||||
testadmin.onreadystatechange = parseAjaxPannelAdmin;
|
||||
testadmin.open("GET", "http://{%REQUEST_URL_HOST%}/admin", true);
|
||||
testadmin.send();
|
||||
}
|
||||
|
||||
function parseAjaxPannelAdmin() {
|
||||
if (this.readyState === 4 && this.status === 403) {
|
||||
var html = "<h3>Login to Adminpannel</h3><form onsubmit='submitloginform();return false;'>";
|
||||
html += "<div><span class='label'>Username:</span><input id='pannels_admin_name'></div>";
|
||||
html += "<div><span class='label'>Passwort:</span><input type='password' id='pannels_admin_pass'></div>";
|
||||
html += "<div><span class='login'><input type='submit'></span></div></form>";
|
||||
document.getElementById("pannels_admin").innerHTML = html;
|
||||
} else if (this.readyState === 4 && this.status === 200) {
|
||||
document.getElementById("pannels_admin").innerHTML = "<a href='/admin/' target='_blank'>Adminpannel</a>";
|
||||
}
|
||||
}
|
||||
|
||||
function submitloginform() {
|
||||
var adminlogin = new XMLHttpRequest();
|
||||
adminlogin.onreadystatechange = parseAjaxLogin;
|
||||
adminlogin.open("POST", "http://{%REQUEST_URL_HOST%}/admin/login", true);
|
||||
adminlogin.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
||||
adminlogin.send("user=" + encodeURI(document.getElementById("pannels_admin_name").value) + "&pass=" + encodeURI(document.getElementById("pannels_admin_pass").value));
|
||||
}
|
||||
|
||||
function parseAjaxLogin() {
|
||||
if (this.readyState === 4 && this.status === 200) {
|
||||
update_pannels_admin();
|
||||
}
|
||||
}
|
||||
}.Start();
|
@ -1,21 +1,22 @@
|
||||
setInterval(overlayrunner, 1000);
|
||||
function overlayrunner() {
|
||||
var ccount = new XMLHttpRequest();
|
||||
ccount.onreadystatechange = parseAjaxCount;
|
||||
ccount.open("GET", "/cameracount", true);
|
||||
ccount.send();
|
||||
var cdensity = new XMLHttpRequest();
|
||||
cdensity.onreadystatechange = parseAjaxDensity;
|
||||
cdensity.open("GET", "/crowdcount", true);
|
||||
cdensity.send();
|
||||
}
|
||||
|
||||
function parseAjaxCount() {
|
||||
if (this.readyState === 4 && this.status === 200) {
|
||||
var cameracounts = JSON.parse(this.responseText);
|
||||
var OverlayObject = {
|
||||
/// private variables
|
||||
_DensitySettings: {},
|
||||
/// public functions
|
||||
ParseAJAXCameraModel: function (json) {
|
||||
this._ParseAJAXCount(json.Counter);
|
||||
this._ParseAJAXDensity(json.Density);
|
||||
},
|
||||
ParseAJAXSettings: function (json) {
|
||||
this._DensitySettings = json["DensityArea"];
|
||||
},
|
||||
Start: function () {
|
||||
return this;
|
||||
},
|
||||
/// private functions
|
||||
_ParseAJAXCount: function (cameracounts) {
|
||||
var camerastext = "";
|
||||
for (var cameraid in cameracounts) {
|
||||
if (cameracounts.hasOwnProperty(cameraid)) {
|
||||
if (Object.prototype.hasOwnProperty.call(cameracounts, cameraid)) {
|
||||
var camera = cameracounts[cameraid];
|
||||
var cameratext = "<div class='camera'>";
|
||||
cameratext += "<span class='name'>" + cameraid + "</span>";
|
||||
@ -27,23 +28,21 @@ function parseAjaxCount() {
|
||||
}
|
||||
}
|
||||
document.getElementById("cameracount").innerHTML = camerastext;
|
||||
}
|
||||
}
|
||||
|
||||
function parseAjaxDensity() {
|
||||
if (this.readyState === 4 && this.status === 200) {
|
||||
var cameradensy = JSON.parse(this.responseText);
|
||||
},
|
||||
_ParseAJAXDensity: function (cameradensy) {
|
||||
var densystext = "";
|
||||
for (var densyid in cameradensy) {
|
||||
if (cameradensy.hasOwnProperty(densyid)) {
|
||||
var densy = cameradensy[densyid];
|
||||
var densytext = "<div class='camera'>";
|
||||
densytext += "<span class='name'>" + densyid + "</span>";
|
||||
densytext += "<span class='count'>" + densy["DensityCount"] + "</span>";
|
||||
densytext += "</div>";
|
||||
densystext += densytext;
|
||||
if (Object.prototype.hasOwnProperty.call(cameradensy, densyid)) {
|
||||
if (Object.prototype.hasOwnProperty.call(this._DensitySettings, densyid)) {
|
||||
var densy = cameradensy[densyid];
|
||||
var densytext = "<div class='camera'>";
|
||||
densytext += "<span class='name'>" + this._DensitySettings[densyid].Alias + "</span>";
|
||||
densytext += "<span class='count'>" + densy["DensityCount"] + "</span>";
|
||||
densytext += "</div>";
|
||||
densystext += densytext;
|
||||
}
|
||||
}
|
||||
}
|
||||
document.getElementById("crwoddensy").innerHTML = densystext;
|
||||
}
|
||||
}
|
||||
}.Start();
|
64
README.md
@ -1,19 +1,45 @@
|
||||
# Fraunhofer.Fit.IoT.LoraMap (Lora-Map)
|
||||
Program that displays items with coordinates from Mqtt on a map
|
||||
|
||||
## Docker
|
||||
* Build: `docker-compose build`
|
||||
* Provide: `./Lora-Map/config/requests.conf` and `./Lora-Map/config/settings.conf`
|
||||
* Run `docker-compose up -d`
|
||||
|
||||
## Linking to
|
||||
### Internal
|
||||
* BlubbFish.Utils ([Utils](http://git.blubbfish.net/vs_utils/Utils))
|
||||
* BlubbFish.Utils.IoT ([Utils-IoT](http://git.blubbfish.net/vs_utils/Utils-IoT))
|
||||
* BlubbFish.Utils.IoT.Bots ([Bot-Utils](http://git.blubbfish.net/vs_utils/Bot-Utils))
|
||||
* BlubbFish.Utils.IoT.Connector.Data.Mqtt ([ConnectorDataMqtt](http://git.blubbfish.net/vs_utils/ConnectorDataMqtt))
|
||||
|
||||
### External
|
||||
* litjson
|
||||
* M2Mqtt
|
||||
* Mono.Posix
|
||||
# Fraunhofer.Fit.IoT.LoraMap (Lora-Map)
|
||||
<!-- Short description of the project. -->
|
||||
|
||||
Program that displays items with coordinates from Mqtt on a map. This readme is meant for describing the application.
|
||||
|
||||

|
||||
<!-- A teaser figure may be added here. It is best to keep the figure small (<500KB) and in the same repo -->
|
||||
|
||||
## Getting Started
|
||||
<!-- Instruction to make the project up and running. -->
|
||||
|
||||
The project documentation is available on the [Wiki](https://github.com/MONICA-Project/lora-map/wiki).
|
||||
|
||||
## Deployment
|
||||
<!-- Deployment/Installation instructions. If this is software library, change this section to "Usage" and give usage examples -->
|
||||
|
||||
This repository is only for containing the code from Lora-Map. If you want to develop, please goto the [Map-Project](https://github.com/MONICA-Project/map-project). This repository contains all references as github submodules, even this one.
|
||||
|
||||
## Development
|
||||
<!-- Developer instructions. -->
|
||||
* Versioning: Use [SemVer](http://semver.org/) and tag the repository with full version string. E.g. `v1.0.0`
|
||||
|
||||
### Prerequisite
|
||||
This projects depends on different librarys.
|
||||
|
||||
#### Linking to
|
||||
##### Internal
|
||||
* BlubbFish.Utils ([Utils](http://git.blubbfish.net/vs_utils/Utils))
|
||||
* BlubbFish.Utils.IoT ([Utils-IoT](http://git.blubbfish.net/vs_utils/Utils-IoT))
|
||||
* BlubbFish.Utils.IoT.Bots ([Bot-Utils](http://git.blubbfish.net/vs_utils/Bot-Utils))
|
||||
* BlubbFish.Utils.IoT.Connector.Data.Mqtt ([ConnectorDataMqtt](http://git.blubbfish.net/vs_utils/ConnectorDataMqtt))
|
||||
|
||||
##### External
|
||||
* litjson
|
||||
* M2Mqtt
|
||||
* CordinateSharp
|
||||
|
||||
## Contributing
|
||||
Contributions are welcome.
|
||||
|
||||
Please fork, make your changes, and submit a pull request. For major changes, please open an issue first and discuss it with the other authors.
|
||||
|
||||
## Affiliation
|
||||

|
||||
This work is supported by the European Commission through the [MONICA H2020 PROJECT](https://www.monica-project.eu) under grant agreement No 732350.
|
BIN
doc/Alert.png
Normal file
After Width: | Height: | Size: 412 KiB |
323
doc/Communcation.yml
Normal file
@ -0,0 +1,323 @@
|
||||
asyncapi: 2.0.0
|
||||
info:
|
||||
title: Lora-Internal-Flow
|
||||
version: '1.0.0'
|
||||
description: |
|
||||
Internal Communication for:
|
||||
* Lora-Gateway
|
||||
* Lora-Map
|
||||
license:
|
||||
name: LGPL3
|
||||
url: http://www.gnu.org/licenses/lgpl-3.0.html
|
||||
|
||||
servers:
|
||||
production:
|
||||
url: 127.0.0.1:{port}
|
||||
protocol: mqtt
|
||||
description: Lora-Broker
|
||||
security:
|
||||
- userPassword: []
|
||||
variables:
|
||||
port:
|
||||
description: Secure connection (TLS) is available through port 8883.
|
||||
default: '1883'
|
||||
enum:
|
||||
- '1883'
|
||||
- '8883'
|
||||
|
||||
defaultContentType: application/json
|
||||
|
||||
channels:
|
||||
lora/data/{deviceID}:
|
||||
description: Topic witch contains the tracking data.
|
||||
parameters:
|
||||
deviceID:
|
||||
$ref: '#/components/parameters/deviceID'
|
||||
subscribe:
|
||||
operationId: loradata
|
||||
message:
|
||||
$ref: '#/components/messages/loradata'
|
||||
|
||||
|
||||
lora/panic/{deviceID}:
|
||||
description: Topic witch contains the tracking data, when the panic buttons was pressed
|
||||
parameters:
|
||||
deviceID:
|
||||
$ref: '#/components/parameters/deviceID'
|
||||
subscribe:
|
||||
operationId: lorapanic
|
||||
message:
|
||||
$ref: '#/components/messages/loradata'
|
||||
|
||||
|
||||
lora/status/{deviceID}:
|
||||
description: Topic witch contains status of the devices
|
||||
parameters:
|
||||
deviceID:
|
||||
$ref: '#/components/parameters/deviceID'
|
||||
subscribe:
|
||||
operationId: lorastatus
|
||||
message:
|
||||
$ref: '#/components/messages/lorastatus'
|
||||
|
||||
components:
|
||||
messages:
|
||||
loradata:
|
||||
name: trackerData
|
||||
title: Positionsdata
|
||||
summary: Informs you about a Position and Status of a Tracker
|
||||
contentType: application/json
|
||||
payload:
|
||||
$ref: "#/components/schemas/loradataPayload"
|
||||
lorastatus:
|
||||
name: loraStatus
|
||||
title: Statusdata
|
||||
summary: Informs you about a Status of a Tracker
|
||||
payload:
|
||||
$ref: "#/components/schemas/lorastausPayload"
|
||||
|
||||
schemas:
|
||||
loradataPayload:
|
||||
$ref: "#/components/schemas/loradataObject"
|
||||
|
||||
lorastausPayload:
|
||||
$ref: "#/components/schemas/lorastatusObject"
|
||||
|
||||
lorastatusObject:
|
||||
type: object
|
||||
properties:
|
||||
Bandwidth:
|
||||
type: integer
|
||||
description: Bandwidth on witch the Signal was recieved
|
||||
minimum: 7800
|
||||
maximum: 500000
|
||||
BatteryLevel:
|
||||
type: number
|
||||
description: Voltage of the battery from the device
|
||||
minimum: 2.5
|
||||
maximum: 5
|
||||
Calculatedcrc:
|
||||
type: integer
|
||||
description: The calculated CRC
|
||||
Codingrate:
|
||||
type: integer
|
||||
description: The Codingrate in witch the Signal was recieved
|
||||
minimum: 5
|
||||
maximum: 8
|
||||
Crcstatus:
|
||||
type: string
|
||||
description: Shows the CRC-Status in a Field
|
||||
enum:
|
||||
- Ok
|
||||
- Bad
|
||||
- No
|
||||
DeviceStatus:
|
||||
type: string
|
||||
description: Shows the internal state in a Field
|
||||
enum:
|
||||
- Startup
|
||||
- Powersave
|
||||
- Shutdown
|
||||
Frequency:
|
||||
type: integer
|
||||
description: The Frequency on that the Message was arrived
|
||||
FrequencyOffset:
|
||||
type: integer
|
||||
description: The internal offset to the base frequency, to compensate cheap china rf modules
|
||||
Host:
|
||||
type: string
|
||||
description: Name of the Gateway that Recieves the Data
|
||||
IpAddress:
|
||||
type: string
|
||||
description: IP-Address of the device, for debug
|
||||
default: "0.0.0.0"
|
||||
format: "[0-9]\\.[0-9]\\.[0-9]\\.[0-9]"
|
||||
Name:
|
||||
type: string
|
||||
description: Name of the GPS-Tracker, must be unique between every Device
|
||||
format: "/[a-z]{2}/i"
|
||||
PacketRssi:
|
||||
type: number
|
||||
description: Recieve Signal Strength Index for the whole LORA-Messgae
|
||||
Receivedtime:
|
||||
type: string
|
||||
description: Timestamp of the Gateway, when it recieves the LORA-Message
|
||||
format: dd/mm/YYYY hh:MM:ss
|
||||
default: 01/01/2019 12:00:00
|
||||
Recieverinterface:
|
||||
type: integer
|
||||
description: Internal virtual Radio of the Gateway, witch recieves the LORA-Messange
|
||||
Recieverradio:
|
||||
type: integer
|
||||
description: Internal Radio of the Gateway, witch recieves the LORA-Messange
|
||||
Rssi:
|
||||
type: number
|
||||
description: Recieve Signal Strength Index for the LORA-Message
|
||||
Snr:
|
||||
type: number
|
||||
description: Signal to Noise Ratio of the LORA-Message
|
||||
Snrmax:
|
||||
type: number
|
||||
description: Maximum Signal to Noise Ratio of the LORA-Message
|
||||
Snrmin:
|
||||
type: number
|
||||
description: Minimum Signal to Noise Ratio of the LORA-Message
|
||||
Spreadingfactor:
|
||||
type: integer
|
||||
description: The Spreadingfactor of the LORA-Message
|
||||
minimum: 7
|
||||
maximum: 12
|
||||
Time:
|
||||
type: integer
|
||||
description: Internal Timecounter of the LORA-Reciever
|
||||
Version:
|
||||
type: integer
|
||||
description: Software-Versionsnumber of the Device
|
||||
WifiActive:
|
||||
type: boolean
|
||||
description: Status if the Device successufly connect to a wifi
|
||||
WifiSsid:
|
||||
type: string
|
||||
description: SSID of the WIFI witch the device connects to.
|
||||
|
||||
loradataObject:
|
||||
type: object
|
||||
required:
|
||||
- BatteryLevel
|
||||
- Gps
|
||||
- Name
|
||||
- Receivedtime
|
||||
- Rssi
|
||||
- Snr
|
||||
properties:
|
||||
Bandwidth:
|
||||
type: integer
|
||||
description: Bandwidth on witch the Signal was recieved
|
||||
minimum: 7800
|
||||
maximum: 500000
|
||||
BatteryLevel:
|
||||
type: number
|
||||
description: Voltage of the battery from the device
|
||||
minimum: 2.5
|
||||
maximum: 5
|
||||
Calculatedcrc:
|
||||
type: integer
|
||||
description: The calculated CRC
|
||||
Codingrate:
|
||||
type: integer
|
||||
description: The Codingrate in witch the Signal was recieved
|
||||
minimum: 5
|
||||
maximum: 8
|
||||
Crcstatus:
|
||||
type: string
|
||||
description: Shows the CRC-Status in a Field
|
||||
enum:
|
||||
- Ok
|
||||
- Bad
|
||||
- No
|
||||
Frequency:
|
||||
type: integer
|
||||
description: The Frequency on that the Message was arrived
|
||||
Gps:
|
||||
type: object
|
||||
description: Gps-Data of a Message
|
||||
required:
|
||||
- Fix
|
||||
- Hdop
|
||||
- Height
|
||||
- LastGPSPos
|
||||
- LastLatitude
|
||||
- LastLongitude
|
||||
- Latitude
|
||||
- Longitude
|
||||
properties:
|
||||
Fix:
|
||||
type: boolean
|
||||
description: Status of the Tracker, true if it has GPS-Signal
|
||||
Hdop:
|
||||
type: number
|
||||
description: Dislocation from GPS-Reciever
|
||||
minimum: 0.8
|
||||
maximum: 25
|
||||
Height:
|
||||
type: number
|
||||
description: Height of the GPS-Reciever
|
||||
LastGPSPos:
|
||||
type: string
|
||||
description: Timestamp when the GPS-Reciever has its last position
|
||||
format: dd/mm/YYYY hh:MM:ss
|
||||
default: 01/01/2019 12:00:00
|
||||
LastLatitude:
|
||||
type: number
|
||||
description: Last Latitude of the GPS-Reciever
|
||||
default: 50.7
|
||||
LastLongitude:
|
||||
type: number
|
||||
description: Last Longitude of the GPS-Reciever
|
||||
default: 7.2
|
||||
Latitude:
|
||||
type: number
|
||||
description: Latitude of the GPS-Reciever
|
||||
default: 50.7
|
||||
Longitude:
|
||||
type: number
|
||||
description: Longitude of the GPS-Reciever
|
||||
default: 7.2
|
||||
Time:
|
||||
type: string
|
||||
description: Timestamp of the GPS-Reciever, that it gets from the Satelites
|
||||
format: dd/mm/YYYY hh:MM:ss
|
||||
default: 01/01/2019 12:00:00
|
||||
Host:
|
||||
type: string
|
||||
description: Name of the Gateway that Recieves the Data
|
||||
Name:
|
||||
type: string
|
||||
description: Name of the GPS-Tracker, must be unique between every Device
|
||||
format: "/[a-z]{2}/i"
|
||||
PacketRssi:
|
||||
type: number
|
||||
description: Recieve Signal Strength Index for the whole LORA-Messgae
|
||||
Receivedtime:
|
||||
type: string
|
||||
description: Timestamp of the Gateway, when it recieves the LORA-Message
|
||||
format: dd/mm/YYYY hh:MM:ss
|
||||
default: 01/01/2019 12:00:00
|
||||
Recieverinterface:
|
||||
type: integer
|
||||
description: Internal virtual Radio of the Gateway, witch recieves the LORA-Messange
|
||||
Recieverradio:
|
||||
type: integer
|
||||
description: Internal Radio of the Gateway, witch recieves the LORA-Messange
|
||||
Rssi:
|
||||
type: number
|
||||
description: Recieve Signal Strength Index for the LORA-Message
|
||||
Snr:
|
||||
type: number
|
||||
description: Signal to Noise Ratio of the LORA-Message
|
||||
Snrmax:
|
||||
type: number
|
||||
description: Maximum Signal to Noise Ratio of the LORA-Message
|
||||
Snrmin:
|
||||
type: number
|
||||
description: Minimum Signal to Noise Ratio of the LORA-Message
|
||||
Spreadingfactor:
|
||||
type: integer
|
||||
description: The Spreadingfactor of the LORA-Message
|
||||
minimum: 7
|
||||
maximum: 12
|
||||
Time:
|
||||
type: integer
|
||||
description: Internal Timecounter of the LORA-Reciever
|
||||
|
||||
|
||||
securitySchemes:
|
||||
userPassword:
|
||||
type: userPassword
|
||||
description: Using Username and Password to connect to online broker
|
||||
|
||||
parameters:
|
||||
deviceID:
|
||||
description: The ID of the streetlight.
|
||||
schema:
|
||||
type: string
|
1858
doc/Communication.md
Normal file
BIN
doc/Details.pdn
Normal file
BIN
doc/Details.png
Normal file
After Width: | Height: | Size: 406 KiB |
BIN
doc/Empfang.png
Normal file
After Width: | Height: | Size: 412 KiB |
BIN
doc/Filter-Select.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
doc/Filter.png
Normal file
After Width: | Height: | Size: 405 KiB |
BIN
doc/Filter2.png
Normal file
After Width: | Height: | Size: 406 KiB |
BIN
doc/Filter3.png
Normal file
After Width: | Height: | Size: 407 KiB |
BIN
doc/Gesamtliste.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
doc/Gesamtliste.psd
Normal file
BIN
doc/Global.png
Normal file
After Width: | Height: | Size: 563 KiB |
BIN
doc/Global.psd
Normal file
BIN
doc/Infos1.png
Normal file
After Width: | Height: | Size: 444 KiB |
BIN
doc/Infos2.png
Normal file
After Width: | Height: | Size: 444 KiB |
BIN
doc/Infos3.png
Normal file
After Width: | Height: | Size: 446 KiB |
BIN
doc/Infos4.png
Normal file
After Width: | Height: | Size: 445 KiB |
BIN
doc/Infos5.png
Normal file
After Width: | Height: | Size: 444 KiB |
BIN
doc/Layer.png
Normal file
After Width: | Height: | Size: 522 KiB |
BIN
doc/Liste.png
Normal file
After Width: | Height: | Size: 408 KiB |