diff --git a/Data/Entities/Address.cs b/Data/Entities/Address.cs
index fd156065c..ce709453e 100644
--- a/Data/Entities/Address.cs
+++ b/Data/Entities/Address.cs
@@ -1,7 +1,9 @@
using BS.Shared;
+using System.Diagnostics;
namespace BeWo.Data.Entities
{
+ [DebuggerDisplay("{Oid}: {Street}, {Town}")]
public class Address : BeWoEntityBase
{
public static string PropertyName_AddressLine1 = "AddressLine1";
@@ -30,6 +32,12 @@ namespace BeWo.Data.Entities
private string _Town;
+ private decimal? _Latitude;
+
+ private decimal? _Longitude;
+
+ private long? _L_Version;
+
public Address()
{
this._Tid = TableID.Address;
@@ -114,7 +122,7 @@ namespace BeWo.Data.Entities
}
}
}
-
+
public virtual string Street
{
get
@@ -147,6 +155,54 @@ namespace BeWo.Data.Entities
}
}
+ public virtual decimal? Latitude
+ {
+ get
+ {
+ return this._Latitude;
+ }
+
+ set
+ {
+ if (this.AreDifferent(this._Latitude, value))
+ {
+ this._Latitude = value;
+ }
+ }
+ }
+
+ public virtual decimal? Longitude
+ {
+ get
+ {
+ return this._Longitude;
+ }
+
+ set
+ {
+ if (this.AreDifferent(this._Longitude, value))
+ {
+ this._Longitude = value;
+ }
+ }
+ }
+
+ public virtual long? L_Version
+ {
+ get
+ {
+ return this._L_Version;
+ }
+
+ set
+ {
+ if (this.AreDifferent(this._L_Version, value))
+ {
+ this._L_Version = value;
+ }
+ }
+ }
+
public virtual Address CopyToNew()
{
return new Address
@@ -161,5 +217,13 @@ namespace BeWo.Data.Entities
Town = this.Town
};
}
+
+ public override int GetHashCode()
+ {
+ if (this is null)
+ return 0;
+
+ return Oid.Value.GetHashCode();
+ }
}
}
\ No newline at end of file
diff --git a/Data/Entities/AddressRoute.cs b/Data/Entities/AddressRoute.cs
index d5c55c453..b5f2337ee 100644
--- a/Data/Entities/AddressRoute.cs
+++ b/Data/Entities/AddressRoute.cs
@@ -1,18 +1,20 @@
using BS.Shared;
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BeWo.Data.Entities
{
+ [DebuggerDisplay("{Oid}({Origin.Oid},{Destination.Oid}): {Distance_in_meter}m, {Time_in_seconds}s")]
public class AddressRoute : BeWoEntityBase
{
- private long address1_oid;
- private long address1_version;
- private long address2_oid;
- private long address2_version;
+ private Address _Origin;
+ private long _Origin_Version;
+ private Address _Destination;
+ private long _Destination_Version;
private int distance_in_meter;
private string distance_in_meter_txt;
@@ -24,62 +26,62 @@ namespace BeWo.Data.Entities
_Tid = TableID.AddressRoute;
}
- public virtual long Address1_Oid
+ public virtual Address Origin
{
get
{
- return address1_oid;
+ return _Origin;
}
set
{
- if (AreDifferent(address1_oid, value))
+ if (AreDifferent(_Origin, value))
{
- address1_oid = value;
+ _Origin = value;
}
}
}
- public virtual long Address1_Version
+ public virtual long Origin_Version
{
get
{
- return address1_version;
+ return _Origin_Version;
}
set
{
- if (AreDifferent(address1_version, value))
+ if (AreDifferent(_Origin_Version, value))
{
- address1_version = value;
+ _Origin_Version = value;
}
}
}
- public virtual long Address2_Oid
+ public virtual Address Destination
{
get
{
- return address2_oid;
+ return _Destination;
}
set
{
- if (AreDifferent(address2_oid, value))
+ if (AreDifferent(_Destination, value))
{
- address2_oid = value;
+ _Destination = value;
}
}
}
- public virtual long Address2_Version
+ public virtual long Destination_Version
{
get
{
- return address2_version;
+ return _Destination_Version;
}
set
{
- if (AreDifferent(address2_version, value))
+ if (AreDifferent(_Destination_Version, value))
{
- address2_version = value;
+ _Destination_Version = value;
}
}
}
diff --git a/Data/Mappings/Address.hbm.xml b/Data/Mappings/Address.hbm.xml
index bc2beb473..3aaee5e42 100644
--- a/Data/Mappings/Address.hbm.xml
+++ b/Data/Mappings/Address.hbm.xml
@@ -6,19 +6,22 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Data/Mappings/AddressRoute.hbm.xml b/Data/Mappings/AddressRoute.hbm.xml
index cf0a9649b..13ea6c719 100644
--- a/Data/Mappings/AddressRoute.hbm.xml
+++ b/Data/Mappings/AddressRoute.hbm.xml
@@ -15,11 +15,12 @@
-
-
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/DownloadServer/Web.config b/DownloadServer/Web.config
index 97488bee4..ddb1139ee 100644
--- a/DownloadServer/Web.config
+++ b/DownloadServer/Web.config
@@ -104,6 +104,9 @@
+
+
+
diff --git a/Model/Changes_2023_03_20_Address_Längengrad.txt b/Model/Changes_2023_03_20_Address_Längengrad.txt
new file mode 100644
index 000000000..8a738cba0
--- /dev/null
+++ b/Model/Changes_2023_03_20_Address_Längengrad.txt
@@ -0,0 +1,4 @@
+ALTER TABLE `bewodemo`.`address`
+ADD COLUMN `Latitude` DECIMAL(8,6) NULL DEFAULT NULL AFTER `AddressLine2`,
+ADD COLUMN `Longitude` DECIMAL(9,6) NULL DEFAULT NULL AFTER `Latitude`,
+ADD COLUMN `L_Version` BIGINT(19) NULL DEFAULT NULL AFTER `Longitude`;
\ No newline at end of file
diff --git a/Service/DCEntityMapper/AddressRouteDC_AddressRoute.cs b/Service/DCEntityMapper/AddressRouteDC_AddressRoute.cs
index 90e6601d8..fd2dbf175 100644
--- a/Service/DCEntityMapper/AddressRouteDC_AddressRoute.cs
+++ b/Service/DCEntityMapper/AddressRouteDC_AddressRoute.cs
@@ -21,10 +21,10 @@ namespace BeWo.Service.DCEntityMapper
pDataContract.UdpUser = pEntity.UdpUser;
pDataContract.SystemEntryID = pEntity.SystemEntryID;
- pDataContract.Address1_Oid = pEntity.Address1_Oid;
- pDataContract.Address1_Version = pEntity.Address1_Version;
- pDataContract.Address2_Oid = pEntity.Address2_Oid;
- pDataContract.Address2_Version = pEntity.Address2_Version;
+ pDataContract.Origin_Address_Oid = pEntity.Origin.Oid.Value;
+ pDataContract.Origin_Address_Version = pEntity.Origin_Version;
+ pDataContract.Destination_Address_Oid = pEntity.Destination.Oid.Value;
+ pDataContract.Destination_Address_Version = pEntity.Destination_Version;
pDataContract.Distance_in_meter = pEntity.Distance_in_meter;
pDataContract.Distance_in_meter_txt = pEntity.Distance_in_meter_txt;
@@ -36,21 +36,23 @@ namespace BeWo.Service.DCEntityMapper
public override AddressRoute MergeWithEntity(AddressRouteDC pDataContract, AddressRoute pEntity)
{
- this.ConcurrencyCheck(pDataContract.Version, pEntity);
+ throw new NotImplementedException("#84971983047130984");
- pEntity.Oid = pDataContract.Oid;
- pEntity.Notice = pDataContract.Notice;
- pEntity.SystemEntryID = pDataContract.SystemEntryID;
+ //this.ConcurrencyCheck(pDataContract.Version, pEntity);
- pEntity.Address1_Oid = pDataContract.Address1_Oid;
- pEntity.Address1_Version = pDataContract.Address1_Version;
- pEntity.Address2_Oid = pDataContract.Address2_Oid;
- pEntity.Address2_Version = pDataContract.Address2_Version;
+ //pEntity.Oid = pDataContract.Oid;
+ //pEntity.Notice = pDataContract.Notice;
+ //pEntity.SystemEntryID = pDataContract.SystemEntryID;
- pEntity.Distance_in_meter = pDataContract.Distance_in_meter;
- pEntity.Distance_in_meter_txt = pDataContract.Distance_in_meter_txt;
- pEntity.Time_in_seconds = pDataContract.Time_in_sec;
- pEntity.Time_in_seconds_txt = pDataContract.Time_in_sec_txt;
+ //pEntity.Origin = pDataContract.Origin_Address_Oid;
+ //pEntity.Address1_Version = pDataContract.Origin_Address_Version;
+ //pEntity.Address2_Oid = pDataContract.Destination_Address_Oid;
+ //pEntity.Address2_Version = pDataContract.Destination_Address_Version;
+
+ //pEntity.Distance_in_meter = pDataContract.Distance_in_meter;
+ //pEntity.Distance_in_meter_txt = pDataContract.Distance_in_meter_txt;
+ //pEntity.Time_in_seconds = pDataContract.Time_in_sec;
+ //pEntity.Time_in_seconds_txt = pDataContract.Time_in_sec_txt;
return pEntity;
}
diff --git a/Service/Service.csproj b/Service/Service.csproj
index a155a263d..eaaf9dd74 100644
--- a/Service/Service.csproj
+++ b/Service/Service.csproj
@@ -484,8 +484,10 @@
+
+
diff --git a/Service/ServiceImplementations/DownloadBeWoServiceImp.cs b/Service/ServiceImplementations/DownloadBeWoServiceImp.cs
index 90ade9f6c..633b62267 100644
--- a/Service/ServiceImplementations/DownloadBeWoServiceImp.cs
+++ b/Service/ServiceImplementations/DownloadBeWoServiceImp.cs
@@ -42,19 +42,28 @@ namespace BeWo.Service.ServiceImplementations
public object CallMeForTesting(string token, object input)
{
- if (token != "dafslihjkriouuorgha3431342..")
- return "Nö";
+ try
+ {
+ if (token != "dafslihjkriouuorgha3431342..")
+ return "Nö";
- var address1 = DAOFactory.GenericDAO.LoadByID(3000);
- var address2 = DAOFactory.GenericDAO.LoadByID(3001);
- var address3 = DAOFactory.GenericDAO.LoadByID(3002);
- var address4 = DAOFactory.GenericDAO.LoadByID(3003);
- var address5 = DAOFactory.GenericDAO.LoadByID(3004);
+ return null;
- var add1 = new Address[] { address1, address2, address5 };
- var add2 = new Address[] { address3, address4 };
+ var address1 = DAOFactory.GenericDAO.LoadByID(3000);
+ var address2 = DAOFactory.GenericDAO.LoadByID(3001);
+ var address3 = DAOFactory.GenericDAO.LoadByID(3002);
+ var address4 = DAOFactory.GenericDAO.LoadByID(3003);
+ var address5 = DAOFactory.GenericDAO.LoadByID(3004);
- AddressRouteManager.GetAddressRoute(add1, add2);
+ var add1 = new Address[] { address1, address2, address5 };
+ var add2 = new Address[] { address3, address4 };
+
+ AddressRouteManager.GetMatrix(add1, add2);
+ }
+ catch(Exception e)
+ {
+
+ }
return null;
}
diff --git a/Service/ServiceImplementations/EmployeeServiceImp.cs b/Service/ServiceImplementations/EmployeeServiceImp.cs
index 5fd1cf5a1..9be9ae2be 100644
--- a/Service/ServiceImplementations/EmployeeServiceImp.cs
+++ b/Service/ServiceImplementations/EmployeeServiceImp.cs
@@ -1500,7 +1500,7 @@ namespace BeWo.Service.ServiceImplementations
}
}
- private List GetDistanceForVertreterEmployees(long customerOid, ref List list, List employees)
+ private void GetDistanceForVertreterEmployees(long customerOid, ref List list, List employees)
{
var customer = DAOFactory.GenericDAO.LoadByID(customerOid);
var school = customer.Customer2OrganisationList.FirstOrDefault(f => f.ValueList.Any(b => b.Entry.Type == ValueListEntryType.EnvironmentOrganisationType && b.Entry.Value.Equals("Schule")));
@@ -1508,14 +1508,15 @@ namespace BeWo.Service.ServiceImplementations
var origin = new Address[] { school.Person.Address };
var destinations = employees.Select(x => x.Person.Address).ToArray();
- var routes = AddressRouteManager.GetAddressRoute(origin, destinations);
+ var matrix = AddressRouteManager.GetMatrix(origin, destinations);
- for (int i = 0; i < destinations.Length; i++)
+ Employee empl; AddressRoute route;
+ foreach (var employee in list)
{
- list[i].AddressRoute = MapperFactory.AddressRouteDC_AddressRoute.MapToNewDC(routes[0, i]);
+ empl = employees.FirstOrDefault(e => e.Person.Oid.Value == employee.PersonOid);
+ route = matrix.GetRoute(school.Person.Address, empl.Person.Address);
+ employee.AddressRoute = MapperFactory.AddressRouteDC_AddressRoute.MapToNewDC(route);
}
-
- return null;
}
public List LoadEmployeeTokenRelationsByOid(IEnumerable pOids)
diff --git a/Service/ServiceUtils/DistanceCalculator/AddressRouteManager.cs b/Service/ServiceUtils/DistanceCalculator/AddressRouteManager.cs
index ce2bdcf37..aa52f5ff3 100644
--- a/Service/ServiceUtils/DistanceCalculator/AddressRouteManager.cs
+++ b/Service/ServiceUtils/DistanceCalculator/AddressRouteManager.cs
@@ -12,196 +12,83 @@ namespace BeWo.Service.ServiceUtils.DistanceCalculator
static AddressRouteManager()
{
- DistanceAPI = new GoogleDistanceMatrixApi();
+ DistanceAPI =
+ new GoogleDistanceMatrixApi();
+ //new OpenrouteServiceAPI();
}
- public static AddressRoute[,] GetAddressRoute(Address[] origins, Address[] destinations)
+ public static AddressRouteMatrix GetMatrix(Address[] origins, Address[] destinations)
{
var routes = DAOFactory.GenericDAO.GetAll();
- var res = new AddressRoute[origins.Length, destinations.Length];
+ var matrix = new AddressRouteMatrix(origins, destinations);
- //var toRequest = new List>();
- var toRequest = new Dictionary, Tuple>();
+ LoadExistingData(ref matrix, routes, out var needUpdate);
- Address origin, destination;
- for (int i = 0; i < origins.Length; i++)
+ var requests = needUpdate.Union(matrix.GetUnkownRoutes()).ToList();
+
+ // Alles aktuell
+ if (!requests.Any())
+ return matrix;
+
+ var ori2req = requests.Select(x => x.Origin).ToHashSet();
+ var des2req = requests.Select(x => x.Destination).ToHashSet();
+
+ DistanceAPI.RequestMissingData(ref matrix, ori2req, des2req);
+
+ foreach (var req in requests)
{
- origin = origins[i];
+ var route = matrix.GetRoute(req.Origin, req.Destination);
- for (int j = 0; j < destinations.Length; j++)
+ if (route is null)
+ throw new NotImplementedException("Unerwartetes Verhalten #4314513094871");
+
+ route.Origin_Version = route.Origin.Version.Value;
+ route.Destination_Version = route.Destination.Version.Value;
+
+ if (!route.Version.HasValue)
{
- destination = destinations[j];
-
- var search = routes.FirstOrDefault(route => route.Address1_Oid == origin.Oid && route.Address2_Oid == destination.Oid);
-
- if (search is AddressRoute)
- {
- if (search.Address1_Version == origin.Version && search.Address2_Version == destination.Version)
- {
- // Gefunden
- res[i, j] = search;
- }
- else
- {
- toRequest.Add(new Tuple(i, j), new Tuple(origin, destination, false, search));
- // Braucht Update
- }
- }
- else
- {
- toRequest.Add(new Tuple(i, j), new Tuple(origin, destination, true, null));
- // Neu laden
- }
+ // Neu
+ DAOFactory.GenericDAO.Insert(req);
+ }
+ else
+ {
+ // Update
+ DAOFactory.GenericDAO.Update(req);
}
}
- // Falls keine Update benötigt werden
- if (!toRequest.Any())
- return res;
-
- var origins2req = toRequest.Select(keyvalue => keyvalue.Value.Item1).ToHashSet().ToArray();
- var destinations2req = toRequest.Select(keyvalue => keyvalue.Value.Item2).ToHashSet().ToArray();
-
- var newRoutes = DistanceAPI.GetAddressRoutes(origins2req, destinations2req);
-
- for (int i = 0; i < origins.Length; i++)
- {
- origin = origins[i];
-
- for (int j = 0; j < destinations.Length; j++)
- {
- destination = destinations[j];
-
- // bereits gefunden
- if (res[i, j] is AddressRoute)
- continue;
-
- var req = toRequest[new Tuple(i, j)];
-
- var newRoute = FindRoute(newRoutes, req.Item1, req.Item2);
-
- if (req.Item3)
- {
- // Neu
- DAOFactory.GenericDAO.Insert(newRoute);
- }
- else
- {
- // Alt
- var oldRoute = req.Item4;
-
- oldRoute.Address1_Version = newRoute.Address1_Version;
- oldRoute.Address2_Version = newRoute.Address2_Version;
-
- oldRoute.Distance_in_meter = newRoute.Distance_in_meter;
- oldRoute.Distance_in_meter_txt = newRoute.Distance_in_meter_txt;
- oldRoute.Time_in_seconds = newRoute.Time_in_seconds;
- oldRoute.Time_in_seconds_txt = newRoute.Time_in_seconds_txt;
-
- DAOFactory.GenericDAO.Update(oldRoute);
- }
- }
- }
-
- return res;
+ return matrix;
}
- public static AddressRoute FindRoute(AddressRoute[,] routes, Address origin, Address destination)
+ public static void LoadExistingData(ref AddressRouteMatrix matrix, IList routes, out List needUpdate)
{
- for (int i = 0; i < routes.GetLength(0); i++)
- {
- for (int j = 0; j < routes.GetLength(1); j++)
- {
- var route = routes[i, j];
+ needUpdate = new List();
- if (origin.Oid == route.Address1_Oid && destination.Oid == route.Address2_Oid)
- return route;
+ foreach (var route in routes)
+ {
+ var origin = route.Origin;
+ var destination = route.Destination;
+
+ if (!matrix.CanUseRoute(origin, destination))
+ continue;
+
+ if (origin.Version == route.Origin_Version && destination.Version == route.Destination_Version)
+ {
+ // Ist aktuell
+ matrix.SetRoute(origin, destination, route);
+ }
+ else
+ {
+ // Braucht Update
+ matrix.SetRoute(origin, destination, route);
+ needUpdate.Add(route);
}
}
-
- throw new NotImplementedException("#974289");
}
- //public static AddressRoute GetAddressRoute(Address address1, Address address2)
- //{
- // var routes = DAOFactory.GenericDAO.GetAll();
-
- // foreach (var route in routes)
- // {
- // if (route.Address1_Oid == address1.Oid && route.Address2_Oid == address2.Oid)
- // {
- // if (route.Address1_Version == address1.Version && route.Address2_Version == address2.Version)
- // {
- // // Route korrekt vorhanden
- // return route;
- // }
- // else
- // {
- // // Route vorhanden, aber Addresse hat update
- // return UpdateAddressRoute(route, address1, address2);
- // }
- // }
- // }
-
- // // Route nicht vorhanden
- // return InsertNewAddressRoute(address1, address2);
- //}
-
- //public static void DeleteAddressRoute(long oid) => DeleteAddressRoute(DAOFactory.GenericDAO.LoadByID(oid));
-
- //public static void DeleteAddressRoute(AddressRoute route)
- //{
- // if (route is object)
- // DAOFactory.GenericDAO.Delete(route);
- //}
-
- //public static AddressRoute InsertNewAddressRoute(Address address1, Address address2)
- //{
- // var newRoute = new AddressRoute
- // {
- // Address1_Oid = address1.Oid.Value,
- // Address2_Oid = address2.Oid.Value
- // };
-
- // RequestAddressRoute(ref newRoute, address1, address2);
-
- // DAOFactory.GenericDAO.Insert(newRoute);
-
- // return newRoute;
- //}
-
- //public static AddressRoute UpdateAddressRoute(AddressRoute route, Address address1, Address address2)
- //{
- // RequestAddressRoute(ref route, address1, address2);
-
- // DAOFactory.GenericDAO.Update(route);
-
- // return route;
- //}
-
- //public static AddressRoute RequestAddressRoute(ref AddressRoute route, Address address1, Address address2)
- //{
- // route.Address1_Version = address1.Version.Value;
- // route.Address2_Version = address2.Version.Value;
-
- // // Calculate Distance
-
- // var api = new GoogleDistanceMatrixApi(address1, address2);
- // var task = api.GetResponse();
-
- // task.Wait();
-
- // if (task.Exception is object)
- // {
- // throw task.Exception;
- // }
-
- // route.Distance_in_meter = task.Result.Rows[0].Elements[0].Distance.Value;
- // route.Distance_in_meter_txt = task.Result.Rows[0].Elements[0].Distance.Text;
- // route.Time_in_seconds = task.Result.Rows[0].Elements[0].Duration.Value;
- // route.Time_in_seconds_txt = task.Result.Rows[0].Elements[0].Duration.Text;
-
- // return route;
- //}
+ public static string AddressToString(Address address)
+ {
+ return $"{address.Street}, {address.PostalCode}, {address.Town}, {address.State}, {address.Country}";
+ }
}
}
diff --git a/Service/ServiceUtils/DistanceCalculator/AddressRouteMatrix.cs b/Service/ServiceUtils/DistanceCalculator/AddressRouteMatrix.cs
new file mode 100644
index 000000000..99c0c4628
--- /dev/null
+++ b/Service/ServiceUtils/DistanceCalculator/AddressRouteMatrix.cs
@@ -0,0 +1,84 @@
+using BeWo.Data.Entities;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BeWo.Service.ServiceUtils.DistanceCalculator
+{
+ public class AddressRouteMatrix
+ {
+ public int OriginsLength { get; set; }
+ public int DestinationsLength { get; set; }
+
+ public Address[] OriginAddresses { get; set; }
+ public Address[] DestinationAddresses { get; set; }
+ public Dictionary Origins { get; set; }
+ public Dictionary Destinations { get; set; }
+ public AddressRoute[,] Routes { get; set; }
+
+ public AddressRouteMatrix(Address[] originAddresses, Address[] destinationAddresses)
+ {
+ OriginAddresses = originAddresses;
+ Origins = new Dictionary();
+ OriginsLength = originAddresses.Length;
+
+ DestinationAddresses = destinationAddresses;
+ Destinations = new Dictionary();
+ DestinationsLength = destinationAddresses.Length;
+
+ int i;
+ for (i = 0; i < OriginsLength; i++)
+ {
+ Origins.Add(originAddresses[i], i);
+ }
+
+ for (i = 0; i < DestinationsLength; i++)
+ {
+ Destinations.Add(destinationAddresses[i], i);
+ }
+
+ Routes = new AddressRoute[OriginsLength, DestinationsLength];
+ }
+
+ public void SetRoute(Address origin, Address destination, AddressRoute value) => Routes[Origins[origin], Destinations[destination]] = value;
+ public AddressRoute GetRoute(Address origin, Address destination)
+ {
+ return Routes[Origins[origin], Destinations[destination]];
+ }
+
+ public IEnumerable GetUnkownRoutes()
+ {
+ for (int i = 0; i < OriginsLength; i++)
+ {
+ for (int j = 0; j < DestinationsLength; j++)
+ {
+ var route = Routes[i, j];
+
+ if (route is null)
+ {
+ route = new AddressRoute
+ {
+ Origin = OriginAddresses[i],
+ Destination = DestinationAddresses[j]
+ };
+
+ Routes[i, j] = route;
+
+ yield return route;
+ }
+ }
+ }
+ }
+
+ public bool CanUseRoute(Address origin, Address destination)
+ {
+ if (!Origins.ContainsKey(origin))
+ return false;
+ if (!Destinations.ContainsKey(destination))
+ return false;
+ return true;
+ }
+ }
+}
diff --git a/Service/ServiceUtils/DistanceCalculator/GoogleDistanceMatrixAPI.cs b/Service/ServiceUtils/DistanceCalculator/GoogleDistanceMatrixAPI.cs
index 13e61c228..f5d493ac2 100644
--- a/Service/ServiceUtils/DistanceCalculator/GoogleDistanceMatrixAPI.cs
+++ b/Service/ServiceUtils/DistanceCalculator/GoogleDistanceMatrixAPI.cs
@@ -48,6 +48,8 @@ namespace BeWo.Service.ServiceUtils.DistanceCalculator
private string Key { get; set; }
private string Url { get; set; }
+ private AddressRouteMatrix Matrix { get; set; }
+
private Address[] OriginAddresses { get; set; }
private Address[] DestinationAddresses { get; set; }
@@ -68,12 +70,13 @@ namespace BeWo.Service.ServiceUtils.DistanceCalculator
Key = appSettings["GoogleDistanceMatrixApiKey"];
}
- public AddressRoute[,] GetAddressRoutes(Address[] originAddresses, Address[] destinationAddresses)
+ public void RequestMissingData(ref AddressRouteMatrix matrix, IEnumerable origins, IEnumerable destinations)
{
- OriginAddresses = originAddresses;
- DestinationAddresses = destinationAddresses;
+ Matrix = matrix;
+ OriginAddresses = origins.ToArray();
+ DestinationAddresses = destinations.ToArray();
- var task = GetResponse();
+ var task = GetMatrix();
task.Wait();
@@ -81,11 +84,9 @@ namespace BeWo.Service.ServiceUtils.DistanceCalculator
{
throw task.Exception;
}
-
- return task.Result;
}
- public async Task GetResponse()
+ public async Task GetMatrix()
{
using (var client = new HttpClient())
{
@@ -100,33 +101,33 @@ namespace BeWo.Service.ServiceUtils.DistanceCalculator
{
var content = await response.Content.ReadAsStringAsync();
- return ToAddressRouteArray(JsonConvert.DeserializeObject(content));
+ return FillMatrix(JsonConvert.DeserializeObject(content));
}
}
}
- public AddressRoute[,] ToAddressRouteArray(Response response)
+ public AddressRouteMatrix FillMatrix(Response response)
{
- var res = new AddressRoute[OriginAddresses.Length, DestinationAddresses.Length];
-
for (int i = 0; i < response.Rows.Length; i++)
{
var row = response.Rows[i];
+ var origin = OriginAddresses[i];
for (int j = 0; j < row.Elements.Length; j++)
{
var element = row.Elements[j];
+ var destination = DestinationAddresses[j];
- res[i, j] = ToAddressRoute(element);
+ var route = Matrix.GetRoute(origin, destination);
- res[i, j].Address1_Oid = OriginAddresses[i].Oid.Value;
- res[i, j].Address1_Version = OriginAddresses[i].Version.Value;
- res[i, j].Address2_Oid = DestinationAddresses[j].Oid.Value;
- res[i, j].Address2_Version = DestinationAddresses[j].Version.Value;
+ route.Distance_in_meter = element.Distance.Value;
+ route.Distance_in_meter_txt = element.Distance.Text;
+ route.Time_in_seconds = element.Duration.Value;
+ route.Time_in_seconds_txt = element.Duration.Text;
}
}
- return res;
+ return Matrix;
}
public AddressRoute ToAddressRoute(Response.Element element)
@@ -143,16 +144,11 @@ namespace BeWo.Service.ServiceUtils.DistanceCalculator
private string GetRequestUrl()
{
- var originAddresses = OriginAddresses.Select(str => ToGoogle(str)).Select(HttpUtility.UrlEncode).ToArray();
+ var originAddresses = OriginAddresses.Select(str => AddressRouteManager.AddressToString(str)).Select(HttpUtility.UrlEncode).ToArray();
var origins = string.Join("|", originAddresses);
- var destinationAddresses = DestinationAddresses.Select(str => ToGoogle(str)).Select(HttpUtility.UrlEncode).ToArray();
+ var destinationAddresses = DestinationAddresses.Select(str => AddressRouteManager.AddressToString(str)).Select(HttpUtility.UrlEncode).ToArray();
var destinations = string.Join("|", destinationAddresses);
return $"{Url}?origins={origins}&destinations={destinations}&key={Key}";
}
-
- public static string ToGoogle(Address add)
- {
- return $"{add.Street}, {add.PostalCode}, {add.Town}, {add.State}, {add.Country}";
- }
}
}
diff --git a/Service/ServiceUtils/DistanceCalculator/IDistanceAPI.cs b/Service/ServiceUtils/DistanceCalculator/IDistanceAPI.cs
index 8d4723f50..9204b8712 100644
--- a/Service/ServiceUtils/DistanceCalculator/IDistanceAPI.cs
+++ b/Service/ServiceUtils/DistanceCalculator/IDistanceAPI.cs
@@ -10,6 +10,10 @@ namespace BeWo.Service.ServiceUtils.DistanceCalculator
{
public interface IDistanceAPI
{
- AddressRoute[,] GetAddressRoutes(Address[] originAddresses, Address[] destinationAddresses);
+ //AddressRoute[,] GetAddressRoutes(Address[] originAddresses, Address[] destinationAddresses);
+
+ //AddressRouteMatrix GetAddressRouteMatrix(Address[] originAddresses, Address[] destinationAddresses);
+
+ void RequestMissingData(ref AddressRouteMatrix matrix, IEnumerable origins, IEnumerable destinations);
}
}
diff --git a/Service/ServiceUtils/DistanceCalculator/OpenrouteServiceAPI.cs b/Service/ServiceUtils/DistanceCalculator/OpenrouteServiceAPI.cs
new file mode 100644
index 000000000..3c55f0025
--- /dev/null
+++ b/Service/ServiceUtils/DistanceCalculator/OpenrouteServiceAPI.cs
@@ -0,0 +1,259 @@
+using BeWo.Data.Access;
+using BeWo.Data.Entities;
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Globalization;
+using System.Linq;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Text;
+using System.Threading.Tasks;
+using System.Web;
+using Task = System.Threading.Tasks.Task;
+
+namespace BeWo.Service.ServiceUtils.DistanceCalculator
+{
+ public class OpenrouteServiceAPI : IDistanceAPI
+ {
+ public class ResponseGeo
+ {
+ public Feature[] Features { get; set; }
+
+ public class Feature
+ {
+ public string Type { get; set; }
+ public Geometry Geometry { get; set; }
+ }
+
+ public class Geometry
+ {
+ public string Type { get; set; }
+ public decimal[] Coordinates { get; set; }
+ }
+ }
+
+ public class ResponseMatrix
+ {
+ public decimal[,] Durations { get; set; }
+ public decimal[,] Distances { get; set; }
+ }
+
+ private string Key { get; set; }
+ private string GeoKey { get; set; }
+ private string Url { get; set; }
+
+ private AddressRouteMatrix Matrix { get; set; }
+
+ private Address[] OriginAddresses { get; set; }
+ private Address[] DestinationAddresses { get; set; }
+
+ public OpenrouteServiceAPI()
+ {
+ var appSettings = ConfigurationManager.AppSettings;
+
+ if (string.IsNullOrEmpty(appSettings["OpenrouteServiceApiUrl"]))
+ {
+ throw new Exception("OpenrouteServiceApiUrl is not set in AppSettings.");
+ }
+ Url = appSettings["OpenrouteServiceApiUrl"];
+
+ if (string.IsNullOrEmpty(appSettings["OpenrouteServiceApiKey"]))
+ {
+ throw new Exception("OpenrouteServiceApiKey is not set in AppSettings.");
+ }
+ Key = appSettings["OpenrouteServiceApiKey"];
+
+ if (string.IsNullOrEmpty(appSettings["OpenrouteServiceApiUrlGeocode"]))
+ {
+ throw new Exception("OpenrouteServiceApiUrlGeocode is not set in AppSettings.");
+ }
+ GeoKey = appSettings["OpenrouteServiceApiUrlGeocode"];
+ }
+
+ public void RequestMissingData(ref AddressRouteMatrix matrix, IEnumerable origins, IEnumerable destinations)
+ {
+ Matrix = matrix;
+ OriginAddresses = origins.ToArray();
+ DestinationAddresses = destinations.ToArray();
+
+ if (!(origins.Any() && destinations.Any()))
+ throw new NotImplementedException("Keine Addresse angefragt");
+
+ LoadCoordinates().Wait();
+
+ var task = GetMatrix();
+
+ task.Wait();
+
+ if (task.Exception is object)
+ {
+ throw task.Exception;
+ }
+ }
+
+ public async Task LoadCoordinates()
+ {
+ // Update Koordinaten
+ var items = OriginAddresses.Union(DestinationAddresses).ToHashSet();
+ foreach (var item in items)
+ {
+ if (item.L_Version is object && item.L_Version == item.Version)
+ continue;
+
+ await LoadCoordinate(item);
+
+ DAOFactory.GenericDAO.Update(item);
+ }
+ }
+
+ public async Task LoadCoordinate(Address address)
+ {
+ using (var client = new HttpClient())
+ {
+ var uri = new Uri(GetGeocodeUrl(address));
+
+ client.DefaultRequestHeaders.Clear();
+ client.DefaultRequestHeaders.TryAddWithoutValidation("accept", "application/json; charset=utf-8");
+ client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json; charset=utf-8");
+
+ using (var response = await client.GetAsync(uri))
+ {
+ string responseData = await response.Content.ReadAsStringAsync();
+
+ if (response.IsSuccessStatusCode)
+ {
+ try
+ {
+ var data = JsonConvert.DeserializeObject(responseData);
+
+ address.Longitude = data.Features[0].Geometry.Coordinates[0];
+ address.Latitude = data.Features[0].Geometry.Coordinates[1];
+ address.L_Version = address.Version.Value + 1;
+
+ return;
+ }
+ catch (Exception e)
+ {
+ throw e;
+ }
+
+ }
+ else
+ {
+ throw new Exception("OpenrouteServiceAPI failed with status code: " + response.StatusCode + " |||Data: " + responseData);
+ }
+ }
+ }
+ }
+
+ public async Task GetMatrix()
+ {
+ using (var client = new HttpClient())
+ {
+ var uri = new Uri(Url);
+
+ client.DefaultRequestHeaders.Clear();
+ client.DefaultRequestHeaders.TryAddWithoutValidation("accept", "application/json; charset=utf-8");
+ client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json; charset=utf-8");
+ client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Key);
+
+ using (var content = new StringContent(GetMatrixBodyContentString()))
+ //using (var content = new StringContent("{\"locations\":[[48.477473,9.70093],[49.153868,9.207916]]}"))
+ {
+ content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
+ using (var response = await client.PostAsync(uri, content))
+ {
+ string responseData = await response.Content.ReadAsStringAsync();
+
+ if (response.IsSuccessStatusCode)
+ {
+ var data = JsonConvert.DeserializeObject(responseData);
+
+ return FillMatrix(data);
+ }
+ else
+ {
+ throw new Exception("OpenrouteServiceAPI failed with status code: " + response.StatusCode + " |||Data: " + responseData);
+ }
+ }
+ }
+ }
+ }
+
+ public AddressRouteMatrix FillMatrix(ResponseMatrix response)
+ {
+ for (int i = 0; i < response.Durations.GetLength(0); i++)
+ {
+ for (int j = 0; j < response.Durations.GetLength(1); j++)
+ {
+ var distance = response.Distances[i, j];
+ var duration = response.Durations[i, j];
+
+ var origin = OriginAddresses[i];
+ var destination = DestinationAddresses[j];
+
+ var route = Matrix.GetRoute(origin, destination);
+
+ route.Distance_in_meter = (int) (distance * 1000);
+ route.Time_in_seconds = (int) duration;
+ }
+ }
+
+ return Matrix;
+ }
+
+ private string GetGeocodeUrl(Address address)
+ {
+ var html = HttpUtility.UrlEncode(AddressRouteManager.AddressToString(address));
+ return $"{GeoKey}?api_key={Key}&text={html}&sources=openstreetmap&size=1";
+ }
+
+ private string GetMatrixBodyContentString()
+ {
+ var sb = new StringBuilder();
+
+ var origins = OriginAddresses.Select(GetCoordinates);
+ var olen = OriginAddresses.Count();
+ var destination = DestinationAddresses.Select(GetCoordinates);
+ var dlen = DestinationAddresses.Count();
+
+ sb.Append("{\"locations\":");
+ sb.Append("[");
+ sb.Append(string.Join(",", origins.Union(destination)));
+ sb.Append("]");
+
+ sb.Append(",\"metrics\":[\"distance\",\"duration\"]");
+ sb.Append(",\"units\":\"km\"");
+
+ sb.Append(",\"sources\":");
+ sb.Append(GetList(0, olen - 1));
+
+ sb.Append(",\"destinations\":");
+ sb.Append(GetList(olen, olen + dlen - 1));
+
+ sb.Append("}");
+
+ return sb.ToString();
+ }
+
+ private string GetCoordinates(Address add) => $"[{add.Longitude.Value.ToString(new CultureInfo("en-US"))},{add.Latitude.Value.ToString(new CultureInfo("en-US"))}]";
+
+ private string GetList(int x, int y)
+ {
+ if (y < x)
+ throw new ArgumentException($"y({y}) darf nicht kleiner als x({x}) sein");
+
+ var diff = y - x;
+ var list = new int[diff + 1];
+
+ for (int i = 0; i <= diff; i++)
+ {
+ list[i] = x + i;
+ }
+
+ return "[" + string.Join(",", list) + "]";
+ }
+ }
+}
diff --git a/Shared/DataContracts/AddressRouteDC.cs b/Shared/DataContracts/AddressRouteDC.cs
index aeb129359..8b46ced92 100644
--- a/Shared/DataContracts/AddressRouteDC.cs
+++ b/Shared/DataContracts/AddressRouteDC.cs
@@ -34,16 +34,16 @@ namespace BS.Shared.DataContracts
public SystemEntryID? SystemEntryID { get; set; }
[DataMember]
- public long Address1_Oid { get; set; }
+ public long Origin_Address_Oid { get; set; }
[DataMember]
- public long Address1_Version { get; set; }
+ public long Origin_Address_Version { get; set; }
[DataMember]
- public long Address2_Oid { get; set; }
+ public long Destination_Address_Oid { get; set; }
[DataMember]
- public long Address2_Version { get; set; }
+ public long Destination_Address_Version { get; set; }
[DataMember]
public int Distance_in_meter { get; set; }