Skip to main content

Posemesh Domains

Starting from ConjureKit v0.6.82, you can access and interact with posemesh domains. A domain is a persistent coordinate system corresponding to a physical space. Additionally, the domain owners can store spatial data like walkable areas, occlusion boxes, and 3D scene reconstructions that app developers can access to build rich AR experiences that fit into the context of the physical space around them.

Introduction to Domain SDK

The Domain SDK provided offers a comprehensive set of functionalities for interacting with the Domain API on the back-end. The SDK is available directly from your Conjurekit instance, which now implements the IDomainSDK interface. We encourage developers to also consult the in-code documentation for more in-depth usage guidance.

The Domain SDK exposes methods to retrieve:

  • From Auki API server:
    • User Login: Allows specific users with posemesh console credentials to log in and work with their posemesh accounts
  • From DDS (Domain Discovery Service) server:
    • Domains: Any domain accessible from any organization
    • StaticLighthouses: Any static lighthouse accessible from any organization, whether in a domain or not
  • From DS (Domain Service) server:
    • Poses: Any stored pose of a lighthouse in a domain
    • Data: Any stored data in a domain

API and DDS servers uris are provided in the configuration file. Domain server address instead is user defined. Note how the actual information contained in a Domain resides on the Domain Server, which can also be a private server.

IMPORTANT NOTE ON LIGHTHOUSES

We are in the process of renaming "lighthouses" to "portals"; in the meantime you may see them referenced by either name. Both refer to the QR codes used for calibrating into domains and shared sessions.

The Auki.ConjureKit.Domains namespace contains all the necessary classes for interacting with domains. The Domain SDK offers an object-oriented model which provides access to and reflects data from the servers, structured as follows:

%%{init: { 'theme':'dark', 'themeVariables': { 'lineColor': '#aaaaaa', 'arrowheadColor': '#aaaaaa', 'classText': '#aaaaaa' }}}%% classDiagram class DomainServerInfo { - string Id - string OrganizationId - string Url - string Version } class Domain { - string Id - string OrganizationId - DomainServerInfo DomainServer - IReadOnlyDictionary<string, DomainAssociation> LighthousesCached } class StaticLighthouse { - string Id - string ShortId - string OrganizationId - string Name - IReadOnlyDictionary<string, DomainAssociation> DomainsCached } class DomainAssociation { - string LighthouseId - string DomainId - DateTime AddedToDomainAt - PoseInDomain PoseCached } class DomainDataInfo { - string Id - string Name - string Type - string ContentType - long ContentLength } class PoseInDomain { - Vector3 Position - Quaternion Rotation } Domain "1" --> "1" DomainServerInfo : Is in Domain "0..*" --> "1" DomainAssociation : Can be in StaticLighthouse "0..*" --> "1" DomainAssociation : Can be in DomainAssociation "0..1" --> "1" PoseInDomain : Has Domain "0..*" --> "1" DomainDataInfo : Can have

You can interact with the above objects from methods in IDomainSDK and the objects themselves. It's important to note that:

  • a lighthouse can be in 0 or more domains
  • a domain can have 0 or more lighthouses
  • their association can have additional data (such as a pose) or not

Every object exposes methods to interact with other objects. When a method refers to another object, in most cases you can provide the object itself (if you already have it locally) or its Id.

Each method communicating with the server currently provides an onComplete callback with the result and an onError callback with an error description.

Caching System

The SDK keeps internal records of the data that was already retrieved from the server. In other words, the complete object model above is built locally and kept in an internal cache until flushed.

This means that whenever new information is fetched from the server, each object is instantiated only once and stays unique: after that point, every method will always return the same instance with updated information.

This has some advantages:

  • no need to create/update your own objects at each callback
  • the same instance can be retrieved at any point in time from the SDK

For example, once you get a Domain object it can be safely referenced for the duration of your app's life cycle: any operation or new information downloaded from the SDK will directly affect that instance.

This approach has the following consequences in C#:

  • if you need an unmutable copy, you need to create your own
  • if it gets deleted, any part of the app still referencing it will keep a copy

Using the local cache

You are free to keep objects in your own cache or collection of items. However, the SDK provides read-only access to its internal cache, through *Cached properties. Keep in mind that:

  • a cached list/dictionary will only contain items downloaded so far. It does not represent the state on the server.
  • a cached value ICachedValue will have to be checked first if locally available or not.

Most SDK methods will also provide an optional parameter preferCache: when set to true, the SDK will only get items that are missing locally. By default this value is false, which means it always tries to get the latest updates.

Using the Domains SDK

Initialization

To use the Domains SDK correctly, you first need an initialized ConjureKit object with app key and app secret from the posemesh console. The reason for this is to ensure a configuration is given (containing mainserver URIs) and to ensure authentication.

_conjureKit = new ConjureKit(
arCamera.transform,
"YOUR_APP_KEY",
"YOUR_APP_SECRET"
);

_conjureKit.Init(
ConjureKitConfiguration.DefaultConfigUri,
() => Debug.Log("ConjureKit Initialized"),
Debug.LogError);

If you also need the posemesh's real-time multiplayer networking features in your app you should call _conjureKit.Connect instead of _conjureKit.Init. Calling _conjureKit.Connect will automatically initialize ConjureKit and connect to a Hagall session.

_conjureKit.Connect(
(session) => Debug.Log($"ConjureKit Connected to session {session.Id}"),
Debug.LogError);

Authentication

The SDK provides various operations for user authentication. These operations allow users to log in, log out, and check their authentication status.

For example, there are Read and Write access levels to the domains. An example of a Read access operation is calibrating and loading domain-specific spatial data. An example of Write access is editing the calibration data of the domain (i.e. the QR code positions) and the spatial information of the physical space.

Before performing any operations, authentication and initialization are essential steps:

  • Initialize the SDK: Initialize the ConjureKit SDK using your app key and app secret.
  • Login: Authenticate with user credentials to access restricted functionalities. This step is crucial for operations that require user-specific permissions.
  • Logout: Immediately clean any current login status. This is guaranteed even with no internet connection. This step is crucial to log in different users on the same application.
  • Check Login Status: Determine if a user is currently logged in.
  • Retrieve Organization Information: Obtain the organization ID associated with the logged-in user or application.

If no authentication is performed, and whenever the SDK is in a logged out state, the app key will be used and most operations will be read-only and limited to data available to the app without authorization.

Logging In

To log in, use the Login method of the SDK. This method requires the user's posemesh console username and password. Upon successful login, a callback function is invoked to handle the successful authentication.

Example:

_conjurekit.Login(username, password, OnLogin, Debug.LogError);

Logging Out

To log out, simply call the Logout method of the SDK. This method, even offline, always clears any existing login data.

Example:

_conjurekit.Logout();

Checking Authentication Status

The SDK provides methods to check the authentication status of the user. The IsLoggedIn method returns true if any user is currently logged in, while the IsUserLoggedIn method checks if a specific user is logged in.

Example:

bool isLoggedIn = _conjurekit.IsLoggedIn();
bool isUserLoggedIn = _conjurekit.IsUserLoggedIn(username);

Domain Operations

Domains serve as containers for various data and functionalities within the posemesh ecosystem. The SDK provides the following domain-related operations:

  • Retrieve Domain Information: Fetch details of a specific domain by its unique identifier.
  • Retrieve Domains: Get a list of all existing domains or those owned by a specific organization.
  • Retrieve Lighthouses from Domain: Fetch lighthouses associated with a particular domain.
  • Add Lighthouse to Domain: Associate a lighthouse with a domain.
  • Remove Lighthouse from Domain: Disassociate a lighthouse from a domain.
  • Manage Domain Metadata: Access and manipulate metadata associated with a domain.

The SDK facilitates various operations related to domains, including retrieving domain information, adding lighthouses to domains, updating domain data, and more. We show an example of the most basic operations.

Retrieving Domain Information

To retrieve information about a specific domain, use the GetDomain method. This method retrieves domain information by its Id. You can get a domain Id by:

Example:

Domain myDomain;
_conjurekit.GetDomain(domainId, onSuccess: foundDomain =>
{
myDomain = foundDomain;
}, onFailure);

Adding Lighthouses to Domains

To add lighthouses to domains, use the AddLighthouse method of the selected domain. This method adds a specified lighthouse to the domain. This method does NOT set a pose for the lighthouse; it simply registers it into the domain. This creates a new DomainAssociation.

Example:

StaticLighthouse myLighthouse; // instance of your StaticLighthouse
myDomain.AddLighthouse(myLighthouse, onSuccess, onFailure);

Or alternatively with its Id:

myDomain.AddLighthouse(lighthouseId, onSuccess, onFailure);

Removing Lighthouses from Domains

The SDK allows for the removal of lighthouses from domains using the RemoveLighthouse method. This method removes a specified lighthouse from the domain. This deletes an existing DomainAssociation and will of course also delete any existing pose for this lighthouse in the domain.

Example:

myDomain.RemoveLighthouse(myLighthouse, onSuccess, onFailure);

Retrieving Lighthouse Poses

To retrieve poses of lighthouses within a domain, use the GetAllLighthousePoses method. This method provides a quick way to return the poses of all lighthouses within the domain.

Example:

myDomain.GetAllLighthousePoses(onSuccess, onFailure);

Setting Lighthouse Pose in Domains

To set the pose of a lighthouse within a domain, use the AddOrUpdateLighthousePose method of the selected domain. This method sets the pose of the specified lighthouse within the domain (stored in its DomainAssociation). If the lighthouse has not yet been registered to the domain, it will be registered first.

Example:

myDomain.AddOrUpdateLighthousePose(myLighthouse, position, rotation, onSuccess, onFailure);

Removing Lighthouse Pose from Domains

To remove the pose of a lighthouse from a domain, use the RemoveLighthousePose method of the selected domain. This method removes the pose of the specified lighthouse from the domain (stored in its DomainAssociation) but not the lighthouse itself.

Example:

myDomain.RemoveLighthousePose(myLighthouse, onSuccess, onFailure);

Lighthouse Operations

The SDK provides operations for managing lighthouses, including retrieving lighthouse information, setting lighthouse pose in domains, removing lighthouse pose, and more. We show an example of the most basic operations. Most of these operations are equivalent to ones from Domain Operations, but from a different perspective. This is to show how you can easily operate on objects between one another.

Retrieving Lighthouse Information

To retrieve information about a specific lighthouse, use the GetLighthouse method. This method retrieves lighthouse information by its Id.

Example:

StaticLighthouse myLighthouse;
_conjurekit.GetLighthouse(lighthouseId, onSuccess: foundLighthouse =>
{
myLighthouse = foundLighthouse;
}, onFailure);

Adding Lighthouses to Domains

This is an alternative to the method from Domain. To add a lighthouse to a domain, use the AddToDomain method of the selected lighthouse. This method does NOT set a pose for the lighthouse; it simply registers it into the domain.

Example:

Domain myDomain; // instance of your domain
myLighthouse.AddToDomain(myDomain, onSuccess, onFailure);

Or alternatively with its Id:

myLighthouse.AddToDomain(domainId, onSuccess, onFailure);

Removing Lighthouses from Domains

This is an alternative to the method from Domain. To remove a lighthouse from a domain, use the RemoveFromDomain method of the selected lighthouse. This will of course also delete any existing pose for this lighthouse in the domain.

Example:

myLighthouse.RemoveFromDomain(myLighthouse, onSuccess, onFailure);

Domain Data Operations

Domain data operations involve creating, updating, and removing custom data stored on the domain server. Here are some of the supported data-related operations:

  • Create Data: Upload new data to a domain, specifying the data type and content.
  • Update Data: Modify existing data within a domain.
  • Retrieve Data: Fetch data stored within a domain.
  • Remove Data: Delete data from a domain.

Domain data can be fetched as header-only DomainDataInfo (with GetMetadata* methods) or in full (with GetData* methods). When enumerating data it is always suggested to get headers first, and then possibly getting payloads on demand. You can interact with payloads through CRUD operations exposed from Domain or DomainDataInfo.

Here are some example of basic operations:

Retrieving Metadata

To retrieve metadata for specific domain data, users can utilize the GetMetadata method provided by the SDK. This method fetches metadata for a particular data Id or data name and type combination.

Example:

_domainSdk.GetMetadata(dataId, onSuccess, onFailure);

Fetching Data by Type

Users can retrieve data from a domain based on its type using the GetDataByType method. This method returns both metadata and data content for all data entries of a specified type within the domain.

Example:

_domainSdk.GetDataByType(dataType, onSuccess, onFailure);

Creating New Data

The SDK facilitates the creation of new data entries in a domain using the CreateData method. Users can specify the name, type, and payload of the new data, which can be either a byte array or a string.

Example:

_domainSdk.CreateData(name, dataType, *payload*, onSuccess, onFailure);

Updating Existing Data

Existing data entries in a domain can be updated, including their payload, using the UpdateData method. Users must provide the Id of the data to be updated along with the new data payload, which can be either a byte array or a string.

Example:

_domainSdk.UpdateData(dataId, *payload*, onSuccess, onFailure);

or from DomainDataInfo:

DataDomainInfo dataInfo; // your metadata
dataInfo.UpdatePayload(*payload*, onSuccess, onFailure);

Removing Data

To remove/delete data from a domain, users can use the RemoveData method provided by the SDK. This method requires the Id of the data to be removed.

Example:

_domainSdk.RemoveData(dataId, onSuccess, onFailure);

Using Domains from Lighthouses with Manna

To load the domain data, you'll need a domain Id. A common place to find a domain Id is when the user scans a static QR code.

_manna.SetStaticLighthousePoseSelector(OnStaticLighthouseScanned);
private string _domainId;

private void OnStaticLighthouseScanned(StaticLighthouseData lighthouseData, Action<LighthousePose> selectLighthouse)
{
LighthousePose pose = lighthouseData.poses[0];
_domainId = pose.domainId;
selectLighthouse?.Invoke(pose);
}
Reminder

It is indeed possible to have static QR codes (or static lighthouses) registered with more than one domain.

It's also important to note that a lighthouse in a domain does not necessarily imply it has a registered pose, which needs to be set. Hence, the StaticLighthouseData will return an array of valid poses (only from lighthouses with poses) and lets users select which pose to use by calling the selectLighthouse callback. In this example, we are selecting the first available pose. In your application, you might want to implement a more sophisticated domain selection mechanism that suits your app needs better. For example, you could show a domain selector UI to let the user select which domain they want to use or check which of the available domains contain the spatial data needed for your app and select that one.

Once you have the domain Id, you can call the _conjureKit.GetDomain method, which will return a Domain object that can be used to read the domain data.

For example, you can use the Domain object to load information about all the QR codes in that domain:

_conjureKit.GetDomain(_domainId, OnDomainLoaded, Debug.LogError);
domain.GetAllLighthousePoses(lighthousePoses =>
{
foreach (var lighthouse in lighthousePoses)
{
Debug.Log($"{lighthouse.LighthouseId}-{lighthouse.Position}-{lighthouse.Rotation}");
}
},
Debug.LogError);

You can also load custom data stored in the domain. Here for example we want to get the location of a light source in the domain to help achieve more realistic lighting of virtual objects to better match with the real world.

private void OnDomainLoaded(Domain domain)
{
domain.GetMetadataByType("vector3", list =>
{
foreach (DomainDataInfo domainDataInfo in list)
{
if (domainDataInfo.Name == "light")
{
domain.GetData(
domainDataInfo.Id,
(metadata, data) =>
{
// Instantiate a light prefab that has the same location as a real light source in the physical space
Instantiate(lightPrefab, ByteArrayToVector3(data), Quaternion.identity);
},
Debug.LogError);
return;
}
}
}, Debug.LogError);
}

public static Vector3 ByteArrayToVector3(byte[] input)
{
var output = new Vector3
{
x = BitConverter.ToSingle(input, 0 * sizeof(float)),
y = BitConverter.ToSingle(input, 1 * sizeof(float)),
z = BitConverter.ToSingle(input, 2 * sizeof(float))
};

return output;
}

Calling domain.GetMetadataByType will load the metadata of all available data in the domain with the given type (vector3 in this example). You can then search the metadata list to find the data with the name that you want. Here, the domain might have many different things represented by data type vector3 (e.g. lights, sockets, door handles, or any other data that the domain owner decided to make about their physical space). domainDataInfo.Name can be used for further filtering and finding the necessary piece of data.

Edit domain data

To write data to the domain, you need to log in with the posemesh console account that belongs to the same organization as the domain you want to edit.

_conjureKit.Login(
"YOUR_POSEMESH_CONSOLE_LOGIN",
"YOUR_POSEMESH_CONSOLE_PASSWORD",
OnLogin,
Debug.LogError);

When the OnLogin callback is called, you'll have the necessary access to create, update, and remove data in the domain using the same Domain object. For example, if you have the location of a light bulb in your room saved in a Vector3 lightBulbPosition and you want to save that information in the domain, you can do it like this:

private void OnLogin()
{
domain.CreateData(
"light",
"vector3",
Vector3ToByteArray(lightBulbPosition),
dataInfo => Debug.Log($"Data with id {dataInfo.Id} successfully added to the domain"),
Debug.LogError
);
}

public static byte[] Vector3ToByteArray(Vector3 input)
{
byte[] output = new byte[sizeof(float) * 3];
Buffer.BlockCopy(BitConverter.GetBytes(input.x), 0, output, 0 * sizeof(float), sizeof(float));
Buffer.BlockCopy(BitConverter.GetBytes(input.y), 0, output, 1 * sizeof(float), sizeof(float));
Buffer.BlockCopy(BitConverter.GetBytes(input.z), 0, output, 2 * sizeof(float), sizeof(float));

return output;
}