Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added CRS indexing based on an sqlite database #108

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
277 changes: 65 additions & 212 deletions src/ProjNet/CoordinateSystemServices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,94 +14,26 @@
// You should have received a copy of the GNU Lesser General Public License
// along with SharpMap; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Net.Http;
using System.Threading.Tasks;
using ProjNet.CoordinateSystems;
using ProjNet.CoordinateSystems.Transformations;
using ProjNet.Services;

namespace ProjNet
{
/// <summary>
/// A coordinate system services class
/// </summary>
public class CoordinateSystemServices // : ICoordinateSystemServices
public class CoordinateSystemServices
{
//private static ICoordinateSequenceFactory _coordinateSequenceFactory;

///// <summary>
///// Gets or sets a default coordinate sequence factory
///// </summary>
//public static ICoordinateSequenceFactory CoordinateSequenceFactory
//{
// get { return _coordinateSequenceFactory ?? new CoordinateArraySequenceFactory(); }
// set { _coordinateSequenceFactory = value; }
//}

private readonly Dictionary<int, CoordinateSystem> _csBySrid;
private readonly Dictionary<IInfo, int> _sridByCs;

private readonly ICoordinateSystemService _service;
private readonly CoordinateSystemFactory _coordinateSystemFactory;
private readonly CoordinateTransformationFactory _ctFactory;

private readonly ManualResetEvent _initialization = new ManualResetEvent(false);

#region CsEqualityComparer class
private class CsEqualityComparer : EqualityComparer<IInfo>
{
public override bool Equals(IInfo x, IInfo y)
{
return x.AuthorityCode == y.AuthorityCode &&
string.Compare(x.Authority, y.Authority, StringComparison.OrdinalIgnoreCase) == 0;
}

public override int GetHashCode(IInfo obj)
{
if (obj == null) return 0;
return Convert.ToInt32(obj.AuthorityCode) + (obj.Authority != null ? obj.Authority.GetHashCode() : 0);
}
}
#endregion

#region CoordinateSystemKey class

private class CoordinateSystemKey : IInfo
{
public CoordinateSystemKey(string authority, long authorityCode)
{
Authority = authority;
AuthorityCode = authorityCode;
}

public bool EqualParams(object obj)
{
throw new NotSupportedException();
}

public string Name { get { return null; } }
public string Authority { get; private set; }
public long AuthorityCode { get; private set; }
public string Alias { get { return null; } }
public string Abbreviation { get { return null; } }
public string Remarks { get { return null; } }
public string WKT { get { return null; } }
public string XML { get { return null; } }
}

#endregion

/// <summary>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a breaking change, uncomment and mark [Obsolete]

/// Creates an instance of this class
/// </summary>
/// <param name="coordinateSystemFactory">The coordinate sequence factory to use.</param>
/// <param name="coordinateTransformationFactory">The coordinate transformation factory to use</param>
public CoordinateSystemServices(CoordinateSystemFactory coordinateSystemFactory,
CoordinateTransformationFactory coordinateTransformationFactory)
: this(coordinateSystemFactory, coordinateTransformationFactory, null)
{
}

/// <summary>
/// Creates an instance of this class.
Expand All @@ -116,32 +48,9 @@ public CoordinateSystemServices(IEnumerable<KeyValuePair<int, string>> definitio
/// Creates an instance of this class
/// </summary>
public CoordinateSystemServices()
: this(new CoordinateSystemFactory(), new CoordinateTransformationFactory(), null)
: this(new CoordinateSystemFactory(), new CoordinateTransformationFactory())
{
}
//public Func<string, long, string> GetDefinition { get; set; }

/*
public static string GetFromSpatialReferenceOrg(string authority, long code)
{
var url = string.Format("http://spatialreference.org/ref/{0}/{1}/ogcwkt/",
authority.ToLowerInvariant(),
code);
var req = (HttpWebRequest) WebRequest.Create(url);
using (var resp = req.GetResponse())
{
using (var resps = resp.GetResponseStream())
{
if (resps != null)
{
using (var sr = new StreamReader(resps))
return sr.ReadToEnd();
}
}
}
return null;
}
*/

/// <summary>
/// Creates an instance of this class
Expand All @@ -161,93 +70,64 @@ public CoordinateSystemServices(CoordinateSystemFactory coordinateSystemFactory,
throw new ArgumentNullException(nameof(coordinateTransformationFactory));
_ctFactory = coordinateTransformationFactory;

_csBySrid = new Dictionary<int, CoordinateSystem>();
_sridByCs = new Dictionary<IInfo, int>(new CsEqualityComparer());

object enumObj = (object)enumeration ?? DefaultInitialization();
_initialization = new ManualResetEvent(false);
System.Threading.Tasks.Task.Run(() => FromEnumeration((new[] { this, enumObj })));
_service = new DefaultCoordinateService(this, enumeration);
}

//private CoordinateSystemServices(ICoordinateSystemFactory coordinateSystemFactory,
// ICoordinateTransformationFactory coordinateTransformationFactory,
// IEnumerable<KeyValuePair<int, ICoordinateSystem>> enumeration)
// : this(coordinateSystemFactory, coordinateTransformationFactory)
//{
// var enumObj = (object)enumeration ?? DefaultInitialization();
// _initialization = new ManualResetEvent(false);
// ThreadPool.QueueUserWorkItem(FromEnumeration, new[] { this, enumObj });
//}

private static CoordinateSystem CreateCoordinateSystem(CoordinateSystemFactory coordinateSystemFactory, string wkt)
/// <summary>
/// Creates an instance of this class
/// </summary>
/// <param name="coordinateSystemFactory">The coordinate sequence factory to use.</param>
/// <param name="coordinateTransformationFactory">The coordinate transformation factory to use</param>
public CoordinateSystemServices(CoordinateSystemFactory coordinateSystemFactory,
CoordinateTransformationFactory coordinateTransformationFactory)
{
try
{
return coordinateSystemFactory.CreateFromWkt(wkt.Replace("ELLIPSOID", "SPHEROID"));
}
catch (Exception)
{
// as a fallback we ignore projections not supported
return null;
}
}
if (coordinateSystemFactory == null)
throw new ArgumentNullException(nameof(coordinateSystemFactory));
_coordinateSystemFactory = coordinateSystemFactory;

private static IEnumerable<KeyValuePair<int, CoordinateSystem>> DefaultInitialization()
{
yield return new KeyValuePair<int, CoordinateSystem>(4326, GeographicCoordinateSystem.WGS84);
yield return new KeyValuePair<int, CoordinateSystem>(3857, ProjectedCoordinateSystem.WebMercator);
if (coordinateTransformationFactory == null)
throw new ArgumentNullException(nameof(coordinateTransformationFactory));
_ctFactory = coordinateTransformationFactory;

_service = new DatabaseCoordinateService(this);
}

private static void FromEnumeration(CoordinateSystemServices css,
IEnumerable<KeyValuePair<int, CoordinateSystem>> enumeration)
/// <summary>
/// Returns a CoordinateSystem from a url containing the wkt
/// </summary>
/// <param name="url"></param>
/// <returns>Returns null if not found</returns>
public async Task<CoordinateSystem> GetCoordinateSystemFromWeb(string url)
{
foreach (var sridCs in enumeration)
try
{
css.AddCoordinateSystem(sridCs.Key, sridCs.Value);
using (var client = new HttpClient())
{
string wkt = await client.GetStringAsync(url);
return _coordinateSystemFactory.CreateFromWkt(wkt);
}
}
}

private static IEnumerable<KeyValuePair<int, CoordinateSystem>> CreateCoordinateSystems(
CoordinateSystemFactory factory,
IEnumerable<KeyValuePair<int, string>> enumeration)
{
foreach (var sridWkt in enumeration)
catch (HttpRequestException ex)
{
var cs = CreateCoordinateSystem(factory, sridWkt.Value);
if (cs != null)
yield return new KeyValuePair<int, CoordinateSystem>(sridWkt.Key, cs);
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}

private static void FromEnumeration(CoordinateSystemServices css,
IEnumerable<KeyValuePair<int, string>> enumeration)
{
FromEnumeration(css, CreateCoordinateSystems(css._coordinateSystemFactory, enumeration));
return null;
}

private static void FromEnumeration(object parameter)
public CoordinateSystem CreateFromWkt(string wkt)
{
object[] paras = (object[]) parameter;
var css = (CoordinateSystemServices) paras[0];

if (paras[1] is IEnumerable<KeyValuePair<int, string>>)
FromEnumeration(css, (IEnumerable<KeyValuePair<int, string>>) paras[1]);
else
FromEnumeration(css, (IEnumerable<KeyValuePair<int, CoordinateSystem>>)paras[1]);

css._initialization.Set();
return _coordinateSystemFactory.CreateFromWkt(wkt);
}


/// <summary>
/// Returns the coordinate system by <paramref name="srid" /> identifier
/// </summary>
/// <param name="srid">The initialization for the coordinate system</param>
/// <returns>The coordinate system.</returns>
public CoordinateSystem GetCoordinateSystem(int srid)
{
_initialization.WaitOne();
return _csBySrid.TryGetValue(srid, out var cs) ? cs : null;
return _service.GetCoordinateSystem(srid);
}

/// <summary>
Expand All @@ -258,10 +138,7 @@ public CoordinateSystem GetCoordinateSystem(int srid)
/// <returns>The coordinate system.</returns>
public CoordinateSystem GetCoordinateSystem(string authority, long code)
{
int? srid = GetSRID(authority, code);
if (srid.HasValue)
return GetCoordinateSystem(srid.Value);
return null;
return _service.GetCoordinateSystem(authority, code);
}

/// <summary>
Expand All @@ -272,13 +149,7 @@ public CoordinateSystem GetCoordinateSystem(string authority, long code)
/// <returns>The identifier or <value>null</value></returns>
public int? GetSRID(string authority, long authorityCode)
{
var key = new CoordinateSystemKey(authority, authorityCode);
int srid;
_initialization.WaitOne();
if (_sridByCs.TryGetValue(key, out srid))
return srid;

return null;
return _service.GetSRID(authority, authorityCode);
}

/// <summary>
Expand All @@ -305,64 +176,46 @@ public ICoordinateTransformation CreateTransformation(CoordinateSystem source, C
return _ctFactory.CreateFromCoordinateSystems(source, target);
}

protected void AddCoordinateSystem(int srid, CoordinateSystem coordinateSystem)
/// <summary>
/// Adds a coordinate system to the service
/// </summary>
public void AddCoordinateSystem(int srid, CoordinateSystem coordinateSystem)
{
lock (((IDictionary) _csBySrid).SyncRoot)
{
lock (((IDictionary) _sridByCs).SyncRoot)
{
if (_sridByCs.ContainsKey(coordinateSystem))
return;

if (_csBySrid.ContainsKey(srid))
{
if (ReferenceEquals(coordinateSystem, _csBySrid[srid]))
return;

_sridByCs.Remove(_csBySrid[srid]);
_csBySrid[srid] = coordinateSystem;
_sridByCs.Add(coordinateSystem, srid);
}
else
{
_csBySrid.Add(srid, coordinateSystem);
_sridByCs.Add(coordinateSystem, srid);
}
}
}
_service.AddCoordinateSystem(srid, coordinateSystem);
}

protected virtual int AddCoordinateSystem(CoordinateSystem coordinateSystem)
/// <summary>
/// Adds a coordinate system to the service
/// </summary>
public virtual int AddCoordinateSystem(CoordinateSystem coordinateSystem)
{
int srid = (int) coordinateSystem.AuthorityCode;
AddCoordinateSystem(srid, coordinateSystem);

return srid;
return _service.AddCoordinateSystem(coordinateSystem);
}

protected void Clear()
/// <summary>
/// Returns the number of coordinate systems in the service
/// </summary>
public int Count
{
_csBySrid.Clear();
get { return _service.Count; }
}

protected int Count
[Obsolete]
public bool RemoveCoordinateSystem(int srid)
{
get
{
_initialization.WaitOne();
return _sridByCs.Count;
}
throw new NotSupportedException();
}

public bool RemoveCoordinateSystem(int srid)
[Obsolete]
protected void Clear()
{
throw new NotSupportedException();
}

[Obsolete]
public IEnumerator<KeyValuePair<int, CoordinateSystem>> GetEnumerator()
{
_initialization.WaitOne();
return _csBySrid.GetEnumerator();
throw new NotSupportedException();
}
}
}
10 changes: 10 additions & 0 deletions src/ProjNet/CoordinateSystems/Projection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,16 @@ public ProjectionParameter GetParameter(int index)
return _parameters[index];
}

/// <summary>
/// Adds a parameter to the parameter list
/// </summary>
/// <param name="param">The projection parameter to add</param>
public void AddParameter(string name, double value)
{
ProjectionParameter param = new ProjectionParameter(name, value);
_parameters.Add(param);
}

/// <summary>
/// Gets an named parameter of the projection.
/// </summary>
Expand Down
Loading