Skip to content

Object manipulation

Object navigation changes an object’s position and orientation while the application retains control of the edit: which object is affected, when changes are accepted, and what undo restores.

The demos edit one cube at a time. Their integrations use dynamic application tags to make object interactions available while the edit is active.

  1. Click an object to select it. Camera navigation can use that selection for its pivot.
  2. Double-click or press Enter to start editing.
  3. Left-drag translates; middle/right-drag rotates; the wheel moves in depth.
  4. With Rotatrix connected, its ball rotates the object; Shift translates it. The profile’s camera controls remain available.
  5. Enter accepts; Escape restores the starting pose; U undoes an accepted edit.

Native controls work independently of OpenAxis. The integration announces object interaction tags only while an edit is active.

The object adapter connects NavigationSession to the application’s object read and write APIs. Its context identifies an edit operation, so pending input cannot affect a later edit, even if both edits involve the same object.

The integration supplies this adapter and an object observation callback to the same NavigationSession that handles the camera. Application events report native object movement and changes to the active edit.

MyOpenAxisIntegration.start() passes object_adapter=object_adapter and object_observation=object_adapter.read. Native events call native_object_changed() and context_changed().

class MyObjectAdapter:
def __init__(self, app):
self.app = app
def capture_context(self):
return self.app.operation if self.app.alive else None
def is_current(self, context):
return self.app.alive and self.app.operation is context
def read(self, context):
pose = self.app.get_object_pose(context.index)
return ObjectPose(t=pose.position,r=pose.rotation)
def begin_query(self, context):
return MyObjectCapture(self.read(context),self.app.object_bounds(context.index))
def apply_object(self, context, desired, navigation, pivot):
self.app.set_object_pose(context.index,MyObjectPose(desired.t,desired.r))
return WriteResult(True,self.read(context))
def show_pivot(self, context, point):
self.app.set_pivot_marker(point, object_marker=True)

Each edit creates a new stable operation identity, even for the same cube. The adapter checks that identity before output can be applied. Return actual pose readback so native changes and constraints can be reconciled. See comparison precision for choosing tolerances.

Rotatrix needs the object’s current pose and world-space bounds to calculate its movement. The adapter creates a query capture from those application values; NavigationSession asks its resolver for the requested facts.

class MyObjectCapture:
def __init__(self, pose, bounds):
self.pose, self.bounds = pose, bounds
def initial_object_observation(self):
return self.pose
def resolve(self, name):
if name == 'object.pose':
return self.pose.value()
if name == 'object.bounds':
return bounds_value(self.bounds)
return UNAVAILABLE

Camera queries and picking also use the updated geometry. Camera and object streams retain separate pose/correction state in the shared session.

The application owns accept, cancel and undo. A gesture can end while the edit remains active; multiple gestures can contribute to one edit. Accept saves the starting pose for undo, cancel restores it, and shutdown cancels an unfinished edit.

MyObjectOperation contains the target index and starting pose. The native application retains this operation until accept/cancel; MyObjectAdapter only binds it for SDK work. Inspect application.py for the transaction and undo handlers.

An integration binds its application’s own transaction and target. Constraints are reported through actual pose readback; see adapter contracts.

Alternate object edits and camera gestures, then accept or cancel while input is active. Check undo, transformed picking/bounds, and a second edit of the same cube. Old output must leave a later operation untouched.

For automated commands and coverage, use the demo READMEs: Python, C#, TypeScript, and C++.