OpenrouteServiceAPI implementiert, Längengrad bei Addresse

This commit is contained in:
2023-03-22 13:25:43 +01:00
parent d1d846cb1d
commit 864dbce3db
16 changed files with 590 additions and 269 deletions

View File

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

View File

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

View File

@@ -6,19 +6,22 @@
<generator class="identity" />
</id>
<version type="Int64" column="Version" name="Version" />
<property column="Tid" type="BS.Shared.TableID, BS.Shared" name="_Tid" access="field" />
<property column="Tid" type="BS.Shared.TableID, BS.Shared" name="_Tid" access="field" />
<property column="AddressLine1" type="String" name="AddressLine1" length="64" />
<property column="AddressLine2" type="String" name="AddressLine2" length="64" />
<property column="Street" type="String" name="Street" length="256" />
<property column="PostalCode" type="String" name="PostalCode" length="128" />
<property column="Town" type="String" name="Town" length="256" />
<property column="State" type="String" name="State" length="256" />
<property column="Country" type="String" name="Country" length="256" />
<property column="Notice" type="String" name="Notice" length="1024" />
<property column="InsTs" type="DateTime" name="InsTs" />
<property column="InsUser" type="String" name="InsUser" length="256" />
<property column="UdpUser" type="String" name="UdpUser" length="256" />
<property column="IsActive" type="BS.Shared.ActivationTypeId, BS.Shared" name="IsActive" />
<property column="SystemEntryID" type="BS.Shared.SystemEntryID, BS.Shared" name="SystemEntryID" />
<property column="Street" type="String" name="Street" length="256" />
<property column="PostalCode" type="String" name="PostalCode" length="128" />
<property column="Town" type="String" name="Town" length="256" />
<property column="State" type="String" name="State" length="256" />
<property column="Country" type="String" name="Country" length="256" />
<property column="Notice" type="String" name="Notice" length="1024" />
<property column="InsTs" type="DateTime" name="InsTs" />
<property column="InsUser" type="String" name="InsUser" length="256" />
<property column="UdpUser" type="String" name="UdpUser" length="256" />
<property column="IsActive" type="BS.Shared.ActivationTypeId, BS.Shared" name="IsActive" />
<property column="SystemEntryID" type="BS.Shared.SystemEntryID, BS.Shared" name="SystemEntryID" />
<property column="Latitude" type="Decimal" name="Latitude" />
<property column="Longitude" type="Decimal" name="Longitude" />
<property column="L_Version" type="Int64" name="L_Version" />
</class>
</hibernate-mapping>

View File

@@ -15,11 +15,12 @@
<property column="UdpUser" type="String" name="UdpUser" length="256" />
<property column="SystemEntryID" type="BS.Shared.SystemEntryID, BS.Shared" name="SystemEntryID" />
<property column="Address1Oid" type="Int64" name="Address1_Oid" />
<property column="Address1Version" type="Int64" name="Address1_Version" />
<property column="Address2Oid" type="Int64" name="Address2_Oid" />
<property column="Address2Version" type="Int64" name="Address2_Version" />
<property column="Address1Version" type="Int64" name="Origin_Version" />
<property column="Address2Version" type="Int64" name="Destination_Version" />
<property column="DistanceMeter" type="Int32" name="Distance_in_meter" />
<property column="TimeSec" type="Int32" name="Time_in_seconds" />
<many-to-one name="Origin" column="Address1Oid" class="BeWo.Data.Entities.Address, BeWo.Data" cascade="all" fetch="join"/>
<many-to-one name="Destination" column="Address2Oid" class="BeWo.Data.Entities.Address, BeWo.Data" cascade="all" fetch="join"/>
</class>
</hibernate-mapping>

View File

@@ -104,6 +104,9 @@
<add key="DownloadVersionFilePath" value="D:\Rene\ServerBeWoDataExample2\version\update.config" />
<add key="GoogleDistanceMatrixApiUrl" value="https://maps.googleapis.com/maps/api/distancematrix/json" />
<add key="GoogleDistanceMatrixApiKey" value="AIzaSyDZ_tfNwm_YWC9JiCLQtHsd9X2OUUKuL0c" />
<add key="OpenrouteServiceApiUrl" value="https://api.openrouteservice.org/v2/matrix/driving-car" />
<add key="OpenrouteServiceApiUrlGeocode" value="https://api.openrouteservice.org/geocode/search" />
<add key="OpenrouteServiceApiKey" value="5b3ce3597851110001cf62484b0917529e9a4008acda819dc06e47e8" />
</appSettings>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

View File

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

View File

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

View File

@@ -484,8 +484,10 @@
<Compile Include="ServiceProxy\ServiceFacade.cs" />
<Compile Include="ServiceProxy\ServiceGenerated.cs" />
<Compile Include="ServiceUtils\DistanceCalculator\AddressRouteManager.cs" />
<Compile Include="ServiceUtils\DistanceCalculator\AddressRouteMatrix.cs" />
<Compile Include="ServiceUtils\DistanceCalculator\GoogleDistanceMatrixAPI.cs" />
<Compile Include="ServiceUtils\DistanceCalculator\IDistanceAPI.cs" />
<Compile Include="ServiceUtils\DistanceCalculator\OpenrouteServiceAPI.cs" />
<Compile Include="ServiceUtils\Paths\ServerFilePaths.cs" />
<Compile Include="ServiceUtils\Update\UpdateFileLimiter.cs" />
<Compile Include="ServiceUtils\Update\UpdateServerSession.cs" />

View File

@@ -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<Address>(3000);
var address2 = DAOFactory.GenericDAO.LoadByID<Address>(3001);
var address3 = DAOFactory.GenericDAO.LoadByID<Address>(3002);
var address4 = DAOFactory.GenericDAO.LoadByID<Address>(3003);
var address5 = DAOFactory.GenericDAO.LoadByID<Address>(3004);
return null;
var add1 = new Address[] { address1, address2, address5 };
var add2 = new Address[] { address3, address4 };
var address1 = DAOFactory.GenericDAO.LoadByID<Address>(3000);
var address2 = DAOFactory.GenericDAO.LoadByID<Address>(3001);
var address3 = DAOFactory.GenericDAO.LoadByID<Address>(3002);
var address4 = DAOFactory.GenericDAO.LoadByID<Address>(3003);
var address5 = DAOFactory.GenericDAO.LoadByID<Address>(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;
}

View File

@@ -1500,7 +1500,7 @@ namespace BeWo.Service.ServiceImplementations
}
}
private List<CompactVertreterEmployeeDC> GetDistanceForVertreterEmployees(long customerOid, ref List<CompactVertreterEmployeeDC> list, List<Employee> employees)
private void GetDistanceForVertreterEmployees(long customerOid, ref List<CompactVertreterEmployeeDC> list, List<Employee> employees)
{
var customer = DAOFactory.GenericDAO.LoadByID<Customer>(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<EmployeeTokenRelationDC> LoadEmployeeTokenRelationsByOid(IEnumerable<long> pOids)

View File

@@ -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<AddressRoute>();
var res = new AddressRoute[origins.Length, destinations.Length];
var matrix = new AddressRouteMatrix(origins, destinations);
//var toRequest = new List<Tuple<int, Address, int, Address, bool>>();
var toRequest = new Dictionary<Tuple<int, int>, Tuple<Address, Address, bool, AddressRoute>>();
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<int, int>(i, j), new Tuple<Address, Address, bool, AddressRoute>(origin, destination, false, search));
// Braucht Update
}
}
else
{
toRequest.Add(new Tuple<int, int>(i, j), new Tuple<Address, Address, bool, AddressRoute>(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<int, int>(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<AddressRoute> routes, out List<AddressRoute> 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<AddressRoute>();
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<AddressRoute>();
// 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<AddressRoute>(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}";
}
}
}

View File

@@ -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<Address, int> Origins { get; set; }
public Dictionary<Address, int> Destinations { get; set; }
public AddressRoute[,] Routes { get; set; }
public AddressRouteMatrix(Address[] originAddresses, Address[] destinationAddresses)
{
OriginAddresses = originAddresses;
Origins = new Dictionary<Address, int>();
OriginsLength = originAddresses.Length;
DestinationAddresses = destinationAddresses;
Destinations = new Dictionary<Address, int>();
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<AddressRoute> 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;
}
}
}

View File

@@ -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<Address> origins, IEnumerable<Address> 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<AddressRoute[,]> GetResponse()
public async Task<AddressRouteMatrix> 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<Response>(content));
return FillMatrix(JsonConvert.DeserializeObject<Response>(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}";
}
}
}

View File

@@ -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<Address> origins, IEnumerable<Address> destinations);
}
}

View File

@@ -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<Address> origins, IEnumerable<Address> 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<ResponseGeo>(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<AddressRouteMatrix> 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<ResponseMatrix>(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) + "]";
}
}
}

View File

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