Swift flood fill algorithm randomly stopping - swift

Here is the raw code but I will explain it roughly:
func processTile(_ tile: Tile) {
// Add tile to pos list if valid, otherwise prune the
branch
if isBarrier(tile) || alreadyChecked(tile) {
return
} else {
posList.append(tile.pos)
}
depth++ ; if depth > maxDepth { return }
for neighborTile in neighbors(of: tilePos) {
processTile(neighborTile)
}
}
This is the main recursive function. Basically it checks if a tile is part of a room by being neither a barrier tile or already checked. If either one of those cases is true then the branch of the flood tree is pruned and ended. If the tile was valid and was added to the list then the depth is incremented with a check on it. Then the tile's neighbors are all checked with the same process.
For some reason the flood algorithm just stops randomly. I changed the code adding a print() in front of the returns to see why a branch just stops. This worked for all the correct pruning cases where it hits a barrier or already checked tile, but when it would just randomly stop and not check a tile it didn't even log anything.
The only thing I can think of is that Swift stops executing the functions after a certain level of recursion. If this is the case does anyone know what the maximum number of recursions is? And what a possible workaround would be. I'm thinking you would have to make a list of all the "edge" tiles of the flood, and a list of all the "interior" tiles of the flood. Then have a while loop running until there are no edge tiles which just expands the flood.

Related

"While loop" not working in my Anylogic model

I have the model which I posted before on Stack. I am currently running the iterations through 5 Flow Chart blocks contain enter block and service block. when agent fill service block 5 in flow chart 5, the exit block should start to fill block one and so on. I have used While infinite loop to loop between the five flow chart blocks but it isn't working.
while(true)
{
for (Curing_Drying currProcess : collection) {
if (currProcess.allowedDay == (int)time(DAY)) {
currProcess.enter.take(agent);
}
}
if (queue10.size() <= Throughtput1){
break;
}
}
Image for further illustration 1
Image for further illustration 2
Wondering if someone can tell me what is wrong in the code.
Based on the description and the pictures provided, it isn't clear why the while loop is necessary. The On exit action is executed for each Agent arrival to the Exit block. It seems that the intention is to find the appropriate Curing_Drying block based on number of days since the model start time? If so, then just iterating through the collection is enough.
Also, it is generally a good practice to provide more meaningful names to collections. Using simply collection doesn't say anything about the contents and can get pretty confusing later on.

HERE API:Swift. Wierd behaviour : Loops in a route - Creating a route based on GPS trace creates loops. / passthrough waypoints

im trying to create a route that follows a gps trace i provide.
The gps trace is cleaned up and it has no loops in it and is in correct order.
I checked it with other services.
It has 1920 points.
You can find the trace here GPX Files
Sadly if i create a route based on provided sdk example (github) i get loops in my path.
I was hoping you could help me to solve following problems:
how do i avoid loops while creating route by using HERE ios Swift SDK
how do i set route options is such way to follow provided point array and not create a fastest or balanced route.
Since i could not find those functions in Ios sdk i used additional REST API to filter the route a bit to remove all points that were not matched correctly according to here maps... before drawing the route.. ie everything with low probability, warnings, big distance to the road... yet the result is still not good. Here is a cleaned up file.. the file is being created after the original was maped / run once through HERE Maps. In this file all points that have low confidence or produce warnings or have big distance to original points .. are removed. This is the one i use to create a route and it still have the same issues like loops and weird turns.
Thank you very much in advance!
BR.
So far i have this code:
private lazy var router = NMACoreRouter()
#objc func do_routing_stuff( gps_trace :[NMAWaypoint]) {
var stops = [Any]()
stops = gps_trace
let routingMode = NMARoutingMode(routingType: .fastest,
transportMode: .car,
routingOptions: .avoidHighway)
// Trigger the route calculation
router.calculateRoute(withStops: stops ,
routingMode: routingMode)
{ [weak self] routeResult, error in
guard error == .none else {
self?.showMessage("Error:route calculation returned error code \(error.rawValue)")
return
}
guard let result = routeResult, let routes = result.routes, routes.count > 0 else {
self?.showMessage("Error:route result returned is not valid")
return
}
// Let's add the 1st result onto the map
self?.route = routes[0]
self?.updateMapRoute(with: self?.route)
// self?.startNavigation()
}
}
private func updateMapRoute(with route: NMARoute?) {
// remove previously created map route from map
if let previousMapRoute = mapRoute {
mapView.remove(mapObject:previousMapRoute)
}
guard let unwrappedRoute = route else {
return
}
mapRoute = NMAMapRoute(unwrappedRoute)
mapRoute?.traveledColor = .clear
_ = mapRoute.map{ mapView?.add(mapObject: $0) }
// In order to see the entire route, we orientate the
// map view accordingly
if let boundingBox = unwrappedRoute.boundingBox {
geoBoundingBox = boundingBox
mapView.set(boundingBox: boundingBox, animation: .linear)
}
}
in comparison same route presented with leaflet maps.
I believe the problem you have is that you are feeding the Routing API a large number of waypoints, all of which are in close proximity to each other.
You have almost 2000 waypoints in your GPX file (and ~1300 in your cleaned one). Each of these waypoints is less than 10 meters distance from their closest neighbors. This is not the type of data that the Routing API is really designed to work with.
I've experimented with your GPX Trace and I have come up with the following solution: simply skip a bunch of coordinates in your trace.
First, clean up your trace using the Route Matching API (which I believe you have been doing).
Second, pick the first trkpt in the GPX file as your first waypoint for the Routing call. Then skip the next 20 points. Pick the following trkpoint as the second waypoint. Repeat this until you are at the end of the file. Then add the last trkpt in the trace as the final waypoint.
Then call the Routing API and you should get a good match between your trace and your route, without any loops or other weird routing artefacts.
Some notes:
I have picked 20 as the number of traces to skip, because this would put about 200m in between each waypoint. That should be close enough to ensure that the Routing API does not deviate too much from the traced route. For larger traces you may wish to increase that number. For traces in urban environments with lots alternate routes, you may want to use a smaller number.
It's important to clean the data with the Route Matching API first, to avoid picking outliers as waypoints.
Also, you may not wish to use the "avoidHighways" option. Given your use case, there doesn't seem to be a benefit and I could see it causing additional problems.
By now you probably worked it out, but your waypoints are likely landing on bridges or tunnels that are along your route but not on the road you want. I.e. the waypoint is intended to be on the road under the bridge but the routing engine perceives that you want to drive on the bridge.
The routing engine is looping around those roads to drive you on that waypoint on the bridge or in the tunnel.
There is no simple solution to this that I have found.

MRTK V2 - Enable/Disable Spatial Mapping at Runtime

I know that this question has already been asked here twice, but the answers did not fix my problem. I need to enable spatial mapping on runtime. After scanning my environment I want to disable it, or hide at least the visualization of polygons, so I can save some fps. But by disabling spatial mapping I still want to have the colliders of my environment.
What I tried:
1. This example from this post did nothing.
if (disable){
// disable
MixedRealityToolkit.SpatialAwarenessSystem.Disable();
}
else
{
// enable
MixedRealityToolkit.SpatialAwarenessSystem.Enable()
}
2. Trying to disable the visualization gives me every time a nullreference. I guess GetObservers is giving null back or maybe meshOserver is null:
foreach(var observer in MixedRealityToolkit.SpatialAwarenessSystem.GetObservers())
{
var meshObserver = observer as IMixedRealitySpatialAwarenessMeshObserver;
if (meshObserver != null)
{
meshObserver.DisplayOption = SpatialAwarenessMeshDisplayOptions.None;
}
}
3. The example given by mrtk in there SpatialAwarenessMeshDemo scene, shows how to start and stop the observer. By starting everything starts fine but after suspending and clearing the observers the whole spatial map disappears, so my cursor does not align to my environment. So this is not what I need.
SpatialAwarenessSystem.ResumeObservers(); //start
SpatialAwarenessSystem.SuspendObservers();//stop
SpatialAwarenessSystem.ClearObservations();
What I have right now:
My Spatial Awareness Profile looks like this:
My code starts the spatial mapping with ResumeObservers, the foreach-loop gives me a nullreference and SuspendObserver is comment out, because it disables the whole spatial map thing:
if (_isObserverRunning)
{
foreach (var observer in SpatialAwarenessSystem.GetObservers())
{
var meshObserver = observer as IMixedRealitySpatialAwarenessMeshObserver;
if (meshObserver != null)
{
meshObserver.DisplayOption = SpatialAwarenessMeshDisplayOptions.None;
}
}
//SpatialAwarenessSystem.SuspendObservers();
//SpatialAwarenessSystem.ClearObservations();
_isObserverRunning = false;
}
else
{
SpatialAwarenessSystem.ResumeObservers();
_isObserverRunning = true;
}
Question: How do I start and stop spatial mapping the right way, so that I can save some performance and still have the colliders of the spatial map to interact with.
My specs:
MRTK v2.0.0
Unity 2019.2.0f1
Visual Studio 2017
!--Edit--inlcuding-Solution--!
1. With option #1 I was wrong. It does what its meant for, but I used it the wrong way. If you disable for example SpatialAwarenessSystem while running the spatial mapping process, it disables the whole process including the created spatial map. So after that you cant interact with the invironment.
2. What worked for me was using for the start ResumeObservers() in combination with setting display option to visible and for stopping spatial mapping the method SuspendObservers() in combination with display option none.
3. The Nullreference if fixed by rewritting and casting to IMixedRealityDataProviderAccess:
if (CoreServices.SpatialAwarenessSystem is IMixedRealityDataProviderAccess provider)
{
foreach (var observer in provider.GetDataProviders())
{
if (observer is IMixedRealitySpatialAwarenessMeshObserver meshObs)
{
meshObs.DisplayOption = option;
}
}
}
4. Performance: To get your fps back after starting an observer, you really need to disable the system via MixedRealityToolkit.SpatialAwarenessSystem.Disable();, but this will of course disable also the spatial map, so you cant interactive with it anymore.
#Perazim,
The recommendation is based on your option #3. Call ResumeObservers() to start and SuspendObservers() to stop. There is no need to call ClearObservations() unless you wish to have them removed from your scene.
The example calls ClearObservations() to illustrate what was, at the time, a new feature added to the Spatial Awareness system.
Please file an issue on GitHub (https://github.com/microsoft/MixedRealityToolkit-Unity/issues) for #1 (failure of Enable() and Disable() to impact the system). Those methods should behave as advertised.
Thank you!
David

Unity5.6 Collision2D contact points array index out of range error

When I updated my Unity version 5.5 to 5.6, an error occured about the Collision2D.contacts array. When I try to access the contacts array, I can not get contact point info now.
void OnCollisionExit2D(Collision2D col)
{
if (col.gameObject.CompareTag("Ground"))
{
if ((_transform.position.y - col.contacts[0].point.y) > colliderHeight / 2 + .15f)
{
Debug.Log ("Contact count = " + col.contacts.Length);
_onGround = false;
ParticleController.PlayDustEffect ();
}
}
}
Error Log :
IndexOutOfRangeException: Array index is out of range.
Player.OnCollisionExit2D (UnityEngine.Collision2D col) (at Assets/Scripts/CharacterController/Player.cs:759)
How can I fix the error?
Thanks for your time.
It seems the exit point of collision is not computed anymore in Unity 5.6. Some changes about collisions detection have been changed in this version:
Physics: The internal 2D contact processing has been completely re-written, providing a more robust and reliable reporting of contacts.
I guess the logic for it is the following: why would there be a contact point if the two colliders are not touching each other anymore? As there is no contact point anymore, col.contacts is empty there. So when you are trying to access col.contacts[0], the element doesn't exist, triggering the IndexOutOfRangeException.
From the Collision.contacts documentation (not the Collision2D.contacts one, but I suppose the behavior is the same):
Every contact contains a contact point, normal and the two colliders that collided (see ContactPoint). From inside OnCollisionStay or OnCollisionEnter you can always be sure that contacts has at least one element.
So OnCollisionExit does not, in any case, guarantee the presence of at least one point in col.contacts.
For those searching for ArrayIndexOutOfRange errors while trying to access the ContactPoint2D on a Collision2D, it seems that the API is now:
collision.getContacts(myContacts)
where you initialize and pass in an empty array myContacts. See more about this in the documentation about Collision2D.contacts which says:
The specific points of contact with the incoming Collider2D. You
should avoid using this as it produces memory garbage. Use
GetContacts instead.

insertion sort on a singly linked list

Am i right in thinking that it is not possible to perform insertion sort on a singly linked list?
My reasoning: assuming that insertion sort by definition means that, as we move to the right in the outer loop, we move to the left in the inner loop and shift values up (to the right) as required and insert our current value when done with the inner loop. As a result an SLL cannot accomodate such an algorithm. Correct?
Well, I'd sound like the Captain Obvious, but the answer mostly depends on whether you're ok with keeping all iterations directed the same way as elements are linked and still implementing the proper sorting algorithm as per your definition. I don't really want to mess around your definition of insertion sorting, so I'm afraid you'd really have to think yourself. At least for a while. It's an homework anyway... ;)
Ok, here's what I got just before closing the page. You may iterate over an SLL in reversed direction, but this would take n*n/2 traversals to visit all the n elements. So you're theoretically okay with any traversal directions for your sorting loops. Guess it pretty much solves your question.
It is doable and is an interesting problem to explore.
The core of insertion sort algorithm is creating a sorted sequence with the first one element and extending it by adding new element and keeping the sequence is still sorted until it contains all the input data.
Singly linked list can not be traversed back, but you can always start from it's head to search the position for the new element.
The tricky part is when inserting node i before node j, you must handle their neighbor relationship well(I mean both node i and j's neighbor needs to be taken care of).
Here is my code. I hope it useful for you.
int insertSort(Node **pHead)
{
Node *current1 = (*pHead)->next;
Node *pre1 =*pHead;
Node *current2= *pHead;
Node *pre2=*pHead;
while(NULL!=current1)
{
pre2=*pHead;
current2=*pHead;
while((current2->data < current1->data))
{
pre2 = current2;
current2 = current2->next;
}
if(current2 != current1)
{
pre1->next=current1->next;
if(current2==*pHead)
{
current1->next=*pHead;
*pHead = current1;
}
else
{
pre2->next = current1;
current1->next = current2;
}
current1 = pre1->next;
}
else
{
pre1 = pre1->next;
current1 = current1->next;
}
}
return 0;
}