itinero / routing

The routing core of itinero.
Apache License 2.0
222 stars 71 forks source link

Cannot load osm.pbf file on Unity-iOS #139

Open theiajsanchez opened 6 years ago

theiajsanchez commented 6 years ago

Hi,

I'm developing a mobile application on Unity 3D and this library works on android, windows, and osx but when running on iOS it throws an exception on the RouterDb.LoadOsmData() method with the following message: "Get method not found for 'Name'".

Is there a way for solving this issue?

Thanks in advance

xivk commented 6 years ago

Can you give me more details about the exception? Looks like a version conflict or part of the API that Itinero is using is not implemented.

theiajsanchez commented 6 years ago

Of course, here you go: Good result test environments:

Bad result test environment

Unity Project repository: https://bitbucket.org/theiajsanchez/osmunitytest Code used is inside DownloadRoutes() method in the following file: https://bitbucket.org/theiajsanchez/osmunitytest/raw/961290da63e2ba5500d8a17f2f0839444c97a9dd/Assets/Theia%20AR/Scripts/Holitas.cs

Exception Stack Trace: Get Method not found for "Name" at System.Reflection.MonoProperty.GetValue (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] index, System.Globalization.CultureInfo culture) [0x00000] in <00000000000000000000000000000000>:0 at ProtoBuf.Meta.AttributeMap+ReflectionAttributeMap.TryGet (System.String key, System.Boolean publicOnly, System.Object& value) [0x00000] in <00000000000000000000000000000000>:0 at ProtoBuf.Meta.MetaType.ApplyDefaultBehaviour () [0x00000] in <00000000000000000000000000000000>:0 at ProtoBuf.Meta.RuntimeTypeModel.Add (System.Type type, System.Boolean applyDefaultBehaviour) [0x00000] in <00000000000000000000000000000000>:0 at OsmSharp.IO.PBF.PBFReader..ctor (System.IO.Stream stream) [0x00000] in <00000000000000000000000000000000>:0 at OsmSharp.Streams.PBFOsmStreamSource.InitializePBFReader () [0x00000] in <00000000000000000000000000000000>:0 at OsmSharp.Streams.PBFOsmStreamSource.MoveNext (System.Boolean ignoreNodes, System.Boolean ignoreWays, System.Boolean ignoreRelations) [0x00000] in <00000000000000000000000000000000>:0 at OsmSharp.Streams.Filters.OsmStreamFilterDelegate.MoveNext (System.Boolean ignoreNodes, System.Boolean ignoreWays, System.Boolean ignoreRelations) [0x00000] in <00000000000000000000000000000000>:0 at OsmSharp.Streams.OsmStreamTarget.DoPull (System.Boolean ignoreNodes, System.Boolean ignoreWays, System.Boolean ignoreRelations) [0x00000] in <00000000000000000000000000000000>:0 at Itinero.IO.Osm.Streams.RouterDbStreamTarget.OnBeforePull () [0x00000] in <00000000000000000000000000000000>:0 at OsmSharp.Streams.OsmStreamTarget.Pull () [0x00000] in <00000000000000000000000000000000>:0 at Itinero.IO.Osm.RouterDbExtensions.LoadOsmData (Itinero.RouterDb db, OsmSharp.Streams.OsmStreamSource[] sources, Itinero.IO.Osm.LoadSettings settings, Itinero.Profiles.Vehicle[] vehicles) [0x00000] in <00000000000000000000000000000000>:0 at Holitas+c__Iterator0.MoveNext () [0x00000] in <00000000000000000000000000000000>:0 at UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) [0x00000] in <00000000000000000000000000000000>:0

c__Iterator0:MoveNext() UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)
xivk commented 6 years ago

I don't explicitly support Unity but I thought it now is supposed to support netstandard assemblies no? If so try using that.

It seems to me like an issue in protobuf-net and reflection it uses to parse the OSM-PBF data. I assume you are trying to do routing, it's best to preprocess the data into a routerdb and then use it, using the OSM files directly is very inefficient. Check the docs here:

http://docs.itinero.tech/docs/itinero/basic-concepts/routerdb.html

Personal TODO: [ ] Clarify the preprocessing issue in the docs.

theiajsanchez commented 6 years ago

Great, now I'm able to load the serialized file but when trying to resolve a location I get the following error:

ScriptRuntimeException: attempt to call a nil value at Itinero.Profiles.Lua.Execution.VM.Processor.Internal_ExecCall (System.Int32 argsCount, System.Int32 instructionPtr, Itinero.Profiles.Lua.CallbackFunction handler, Itinero.Profiles.Lua.CallbackFunction continuation, System.Boolean thisCall, System.String debugText, Itinero.Profiles.Lua.DynValue unwindHandler) [0x00000] in <00000000000000000000000000000000>:0 at Itinero.Profiles.Lua.Execution.VM.Processor.Processing_Loop (System.Int32 instructionPtr) [0x00000] in <00000000000000000000000000000000>:0 at Itinero.Profiles.Lua.Execution.VM.Processor.Call (Itinero.Profiles.Lua.DynValue function, Itinero.Profiles.Lua.DynValue[] args) [0x00000] in <00000000000000000000000000000000>:0 at Itinero.Profiles.Lua.Script.Call (Itinero.Profiles.Lua.DynValue function, Itinero.Profiles.Lua.DynValue[] args) [0x00000] in <00000000000000000000000000000000>:0 at Itinero.Profiles.Lua.Script.Call (Itinero.Profiles.Lua.DynValue function, System.Object[] args) [0x00000] in <00000000000000000000000000000000>:0 at Itinero.Profiles.Lua.Script.Call (System.Object function, System.Object[] args) [0x00000] in <00000000000000000000000000000000>:0 at Itinero.Profiles.DynamicProfile.FactorAndSpeed (Itinero.Attributes.IAttributeCollection attributes) [0x00000] in <00000000000000000000000000000000>:0 at Itinero.Profiles.ProfileFactorAndSpeedCache.CalculateFor (Itinero.Profiles.Profile[] profiles) [0x00000] in <00000000000000000000000000000000>:0 at Itinero.RouterBaseExtensions.GetIsAcceptable (Itinero.RouterBase router, Itinero.Profiles.IProfileInstance[] profiles) [0x00000] in <00000000000000000000000000000000>:0 at Itinero.Router.TryResolve (Itinero.Profiles.IProfileInstance[] profileInstances, System.Single latitude, System.Single longitude, System.Func`2[T,TResult] isBetter, System.Single maxSearchDistance) [0x00000] in <00000000000000000000000000000000>:0 at Itinero.RouterBaseExtensions.TryResolve (Itinero.RouterBase router, Itinero.Profiles.IProfileInstance[] profiles, System.Single latitude, System.Single longitude, System.Single searchDistanceInMeter) [0x00000] in <00000000000000000000000000000000>:0 at Itinero.RouterBaseExtensions.Resolve (Itinero.RouterBase router, Itinero.Profiles.IProfileInstance[] profiles, System.Single latitude, System.Single longitude, System.Single searchDistanceInMeter) [0x00000] in <00000000000000000000000000000000>:0 at Itinero.RouterBaseExtensions.Resolve (Itinero.RouterBase router, Itinero.Profiles.IProfileInstance profile, System.Single latitude, System.Single longitude, System.Single searchDistanceInMeter) [0x00000] in <00000000000000000000000000000000>:0 at Theia.Clases.RoutesManager+cAnonStorey2.<>m0 () [0x00000] in <00000000000000000000000000000000>:0 at System.Action.Invoke () [0x00000]

The code I'm using for deserialize the file is:

    private void PrepareRouter()
    {
        var stream = File.OpenRead(Path.Combine(WritePath, NombreArchivo));

        // valida que el archivo no este vacio
        if (stream.Length > 0)
        {
            try
            {
                routerDb = RouterDb.Deserialize(stream);
                if(routerDb.IsEmpty) 
                {
                    Debug.Log("Routerdb is empty");
                }
                else 
                {
                    Debug.Log("Routerdb is not empty");
                }
            }
            catch (Exception e)
            {
                Debug.Log("Deserialize exception:" + e.Message);
            }
            Ready = true;
        }
        else
        {
            Debug.Log("Stream length menor a 0");
        }

        stream.Close();
    }

With a debug result of "Routerdb is not empty"

Then I'm trying to resolve the location using the following code:

router = new Router(routerDb);
var Origin = router.Resolve(Vehicle.Car.Fastest(), OriginLat, OriginLng);

OriginLat and OriginLng are two float variables that are should be included in the map. This Resolve is throwing the exception.

Thanks in advance

PD: This same test work fine on Windows, Mac, and Android but not on iOS

xivk commented 6 years ago

This needs someone who has the proper test-environment to check. Still don't have access to a proper macbook.

Keeping this issue open for now, considering Unity as something that should be supported. Perhaps the recent improvements in Unity and .NET core fix this issue?

Bagatobo commented 5 years ago

any news one this one? i'm curious if this issue has been able to be reproduced and/or fixed by now, as i'm about to start the development on an app that has to be released on iOS as well. (unfortunatly i dont have a mac with me to test if it works at the moment.....)

xivk commented 5 years ago

No news on this on unfortunately. If someone can give me pointers or help me out to reproduce this I would be happy to do some debugging to figure out what's going on. I have no experience with Unity.

airbreather commented 5 years ago

Is Lua being interpreted or compiled to native?

I think there are restrictions on what iOS lets you do re: dynamic code generation.

Edit: you may not even be able to do dynamic MSIL code generation either... not sure if anyone's done a MSIL interpreter since the last time I checked, but I think you used to have to AOT everything for iOS, and so you couldn't even do, e.g., System.Reflection.Emit fanciness.

Bagatobo commented 5 years ago

Is Lua being interpreted or compiled to native? I think there are restrictions on what iOS lets you do re: dynamic code generation.

Hmm good catch, but i think if that was the issue (e.G. using System.Reflection in some of the XML-Librariers of Itinero), the error should have happened when trying to compile the app, right? It did happen during runtime tho....

airbreather commented 5 years ago

This is all assuming that iOS actually does, in fact, restrict you from running dynamically generated code. If that's not the case, then ignore the rest of this comment please.

e.G. using System.Reflection in some of the XML-Librariers of Itinero

I don't have any direct experience with this, but in theory, System.Reflection itself is probably mostly fine, since AOT isn't completely incompatible with introspection (it's just harder). That "probably" / "mostly" part: if some member is never used by any "live" code, then the AOT compiler might choose not to emit anything for it at link-time, leading to... actually, leading to errors exactly like what this issue originally opened with.

On the other hand, the example I listed, System.Reflection.Emit, is all about building new .NET code at runtime (often for the purpose of running it immediately). Unless the runtime embeds an MSIL interpreter for some reason (which seems like a ton of effort to make something that would ultimately be slow!), running code that you dynamically generate via that library probably just won't work.

Other dynamic code generation strategies, I expect, would have the same kinds of problems: you have to include an interpreter to make it work at all, and it would probably be so slow that you would want to explore other strategies anyway.

the error should have happened when trying to compile the app, right?

Maybe, but not necessarily. Again, I don't have direct experience, but I expect System.Reflection.Emit itself to be fully functional on iOS, at least the parts that build the assembly*. The problems would happen when you try to actually load the generated assembly at runtime, for the same reason that you probably wouldn't be able to download any other "normal" .NET assembly and then load it.

*edit: apparently it does actually have helpers to run the code without having to manually serialize the assembly and then load it; those parts, of course, wouldn't be "fully functional"

xivk commented 5 years ago

I don't think this has anything to do with iOS blocking this, this has worked before in already deployed iOS apps. If it hadn't I would have had a huge problem.

FYI: I would absolutely love to find a way to compile the lua profiles instead of interpreting them, if anyone has a way to do this let me know. It would solve this problem towards Itinero 2 (in the making), otherwise we may have to get rid of the lua-profiles.

As I mentioned before, any way I can reproduce this myself?

ForkeSeal commented 4 years ago

Any updates on this yet? I am having the exact same issue when using the Router on iOS (Unity). Works fine on Android and Macos

ScriptRuntimeException: attempt to call a nil value