05 – Routes

Please note! All the code snippets in this section have been provided for Android. If you use iOS, Cordova or ReactNative you’ll find it easy to translate them appropriately.

Situm Dashboard allows you to define the wayfinding paths in your building. Based on this information, Situm SDK is able to compute the route from any point A to any point B. This section will teach you the basics about routing.

Routing concepts #

Before we dive in, it will be useful to understand a few concepts first. In Situm, wayfinding paths are configured in Situm Dashboard as a graph, where the edges represent all the passable paths in the building (and the nodes are just the start/end of each edge).

Each edge can have a number of properties (more info here): they can be accessible (suitable for people in wheelchairs, e.g. they avoid elevators), they can represent one-way or two way paths, they can interconnect different floors (representing elevators, escalators, etc.), etc.

When this graph has been configured, Situm SDK is able to compute the route between any two points within the same venue (A and B). Conceptually, this route will be composed of a set of data structures.

StructureDescriptionMore info
Points (nodes)The set of ordered (consecutive) graph nodes that the route traversesComputing your first route
Steps (edges)The set of ordered (consecuive) graph edges that connect those nodes.Extracting route points
SegmentA list of consecutive points that are in the same floor. Extracting route steps (edges)

Computing your first route #

Computing a route with Situm SDK can be break down in 4 steps:

  • Determine the building identifier of the building where you want to retrieve the route.
  • Retrieve the information of that building.
  • Define the points A & B. For each of them, you will need to specify: its floor identifier, its WSG84 coordinates (latitude and longitude).
    • In native Android & iOS, you will also need to provide its cartesian coordinates (X and Y). Situm SDK includes a handy tool, the CoordinateConverter (Android, iOS), that will allow you to compute WSG84 coordinates from cartesian ones, and viceversa.
  • Create the DirectionsRequest object (Android, iOS, Cordova, ReactNative), that defines how the route should be computed: origin, destination, whether it should avoid non accesible paths, etc.
  • Compute the route (or in Situm jargon, requestDirections: Android, iOS, Cordova, ReactNative)!

Internally, the route computation process goes like this:

  1. Among all the edges, finds the one that is closer to point A. Then, proceeds to find the exact point in that edge that is closer to A. Let’s call this point A’.
  2. Performs the same process for point B. Let’s call the resulting point B’.
  3. Computes the shortest route between points A’ and B’.
  4. Generates a route that goes from point A to A’ (a straight line), from point A’ to B’ (computed in step 3), and finally from point B’ to B (another straight line).

The output will be a Route object (Android, iOS, Cordova, ReactNative) that will contain all the relevant information: route nodes or points, edges, segments, indications, etc. The following example shows an Android simple example that shows you how to do it.

package com.example.helloworld;

import androidx.appcompat.app.AppCompatActivity;
import es.situm.sdk.location.util.CoordinateConverter;

import android.os.Bundle;
import android.util.Log;

import es.situm.sdk.SitumSdk;
import es.situm.sdk.directions.DirectionsRequest;
import es.situm.sdk.error.Error;
import es.situm.sdk.model.cartography.BuildingInfo;
import es.situm.sdk.model.cartography.Point;
import es.situm.sdk.model.directions.Indication;
import es.situm.sdk.model.directions.Route;
import es.situm.sdk.model.directions.RouteStep;
import es.situm.sdk.model.location.Coordinate;
import es.situm.sdk.utils.Handler;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getSimpleName();

    private CoordinateConverter coordinateConverter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        SitumSdk.init(this);

        //We will compute routes in building 10194
        String buildingId="10194";

        //First of all, we need to retrieve the information of the building ...
        SitumSdk.communicationManager().fetchBuildingInfo(buildingId, new Handler<BuildingInfo>() {

            @Override
            public void onSuccess(BuildingInfo buildingInfo) {

                //We define the data points A & B between  which we will compute the route
                String floorIdA="29685";
                Coordinate coordinateA = new Coordinate(43.3434333899059, -8.42761197887612);

                String floorIdB="29686";
                Coordinate coordinateB = new Coordinate(43.3451052729103, -8.42827590527984);

                // With this information, we build the coordinate converter ...
                coordinateConverter = new CoordinateConverter(buildingInfo.getBuilding().getDimensions(),buildingInfo.getBuilding().getCenter(),buildingInfo.getBuilding().getRotation());

                // ... which allows us to build the 2 points (A & B) indicating both the global & cartesian coordinates
                Point pointA = new Point(buildingId, floorIdA,  coordinateA, coordinateConverter.toCartesianCoordinate(coordinateA) );
                Point pointB = new Point(buildingId, floorIdB,  coordinateB, coordinateConverter.toCartesianCoordinate(coordinateB) );

                // The DirectionsRequest allows us to configure the route calculation: source point, destination point, other options...
                DirectionsRequest directionsRequest = new DirectionsRequest.Builder().from(pointA, null).to(pointB).build();

                //Finally, we compute the route
                SitumSdk.directionsManager().requestDirections(directionsRequest, new Handler<Route>() {
                    @Override
                    public void onSuccess(Route route) {
                        Log.i(TAG, "Computed route " + route);
                    }

                    @Override
                    public void onFailure(Error error) {
                        Log.e(TAG, "Error" + error);
                    }
                });

            }

            @Override
            public void onFailure(Error error) {
                Log.e(TAG, "Error " + error);
            }
        });
        
    }
    
}

You may modify the appropriate variables to define your own A&B points. Then, if you execute the previous example, you will get a log similar to this:

I/MainActivity: Computed route 
Route{request=DirectionsRequest{from=Point{buildingIdentifier='10194', floorIdentifier='29685', cartesianCoordinate=CartesianCoordinate{x=134,90, y=160,15}, coordinate=Coordinate{latitude=43,343433, longitude=-8,427612}, isOutdoor=false}, bearingFrom=null, to=Point{buildingIdentifier='10194', floorIdentifier='29686', cartesianCoordinate=CartesianCoordinate{x=324,82, y=123,66}, coordinate=Coordinate{latitude=43,345105, longitude=-8,428276}, isOutdoor=false}, accessibilityMode=CHOOSE_SHORTEST, minimizeFloorChanges=false, options: es.situm.sdk.directions.DirectionsOptions@1876eef},
...
points=[Point{buildingIdentifier='10194', floorIdentifier='29685', cartesianCoordinate=CartesianCoordinate{x=134,90, y=160,15}, coordinate=Coordinate{latitude=43,343433, longitude=-8,427612}, isOutdoor=false}, DefaultNode{id=-1} Point{buildingIdentifier='10194', floorIdentifier='29685', cartesianCoordinate=CartesianCoordinate{x=146,26, y=159,26}, coordinate=Coordinate{latitude=43,343528, longitude=-8,427666}, isOutdoor=false}, DefaultNode{id=43} Point{buildingIdentifier='10194', floorIdentifier='29685', cartesianCoordinate=CartesianCoordinate{x=143,13, y=119,11}, coordinate=Coordinate{latitude=43,343667, longitude=-8,427207}, isOutdoor=false}, DefaultNode{id=51} 


....

Success! You have computed your first route. What should you do next?

Extracting route points #

We’ve seen that a route is essentially a set of ordered nodes, connected by edges, that go from point A to B. In the previous log output, you may have noticed that we’ve printed out a set of points. These are the nodes of the route in the right order from the beginning (point A) to the end (point B).

Situm SDK allows you to extract a list of route points (Android, iOS, Cordova, ReactNative). For instance, in Android you may do:

...

SitumSdk.directionsManager().requestDirections(directionsRequest, new Handler<Route>() {

   @Override
   public void onSuccess(Route route) {

      for (Point point: route.getPoints()){
         Log.i(TAG, "Point's building ID " + point.getBuildingIdentifier());
         Log.i(TAG, "Point's floor ID " + point.getFloorIdentifier());
         Log.i(TAG, "Point's Latitude " + point.getCoordinate().getLatitude()  + " Longitude " + point.getCoordinate().getLongitude());
         Log.i(TAG, "Point's Cartesian X " + point.getCartesianCoordinate().getX()  + " Cartesian Y " + point.getCartesianCoordinate().getY());
         Log.i(TAG, "-----");
      }
   }

  ...
}

After execution, you will see the following log:

I/MainActivity: Point's building ID 10194
    Point's floor ID 29686
    Point's Latitude 43.344254545619556 Longitude -8.427709954367506
    Point's Cartesian X 219.771 Cartesian Y 125.749
    -----
    Point's building ID 10194
    Point's floor ID 29686
    Point's Latitude 43.34426453022196 Longitude -8.427803794047842
    Point's Cartesian X 224.218 Cartesian Y 132.022
    -----

...

Each point contains the relevant location information (building identifier, floor identifier, coordinates, etc.). Take a look at the Point Android reference to have an idea of the nature of this information.

Extracting route steps (edges) #

In the previous example, we’ve seen how to extract the ordered nodes or points that conform a route. What about the steps or edges connecting those points? Situm SDK allows to retrieve them as well (Android, iOS, Cordova, not available in ReactNative). For instance, in Android you may do:

...

SitumSdk.directionsManager().requestDirections(directionsRequest, new Handler<Route>() {

    @Override
    public void onSuccess(Route route) {

        for (RouteStep step : route.getSteps()) {

            Log.i(TAG, "Step Id: " + step.getId());
            Log.i(TAG, "Distance (meters) to end of route: " + step.getDistanceToGoal());
            Log.i(TAG, "Distance (meters) to next floor change: " + step.getDistanceToFloorChange());
            Log.i(TAG, "Length (meters) of this edge/step: " + step.getDistance());

            Point from = step.getFrom();
            Point to = step.getTo();
            Log.i(TAG, "FromPoint: BuildingId "+ from.getFloorIdentifier() + " FloorId " + from.getFloorIdentifier() + " Latitude "+ from.getCoordinate().getLatitude() + " Longitude " + from.getCoordinate().getLongitude());
            Log.i(TAG, "ToPoint: BuildingId "+ to.getFloorIdentifier() + " FloorId " + to.getFloorIdentifier() + " Latitude "+ to.getCoordinate().getLatitude() + " Longitude " + to.getCoordinate().getLongitude());

            Log.i(TAG, "----");
        }

    ...
}

After execution, you will see the following log:

I/MainActivity: Step Id: 1
    Distance (meters) to end of route: 283.61143215971987
    Distance (meters) to next floor change: 55.85009662344499
    Length (meters) of this edge/step: 11.391021886334167
    FromPoint: BuildingId 29685 FloorId 29685 Latitude 43.3434333899059 Longitude -8.42761197887612
    ToPoint: BuildingId 29685 FloorId 29685 Latitude 43.34352806065825 Longitude -8.427665920512453
    ----
    Step Id: 2
    Distance (meters) to end of route: 272.2204102733857
    Distance (meters) to next floor change: 44.459074737110825
    Length (meters) of this edge/step: 40.271730829572306
    FromPoint: BuildingId 29685 FloorId 29685 Latitude 43.34352806065825 Longitude -8.427665920512453
    ToPoint: BuildingId 29685 FloorId 29685 Latitude 43.343667245037864 Longitude -8.427207329649177
    ----

...

Each step contains the relevant location information: origin point (“from”), end point (“to”), several pre-computed distances (lenght of edge, distance to next floor change, distance to end destination), etc.

Extracting route segments (set of steps within the same floor) #

The most common operation we might want to perform with a route computed by Situm SDK is to visualize it on top of the building floorplans.

One way to do this is to draw a polyline that traverses all the route points, retrieved as shown in the previous sections. Usually, we will visualize just one floorplan at a time, but the list of points as retrieved in the previous sections contains points across all floors traversed by the route. Therefore, we need to:

  • Filter out the data points so we just visualize those contained in the floor that we want to show.
  • Make sure we don’t incorrectly connect route points when visualizing them. Sometimes, a route may start in a certain floor (e.g. floor 0), go through other floor(s), only to come back to the original floor. A common mistake is to just throw all the “floor 0” points in a list and draw the polyline: therefore, the polyline will incorrectly join points that should not be tied together.

Situm facilitates these operations by providing a way to retrieve segments (Android, iOS, Cordova, ReactNative). Each segment is a list of consecutive route points that are in the same floor. Non-consecutive points within the same floor will be split in different segments. This way, we can just draw one polyline per segment (within the desired floor) and avoid any further trouble.

For example, let’s say a route has 8 data points (P1, P2, P3, P4, P5, P6, P7, P8), being:

  • P1, P2 and P3 in Floor 0.
  • P4 and P5 in Floor 1.
  • P6, P7 and P8 in Floor 0.

Then, we would have 3 segments: 1) segment 1 (P1, P2, P3), 2) segment 2 (P4, P5), segment 3 (P6, P7, P8).

Let’s see some Android code in order to understand this concept:

...

SitumSdk.directionsManager().requestDirections(directionsRequest, new Handler<Route>() {
@Override
    public void onSuccess(Route route) {
        for (RouteSegment segment: route.getSegments()){
    
            Log.i(TAG, "Segment");
            Log.i(TAG, "Floor Id: " + segment.getFloorIdentifier());
    
            for (Point point: segment.getPoints()){
                Log.i(TAG, "Point: BuildingId "+ point.getFloorIdentifier() + " FloorId " + point.getFloorIdentifier() + " Latitude "+ point.getCoordinate().getLatitude() + " Longitude " + point.getCoordinate().getLongitude());
            }
    
            Log.i(TAG, "----");
        }
    }

    ...
}

After execution, you will see the following log:

I/MainActivity: Segment
    Floor Id: 29685
    Point: BuildingId 29685 FloorId 29685 Latitude 43.3434333899059 Longitude -8.42761197887612
    Point: BuildingId 29685 FloorId 29685 Latitude 43.34352806065825 Longitude -8.427665920512453
    Point: BuildingId 29685 FloorId 29685 Latitude 43.343667245037864 Longitude -8.427207329649177
    Point: BuildingId 29685 FloorId 29685 Latitude 43.343702404166145 Longitude -8.427225934618166
    ----
    Segment
    Floor Id: 29686
    Point: BuildingId 29686 FloorId 29686 Latitude 43.34372707052083 Longitude -8.427236219233354
I/MainActivity: Point: BuildingId 29686 FloorId 29686 Latitude 43.343686078274054 Longitude -8.427222991801575
    Point: BuildingId 29686 FloorId 29686 Latitude 43.34371318522387 Longitude -8.427139721270171
    Point: BuildingId 29686 FloorId 29686 Latitude 43.34377374892849 Longitude -8.4271796783137

...

Note that each segment indicates its floor identifier, and then contains the list of consecutive points within that list.

Subscribe to our newsletter

BASIC INFORMATION ON DATA PROTECTION

Data controller: SITUM TECHNOLOGIES, S.L.
Contact: Data controller: situm@situm.es
Responsible for protection: dpo@situm.es
Purpose and legal basis: To manage the sending of SITUM newsletters only with consent.
Legitimation: Express consent of the interested party.
Recipients: The data will not be passed on to third parties with the exception of legal obligations.
Retention period: As long as the interested party remains subscribed to the newsletter (a link to unsubscribe will be available in each newsletter sent by Situm).
Rights: The interested party may at any time revoke their consent, as well as exercise their rights of opposition, access, conservation, rectification, limitation, deletion of data and not be subject to a decision based only on automated data processing, by writing to SITUM at the addresses indicated.
Additional Information: You can consult additional and detailed information on Data Protection in our privacy policy.

Please, download your copy here

Thank you for downloading our whitepaper. Please do not hesitate to contact us if you would like to know more about how our solutions can help your business. Download whitepaper


Close window