Clash Detection UI - Developer#
This page documents the developer-facing API of the omni.physx.clashdetection.ui
extension: carb settings paths, custom configuration hooks, the filtering and grouping
APIs, person-in-charge management, selection pub/sub, and the viewport bridge used
by the Clash Detection UI.
Warning
No stability guarantees. All APIs documented on this page are internal
implementation details of the omni.physx.clashdetection.ui sample UI extension.
They are not part of the official Clash Detection public API.
Classes, functions, signatures, module paths, and
carb.settingskeys may be renamed, moved, or removed in any release without prior notice and without a deprecation period.No backwards-compatibility commitment is made for any symbol documented here.
Do not rely on these APIs in production code or shipping extensions.
The stable, supported API is provided by the lower-level extensions
omni.physx.clashdetection (C++ engine) and omni.physx.clashdetection.core
(Python data structures and serialization). See
Clash Detection Core API for the supported developer interface.
Settings Paths#
All persistent UI settings can be read or written programmatically using
carb.settings.get_settings(). The table below maps each UI option to its
carb.settings path (constants live in ExtensionSettings inside
omni.physxclashdetectionui.settings):
Setting |
carb.settings path |
|---|---|
Show / hide the Clash Detection window |
|
Debug logging (also enables telemetry and anim/point-cloud logging) |
|
Show full prim paths of clashing objects in the results table |
|
Use asynchronous clash detection pipeline |
|
Immediate viewport update during timeline slider drag |
|
Auto-save query on selection change (Query Management window) |
|
Display and edit timecodes as frames |
|
Show empty groups in the Clash Groups window |
|
Example - open the window and enable async pipeline programmatically:
import carb.settings
settings = carb.settings.get_settings()
settings.set_bool("/physics/showClashDetectionWindow", True)
settings.set_bool("/persistent/clashDetection/useAsyncClashPipeline", True)
Persons-in-Charge API#
The Person in Charge column in the results table is populated from a JSON file.
By default the file at <extension_path>/omni/physxclashdetectionui/pic.json is used.
To load a custom list before the extension starts, set ExtensionSettings.pic_file_path
to the path of your JSON file:
from omni.physxclashdetectionui.settings import ExtensionSettings
ExtensionSettings.pic_file_path = "/path/to/my_pic.json"
The JSON file must contain a list of person objects with username, first_name,
last_name, and email fields. An entry with an empty username acts as the
“unassigned” placeholder.
The following classes from omni.physxclashdetectionui.pic_provider implement the
person-in-charge data model:
- class PersonInCharge(
- username: str = '',
- first_name: str = '',
- last_name: str = '',
- email: str = '',
Represents a single person who can be assigned responsibility for a clash result.
Each person is uniquely identified by their
username. An instance with an emptyusernameis used as the “unassigned” placeholder and is always present in thePersonsInChargecollection.- Parameters:
username (str) – Unique identifier for the person. Empty string is allowed.
first_name (str) – First name.
last_name (str) – Last name.
email (str) – Email address.
- username: str
Read-only. Unique identifier for the person.
- first_name: str
Read-only. First name.
- last_name: str
Read-only. Last name.
- email: str
Read-only. Email address.
- full_name: str
Read-only. Derived display name. Returns
"first_name last_name"when both fields are set; falls back to whichever is non-empty, or tousernameif both name fields are empty.
- full_name_email: str
Read-only. Returns
"<full_name> <email>"when an email address is present, otherwise returnsfull_name.
- __lt__(other) bool#
Enables sorting by
full_name.
- class PersonsInCharge#
Collection manager for
PersonInChargeobjects.Maintains an internal dictionary keyed by
username. The unassigned placeholder (username = "") is always present.- pic_none#
- Type:
Class-level sentinel representing the unassigned person:
PersonInCharge("", "<None>"). Returned byget_person()when the requested username is not found.
- get_items() ValuesView[PersonInCharge]#
Returns a view of all registered
PersonInChargeobjects (including the unassigned placeholder).
- get_person(username: str) PersonInCharge#
Look up a person by username. Never returns
None- falls back topic_nonewhen the username is not found.- Parameters:
username (str) – The username to look up.
- Return type:
- fetch(source: str) bool#
Abstract hook for populating the collection from an external source. The base implementation always returns
False. Override in a subclass to load persons from a database, REST endpoint, or other source.- Parameters:
source (str) – Arbitrary source descriptor (path, URL, etc.).
- Returns:
Trueon success,Falseotherwise.- Return type:
bool
Filtering API#
The filter expressions used in the Custom Advanced Filtering window are parsed and
evaluated by two functions and a supporting class in
omni.physxclashdetectionui.filtering:
- parse_filter_expression(
- filter_expression: str,
- upper_cased: bool = True,
Parse a filter expression string into a tree of
FilterNodeobjects.- Parameters:
filter_expression (str) – The filter expression string.
upper_cased (bool) – If
True(default), column names and string literals are upper-cased for case-insensitive matching.
- Returns:
Root
FilterNodeif parsing succeeds;Noneif the expression is malformed (errors are logged viacarb.log_error).- Return type:
FilterNode | None
- Raises:
SyntaxError – On malformed expressions (caught internally;
Noneis returned).
- apply_filter(
- filter_tree: FilterNode | None,
- get_column_value_fn: Callable[[str], Any],
Evaluate a
FilterNodetree against a single data row.- Parameters:
filter_tree (FilterNode | None) – Root node of the parsed filter tree, or
Nonefor “no filter”.get_column_value_fn (Callable[[str], Any]) – Callable that accepts a column name (
str) and returns the value for that column in the current row.
- Returns:
Trueif the row matches the filter (or iffilter_treeisNone).- Return type:
bool
- class FilterNode#
A node in a filter expression parse tree.
Leaf nodes represent comparisons; branch nodes represent
AND/ORlogic.- column: str
Column name for comparison nodes (
Noneon logic nodes).
- op: str
Comparison operator, one of:
=,<,>,<=,>=,<>,!=,IN,NOT IN,LIKE,NOT LIKE.
- value#
Right-hand operand: a
str,int,float, orlist(forIN/NOT IN). May also be a"[ColumnName]"string for column-to-column comparisons.
- left: FilterNode
Left child (for logic nodes).
- right: FilterNode
Right child (for logic nodes).
- logic: str
Logical operator
"AND"or"OR"(Noneon comparison leaf nodes).
- __repr__() str#
Returns
"(<column> <op> <value>)"for leaf nodes, or"(<left> <logic> <right>)"for logic nodes.
Grouping API#
The grouping API in omni.physxclashdetectionui.grouping organizes flat clash result
rows into a USD-prim hierarchy by walking each clashing object’s path upward until a
prim of a recognized kind is found. The resulting tree is represented as a
dictionary of GroupNode objects.
- class GroupNode(group_path: Sdf.Path, group_kind: str = '')#
Hierarchical node for grouping clash results by USD prim path and kind.
Each node represents one USD prim and collects the clash row items whose paths fall under it, plus references to its child group nodes.
- Parameters:
group_path (Sdf.Path) – The USD prim path for this group node.
group_kind (str) – The USD
kindmetadata string for this node (e.g."component","group"). Empty string for the root node.
- group_path: Sdf.Path
Read-only. The USD prim path for this node.
- group_kind: str
Read-only. The USD kind metadata for this node.
- children: set[GroupNode]
Read-only. The set of direct child group nodes.
- clashing_pairs: set[ClashDetectTableRowItem]
Read-only. Clash result items assigned directly to this node (not to its children).
- total_clashes: int
Total number of clashes in this node and all its descendants. Updated by
group()after the tree is built; can also be set directly.
- add_clashing_pair(row_item: ClashDetectTableRowItem) None#
Add a clash result row item to this node’s
clashing_pairsset.
- group(
- stage: Usd.Stage,
- clashing_pairs_list: List[ClashDetectTableRowItem],
- root_prim_path: Sdf.Path | None = None,
- kinds: List[str] | None = None,
- discard_empty_groups: bool = False,
Build a tree of
GroupNodeobjects from a flat list of clash row items.For each row item both
object_a_pathandobject_b_pathare walked up the USD hierarchy. The first ancestor prim whosekindmatches any entry in kinds becomes the owning group node. If no such ancestor exists the row is assigned to the root group node.- Parameters:
stage (Usd.Stage) – The USD stage to operate on.
clashing_pairs_list (List[ClashDetectTableRowItem]) – List of clash row items to group.
root_prim_path (Optional[Sdf.Path]) – Path to use as the tree root. Defaults to the stage pseudo-root when
None.kinds (Optional[List[str]]) – Prim kinds to treat as grouping boundaries. Defaults to
["component", "subcomponent", "group"].discard_empty_groups (bool) – When
True, groups with no directclashing_pairsare pruned from the hierarchy; their non-empty children are promoted one level up.
- Returns:
A dictionary mapping each group’s
Pathto itsGroupNode. The root node is accessible via bothnode_dict[root_prim_path]andnode_dict[None].- Return type:
Dict[Optional[Sdf.Path], GroupNode]
- dump_groups( ) None#
Recursively pretty-print the group hierarchy to
stdout.For each node the output includes the USD path, kind, total clash count, child count, and the individual clashing pairs. Children and pairs are both printed in sorted order.
- dump_groups_to_json( ) None#
Recursively serialize the group hierarchy to JSON and print to
stdout.Each node is represented as a JSON object with keys:
group_path(str),group_kind(str),total_clashes(int),children(list), andclashing_pairs(list of{"object_a_path": …, "object_b_path": …}dicts). Children and pairs are sorted by path string.
Example - group clashes and print the tree:
from pxr import Sdf, Usd
from omni.physxclashdetectionui.grouping import group, dump_groups, dump_groups_to_json
node_dict = group(
stage=stage,
clashing_pairs_list=clash_rows,
root_prim_path=Sdf.Path("/World"),
kinds=["component", "subcomponent"],
discard_empty_groups=True,
)
root_node = node_dict[None] # or node_dict[Sdf.Path("/World")]
dump_groups(node_dict, root_node)
dump_groups_to_json(node_dict, root_node)
Clash Selection API#
omni.physxclashdetectionui.selection.clash_selection provides a lightweight
publish/subscribe mechanism for tracking the active query and the set of currently
selected ClashInfo objects.
Type aliases:
QueryId = NewType("QueryId", int)SelectionContainer = tuple[ClashInfo, ...]
- class ClashSelection#
Tracks the current query ID, timecode, and selected clash infos. Multiple subsystems (viewport bridge, UI panels) subscribe to its change notifications rather than polling.
- query_id: QueryId
Read-only. The ID of the currently active query.
- timecode: float
Read-only. The timecode associated with the most recent selection update or explicit
set_current_timecode()call.
- selection: SelectionContainer
Read-only. Immutable tuple of the currently selected
ClashInfoobjects.
- clear_selection() None#
Clears the current selection and broadcasts the change to all selection listeners. Does nothing if the selection is already empty.
- set_current_timecode(timecode: float) None#
Sets the current timecode and notifies all timecode listeners.
- Parameters:
timecode (float) – New timecode value.
- update_query_id(query_id: QueryId) None#
Changes the active query ID, clears the selection, and broadcasts the change to all selection listeners.
- Parameters:
query_id (QueryId) – New query ID.
- update_selection(
- timecode: float,
- new_selection: Sequence[ClashInfo],
Replaces the selection and timecode simultaneously, then broadcasts the change to all selection listeners.
- Parameters:
timecode (float) – Timecode for the new selection.
new_selection (Sequence[ClashInfo]) – New sequence of selected clash infos.
- subscribe_to_selection_changes(
- callback: Callable,
Register a zero-argument callback that is called whenever the selection or query ID changes.
- Parameters:
callback – Callable with signature
() -> None.- Returns:
A
ListenerSubscriptionhandle. The subscription is active as long as the handle is alive; set it toNoneto unsubscribe.- Return type:
ListenerSubscription
- subscribe_to_timecode_changes(
- callback: Callable,
Register a zero-argument callback that is called whenever the timecode changes.
- Parameters:
callback – Callable with signature
() -> None.- Returns:
A
ListenerSubscriptionhandle.- Return type:
ListenerSubscription
Viewport Bridge API#
omni.physxclashdetectionui.clash_viewport_bridge connects the UI clash selection
state to the clash detection viewport extension. It subscribes to
ClashSelection changes and forwards them to
get_api_instance() so that the viewport
renders the correct clash meshes.
- class ClashViewportBridge(
- clash_data: ClashData,
- clash_selection: ClashSelection,
Manages the interaction between clash detection data and the viewport.
On construction the bridge subscribes to both selection changes and timecode changes from clash_selection, and registers a lazy data-loader callback with the viewport API so that per-frame clash data is fetched from the database on demand.
- Parameters:
clash_data (ClashData) – The open
ClashDatainstance used to load per-frame records.clash_selection (ClashSelection) – The
ClashSelectioninstance to subscribe to.
- destroy() None#
Releases all subscriptions and clears references. Call this when the bridge is no longer needed to avoid memory leaks.
- display_clash_by_clash_info(
- clash_infos: Sequence[ClashInfo],
- timecode: float,
Forward a list of
ClashInfoobjects to the viewport for display at the given timecode. The number of items passed is capped by theCLASH_MESHES_DISPLAY_LIMITviewport setting.- Parameters:
clash_infos (Sequence[ClashInfo]) – Clashes to display.
timecode (float) – The USD timecode at which to display the clash meshes.
- set_display_clashes_in_main_viewport(
- display_clashes_in_main_viewport: bool,
Convenience wrapper that sets both
MAIN_VIEWPORT_SHOW_CLASH_MESHESandMAIN_VIEWPORT_SHOW_CLASH_OUTLINESviewport settings to the given value.- Parameters:
display_clashes_in_main_viewport (bool) –
Trueto show clashes in the main viewport;Falseto hide them.
- hide_all_clash_meshes() None#
Delegates to the viewport API to hide all currently displayed clash meshes. Called automatically on timecode changes.
- setup_for_screenshot_export() None#
Configures viewport settings for screenshot export. Saves the current values of
MAIN_VIEWPORT_SHOW_CLASH_MESHES,CLASH_VIEWPORT_SHOW_CLASHES,MAIN_VIEWPORT_CENTER_CAMERA,CLASH_VIEWPORT_CENTER_CAMERA,MAIN_VIEWPORT_ENABLE_CAMERA_TOLERANCE, andCLASH_VIEWPORT_ENABLE_CAMERA_TOLERANCE, then applies the export-friendly configuration (clash viewport active, camera centering enabled, etc.).- Raises:
Exception – If the
omni.physx.clashdetection.viewportextension is not loaded.
- teardown_for_screenshot_export() None#
Restores the viewport settings saved by
setup_for_screenshot_export().- Raises:
Exception – If the
omni.physx.clashdetection.viewportextension is not loaded.
- static export_screenshot_to_file(
- clash_info: ClashInfo,
- timecode: float,
- clash_screenshot_path: str,
- current_export_index: int,
- total_number_of_exports: int,
- clear_frames: int = 5,
- render_frames: int = 100,
Coroutine - must be awaited (
await ClashViewportBridge.export_screenshot_to_file(...)).Export a screenshot of one clash to a file using the Clash Detection Viewport.
The coroutine:
Ensures the Clash Detection Viewport window is visible.
Seeks the timeline to timecode.
Waits clear_frames app updates to clear the previous render.
Calls
display_clasheson the viewport API.Waits for stage loading to finish (up to 15 frames).
Waits render_frames app updates for translucent materials to settle.
Captures the viewport to a temporary PNG and copies it to clash_screenshot_path.
After the last export, calls
hide_all_clash_meshes()to clean up.
- Parameters:
clash_info (ClashInfo) – The clash to display.
timecode (float) – Timeline position for the screenshot.
clash_screenshot_path (str) – Destination path for the screenshot file.
current_export_index (int) – Zero-based index of this export within the batch.
total_number_of_exports (int) – Total number of exports in the batch.
clear_frames (int) – App updates to wait before displaying the clash. Defaults to
5.render_frames (int) – App updates to wait for rendering to settle. Defaults to
100.
- Raises:
Exception – If the viewport extension is not loaded or the viewport window could not be created.
asyncio.CancelledError – If the export is cancelled; clash meshes are hidden before re-raising.