Skip to content

Commit 51d8404

Browse files
committed
Constraints now follow configurable execution priorities
1 parent d736610 commit 51d8404

File tree

5 files changed

+127
-26
lines changed

5 files changed

+127
-26
lines changed

Assets/MRTK/SDK/Editor/Inspectors/UX/Constraints/ConstraintManagerInspector.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ private static EntryAction RenderManualConstraintItem(SerializedProperty constra
6666

6767
using (new EditorGUILayout.HorizontalScope())
6868
{
69-
EditorGUILayout.LabelField(constraint.GetType().Name, GUILayout.ExpandWidth(true));
69+
EditorGUILayout.LabelField($"Priority {(constraint as TransformConstraint).ExecutionPriority}: {constraint.GetType().Name}", GUILayout.ExpandWidth(true));
7070

7171
if (canRemove)
7272
{
@@ -107,7 +107,7 @@ private void RenderAutoConstraintMenu()
107107
using (new EditorGUILayout.HorizontalScope())
108108
{
109109
string constraintName = constraint.GetType().Name;
110-
EditorGUILayout.LabelField(constraintName);
110+
EditorGUILayout.LabelField($"Priority {(constraint as TransformConstraint).ExecutionPriority}: {constraint.GetType().Name}");
111111
if (GUILayout.Button("Go to component"))
112112
{
113113
Highlighter.Highlight("Inspector", $"{ObjectNames.NicifyVariableName(constraintName)} (Script)");

Assets/MRTK/SDK/Features/Input/Handlers/Constraints/ConstraintManager.cs

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public List<TransformConstraint> SelectedConstraints
4242
get => selectedConstraints;
4343
}
4444

45-
private HashSet<TransformConstraint> constraints = new HashSet<TransformConstraint>();
45+
private List<TransformConstraint> constraints = new List<TransformConstraint>();
4646
private MixedRealityTransform initialWorldPose;
4747

4848
/// <summary>
@@ -56,7 +56,7 @@ public bool AddConstraintToManualSelection(TransformConstraint constraint)
5656
var existingConstraint = selectedConstraints.Find(t => t == constraint);
5757
if (existingConstraint == null)
5858
{
59-
selectedConstraints.Add(constraint);
59+
ConstraintUtils.AddWithPriority(ref selectedConstraints, constraint, new ConstraintExecOrderComparer());
6060
}
6161

6262
return existingConstraint == null;
@@ -95,6 +95,15 @@ public void Initialize(MixedRealityTransform worldPose)
9595
}
9696
}
9797

98+
/// <summary>
99+
/// Re-sort list of constraints. Triggered by constraints
100+
/// when their execution order is modified at runtime.
101+
/// </summary>
102+
internal void RefreshPriorities()
103+
{
104+
constraints.Sort(new ConstraintExecOrderComparer());
105+
}
106+
98107
/// <summary>
99108
/// Registering of a constraint during runtime. This method gets called by the constraint
100109
/// components to auto register in their OnEnable method.
@@ -105,7 +114,7 @@ internal void AutoRegisterConstraint(TransformConstraint constraint)
105114
// add to auto component list
106115
if (constraint.isActiveAndEnabled)
107116
{
108-
constraints.Add(constraint);
117+
ConstraintUtils.AddWithPriority(ref constraints, constraint, new ConstraintExecOrderComparer());
109118
constraint.Initialize(initialWorldPose);
110119
}
111120
}
@@ -127,7 +136,7 @@ protected void Awake()
127136
{
128137
if (constraint.isActiveAndEnabled)
129138
{
130-
constraints.Add(constraint);
139+
ConstraintUtils.AddWithPriority(ref constraints, constraint, new ConstraintExecOrderComparer());
131140
}
132141
}
133142
}
@@ -137,30 +146,20 @@ private void ApplyConstraintsForType(ref MixedRealityTransform transform, bool i
137146
ManipulationHandFlags handMode = isOneHanded ? ManipulationHandFlags.OneHanded : ManipulationHandFlags.TwoHanded;
138147
ManipulationProximityFlags proximityMode = isNear ? ManipulationProximityFlags.Near : ManipulationProximityFlags.Far;
139148

140-
if (autoConstraintSelection)
149+
foreach (var constraint in constraints)
141150
{
142-
foreach (var constraint in constraints)
151+
// If on manual mode, filter executed constraints by which have been manually selected
152+
if (!autoConstraintSelection && !selectedConstraints.Contains(constraint))
143153
{
144-
if (constraint.isActiveAndEnabled &&
145-
constraint.ConstraintType == transformType &&
146-
constraint.HandType.HasFlag(handMode) &&
147-
constraint.ProximityType.HasFlag(proximityMode))
148-
{
149-
constraint.ApplyConstraint(ref transform);
150-
}
154+
continue;
151155
}
152-
}
153-
else
154-
{
155-
foreach (var constraint in selectedConstraints)
156+
157+
if (constraint.isActiveAndEnabled &&
158+
constraint.ConstraintType == transformType &&
159+
constraint.HandType.HasFlag(handMode) &&
160+
constraint.ProximityType.HasFlag(proximityMode))
156161
{
157-
if (constraint.isActiveAndEnabled &&
158-
constraint.ConstraintType == transformType &&
159-
constraint.HandType.HasFlag(handMode) &&
160-
constraint.ProximityType.HasFlag(proximityMode))
161-
{
162-
constraint.ApplyConstraint(ref transform);
163-
}
162+
constraint.ApplyConstraint(ref transform);
164163
}
165164
}
166165
}

Assets/MRTK/SDK/Features/Input/Handlers/Constraints/TransformConstraint.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,27 @@ public ManipulationProximityFlags ProximityType
4141
set => proximityType = value;
4242
}
4343

44+
[SerializeField]
45+
[Tooltip("Execution order priority of this constraint. Lower numbers will be executed before higher numbers.")]
46+
private int executionOrder = 0;
47+
48+
/// <summary>
49+
/// Execution order priority of this constraint. Lower numbers will be executed before higher numbers.
50+
/// </summary>
51+
public int ExecutionPriority
52+
{
53+
get => executionOrder;
54+
set {
55+
executionOrder = value;
56+
57+
// Notify all ConstraintManagers to re-sort these priorities.
58+
foreach(var mgr in gameObject.GetComponents<ConstraintManager>())
59+
{
60+
mgr.RefreshPriorities();
61+
}
62+
}
63+
}
64+
4465
protected MixedRealityTransform worldPoseOnManipulationStart;
4566

4667
public abstract TransformFlags ConstraintType { get; }
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using UnityEngine;
5+
using System.Collections.Generic;
6+
using Microsoft.MixedReality.Toolkit.UI;
7+
8+
namespace Microsoft.MixedReality.Toolkit.Utilities
9+
{
10+
/// <summary>
11+
/// Defines a comparer to sort TransformConstraints by their
12+
/// requested execution order, or any other priority
13+
/// mechanism that a subclass utilizes.
14+
/// </summary>
15+
public class ConstraintExecOrderComparer : IComparer<TransformConstraint>
16+
{
17+
/// <returns>
18+
/// Returns < 0 if x should be executed first.
19+
/// Returns > 0 if y should be executed first.
20+
/// Returns = 0 if they are of equivalent execution priority.
21+
/// </returns>
22+
public virtual int Compare(TransformConstraint x, TransformConstraint y)
23+
{
24+
return x.ExecutionPriority - y.ExecutionPriority;
25+
}
26+
}
27+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using UnityEngine;
5+
using System.Collections.Generic;
6+
using Microsoft.MixedReality.Toolkit.UI;
7+
8+
namespace Microsoft.MixedReality.Toolkit.Utilities
9+
{
10+
/// <summary>
11+
/// Utilities for the management of constraints.
12+
/// </summary>
13+
internal static class ConstraintUtils
14+
{
15+
/// <summary>
16+
/// Adds a constraint to the specified already-sorted list of constraints, maintaining
17+
/// execution priority order. SortedSet is not used, as equal priorities
18+
/// break duplicate-checking with SortedSet, as well as SortedSet not being
19+
/// able to handle runtime-changing exec priorities.
20+
/// </summary>
21+
/// <param name="constraintList">Sorted list of existing priorites</param>
22+
/// <param name="constraint">Constraint to add</param>
23+
/// <param name="comparer">ConstraintExecOrderComparer for comparing two constraint priorities</param>
24+
internal static void AddWithPriority(ref List<TransformConstraint> constraintList, TransformConstraint constraint, ConstraintExecOrderComparer comparer)
25+
{
26+
if(constraintList.Contains(constraint))
27+
{
28+
return;
29+
}
30+
31+
if(constraintList.Count == 0 || comparer.Compare(constraintList[constraintList.Count-1], constraint) < 0)
32+
{
33+
constraintList.Add(constraint);
34+
return;
35+
}
36+
else if(comparer.Compare(constraintList[0], constraint) > 0)
37+
{
38+
constraintList.Insert(0, constraint);
39+
return;
40+
}
41+
else
42+
{
43+
int idx = constraintList.BinarySearch(constraint, comparer);
44+
if(idx < 0)
45+
{
46+
// idx will be the two's complement of the index of the
47+
// next element that is "larger" than the given constraint.
48+
idx = ~idx;
49+
}
50+
constraintList.Insert(idx, constraint);
51+
}
52+
}
53+
}
54+
}

0 commit comments

Comments
 (0)