Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

First commit

  • Loading branch information...
commit 2ae53aba9cd6d44ad529f2376c5ca981fd392c49 0 parents
@sibartlett authored
Showing with 35,736 additions and 0 deletions.
  1. +108 −0 .gitignore
  2. +6 −0 .nuget/NuGet.Config
  3. BIN  .nuget/NuGet.exe
  4. +143 −0 .nuget/NuGet.targets
  5. +71 −0 Geo.Raven/Geo.Raven.csproj
  6. BIN  Geo.Raven/Geo.Raven.nuspec
  7. +33 −0 Geo.Raven/GeoContractResolver.cs
  8. +37 −0 Geo.Raven/GeoIndexCreationTask.cs
  9. +25 −0 Geo.Raven/GeoRavenExtensions.cs
  10. +35 −0 Geo.Raven/Properties/AssemblyInfo.cs
  11. +4 −0 Geo.Raven/packages.config
  12. +78 −0 Geo.Tests/Geo.Tests.csproj
  13. +39 −0 Geo.Tests/Geo/GeoPointCalculationsTests.cs
  14. +26 −0 Geo.Tests/Geo/GeoPointTests.cs
  15. +40 −0 Geo.Tests/Gps/Serialization/GpxSerializerTests.cs
  16. +29 −0 Geo.Tests/Gps/Serialization/IgcDeSerializerTests.cs
  17. +29 −0 Geo.Tests/Gps/Serialization/NmeaDeSerializerTests.cs
  18. +38 −0 Geo.Tests/Gps/Serialization/SerializerTestFixtureBase.cs
  19. +35 −0 Geo.Tests/Properties/AssemblyInfo.cs
  20. +4 −0 Geo.Tests/packages.config
  21. +39 −0 Geo.sln
  22. +105 −0 Geo/Geo.csproj
  23. BIN  Geo/Geo.nuspec
  24. +147 −0 Geo/GeoUtil.cs
  25. +35 −0 Geo/Geometries/Bounds.cs
  26. +43 −0 Geo/Geometries/GeodeticCalculations.cs
  27. +22 −0 Geo/Geometries/GeodeticLine.cs
  28. +8 −0 Geo/Geometries/ILatLngCoordinate.cs
  29. +7 −0 Geo/Geometries/IPoint.cs
  30. +105 −0 Geo/Geometries/LatLngCoordinate.cs
  31. +54 −0 Geo/Geometries/LineString.cs
  32. +30 −0 Geo/Geometries/LineStringExtensions.cs
  33. +67 −0 Geo/Geometries/MultiPoint.cs
  34. +83 −0 Geo/Geometries/Point.cs
  35. +40 −0 Geo/Gps/Fix.cs
  36. +70 −0 Geo/Gps/GpsData.cs
  37. +48 −0 Geo/Gps/Metadata/GpsMetadata.cs
  38. +38 −0 Geo/Gps/Metadata/Metadata.cs
  39. +20 −0 Geo/Gps/Metadata/RouteMetadata.cs
  40. +20 −0 Geo/Gps/Metadata/TrackMetadata.cs
  41. +17 −0 Geo/Gps/Route.cs
  42. +182 −0 Geo/Gps/Serialization/Gpx10Serializer.cs
  43. +273 −0 Geo/Gps/Serialization/Gpx11Serializer.cs
  44. +19 −0 Geo/Gps/Serialization/IGpsFileDeSerializer.cs
  45. +129 −0 Geo/Gps/Serialization/IgcDeSerializer.cs
  46. +105 −0 Geo/Gps/Serialization/NmeaDeSerializer.cs
  47. +68 −0 Geo/Gps/Serialization/Xml/GpsXmlSerializer.cs
  48. +1,796 −0 Geo/Gps/Serialization/Xml/Gpx10/gpx10.cs
  49. +231 −0 Geo/Gps/Serialization/Xml/Gpx10/gpx10.xsd
  50. +1,189 −0 Geo/Gps/Serialization/Xml/Gpx11/gpx11.cs
  51. +788 −0 Geo/Gps/Serialization/Xml/Gpx11/gpx11.xsd
  52. +18 −0 Geo/Gps/Track.cs
  53. +17 −0 Geo/Helpers.cs
  54. +123 −0 Geo/Measure/Distance.cs
  55. +16 −0 Geo/Measure/DistanceUnit.cs
  56. +35 −0 Geo/Measure/DistanceUnitExtensions.cs
  57. +138 −0 Geo/Measure/Speed.cs
  58. +14 −0 Geo/Measure/SpeedUnit.cs
  59. +35 −0 Geo/Measure/SpeedUnitExtensions.cs
  60. +34 −0 Geo/Measure/UnitAttribute.cs
  61. +48 −0 Geo/Measure/UnitMetadata.cs
  62. +35 −0 Geo/Properties/AssemblyInfo.cs
  63. +246 −0 Geo/Reference/Ellipsoid.cs
  64. +165 −0 lgpl.txt
  65. +43 −0 readme.md
  66. +1 −0  reference/gpx/Bergamo to Manchester.gpx
  67. +1 −0  reference/gpx/CDG to JNB flight.gpx
  68. +1 −0  reference/gpx/Flight Bremen - Malta.gpx
  69. +1 −0  reference/gpx/Flight Kigali to Kilimanjaro.gpx
  70. +1 −0  reference/gpx/Glasgow to Keflavik.gpx
  71. +1 −0  reference/gpx/KLX to MAN.gpx
  72. +46 −0 reference/gpx/MiddleOfTheSea.gpx
  73. +3,276 −0 reference/gpx/Trails-iPhone.gpx
  74. +2,448 −0 reference/gpx/alantrl.gpx
  75. +381 −0 reference/gpx/alanwpr.gpx
  76. +499 −0 reference/gpx/bounds-test.gpx
  77. +16 −0 reference/gpx/bushnell.gpx
  78. +253 −0 reference/gpx/bushnell_trl.gpx
  79. +178 −0 reference/gpx/compegps-wpt.gpx
  80. +26 −0 reference/gpx/compegps_time_wpt.gpx
  81. +22 −0 reference/gpx/cototestmarker.gpx
  82. +17 −0 reference/gpx/dop-test.gpx
  83. +35 −0 reference/gpx/enigma.gpx
  84. +1,131 −0 reference/gpx/expertgps.gpx
  85. +526 −0 reference/gpx/garmin_gpi.gpx
  86. +526 −0 reference/gpx/garmin_gpi2.gpx
  87. +4,620 −0 reference/gpx/garmin_symbols.gpx
  88. +3,176 −0 reference/gpx/gdb-sample.gpx
  89. +73 −0 reference/gpx/geocaching.gpx
  90. +55 −0 reference/gpx/geonet-sample.gpx
  91. +234 −0 reference/gpx/ggv_ovl~ovl.gpx
  92. +34 −0 reference/gpx/gn-targets.gpx
  93. +139 −0 reference/gpx/gopal-11-gpx.gpx
  94. +101 −0 reference/gpx/grid-bng~csv.gpx
  95. +87 −0 reference/gpx/grid-swiss~csv.gpx
  96. +204 −0 reference/gpx/grid-utm~csv.gpx
  97. +734 −0 reference/gpx/hiketech.gpx
  98. +46 −0 reference/gpx/holux.gpx
  99. +549 −0 reference/gpx/igc1.gpx
  100. +2,563 −0 reference/gpx/igc1_baro.gpx
  101. +55 −0 reference/gpx/igo2008_poi~upoi.gpx
  102. +139 −0 reference/gpx/ik3d-sample.gpx
  103. +2,781 −0 reference/gpx/memory-map_v24~mmo.gpx
  104. +3,200 −0 reference/gpx/memory-map~mmo.gpx
  105. +35 −0 reference/gpx/multiple-links.gpx
Sorry, we could not display the entire diff because it was too big.
108 .gitignore
@@ -0,0 +1,108 @@
+
+<!-- saved from url=(0063)https://raw.github.com/github/gitignore/master/CSharp.gitignore -->
+<html><script type="text/javascript">window["_gaUserPrefs"] = { ioo : function() { return true; } }</script><script id="tinyhippos-injected">if (window.top.require) { window.top.require("ripple/bootstrap").inject(window, document); }</script><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><script>window["_GOOG_TRANS_EXT_VER"] = "1";</script><script>window["_GOOG_TRANS_EXT_VER"] = "1";</script></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;"># Build Folders (you can keep bin if you'd like, to store dlls and pdbs)
+[Bb]in/
+[Oo]bj/
+
+# mstest test results
+TestResults
+
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.sln.docstates
+
+# Build results
+[Dd]ebug/
+[Rr]elease/
+x64/
+*_i.c
+*_p.c
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.log
+*.vspscc
+*.vssscc
+.builds
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opensdf
+*.sdf
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*
+
+# NCrunch
+*.ncrunch*
+.*crunch*.local.xml
+
+# Installshield output folder
+[Ee]xpress
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish
+
+# Publish Web Output
+*.Publish.xml
+
+# NuGet Packages Directory
+packages
+
+# Windows Azure Build Output
+csx
+*.build.csdef
+
+# Others
+[Bb]in
+[Oo]bj
+sql
+TestResults
+[Tt]est[Rr]esult*
+*.Cache
+ClientBin
+[Ss]tyle[Cc]op.*
+~$*
+*.dbmdl
+Generated_Code #added for RIA/Silverlight projects
+
+# Backup &amp; report files from converting an old project file to a newer
+# Visual Studio version. Backup files are not needed, because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+</pre></body><link rel="stylesheet" type="text/css" href="data:text/css,"></html>
6 .nuget/NuGet.Config
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <solution>
+ <add key="disableSourceControlIntegration" value="true" />
+ </solution>
+</configuration>
BIN  .nuget/NuGet.exe
Binary file not shown
143 .nuget/NuGet.targets
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">$(MSBuildProjectDirectory)\..\</SolutionDir>
+
+ <!-- Enable the restore command to run before builds -->
+ <RestorePackages Condition=" '$(RestorePackages)' == '' ">false</RestorePackages>
+
+ <!-- Property that enables building a package from a project -->
+ <BuildPackage Condition=" '$(BuildPackage)' == '' ">false</BuildPackage>
+
+ <!-- Determines if package restore consent is required to restore packages -->
+ <RequireRestoreConsent Condition=" '$(RequireRestoreConsent)' != 'false' ">true</RequireRestoreConsent>
+
+ <!-- Download NuGet.exe if it does not already exist -->
+ <DownloadNuGetExe Condition=" '$(DownloadNuGetExe)' == '' ">false</DownloadNuGetExe>
+ </PropertyGroup>
+
+ <ItemGroup Condition=" '$(PackageSources)' == '' ">
+ <!-- Package sources used to restore packages. By default will used the registered sources under %APPDATA%\NuGet\NuGet.Config -->
+ <!--
+ <PackageSource Include="https://nuget.org/api/v2/" />
+ <PackageSource Include="https://my-nuget-source/nuget/" />
+ -->
+ </ItemGroup>
+
+ <PropertyGroup Condition=" '$(OS)' == 'Windows_NT'">
+ <!-- Windows specific commands -->
+ <NuGetToolsPath>$([System.IO.Path]::Combine($(SolutionDir), ".nuget"))</NuGetToolsPath>
+ <PackagesConfig>$([System.IO.Path]::Combine($(ProjectDir), "packages.config"))</PackagesConfig>
+ <PackagesDir>$([System.IO.Path]::Combine($(SolutionDir), "packages"))</PackagesDir>
+ </PropertyGroup>
+
+ <PropertyGroup Condition=" '$(OS)' != 'Windows_NT'">
+ <!-- We need to launch nuget.exe with the mono command if we're not on windows -->
+ <NuGetToolsPath>$(SolutionDir).nuget</NuGetToolsPath>
+ <PackagesConfig>packages.config</PackagesConfig>
+ <PackagesDir>$(SolutionDir)packages</PackagesDir>
+ </PropertyGroup>
+
+ <PropertyGroup>
+ <!-- NuGet command -->
+ <NuGetExePath Condition=" '$(NuGetExePath)' == '' ">$(NuGetToolsPath)\nuget.exe</NuGetExePath>
+ <PackageSources Condition=" $(PackageSources) == '' ">@(PackageSource)</PackageSources>
+
+ <NuGetCommand Condition=" '$(OS)' == 'Windows_NT'">"$(NuGetExePath)"</NuGetCommand>
+ <NuGetCommand Condition=" '$(OS)' != 'Windows_NT' ">mono --runtime=v4.0.30319 $(NuGetExePath)</NuGetCommand>
+
+ <PackageOutputDir Condition="$(PackageOutputDir) == ''">$(TargetDir.Trim('\\'))</PackageOutputDir>
+
+ <RequireConsentSwitch Condition=" $(RequireRestoreConsent) == 'true' ">-RequireConsent</RequireConsentSwitch>
+ <!-- Commands -->
+ <RestoreCommand>$(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(RequireConsentSwitch) -o "$(PackagesDir)"</RestoreCommand>
+ <BuildCommand>$(NuGetCommand) pack "$(ProjectPath)" -p Configuration=$(Configuration) -o "$(PackageOutputDir)" -symbols</BuildCommand>
+
+ <!-- Make the build depend on restore packages -->
+ <BuildDependsOn Condition="$(RestorePackages) == 'true'">
+ RestorePackages;
+ $(BuildDependsOn);
+ </BuildDependsOn>
+
+ <!-- Make the build depend on restore packages -->
+ <BuildDependsOn Condition="$(BuildPackage) == 'true'">
+ $(BuildDependsOn);
+ BuildPackage;
+ </BuildDependsOn>
+ </PropertyGroup>
+
+ <Target Name="CheckPrerequisites">
+ <!-- Raise an error if we're unable to locate nuget.exe -->
+ <Error Condition="'$(DownloadNuGetExe)' != 'true' AND !Exists('$(NuGetExePath)')" Text="Unable to locate '$(NuGetExePath)'" />
+ <SetEnvironmentVariable EnvKey="VisualStudioVersion" EnvValue="$(VisualStudioVersion)" Condition=" '$(VisualStudioVersion)' != '' AND '$(OS)' == 'Windows_NT' " />
+ <DownloadNuGet OutputFilename="$(NuGetExePath)" Condition=" '$(DownloadNuGetExe)' == 'true' AND !Exists('$(NuGetExePath)')" />
+ </Target>
+
+ <Target Name="RestorePackages" DependsOnTargets="CheckPrerequisites">
+ <Exec Command="$(RestoreCommand)"
+ Condition="'$(OS)' != 'Windows_NT' And Exists('$(PackagesConfig)')" />
+
+ <Exec Command="$(RestoreCommand)"
+ LogStandardErrorAsError="true"
+ Condition="'$(OS)' == 'Windows_NT' And Exists('$(PackagesConfig)')" />
+ </Target>
+
+ <Target Name="BuildPackage" DependsOnTargets="CheckPrerequisites">
+ <Exec Command="$(BuildCommand)"
+ Condition=" '$(OS)' != 'Windows_NT' " />
+
+ <Exec Command="$(BuildCommand)"
+ LogStandardErrorAsError="true"
+ Condition=" '$(OS)' == 'Windows_NT' " />
+ </Target>
+
+ <UsingTask TaskName="DownloadNuGet" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
+ <ParameterGroup>
+ <OutputFilename ParameterType="System.String" Required="true" />
+ </ParameterGroup>
+ <Task>
+ <Reference Include="System.Core" />
+ <Using Namespace="System" />
+ <Using Namespace="System.IO" />
+ <Using Namespace="System.Net" />
+ <Using Namespace="Microsoft.Build.Framework" />
+ <Using Namespace="Microsoft.Build.Utilities" />
+ <Code Type="Fragment" Language="cs">
+ <![CDATA[
+ try {
+ OutputFilename = Path.GetFullPath(OutputFilename);
+
+ Log.LogMessage("Downloading latest version of NuGet.exe...");
+ WebClient webClient = new WebClient();
+ webClient.DownloadFile("https://nuget.org/nuget.exe", OutputFilename);
+
+ return true;
+ }
+ catch (Exception ex) {
+ Log.LogErrorFromException(ex);
+ return false;
+ }
+ ]]>
+ </Code>
+ </Task>
+ </UsingTask>
+
+ <UsingTask TaskName="SetEnvironmentVariable" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
+ <ParameterGroup>
+ <EnvKey ParameterType="System.String" Required="true" />
+ <EnvValue ParameterType="System.String" Required="true" />
+ </ParameterGroup>
+ <Task>
+ <Using Namespace="System" />
+ <Code Type="Fragment" Language="cs">
+ <![CDATA[
+ try {
+ Environment.SetEnvironmentVariable(EnvKey, EnvValue, System.EnvironmentVariableTarget.Process);
+ }
+ catch {
+ }
+ ]]>
+ </Code>
+ </Task>
+ </UsingTask>
+</Project>
71 Geo.Raven/Geo.Raven.csproj
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{DEB5E2DA-E260-4D7C-9B91-476534521DEC}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Geo.Raven</RootNamespace>
+ <AssemblyName>Geo.Raven</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
+ <RestorePackages>true</RestorePackages>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <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' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Raven.Abstractions, Version=1.2.0.0, Culture=neutral, PublicKeyToken=37f41c7f99471593, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\RavenDB.Client.1.2.2001-Unstable\lib\net40\Raven.Abstractions.dll</HintPath>
+ </Reference>
+ <Reference Include="Raven.Client.Lightweight, Version=1.2.0.0, Culture=neutral, PublicKeyToken=37f41c7f99471593, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\RavenDB.Client.1.2.2001-Unstable\lib\net40\Raven.Client.Lightweight.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="GeoContractResolver.cs" />
+ <Compile Include="GeoIndexCreationTask.cs" />
+ <Compile Include="GeoRavenExtensions.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="Geo.Raven.nuspec" />
+ <None Include="packages.config" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Geo\Geo.csproj">
+ <Project>{b2e32781-a0ae-4803-8de0-92a95f218363}</Project>
+ <Name>Geo</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <Import Project="$(SolutionDir)\.nuget\nuget.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
BIN  Geo.Raven/Geo.Raven.nuspec
Binary file not shown
33 Geo.Raven/GeoContractResolver.cs
@@ -0,0 +1,33 @@
+using System.Reflection;
+using Geo.Geometries;
+using Raven.Imports.Newtonsoft.Json.Serialization;
+
+namespace Geo.Raven
+{
+ public class GeoContractResolver : DefaultContractResolver
+ {
+ private readonly Assembly _assembly = typeof (ILatLngCoordinate).Assembly;
+
+ protected override JsonProperty CreateProperty(MemberInfo member, global::Raven.Imports.Newtonsoft.Json.MemberSerialization memberSerialization)
+ {
+ var prop = base.CreateProperty(member, memberSerialization);
+
+ if(member.DeclaringType !=null)
+ {
+ if (member.DeclaringType.Assembly == _assembly)
+ {
+ if (!prop.Writable)
+ {
+ var property = member as PropertyInfo;
+ if (property != null)
+ {
+ prop.Writable = property.GetSetMethod(true) != null;
+ }
+ }
+ }
+ }
+
+ return prop;
+ }
+ }
+}
37 Geo.Raven/GeoIndexCreationTask.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Text.RegularExpressions;
+using Geo.Geometries;
+using Raven.Abstractions.Indexing;
+using Raven.Client.Indexes;
+
+namespace Geo.Raven
+{
+ public class GeoIndexCreationTask<TDocument> : GeoIndexCreationTask<TDocument, TDocument>
+ {
+ }
+
+ public class GeoIndexCreationTask<TDocument, TReduceResult> : AbstractIndexCreationTask<TDocument, TReduceResult>
+ {
+ public object GeoIndex(ILatLngCoordinate coordinate)
+ {
+ throw new NotSupportedException("This method is provided solely to allow query translation on the server");
+ }
+
+ public override IndexDefinition CreateIndexDefinition()
+ {
+ var definition = base.CreateIndexDefinition();
+ definition.Map = TransformGeoIndexes(definition.Map);
+ definition.Reduce = TransformGeoIndexes(definition.Reduce);
+ return definition;
+ }
+
+ private static string TransformGeoIndexes(string value)
+ {
+ if (value == null)
+ return null;
+
+ return Regex.Replace(value, @"(this.)?GeoIndex\((?<prop>[\w\d\s\.]+)\)", match =>
+ string.Format("SpatialIndex.Generate({0}.Latitude, {0}.Longitude)", match.Groups["prop"].Value));
+ }
+ }
+}
25 Geo.Raven/GeoRavenExtensions.cs
@@ -0,0 +1,25 @@
+using Geo.Geometries;
+using Geo.Measure;
+using Geo.Raven;
+
+namespace Raven.Client
+{
+ public static class GeoRavenExtensions
+ {
+ public static IDocumentStore ApplyGeoConventions(this IDocumentStore store)
+ {
+ store.Conventions.JsonContractResolver = new GeoContractResolver();
+ return store;
+ }
+
+ public static IDocumentQueryBase<T, TSelf> WithinRadiusOf<T, TSelf>(this IDocumentQueryBase<T, TSelf> self, double radiusMiles, ILatLngCoordinate coord) where TSelf : IDocumentQueryBase<T, TSelf>
+ {
+ return self.WithinRadiusOf(radiusMiles, coord.Latitude, coord.Longitude);
+ }
+
+ public static IDocumentQueryBase<T, TSelf> WithinRadiusOf<T, TSelf>(this IDocumentQueryBase<T, TSelf> self, Distance radius, ILatLngCoordinate coord) where TSelf : IDocumentQueryBase<T, TSelf>
+ {
+ return self.WithinRadiusOf(radius.ConvertTo(DistanceUnit.Mile).Value, coord.Latitude, coord.Longitude);
+ }
+ }
+}
35 Geo.Raven/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Geo.Raven")]
+[assembly: AssemblyDescription("RavenDB Integration for Geo")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Geo.Raven")]
+[assembly: AssemblyCopyright("Copyright © Simon Bartlett 2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("44f6700e-053e-493c-bd36-5b9c842cf326")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("0.1.0.0")]
+[assembly: AssemblyFileVersion("0.1.0.0")]
4 Geo.Raven/packages.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="RavenDB.Client" version="1.2.2001-Unstable" targetFramework="net45" />
+</packages>
78 Geo.Tests/Geo.Tests.csproj
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{8201E372-6373-432A-A360-73C744426075}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Geo.Tests</RootNamespace>
+ <AssemblyName>Geo.Tests</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <TargetFrameworkProfile>
+ </TargetFrameworkProfile>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
+ <RestorePackages>true</RestorePackages>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <Prefer32Bit>false</Prefer32Bit>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <Prefer32Bit>false</Prefer32Bit>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="nunit.framework">
+ <HintPath>..\packages\NUnit.2.6.1\lib\nunit.framework.dll</HintPath>
+ </Reference>
+ <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.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Geo\GeoPointCalculationsTests.cs" />
+ <Compile Include="Geo\GeoPointTests.cs" />
+ <Compile Include="Gps\Serialization\GpxSerializerTests.cs" />
+ <Compile Include="Gps\Serialization\IgcDeSerializerTests.cs" />
+ <Compile Include="Gps\Serialization\NmeaDeSerializerTests.cs" />
+ <Compile Include="Gps\Serialization\SerializerTestFixtureBase.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="packages.config" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Geo\Geo.csproj">
+ <Project>{b2e32781-a0ae-4803-8de0-92a95f218363}</Project>
+ <Name>Geo</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup />
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <Import Project="$(SolutionDir)\.nuget\nuget.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
39 Geo.Tests/Geo/GeoPointCalculationsTests.cs
@@ -0,0 +1,39 @@
+using Geo.Geometries;
+using Geo.Measure;
+using NUnit.Framework;
+
+namespace Geo.Tests.Geo
+{
+ [TestFixture]
+ public class GeoPointCalculationsTests
+ {
+ [TestCase(25, 1543.0305675812808d)]
+ [TestCase(-25, -1543.0305675812808d)]
+ public void MeridionalParts(double latitude, double parts)
+ {
+ var result = new Point(latitude, 0).CalculateMeridionalParts();
+ Assert.That(result, Is.EqualTo(parts));
+ }
+
+ [TestCase(25, 1493.5497673574687d)]
+ public void MeridionalDistance(double latitude, double parts)
+ {
+ var result = new Point(latitude, 0).CalculateMeridionalDistance();
+ Assert.That(result.ConvertTo(DistanceUnit.Nm).Value, Is.EqualTo(parts));
+ }
+
+ [TestCase(0, 0, 10, 10, 845.10005801566729d)]
+ public void RhumbLineDistance(double lat1, double lon1, double lat2, double lon2, double distance)
+ {
+ var result = new Point(lat1, lon1).CalculateRhumbLine(new Point(lat2, lon2));
+ Assert.That(result.Distance.ConvertTo(DistanceUnit.Nm).Value, Is.EqualTo(distance));
+ }
+
+ [TestCase(0, 0, 10, 10, 45.04429310980561)]
+ public void RhumbLineCourse(double lat1, double lon1, double lat2, double lon2, double distance)
+ {
+ var result = new Point(lat1, lon1).CalculateRhumbLine(new Point(lat2, lon2));
+ Assert.That(result.TrueBearing12, Is.EqualTo(distance));
+ }
+ }
+}
26 Geo.Tests/Geo/GeoPointTests.cs
@@ -0,0 +1,26 @@
+using Geo.Geometries;
+using NUnit.Framework;
+
+namespace Geo.Tests.Geo
+{
+ [TestFixture]
+ public class GeoPointTests
+ {
+ [TestCase(" 42.294498 -89.637901 ", 42.294498, -89.637901)]
+ [TestCase("12 34.56'N 123 45.55'E", 12.576, 123.75916666666667)]
+ [TestCase("12.345°N 123.456°E", 12.345, 123.456)]
+ [TestCase("12.345N 123.456E", 12.345, 123.456)]
+ [TestCase("12°N 34°W", 12, -34)]
+ [TestCase("42.294498, -89.637901", 42.294498, -89.637901)]
+ [TestCase("42° 17′ 40″ N, 89° 38′ 16″ W", 42.294444444444444d, -89.637777777777785d)]
+ [TestCase("5107212N 00149174W", 51.1202, -1.8195666666666668d)]
+ [TestCase("5107212N00149174W", 51.1202, -1.8195666666666668d)]
+ public void TryParseCoordinate(string coordinate, double latitude, double longitude)
+ {
+ var result = Point.ParseCoordinate(coordinate);
+ Assert.That(result, Is.Not.Null);
+ Assert.That(result.Latitude, Is.EqualTo(latitude));
+ Assert.That(result.Longitude, Is.EqualTo(longitude));
+ }
+ }
+}
40 Geo.Tests/Gps/Serialization/GpxSerializerTests.cs
@@ -0,0 +1,40 @@
+using System.IO;
+using Geo.Gps.Serialization;
+using NUnit.Framework;
+
+namespace Geo.Tests.Gps.Serialization
+{
+ [TestFixture]
+ public class GpxSerializerTests : SerializerTestFixtureBase
+ {
+ [Test]
+ public void CanParseAll()
+ {
+ var gpx10 = new Gpx10Serializer();
+ var gpx11 = new Gpx11Serializer();
+ var dir = GetReferenceFileDirectory("gpx").EnumerateFiles();
+ foreach (var fileInfo in dir)
+ {
+ using (var stream = new FileStream(fileInfo.FullName, FileMode.Open))
+ {
+ if (gpx10.CanDeSerialize(stream))
+ {
+ var data = gpx10.DeSerialize(stream);
+ data.ToGpx();
+ data.ToGpx(1);
+ }
+ else if (gpx11.CanDeSerialize(stream))
+ {
+ var data = gpx11.DeSerialize(stream);
+ data.ToGpx();
+ data.ToGpx(1);
+ }
+ else
+ {
+ Assert.True(false, fileInfo.Name);
+ }
+ }
+ }
+ }
+ }
+}
29 Geo.Tests/Gps/Serialization/IgcDeSerializerTests.cs
@@ -0,0 +1,29 @@
+using System.IO;
+using System.Linq;
+using Geo.Gps.Serialization;
+using NUnit.Framework;
+
+namespace Geo.Tests.Gps.Serialization
+{
+ [TestFixture]
+ public class IgcDeSerializerTests : SerializerTestFixtureBase
+ {
+ [Test]
+ public void igc2()
+ {
+ var file = GetReferenceFileDirectory("igc").GetFiles().First(x => x.Name == "igc2.igc");
+ using (var stream = new FileStream(file.FullName, FileMode.Open))
+ {
+ var parser = new IgcDeSerializer();
+ var canParse = parser.CanDeSerialize(stream);
+ var result = parser.DeSerialize(stream);
+
+ Assert.That(canParse, Is.EqualTo(true));
+ Assert.That(result.Waypoints.Count, Is.EqualTo(0));
+ Assert.That(result.Tracks.Count, Is.EqualTo(1));
+ Assert.That(result.Tracks[0].Segments.Count, Is.EqualTo(1));
+ Assert.That(result.Tracks[0].Segments[0].Count, Is.EqualTo(9));
+ }
+ }
+ }
+}
29 Geo.Tests/Gps/Serialization/NmeaDeSerializerTests.cs
@@ -0,0 +1,29 @@
+using System.IO;
+using System.Linq;
+using Geo.Gps.Serialization;
+using NUnit.Framework;
+
+namespace Geo.Tests.Gps.Serialization
+{
+ [TestFixture]
+ public class NmeaDeSerializerTests : SerializerTestFixtureBase
+ {
+ [Test]
+ public void Stockholm_Walk()
+ {
+ var file = GetReferenceFileDirectory("nmea").GetFiles().First(x => x.Name == "Stockholm_Walk.nmea");
+ using (var stream = new FileStream(file.FullName, FileMode.Open))
+ {
+ var parser = new NmeaDeSerializer();
+ var canParse = parser.CanDeSerialize(stream);
+ var result = parser.DeSerialize(stream);
+
+ Assert.That(canParse, Is.EqualTo(true));
+ Assert.That(result.Waypoints.Count, Is.EqualTo(0));
+ Assert.That(result.Tracks.Count, Is.EqualTo(1));
+ Assert.That(result.Tracks[0].Segments.Count, Is.EqualTo(1));
+ Assert.That(result.Tracks[0].Segments[0].Count, Is.EqualTo(674));
+ }
+ }
+ }
+}
38 Geo.Tests/Gps/Serialization/SerializerTestFixtureBase.cs
@@ -0,0 +1,38 @@
+using System.IO;
+using System.Linq;
+
+namespace Geo.Tests.Gps.Serialization
+{
+ public abstract class SerializerTestFixtureBase
+ {
+ protected DirectoryInfo GetReferenceFileDirectory(params string[] subDirectories)
+ {
+ var dir = new DirectoryInfo(Directory.GetCurrentDirectory());
+ while (dir != null)
+ {
+ var refDir = dir.EnumerateDirectories().FirstOrDefault(x => x.Name == "reference");
+
+ if (refDir != null)
+ {
+
+ if (subDirectories == null || subDirectories.Length == 0)
+ dir = refDir;
+ else
+ {
+ foreach (var directory in subDirectories)
+ {
+ if (refDir != null)
+ refDir = refDir.EnumerateDirectories().FirstOrDefault(x => x.Name == directory);
+ }
+ dir = refDir;
+ }
+ break;
+ }
+
+ dir = dir.Parent;
+ }
+
+ return dir;
+ }
+ }
+}
35 Geo.Tests/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Geo.Tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Geo.Tests")]
+[assembly: AssemblyCopyright("Copyright © Simon Bartlett 2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("ed3d869c-57a9-45df-b8ca-4ebc01a1dedc")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
4 Geo.Tests/packages.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="NUnit" version="2.6.1" targetFramework="net45" />
+</packages>
39 Geo.sln
@@ -0,0 +1,39 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Geo", "Geo\Geo.csproj", "{B2E32781-A0AE-4803-8DE0-92A95F218363}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Geo.Tests", "Geo.Tests\Geo.Tests.csproj", "{8201E372-6373-432A-A360-73C744426075}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Geo.Raven", "Geo.Raven\Geo.Raven.csproj", "{DEB5E2DA-E260-4D7C-9B91-476534521DEC}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{D0D0BB2E-7906-44A7-805C-AAA607C9C6E9}"
+ ProjectSection(SolutionItems) = preProject
+ .nuget\NuGet.Config = .nuget\NuGet.Config
+ .nuget\NuGet.exe = .nuget\NuGet.exe
+ .nuget\NuGet.targets = .nuget\NuGet.targets
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {B2E32781-A0AE-4803-8DE0-92A95F218363}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B2E32781-A0AE-4803-8DE0-92A95F218363}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B2E32781-A0AE-4803-8DE0-92A95F218363}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B2E32781-A0AE-4803-8DE0-92A95F218363}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8201E372-6373-432A-A360-73C744426075}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8201E372-6373-432A-A360-73C744426075}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8201E372-6373-432A-A360-73C744426075}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8201E372-6373-432A-A360-73C744426075}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DEB5E2DA-E260-4D7C-9B91-476534521DEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DEB5E2DA-E260-4D7C-9B91-476534521DEC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DEB5E2DA-E260-4D7C-9B91-476534521DEC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DEB5E2DA-E260-4D7C-9B91-476534521DEC}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
105 Geo/Geo.csproj
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{B2E32781-A0AE-4803-8DE0-92A95F218363}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Geo</RootNamespace>
+ <AssemblyName>Geo</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <TargetFrameworkProfile>
+ </TargetFrameworkProfile>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <Prefer32Bit>false</Prefer32Bit>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <Prefer32Bit>false</Prefer32Bit>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Geometries\Bounds.cs" />
+ <Compile Include="Geometries\ILatLngCoordinate.cs" />
+ <Compile Include="Geometries\IPoint.cs" />
+ <Compile Include="Geometries\LatLngCoordinate.cs" />
+ <Compile Include="GeoUtil.cs" />
+ <Compile Include="Geometries\LineString.cs" />
+ <Compile Include="Geometries\MultiPoint.cs" />
+ <Compile Include="Gps\Metadata\Metadata.cs" />
+ <Compile Include="Gps\Serialization\Gpx10Serializer.cs" />
+ <Compile Include="Gps\Serialization\Xml\GpsXmlSerializer.cs" />
+ <Compile Include="Gps\Serialization\Xml\Gpx10\gpx10.cs">
+ <DependentUpon>gpx10.xsd</DependentUpon>
+ </Compile>
+ <Compile Include="Gps\Serialization\Xml\Gpx11\gpx11.cs">
+ <DependentUpon>gpx11.xsd</DependentUpon>
+ </Compile>
+ <Compile Include="Gps\Route.cs" />
+ <Compile Include="Gps\Metadata\RouteMetadata.cs" />
+ <Compile Include="Gps\Track.cs" />
+ <Compile Include="Gps\Metadata\TrackMetadata.cs" />
+ <Compile Include="Measure\DistanceUnit.cs" />
+ <Compile Include="Measure\SpeedUnit.cs" />
+ <Compile Include="Measure\SpeedUnitExtensions.cs" />
+ <Compile Include="Measure\DistanceUnitExtensions.cs" />
+ <Compile Include="Measure\UnitAttribute.cs" />
+ <Compile Include="Measure\UnitMetadata.cs" />
+ <Compile Include="Reference\Ellipsoid.cs" />
+ <Compile Include="Gps\Metadata\GpsMetadata.cs" />
+ <Compile Include="Measure\Distance.cs" />
+ <Compile Include="Geometries\GeodeticLine.cs" />
+ <Compile Include="Geometries\GeodeticCalculations.cs" />
+ <Compile Include="Gps\Fix.cs" />
+ <Compile Include="Geometries\Point.cs" />
+ <Compile Include="Geometries\LineStringExtensions.cs" />
+ <Compile Include="Measure\Speed.cs" />
+ <Compile Include="Gps\GpsData.cs" />
+ <Compile Include="Gps\Serialization\IGpsFileDeSerializer.cs" />
+ <Compile Include="Gps\Serialization\Gpx11Serializer.cs" />
+ <Compile Include="Gps\Serialization\IgcDeSerializer.cs" />
+ <Compile Include="Gps\Serialization\NmeaDeSerializer.cs" />
+ <Compile Include="Helpers.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="Geo.nuspec" />
+ <None Include="Gps\Serialization\Xml\Gpx10\gpx10.xsd">
+ <SubType>Designer</SubType>
+ </None>
+ <None Include="Gps\Serialization\Xml\Gpx11\gpx11.xsd">
+ <SubType>Designer</SubType>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
BIN  Geo/Geo.nuspec
Binary file not shown
147 Geo/GeoUtil.cs
@@ -0,0 +1,147 @@
+using System;
+using System.Text.RegularExpressions;
+
+namespace Geo
+{
+ internal static class GeoUtil
+ {
+ private const string OrdRegex = @"^(?<Deg>[+-]?(?:\d+\.?\d*|\d*\.?\d+)[\r\n]*)[°Dd\s]*(?<Min>[+-]?(?:\d+\.?\d*|\d*\.?\d+)[\r\n]*)?[°'′Mm\s]*(?<Sec>[+-]?(?:\d+\.?\d*|\d*\.?\d+)[\r\n]*)?[\""″\s]*(?<Dir>[NnSsEeWw])?$";
+
+ internal static bool TryParseOrdinateInternal(string ordinateString, OrdinateType type, out double ordinate)
+ {
+ ordinate = default(double);
+ if (string.IsNullOrWhiteSpace(ordinateString))
+ return false;
+
+ ordinateString = ordinateString.Trim();
+
+ var match = Regex.Match(ordinateString, OrdRegex);
+
+ if(match.Success)
+ {
+ var rDeg = match.Groups["Deg"].Value;
+ var rMin = match.Groups["Min"].Value;
+ var rSec = match.Groups["Sec"].Value;
+ var rDir = match.Groups["Dir"].Value;
+
+ int direction = 1;
+ if (!string.IsNullOrEmpty(rDir))
+ {
+ switch (rDir)
+ {
+ case "N":
+ case "n":
+ type = OrdinateType.Latitude;
+ break;
+ case "S":
+ case "s":
+ type = OrdinateType.Latitude;
+ direction = -1;
+ break;
+ case "E":
+ case "e":
+ type = OrdinateType.Longitude;
+ break;
+ case "W":
+ case "w":
+ type = OrdinateType.Longitude;
+ direction = -1;
+ break;
+ }
+ }
+
+ if(string.IsNullOrEmpty(rMin) && string.IsNullOrEmpty(rSec))
+ {
+ int test;
+ var maxLength = type == OrdinateType.Latitude ? 2 : 3;
+ if (int.TryParse(rDeg, out test))
+ if(rDeg.Length > maxLength)
+ {
+ if(rDeg.Length == 5 + maxLength)
+ {
+ rMin = rDeg.Substring(maxLength, 2) + "." + rDeg.Substring(maxLength + 2, 3);
+ rDeg = rDeg.Substring(0, maxLength);
+ }
+ }
+ }
+
+ double deg;
+
+ if(double.TryParse(rDeg, out deg))
+ {
+ double min;
+ double sec;
+ double.TryParse(rMin, out min);
+ double.TryParse(rSec, out sec);
+
+ var result = (deg + min / 60 + sec / 3600) * direction;
+
+ if (Validate(result, type, out ordinate))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static bool Validate(double ordinate, OrdinateType type, out double result)
+ {
+ if (type == OrdinateType.Latitude && ordinate <= 90 && ordinate >= -90 ||
+ type != OrdinateType.Latitude && ordinate <= 180 && ordinate >= -180)
+ {
+ result = ordinate;
+ return true;
+ }
+ result = default(double);
+ return false;
+ }
+
+
+ internal enum OrdinateType
+ {
+ Unknown,
+ Latitude,
+ Longitude,
+ }
+
+ public static Tuple<string,string> SplitCoordinateString(string coordinate)
+ {
+ if(string.IsNullOrWhiteSpace(coordinate))
+ return null;
+
+ coordinate = coordinate.Trim();
+ string[] ordinates = null;
+
+ if (Regex.IsMatch(coordinate, "^[^,]*,[^,]*$"))
+ {
+ ordinates = coordinate.Split(',');
+ }
+
+ else if (Regex.IsMatch(coordinate, "^[^\\s]*[\\s]+[^\\s]*$"))
+ {
+ var index = Regex.Match(coordinate, "\\s").Index + 1;
+ ordinates = new[]
+ {
+ coordinate.Substring(0, index),
+ coordinate.Substring(index, coordinate.Length - index)
+ };
+ }
+
+ else if (Regex.IsMatch(coordinate, "^[^NnSsEeWw]*[NnSs][^NnSsEeWw]*[EeWw]$"))
+ {
+ var index = Regex.Match(coordinate, "[NnSs]").Index + 1;
+ ordinates = new[]
+ {
+ coordinate.Substring(0, index),
+ coordinate.Substring(index, coordinate.Length - index)
+ };
+ }
+
+ if (ordinates == null)
+ return null;
+
+ return new Tuple<string, string>(
+ ordinates[0].Trim(), ordinates[1].Trim()
+ );
+ }
+ }
+}
35 Geo/Geometries/Bounds.cs
@@ -0,0 +1,35 @@
+using System;
+
+namespace Geo.Geometries
+{
+ public class Bounds
+ {
+ public Bounds(double minLat, double minLon, double maxLat, double maxLon)
+ {
+ MinLat = minLat;
+ MinLon = minLon;
+ MaxLat = maxLat;
+ MaxLon = maxLon;
+ }
+
+ public double MinLat { get; set; }
+ public double MinLon { get; set; }
+ public double MaxLat { get; set; }
+ public double MaxLon { get; set; }
+
+ public Bounds CreateNewMaxBounds(Bounds other)
+ {
+ if (other == null)
+ {
+ return new Bounds(MinLat, MinLon, MaxLat, MaxLon);
+ }
+
+ return new Bounds(
+ Math.Min(MinLat, other.MinLat),
+ Math.Min(MinLon, other.MinLon),
+ Math.Min(MaxLat, other.MaxLat),
+ Math.Min(MaxLon, other.MaxLon)
+ );
+ }
+ }
+}
43 Geo/Geometries/GeodeticCalculations.cs
@@ -0,0 +1,43 @@
+using Geo.Measure;
+using Geo.Reference;
+
+namespace Geo.Geometries
+{
+ public static class GeodeticCalculations
+ {
+ public static double CalculateMeridionalParts(this ILatLngCoordinate point)
+ {
+ return Ellipsoid.Current.CalculateMeridionalParts(point.Latitude);
+ }
+
+ public static Distance CalculateMeridionalDistance(this ILatLngCoordinate point)
+ {
+ return new Distance(Ellipsoid.Current.CalculateMeridionalDistance(point.Latitude));
+ }
+
+ public static GeodeticLine CalculateShortestLine(this ILatLngCoordinate point1, ILatLngCoordinate point2)
+ {
+ return Ellipsoid.Current.CalculateOrthodromicLine(point1, point2);
+ }
+
+ public static GeodeticLine CalculateGreatCircleLine(this ILatLngCoordinate point1, ILatLngCoordinate point2)
+ {
+ return Ellipsoid.Current.CalculateOrthodromicLine(point1, point2);
+ }
+
+ public static GeodeticLine CalculateOrthodromicLine(this ILatLngCoordinate point1, ILatLngCoordinate point2)
+ {
+ return Ellipsoid.Current.CalculateOrthodromicLine(point1, point2);
+ }
+
+ public static GeodeticLine CalculateRhumbLine(this ILatLngCoordinate point1, ILatLngCoordinate point2)
+ {
+ return Ellipsoid.Current.CalculateLoxodromicLine(point1, point2);
+ }
+
+ public static GeodeticLine CalculateLoxodromicLine(this ILatLngCoordinate point1, ILatLngCoordinate point2)
+ {
+ return Ellipsoid.Current.CalculateLoxodromicLine(point1, point2);
+ }
+ }
+}
22 Geo/Geometries/GeodeticLine.cs
@@ -0,0 +1,22 @@
+using Geo.Measure;
+
+namespace Geo.Geometries
+{
+ public class GeodeticLine
+ {
+ public GeodeticLine(ILatLngCoordinate point1, ILatLngCoordinate point2, double distance, double trueBearing12, double trueBearing21)
+ {
+ Coordinate1 = point1;
+ Coordinate2 = point2;
+ TrueBearing12 = trueBearing12;
+ TrueBearing21 = trueBearing21;
+ Distance = new Distance(distance);
+ }
+
+ public ILatLngCoordinate Coordinate1 { get; private set; }
+ public ILatLngCoordinate Coordinate2 { get; private set; }
+ public Distance Distance { get; private set; }
+ public double TrueBearing12 { get; private set; }
+ public double TrueBearing21 { get; private set; }
+ }
+}
8 Geo/Geometries/ILatLngCoordinate.cs
@@ -0,0 +1,8 @@
+namespace Geo.Geometries
+{
+ public interface ILatLngCoordinate
+ {
+ double Latitude { get; }
+ double Longitude { get; }
+ }
+}
7 Geo/Geometries/IPoint.cs
@@ -0,0 +1,7 @@
+namespace Geo.Geometries
+{
+ public interface IPoint : ILatLngCoordinate
+ {
+ double? Elevation { get; }
+ }
+}
105 Geo/Geometries/LatLngCoordinate.cs
@@ -0,0 +1,105 @@
+using System;
+
+namespace Geo.Geometries
+{
+ public class LatLngCoordinate : ILatLngCoordinate
+ {
+ private LatLngCoordinate()
+ {
+ }
+
+ public LatLngCoordinate(double latitude, double longitude)
+ {
+ Validate(latitude, longitude);
+ Latitude = latitude;
+ Longitude = longitude;
+ }
+
+ public double Latitude { get; protected set; }
+ public double Longitude { get; protected set; }
+
+ public override string ToString()
+ {
+ return Latitude + ", " + Longitude;
+ }
+
+ protected bool Equals(LatLngCoordinate other)
+ {
+ return Latitude.Equals(other.Latitude) && Longitude.Equals(other.Longitude);
+ }
+
+ internal static void Validate(double latitude, double longitude)
+ {
+ if (latitude > 90 || latitude < -90)
+ throw new ArgumentOutOfRangeException("latitude");
+
+ if (longitude > 180 || longitude < -180)
+ throw new ArgumentOutOfRangeException("longitude");
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ return obj.GetType() == GetType() && Equals((LatLngCoordinate) obj);
+ }
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ return (Latitude.GetHashCode()*397) ^ Longitude.GetHashCode();
+ }
+ }
+
+ public static LatLngCoordinate Parse(string coordinate)
+ {
+ if (coordinate == null)
+ throw new ArgumentNullException("coordinate");
+
+ if (string.IsNullOrWhiteSpace(coordinate))
+ throw new ArgumentException("Value was empty", "coordinate");
+
+ LatLngCoordinate result;
+ if (!TryParse(coordinate, out result))
+ throw new FormatException("Coordinate (" + coordinate + ") is a not supported format.");
+
+ return result;
+ }
+
+ public static LatLngCoordinate TryParse(string coordinate)
+ {
+ LatLngCoordinate result;
+ TryParse(coordinate, out result);
+ return result;
+ }
+
+ public static bool TryParse(string coordinate, out LatLngCoordinate result)
+ {
+ var a = GeoUtil.SplitCoordinateString(coordinate);
+ if (a != null)
+ {
+ double lat;
+ double lon;
+ if (GeoUtil.TryParseOrdinateInternal(a.Item1, GeoUtil.OrdinateType.Latitude, out lat))
+ if (GeoUtil.TryParseOrdinateInternal(a.Item2, GeoUtil.OrdinateType.Longitude, out lon))
+ {
+ result = new LatLngCoordinate(lat, lon);
+ return true;
+ }
+ }
+ result = default(LatLngCoordinate);
+ return false;
+ }
+
+ public Point ToPoint()
+ {
+ return new Point(this);
+ }
+
+ public Point ToPoint(double z)
+ {
+ return new Point(this, z);
+ }
+ }
+}
54 Geo/Geometries/LineString.cs
@@ -0,0 +1,54 @@
+using System.Collections.Generic;
+using Geo.Measure;
+
+namespace Geo.Geometries
+{
+ public class LineString : LineString<Point>
+ {
+ public LineString()
+ {
+ }
+
+ public LineString(IEnumerable<Point> items) : base(items)
+ {
+ }
+ }
+
+ public class LineString<T> : MultiPoint<T> where T : IPoint
+ {
+ public LineString()
+ {
+ }
+
+ public LineString(IEnumerable<T> items) : base(items)
+ {
+ }
+
+ public T StartPoint
+ {
+ get
+ {
+ return IsEmpty ? default(T) : InternalList[0];
+ }
+ }
+
+ public T EndPoint
+ {
+ get
+ {
+ return IsEmpty ? default(T) : InternalList[InternalList.Count - 1];
+ }
+ }
+
+ public Distance CalculateLength()
+ {
+ var distance = new Distance(0);
+
+ if (InternalList.Count > 1)
+ for (var i = 1; i < Count; i++)
+ distance += InternalList[i - 1].CalculateShortestLine(InternalList[i]).Distance;
+
+ return distance;
+ }
+ }
+}
30 Geo/Geometries/LineStringExtensions.cs
@@ -0,0 +1,30 @@
+using System;
+using Geo.Gps;
+using Geo.Measure;
+
+namespace Geo.Geometries
+{
+ public static class LineStringExtensions
+ {
+ public static Speed GetAverageSpeed<T>(this LineString<T> lineString) where T : Fix
+ {
+ var distance = lineString.CalculateLength();
+ return new Speed(distance.SiValue, lineString.GetDuration());
+ }
+
+ public static TimeSpan GetDuration<T>(this LineString<T> lineString) where T : Fix
+ {
+ return lineString.StartPoint.TimeUtc - lineString.EndPoint.TimeUtc;
+ }
+
+ public static DateTime GetStartTime<T>(this LineString<T> lineString) where T : Fix
+ {
+ return lineString.StartPoint.TimeUtc;
+ }
+
+ public static DateTime GetEndTime<T>(this LineString<T> lineString) where T : Fix
+ {
+ return lineString.EndPoint.TimeUtc;
+ }
+ }
+}
67 Geo/Geometries/MultiPoint.cs
@@ -0,0 +1,67 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Geo.Geometries
+{
+ public class MultiPoint : MultiPoint<Point>
+ {
+ public MultiPoint()
+ {
+ }
+
+ public MultiPoint(IEnumerable<Point> items) : base(items)
+ {
+ }
+ }
+
+ public class MultiPoint<T> : IEnumerable<T> where T : IPoint
+ {
+ protected List<T> InternalList = new List<T>();
+
+ public MultiPoint()
+ {
+ }
+
+ public MultiPoint(IEnumerable<T> items)
+ {
+ InternalList.AddRange(items);
+ }
+
+ public IEnumerator<T> GetEnumerator()
+ {
+ return InternalList.GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return InternalList.GetEnumerator();
+ }
+
+ public bool IsEmpty
+ {
+ get { return InternalList.Count == 0; }
+ }
+
+ public int Count
+ {
+ get { return InternalList.Count; }
+ }
+
+ public void Add(T point)
+ {
+ InternalList.Add(point);
+ }
+
+ public T this[int index]
+ {
+ get { return InternalList[index]; }
+ }
+
+ public Bounds GetBounds()
+ {
+ return IsEmpty ? null :
+ new Bounds(this.Min(x => x.Latitude), this.Min(x => x.Longitude), this.Max(x => x.Latitude), this.Max(x => x.Longitude));
+ }
+ }
+}
83 Geo/Geometries/Point.cs
@@ -0,0 +1,83 @@
+namespace Geo.Geometries
+{
+ public class Point : IPoint
+ {
+ private Point()
+ {
+ }
+
+ public Point(double latitude, double longitude)
+ {
+ LatLngCoordinate.Validate(latitude, longitude);
+ Latitude = latitude;
+ Longitude = longitude;
+ }
+
+ public Point(double latitude, double longitude, double z) : this(latitude, longitude)
+ {
+ Elevation = z;
+ }
+
+ public Point(ILatLngCoordinate coordinate) : this(coordinate.Latitude, coordinate.Longitude)
+ {
+ }
+
+ public Point(ILatLngCoordinate coordinate, double z) : this(coordinate.Latitude, coordinate.Longitude, z)
+ {
+ }
+
+ public double Latitude { get; protected set; }
+ public double Longitude { get; protected set; }
+ public double? Elevation { get; protected set; }
+
+ public override string ToString()
+ {
+ if(Elevation == null)
+ return Latitude + ", " + Longitude;
+ return Latitude + ", " + Longitude + ", " + Elevation.Value;
+ }
+
+ protected bool Equals(Point other)
+ {
+ return Latitude.Equals(other.Latitude) && Longitude.Equals(other.Longitude) && Elevation.Equals(other.Elevation);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ return obj.GetType() == GetType() && Equals((Point) obj);
+ }
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ var hashCode = Latitude.GetHashCode();
+ hashCode = (hashCode*397) ^ Longitude.GetHashCode();
+ hashCode = (hashCode*397) ^ Elevation.GetHashCode();
+ return hashCode;
+ }
+ }
+
+ public static Point ParseCoordinate(string coordinate)
+ {
+ return LatLngCoordinate.Parse(coordinate).ToPoint();
+ }
+
+ public static Point TryParseCoordinate(string coordinate)
+ {
+ LatLngCoordinate result;
+ var success = LatLngCoordinate.TryParse(coordinate, out result);
+ return success ? result.ToPoint() : default(Point);
+ }
+
+ public static bool TryParseCoordinate(string coordinate, out Point result)
+ {
+ LatLngCoordinate res;
+ var success = LatLngCoordinate.TryParse(coordinate, out res);
+ result = success ? res.ToPoint() : default(Point);
+ return success;
+ }
+ }
+}
40 Geo/Gps/Fix.cs
@@ -0,0 +1,40 @@
+using System;
+using Geo.Geometries;
+
+namespace Geo.Gps
+{
+ public class Fix : Point
+ {
+ public Fix(double lat, double lon, DateTime dateTime) : base(lat, lon)
+ {
+ TimeUtc = dateTime;
+ }
+
+ public Fix(double lat, double lon, double z, DateTime dateTime) : base(lat, lon, z)
+ {
+ TimeUtc = dateTime;
+ }
+
+ public DateTime TimeUtc { get; set; }
+
+ protected bool Equals(Fix other)
+ {
+ return base.Equals(other) && TimeUtc.Equals(other.TimeUtc);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ return obj.GetType() == GetType() && Equals((Fix) obj);
+ }
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ return (base.GetHashCode()*397) ^ TimeUtc.GetHashCode();
+ }
+ }
+ }
+}
70 Geo/Gps/GpsData.cs
@@ -0,0 +1,70 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Geo.Geometries;
+using Geo.Gps.Metadata;
+using Geo.Gps.Serialization;
+
+namespace Geo.Gps
+{
+ public class GpsData
+ {
+ private static readonly List<IGpsFileSerializer> FileSerializers;
+ private static readonly List<IGpsFileDeSerializer> FileParsers;
+
+ static GpsData()
+ {
+ FileSerializers = new List<IGpsFileSerializer>
+ {
+ new Gpx10Serializer(),
+ new Gpx11Serializer(),
+ };
+ FileParsers = new List<IGpsFileDeSerializer>(FileSerializers)
+ {
+ new IgcDeSerializer(),
+ new NmeaDeSerializer(),
+ };
+ }
+
+ public GpsData()
+ {
+ Metadata = new GpsMetadata();
+ Routes = new List<Route>();
+ Tracks = new List<Track>();
+ Waypoints=new MultiPoint<Point>();
+ }
+
+ public GpsMetadata Metadata { get; private set; }
+ public List<Route> Routes { get; set; }
+ public List<Track> Tracks { get; set; }
+ public MultiPoint<Point> Waypoints { get; set; }
+
+ public string ToGpx()
+ {
+ return FileSerializers[1].SerializeToString(this);
+ }
+
+ public string ToGpx(decimal version)
+ {
+ var index = version == 1m ? 0 : 1;
+ return FileSerializers[index].SerializeToString(this);
+ }
+
+ public static IEnumerable<string> SupportedGpsLogFileExtensions
+ {
+ get { return FileParsers.SelectMany(x => x.FileExtensions).Distinct().OrderBy(x => x); }
+ }
+
+ public static GpsData Parse(Stream stream)
+ {
+ var parser = FileParsers.FirstOrDefault(x => x.CanDeSerialize(stream));
+ return parser == null ? null : parser.DeSerialize(stream);
+ }
+
+ public static GpsData Parse(string path)
+ {
+ using (var stream = new FileStream(path, FileMode.Open))
+ return Parse(stream);
+ }
+ }
+}
48 Geo/Gps/Metadata/GpsMetadata.cs
@@ -0,0 +1,48 @@
+namespace Geo.Gps.Metadata
+{
+ public class GpsMetadata : Metadata<GpsMetadata.MetadataKeys>
+ {
+ public GpsMetadata() : base(new MetadataKeys())
+ {
+ }
+
+ public class MetadataKeys
+ {
+ public AuthorKeys Author = new AuthorKeys();
+ public CopyrightKeys Copyright = new CopyrightKeys();
+ public VehicleKeys Vehicle = new VehicleKeys();
+
+ internal MetadataKeys()
+ {
+ }
+
+ public string Name { get { return "name"; } }
+ public string Description { get { return "description"; } }
+ public string Keywords { get { return "keywords"; } }
+ public string Link { get { return "link"; } }
+ public string Software { get { return "creator"; } }
+
+ public class AuthorKeys
+ {
+ public string Name { get { return "author.name"; } }
+ public string Email { get { return "author.email"; } }
+ public string Link { get { return "author.link"; } }
+ }
+
+ public class CopyrightKeys
+ {
+ public string Author { get { return "copyright.author"; } }
+ public string Year { get { return "copyright.year"; } }
+ public string License { get { return "copyright.license"; } }
+ }
+
+ public class VehicleKeys
+ {
+ public string Model { get { return "vehicle.model"; } }
+ public string Identifier { get { return "vehicle.identifier"; } }
+ public string Crew1 { get { return "vehicle.crew1"; } }
+ public string Crew2 { get { return "vehicle.crew2"; } }
+ }
+ }
+ }
+}
38 Geo/Gps/Metadata/Metadata.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+
+namespace Geo.Gps.Metadata
+{
+ public abstract class Metadata<TKeys> : Dictionary<string, string>
+ {
+ private readonly TKeys _metadataKeys;
+
+ protected Metadata(TKeys metadataKeys)
+ {
+ _metadataKeys = metadataKeys;
+ }
+
+ public string Attribute(Func<TKeys, string> attribute)
+ {
+ var key = attribute(_metadataKeys);
+ string result;
+ TryGetValue(key, out result);
+ return result;
+ }
+
+ public void Attribute(Func<TKeys, string> attribute, string value)
+ {
+ if (!string.IsNullOrWhiteSpace(value))
+ {
+ var key = attribute(_metadataKeys);
+ this[key] = value.Trim();
+ }
+ }
+
+ public void RemoveAttribute(Func<TKeys, string> attribute)
+ {
+ var key = attribute(_metadataKeys);
+ Remove(key);
+ }
+ }
+}
20 Geo/Gps/Metadata/RouteMetadata.cs
@@ -0,0 +1,20 @@
+namespace Geo.Gps.Metadata
+{
+ public class RouteMetadata : Metadata<RouteMetadata.MetadataKeys>
+ {
+ public RouteMetadata() : base(new MetadataKeys())
+ {
+ }
+
+ public class MetadataKeys
+ {
+ internal MetadataKeys()
+ {
+ }
+
+ public string Name { get { return "name"; } }
+ public string Description { get { return "description"; } }
+ public string Comment { get { return "comment"; } }
+ }
+ }
+}
20 Geo/Gps/Metadata/TrackMetadata.cs
@@ -0,0 +1,20 @@
+namespace Geo.Gps.Metadata
+{
+ public class TrackMetadata : Metadata<TrackMetadata.MetadataKeys>
+ {
+ public TrackMetadata() : base(new MetadataKeys())
+ {
+ }
+
+ public class MetadataKeys
+ {
+ internal MetadataKeys()
+ {
+ }
+
+ public string Name { get { return "name"; } }
+ public string Description { get { return "description"; } }
+ public string Comment { get { return "comment"; } }
+ }
+ }
+}
17 Geo/Gps/Route.cs
@@ -0,0 +1,17 @@
+using Geo.Geometries;
+using Geo.Gps.Metadata;
+
+namespace Geo.Gps
+{
+ public class Route
+ {
+ public Route()
+ {
+ Metadata = new RouteMetadata();
+ LineString = new LineString<Point>();
+ }
+
+ public RouteMetadata Metadata { get; private set; }
+ public LineString<Point> LineString { get; set; }
+ }
+}
182 Geo/Gps/Serialization/Gpx10Serializer.cs
@@ -0,0 +1,182 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Geo.Geometries;
+using Geo.Gps.Serialization.Xml;
+using Geo.Gps.Serialization.Xml.Gpx10;
+
+namespace Geo.Gps.Serialization
+{
+ public class Gpx10Serializer : GpsXmlSerializer<gpx>
+ {
+ public override string[] FileExtensions
+ {
+ get { return new[] {"gpx"}; }
+ }
+
+ public override Uri FileFormatSpecificationUri
+ {
+ get { return new Uri("http://www.topografix.com/GPX/1/0/gpx.xsd"); }
+ }
+
+ protected override GpsData DeSerialize(gpx xml)
+ {
+ var data = new GpsData();
+ ParseMetadata(xml, data);
+ ParseRoute(xml, data);
+ ParseTracks(xml, data);
+ ParseWaypoints(xml, data);
+ return data;
+ }
+
+ protected override gpx Serialize(GpsData data)
+ {
+ var xml = new gpx();
+ SerializeMetadata(data, xml, x => x.Software, (gpx, s) => gpx.creator = s);
+ SerializeMetadata(data, xml, x => x.Name, (gpx, s) => gpx.name = s);
+ SerializeMetadata(data, xml, x => x.Description, (gpx, s) => gpx.desc = s);
+ SerializeMetadata(data, xml, x => x.Keywords, (gpx, s) => gpx.keywords = s);
+ SerializeMetadata(data, xml, x => x.Link, (gpx, s) => gpx.url = s);
+ SerializeMetadata(data, xml, x => x.Author.Name, (gpx, s) => gpx.author = s);
+ SerializeMetadata(data, xml, x => x.Author.Email, (gpx, s) => gpx.email = s);
+
+ xml.trk = SerializeTracks(data).ToArray();
+ xml.rte = SerializeRoutes(data).ToArray();
+ xml.wpt = SerializeWaypoints(data).ToArray();
+
+ return xml;
+ }
+
+ private IEnumerable<gpxWpt> SerializeWaypoints(GpsData data)
+ {
+ return data.Waypoints.Select(waypoint => new gpxWpt
+ {
+ lat = (decimal)waypoint.Latitude,
+ lon = (decimal)waypoint.Longitude,
+ ele = waypoint.Elevation == null ? 0m : (decimal)waypoint.Elevation
+ });
+ }
+
+ private IEnumerable<gpxTrk> SerializeTracks(GpsData data)
+ {
+ foreach (var track in data.Tracks)
+ {
+ var trk = new gpxTrk();
+
+ SerializeTrackMetadata(track, trk, x => x.Name, (gpx, s) => gpx.name = s);
+ SerializeTrackMetadata(track, trk, x => x.Description, (gpx, s) => gpx.desc = s);
+ SerializeTrackMetadata(track, trk, x => x.Comment, (gpx, s) => gpx.cmt = s);
+
+ trk.trkseg = new gpxTrkTrksegTrkpt[track.Segments.Count][];
+ for (var i = 0; i < track.Segments.Count; i++)
+ {
+ var segment = track.Segments[i];
+ var pts = new gpxTrkTrksegTrkpt[segment.Count];
+ for (var j = 0; j < segment.Count; j++)
+ {
+ pts[j] = new gpxTrkTrksegTrkpt
+ {
+ lat = (decimal)segment[j].Latitude,
+ lon = (decimal)segment[j].Longitude,
+ ele = segment[j].Elevation == null ? 0m : (decimal)segment[j].Elevation
+ };
+ }
+ trk.trkseg[i] = pts;
+ }
+
+ yield return trk;
+ }
+ }
+
+ private IEnumerable<gpxRte> SerializeRoutes(GpsData data)
+ {
+ foreach (var route in data.Routes)
+ {
+ var rte = new gpxRte();
+
+ SerializeRouteMetadata(route, rte, x => x.Name, (gpx, s) => gpx.name = s);
+ SerializeRouteMetadata(route, rte, x => x.Description, (gpx, s) => gpx.desc = s);
+ SerializeRouteMetadata(route, rte, x => x.Comment, (gpx, s) => gpx.cmt = s);
+
+ rte.rtept = new gpxRteRtept[route.LineString.Count];
+ for (var j = 0; j < route.LineString.Count; j++)
+ {
+ rte.rtept[j] = new gpxRteRtept
+ {
+ lat = (decimal)route.LineString[j].Latitude,
+ lon = (decimal)route.LineString[j].Longitude,
+ ele = route.LineString[j].Elevation == null ? 0m : (decimal)route.LineString[j].Elevation
+ };
+ }
+ yield return rte;
+ }
+ }
+
+
+ private static void ParseMetadata(gpx xml, GpsData data)
+ {
+ data.Metadata.Attribute(x => x.Software, xml.creator);
+ data.Metadata.Attribute(x => x.Name, xml.name);
+ data.Metadata.Attribute(x => x.Description, xml.desc);
+ data.Metadata.Attribute(x => x.Keywords, xml.keywords);
+ data.Metadata.Attribute(x => x.Link, xml.url);
+ data.Metadata.Attribute(x => x.Author.Name, xml.author);
+ data.Metadata.Attribute(x => x.Author.Email, xml.email);
+ }
+
+ private static void ParseTracks(gpx xml, GpsData data)
+ {
+ if (xml.trk != null)
+ foreach (var trkType in xml.trk)
+ {
+ var track = new Track();
+
+ track.Metadata.Attribute(x => x.Name, trkType.name);
+ track.Metadata.Attribute(x => x.Description, trkType.desc);
+ track.Metadata.Attribute(x => x.Comment, trkType.cmt);
+
+ foreach (var trksegTrkpt in trkType.trkseg)
+ {
+ var segment = new LineString<Fix>();
+ foreach (var wptType in trksegTrkpt)
+ {
+ var fix = new Fix((double)wptType.lat, (double)wptType.lon, (double)wptType.ele, wptType.time);
+ segment.Add(fix);
+ }
+ track.Segments.Add(segment);
+ }
+ data.Tracks.Add(track);
+ }
+ }
+
+ private static void ParseRoute(gpx xml, GpsData data)
+ {
+ if (xml.rte != null)
+ foreach (var rteType in xml.rte)
+ {
+ var route = new Route();
+ route.Metadata.Attribute(x => x.Name, rteType.name);
+ route.Metadata.Attribute(x => x.Description, rteType.desc);
+ route.Metadata.Attribute(x => x.Comment, rteType.cmt);
+
+ route.LineString = new LineString<Point>();
+ foreach (var wptType in rteType.rtept)
+ {
+ var fix = new Fix((double)wptType.lat, (double)wptType.lon, (double)wptType.ele, wptType.time);
+ route.LineString.Add(fix);
+ }
+ data.Routes.Add(route);
+ }
+ }
+
+ private static void ParseWaypoints(gpx xml, GpsData data)
+ {
+ if (xml.wpt != null)
+ foreach (var wptType in xml.wpt)
+ {
+ var fix = new Fix((double)wptType.lat, (double)wptType.lon, (double)wptType.ele, wptType.time);
+ data.Waypoints.Add(fix);
+ }
+ }
+ }
+}
273 Geo/Gps/Serialization/Gpx11Serializer.cs
@@ -0,0 +1,273 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Geo.Geometries;
+using Geo.Gps.Serialization.Xml;
+using Geo.Gps.Serialization.Xml.Gpx11;
+
+namespace Geo.Gps.Serialization
+{
+ public class Gpx11Serializer : GpsXmlSerializer<gpxType>
+ {
+ public override string[] FileExtensions { get { return new[] { "gpx" }; } }
+
+ public override Uri FileFormatSpecificationUri { get { return new Uri("http://www.topografix.com/GPX/1/1/gpx.xsd"); } }
+
+ protected override GpsData DeSerialize(gpxType xml)
+ {
+ var data = new GpsData();
+ ParseMetadata(xml, data);
+ ParseRoute(xml, data);
+ ParseTracks(xml, data);
+ ParseWaypoints(xml, data);
+ return data;
+ }
+
+ protected override gpxType Serialize(GpsData data)
+ {
+ var xml = new gpxType();
+ SerializeMetadata(data, xml, x => x.Software, (gpx, s) => gpx.creator = s);
+ SerializeMetadata(data, xml, x => x.Name, (gpx, s) =>
+ {
+ if (gpx.metadata == null)
+ gpx.metadata = new metadataType();
+ gpx.metadata.name = s;
+ });
+ SerializeMetadata(data, xml, x => x.Description, (gpx, s) =>
+ {
+ if (gpx.metadata == null)
+ gpx.metadata = new metadataType();
+ gpx.metadata.desc = s;
+ });
+ SerializeMetadata(data, xml, x => x.Keywords, (gpx, s) =>
+ {
+ if (gpx.metadata == null)
+ gpx.metadata = new metadataType();
+ gpx.metadata.keywords = s;
+ });
+
+ SerializeMetadata(data, xml, x => x.Link, (gpx, s) =>
+ {
+ if (gpx.metadata == null)
+ gpx.metadata = new metadataType();
+ if (gpx.metadata.link == null)
+ gpx.metadata.link = new linkType[1];
+ gpx.metadata.link[0] = new linkType { href = s };
+ });
+
+ SerializeMetadata(data, xml, x => x.Copyright.Author, (gpx, s) =>
+ {
+ if (gpx.metadata == null)
+ gpx.metadata = new metadataType();
+ if (gpx.metadata.copyright == null)
+ gpx.metadata.copyright = new copyrightType();
+ gpx.metadata.copyright.author = s;
+ });
+ SerializeMetadata(data, xml, x => x.Copyright.License, (gpx, s) =>
+ {
+ if (gpx.metadata == null)
+ gpx.metadata = new metadataType();
+ if (gpx.metadata.copyright == null)
+ gpx.metadata.copyright = new copyrightType();
+ gpx.metadata.copyright.license = s;
+ });
+ SerializeMetadata(data, xml, x => x.Copyright.Year, (gpx, s) =>
+ {
+ if (gpx.metadata == null)
+ gpx.metadata = new metadataType();
+ if (gpx.metadata.copyright == null)
+ gpx.metadata.copyright = new copyrightType();
+ gpx.metadata.copyright.year = s;
+ });
+
+ SerializeMetadata(data, xml, x => x.Author.Name, (gpx, s) =>
+ {
+ if (gpx.metadata == null)
+ gpx.metadata = new metadataType();
+ if (gpx.metadata.author == null)
+ gpx.metadata.author = new personType();
+ gpx.metadata.author.name = s;
+ });
+ SerializeMetadata(data, xml, x => x.Author.Email, (gpx, s) =>
+ {
+ if (gpx.metadata == null)
+ gpx.metadata = new metadataType();
+ if (gpx.metadata.author == null)
+ gpx.metadata.author = new personType();
+ var parts = s.Split(new[] {'@'});
+ gpx.metadata.author.email = new emailType
+ {
+ id = parts[0],
+ domain = parts[1],
+ };
+ });
+
+ SerializeMetadata(data, xml, x => x.Author.Link, (gpx, s) =>
+ {
+ if (gpx.metadata == null)
+ gpx.metadata = new metadataType();
+ if (gpx.metadata.author == null)
+ gpx.metadata.author = new personType();
+ if (gpx.metadata.author.link == null)
+ gpx.metadata.author.link = new linkType();
+ gpx.metadata.author.link.href = s;
+ });
+
+ xml.trk = SerializeTracks(data).ToArray();
+ xml.rte = SerializeRoutes(data).ToArray();
+ xml.wpt = SerializeWaypoints(data).ToArray();
+
+ return xml;
+ }
+
+ private IEnumerable<wptType> SerializeWaypoints(GpsData data)
+ {
+ return data.Waypoints.Select(waypoint => new wptType
+ {
+ lat = (decimal)waypoint.Latitude,
+ lon = (decimal)waypoint.Longitude,
+ ele = waypoint.Elevation == null ? 0m : (decimal)waypoint.Elevation
+ });
+ }
+
+ private IEnumerable<trkType> SerializeTracks(GpsData data)
+ {
+ foreach (var track in data.Tracks)
+ {
+ var trk = new trkType();
+
+ SerializeTrackMetadata(track, trk, x => x.Name, (gpx, s) => gpx.name = s);
+ SerializeTrackMetadata(track, trk, x => x.Description, (gpx, s) => gpx.desc = s);
+ SerializeTrackMetadata(track, trk, x => x.Comment, (gpx, s) => gpx.cmt = s);
+
+ trk.trkseg = new trksegType[track.Segments.Count];
+ for (var i = 0; i < track.Segments.Count; i++)
+ {
+ var segment = track.Segments[i];
+ var pts = new wptType[segment.Count];
+ for (var j = 0; j < segment.Count; j++)
+ {
+ pts[j] = new wptType
+ {
+ lat = (decimal)segment[j].Latitude,
+ lon = (decimal)segment[j].Longitude,
+ ele = segment[j].Elevation == null ? 0m : (decimal)segment[j].Elevation
+ };
+ }
+ trk.trkseg[i] = new trksegType { trkpt = pts };
+ }
+
+ yield return trk;
+ }
+ }
+
+ private IEnumerable<rteType> SerializeRoutes(GpsData data)
+ {
+ foreach (var route in data.Routes)
+ {
+ var rte = new rteType();
+
+ SerializeRouteMetadata(route, rte, x => x.Name, (gpx, s) => gpx.name = s);
+ SerializeRouteMetadata(route, rte, x => x.Description, (gpx, s) => gpx.desc = s);