Compare commits

..

77 Commits

Author SHA1 Message Date
d90230ef14 netcore 3.1 also needed in buildscript 2021-04-10 20:53:34 +02:00
26c6f75ae9 fixing github actions 2021-04-10 20:35:47 +02:00
3705d78dcd 1.3.1 Refactory is the king 2021-04-10 20:32:24 +02:00
7dc841fe5c Update Doku 2020-02-12 14:30:36 +01:00
Philip Schell
61ed34899d
[1.3.0] New Gateway
## New Features
* Implement Lora-Gateway-Data 1.1.0 Format
## Bugfixes
## Changes
* Refactoring
* Make requests.conf not needed anymore.
2020-01-20 14:39:51 +01:00
c96941b048 [1.3.0] New Gateway 2020-01-20 14:37:06 +01:00
c4c8f6164b Fix tiny warning 2020-01-19 23:16:16 +01:00
0a60a82b8c Refactoring Alarmitem, becuase its only a bit different from PositionItem, so use oop 2020-01-19 23:08:43 +01:00
Philip Schell
88003a17bb
Merge pull request #30 from MONICA-Project/v1.3.1
Using wront branch
2020-01-19 16:31:52 +01:00
65c5f500d1 Make PositionItem ready Lora-Gateway-Data 1.1.0 data 2020-01-18 11:49:58 +01:00
Philip Schell
977e5415fd
Merge pull request #29 from MONICA-Project/v1.2.10
Create Release v1.2.10
2019-12-11 11:55:29 +01:00
655e010a53 [1.2.10] Refactoring is the thing 2019-12-11 11:51:37 +01:00
479a3b72d4 Move to NET .Core 2019-12-10 15:17:58 +01:00
bef2f6d129 Add netcore 2019-12-09 15:05:52 +01:00
88344a64c4 Tiny fix in fontcolor 2019-11-24 16:32:51 +01:00
1e0690fed1 Update Sensor 2019-11-21 14:36:06 +01:00
da34f0566d Start add Feature Sensors on map 2019-11-20 20:04:23 +01:00
ec2500d72f Rename and add root files 2019-11-06 19:35:27 +01:00
07045a8450 Rename 2019-10-29 18:07:17 +01:00
1082a85ad5 renaming folder 2019-10-29 17:56:44 +01:00
f8cd3b4037 Reordering 2019-10-29 17:55:26 +01:00
8e93703e2a new README.md 2019-10-29 11:46:52 +01:00
17c20a9b69 Doku weiter 2019-10-28 15:33:16 +01:00
0739e18714 Layer und Wetter eingefügt 2019-10-07 09:30:58 +02:00
71b43d1c9d README.md weitergearbeitet 2019-10-04 19:01:25 +02:00
8db03227fe Mehr Doku 2019-10-04 18:20:09 +02:00
4cca4351bc Zugeschnitten 2019-10-04 13:49:32 +02:00
f43971e8be Update Communication Docu 2019-09-25 13:43:08 +02:00
986a122333 Parse also all Doublevalues as Int
Start Docu
2019-09-24 15:13:36 +02:00
377bdfe9e0 Screenshots for Doku 2019-09-20 14:32:59 +02:00
521bb6c4c6 popup box max width bigger 2019-09-07 17:20:56 +02:00
6b1fca9109 Create Aliases for Camera Count
Filter Fight under level
2019-09-07 16:09:23 +02:00
286f931e59 Display GateCounting Boxes in a line not a collumn 2019-09-06 19:19:04 +02:00
7641cb50eb Change Sani to Rettungsdienst 2019-09-06 19:18:06 +02:00
fa02c89674 Search in Description of Polygons 2019-09-06 19:17:34 +02:00
7c7e15e1b2 Numbers on places are not clickable, also as the grid 2019-09-03 23:26:16 +02:00
617eef2f5f Show Numbers from a Place not with linebreaking 2019-09-03 23:04:45 +02:00
cec861cd7c Searchfunction case insensitive 2019-09-02 16:03:49 +02:00
69e1ff73b0 Correct Changelog please 2019-09-02 08:55:18 +02:00
df0593ee38 Change Online Map MaxZoom to 20 2019-08-31 22:55:55 +02:00
f192cc7b52 Merge branch 'v1.2.9' into 'master'
[1.2.9] The PüMa Release

See merge request monica/lora-map/lora-map!2
2019-08-30 15:53:51 +02:00
10f9e32678 Prepare for next release 2019-08-30 15:34:16 +02:00
1f3d864249 #15 suche nach ständen einbauen 2019-08-30 15:04:51 +02:00
1d0d64d314 #16 filter nach kategorien/tracker einbauen 2019-08-29 21:12:08 +02:00
de28446c0d bf 2019-08-28 13:11:05 +02:00
968f6f411b Tiny Weather fixes 2019-08-28 12:51:16 +02:00
3fda36ecbc #16 Start of Frontend 2019-08-25 19:15:46 +02:00
98bd2cafe9 #16 Implement Backend for Settings 2019-08-25 14:19:48 +02:00
26bbf9c6c5 Start of #16 2019-08-23 14:09:52 +02:00
28bf1c585b #27 Draw Camera-Desity bock on map 2019-08-22 13:45:11 +02:00
438584f4b9 Begin of #27, Implement Settings 2019-08-21 19:12:26 +02:00
e388eb6626 #28 Fightdedection Plygon on Map 2019-08-21 13:19:02 +02:00
84162714fe #28 Settings now editable 2019-08-20 20:03:53 +02:00
680b4b5d82 Start working on #28 2019-08-20 15:24:34 +02:00
9f9c8e63ef #24 Add information about weather/warning 2019-08-20 13:08:56 +02:00
c4a23751c1 #24 Implement Backendstuff 2019-08-19 19:57:42 +02:00
f65b81b369 Add Correct Dispose Handling 2019-08-02 19:04:51 +02:00
36a6b86a5b Start of WeatherWarnings 2019-08-01 17:29:16 +02:00
b1832da477 #19 grid automatisch generieren 2019-07-30 21:17:56 +02:00
a2b3f2c5da Add setting model to code
#19 grid automatisch generieren
2019-07-30 15:34:45 +02:00
d0a4430d0e add settings.json 2019-07-29 14:42:42 +02:00
82d51c5dc1 Refactoring Adminpannel 2019-07-26 11:48:30 +02:00
123411eca6 Refactoring Js finished
Make only one request per second instead of four per AJAX
2019-07-25 11:14:04 +02:00
22c37456e9 Move querys together 2019-07-17 15:55:01 +02:00
f4efe2ab66 Refactoring of all JS finished. 2019-07-17 14:23:06 +02:00
b214aaecee Javascript Refactoring... 2019-07-16 15:42:49 +02:00
3542b87156 Merge branch 'v1.2.8' into 'master'
[1.2.8] Improving the UI

See merge request monica/lora-map/lora-map!1
2019-07-10 14:26:27 +02:00
4f628a5a01 [1.2.8] Improving the UI 2019-07-10 14:14:09 +02:00
137edb6011 #18 history an panikbutton pressed
also add some errorhandling with locks
fixing js minors
2019-07-09 20:41:51 +02:00
18f80904b3 #18 history an panikbutton pressed
c# Part
2019-07-09 15:34:54 +02:00
a1b669cd68 #25 Icons flickering when using ssl 2019-07-09 11:14:32 +02:00
51689abb64 #12 Make icon transparent if there is no data update 2019-07-03 15:53:19 +02:00
7924214b66 Changes to new Mqtt topic for camera density 2019-07-03 14:06:38 +02:00
fbefdd156f Move CoordinateSharp to own Library 2019-06-28 14:07:12 +02:00
c4dbea12b3 #14 show description on map in tooltip on area 2019-06-27 11:22:52 +02:00
7be6245ed3 #13 fixing issue with port when using proxy 2019-06-27 11:07:05 +02:00
1d74703504 Move the Dockerreadmepart also upwards
Start Version 1.2.8
2019-06-24 18:17:23 +02:00
110 changed files with 6505 additions and 48444 deletions

106
.github/workflows/dotnetcore.yml vendored Normal file
View 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
View File

@ -1,3 +1,4 @@
/.vs
/Lora-Map/obj
/Lora-Map/bin
/Doku/.vs

View File

@ -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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -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

View File

@ -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>

File diff suppressed because it is too large Load Diff

View File

@ -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;
}
}
}
}

View File

@ -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]);
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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
}
}

View File

@ -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);
}
}
}

View File

@ -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
}
}

View File

@ -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));
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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));
}
}

View File

@ -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);
}
}
}

View File

@ -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));
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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 };
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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;
}
}
}

View 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;
}
}
}

View File

@ -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>

View File

@ -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
}
}
}

View File

@ -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 {

View File

@ -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;
}
}

View File

@ -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"];

View File

@ -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;
}
}
}

View 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;
}
}
}
}

View 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));
}
}
}
}
}
}

View File

@ -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;
}
}

View 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());
}
}
}
}
}
}

View 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);
}
}
}

View 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", "{}");
}
}
}
}

View File

@ -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"];
}
}
}

View 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"];
}
}

View 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();
}
}

View 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
View 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", "&copy; <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>();
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}
}

View 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];
}
}
}

View File

@ -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"));
}
}
}

View File

@ -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
*/

View File

@ -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", "&copy; <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();
}
}
}

View File

@ -1,2 +0,0 @@
[js/map.js]
start_location=50.7, 7.2

View File

@ -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

View File

@ -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")"

View File

@ -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

View File

@ -1,2 +1,6 @@
#!/bin/bash
useradd -M loramapbot
usermod -L loramapbot
groupadd loramapbot
usermod -G loramapbot,adm loramapbot

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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>

View 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;
}
};

View 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);
}
};

View File

@ -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] || "" };
}
};

View 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;
},
};

View File

@ -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;

Binary file not shown.

After

Width:  |  Height:  |  Size: 848 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -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>

View File

@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -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.
![Picture of the Application](Lora-Map.jpg)
<!-- 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
![MONICA](https://github.com/MONICA-Project/template/raw/master/monica.png)
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 KiB

323
doc/Communcation.yml Normal file
View 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

File diff suppressed because it is too large Load Diff

BIN
doc/Details.pdn Normal file

Binary file not shown.

BIN
doc/Details.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 KiB

BIN
doc/Empfang.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 KiB

BIN
doc/Filter-Select.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
doc/Filter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 KiB

BIN
doc/Filter2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 KiB

BIN
doc/Filter3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 KiB

BIN
doc/Gesamtliste.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
doc/Gesamtliste.psd Normal file

Binary file not shown.

BIN
doc/Global.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 563 KiB

BIN
doc/Global.psd Normal file

Binary file not shown.

BIN
doc/Infos1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 KiB

BIN
doc/Infos2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 KiB

BIN
doc/Infos3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 446 KiB

BIN
doc/Infos4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 KiB

BIN
doc/Infos5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 KiB

BIN
doc/Layer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 KiB

BIN
doc/Liste.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 KiB

Some files were not shown because too many files have changed in this diff Show More