Skip to content

Commit

Permalink
feat(Tracking): add limits to pinch scaler
Browse files Browse the repository at this point in the history
The PinchScaler component can now have min/max scale limits applied
to it as well as limiting the axes that will be scaled.
  • Loading branch information
thestonefox committed May 1, 2023
1 parent 57ac8be commit 498ff2d
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 17 deletions.
101 changes: 85 additions & 16 deletions Runtime/Tracking/Modification/PinchScaler.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace Zinnia.Tracking.Modification
{
using UnityEngine;
using Zinnia.Data.Type;
using Zinnia.Extension;
using Zinnia.Process;

Expand All @@ -9,6 +10,7 @@
/// </summary>
public class PinchScaler : MonoBehaviour, IProcessable
{
[Header("Scale Settings")]
[Tooltip("The target to scale.")]
[SerializeField]
private GameObject target;
Expand Down Expand Up @@ -68,6 +70,40 @@ public GameObject SecondaryPoint
}
}
}
[Tooltip("Determines whether to use local or global scale.")]
[SerializeField]
private bool useLocalScale = true;
/// <summary>
/// Determines whether to use local or global scale.
/// </summary>
public bool UseLocalScale
{
get
{
return useLocalScale;
}
set
{
useLocalScale = value;
}
}
[Tooltip("Determines whether to calculate the multiplier using Mathf.Pow(float, float).")]
[SerializeField]
private bool calculateByPower;
/// <summary>
/// Determines whether to calculate the multiplier using <see cref="Mathf.Pow(float, float)"/>.
/// </summary>
public bool CalculateByPower
{
get
{
return calculateByPower;
}
set
{
calculateByPower = value;
}
}
[Tooltip("A scale factor multiplier.")]
[SerializeField]
private float multiplier = 1f;
Expand All @@ -85,38 +121,57 @@ public float Multiplier
multiplier = value;
}
}
[Tooltip("Determines whether to use local or global scale.")]

[Header("Restriction Settings")]
[Tooltip("Determines which axes to apply the modification on>.")]
[SerializeField]
private bool useLocalScale = true;
private Vector3State applyScaleOnAxis = Vector3State.True;
/// <summary>
/// Determines whether to use local or global scale.
/// Determines which axes to apply the modification on>.
/// </summary>
public bool UseLocalScale
public Vector3State ApplyScaleOnAxis
{
get
{
return useLocalScale;
return applyScaleOnAxis;
}
set
{
useLocalScale = value;
applyScaleOnAxis = value;
}
}
[Tooltip("Determines whether to calculate the multiplier using Mathf.Pow(float, float).")]
[Tooltip("The minimum allowed scale.")]
[SerializeField]
private bool calculateByPower;
private Vector3 minimumScaleLimit = Vector3.one * float.NegativeInfinity;
/// <summary>
/// Determines whether to calculate the multiplier using <see cref="Mathf.Pow(float, float)"/>.
/// The minimum allowed scale.
/// </summary>
public bool CalculateByPower
public Vector3 MinimumScaleLimit
{
get
{
return calculateByPower;
return minimumScaleLimit;
}
set
{
calculateByPower = value;
minimumScaleLimit = value;
}
}
[Tooltip("The maximum allowed scale.")]
[SerializeField]
private Vector3 maximumScaleLimit = Vector3.one * float.PositiveInfinity;
/// <summary>
/// The maximum allowed scale.
/// </summary>
public Vector3 MaximumScaleLimit
{
get
{
return maximumScaleLimit;
}
set
{
maximumScaleLimit = value;
}
}

Expand Down Expand Up @@ -232,6 +287,20 @@ protected virtual void Scale()
previousDistance = GetDistance();
}

/// <summary>
/// Applies the scale limits to the given scale value.
/// </summary>
/// <param name="scale">The scale value to apply limits to.</param>
/// <returns>The scale value with limits applied.</returns>
protected virtual Vector3 ApplyLimits(Vector3 scale)
{
return new Vector3(
ApplyScaleOnAxis.xState ? Mathf.Clamp(scale.x, minimumScaleLimit.x, maximumScaleLimit.x) : GetTargetScale().x,
ApplyScaleOnAxis.yState ? Mathf.Clamp(scale.y, minimumScaleLimit.y, maximumScaleLimit.y) : GetTargetScale().y,
ApplyScaleOnAxis.zState ? Mathf.Clamp(scale.z, minimumScaleLimit.z, maximumScaleLimit.z) : GetTargetScale().z
);
}

/// <summary>
/// Scales the object by the distance delta multiplied against the multiplier.
/// </summary>
Expand All @@ -241,11 +310,11 @@ protected virtual void ScaleByMultiplier()
Vector3 newScale = Vector3.one * distanceDelta * Multiplier;
if (UseLocalScale)
{
Target.transform.localScale += newScale;
Target.transform.localScale = ApplyLimits(Target.transform.localScale + newScale);
}
else
{
Target.transform.SetGlobalScale(Target.transform.lossyScale + newScale);
Target.transform.SetGlobalScale(ApplyLimits(Target.transform.lossyScale + newScale));
}
}

Expand All @@ -259,11 +328,11 @@ protected virtual void ScaleByPower()

if (UseLocalScale)
{
Target.transform.localScale = Vector3.Scale(Target.transform.localScale, scaleVector);
Target.transform.localScale = ApplyLimits(Vector3.Scale(Target.transform.localScale, scaleVector));
}
else
{
Target.transform.SetGlobalScale(Vector3.Scale(Target.transform.lossyScale, scaleVector));
Target.transform.SetGlobalScale(ApplyLimits(Vector3.Scale(Target.transform.lossyScale, scaleVector)));
}
}

Expand Down
46 changes: 45 additions & 1 deletion Tests/Editor/Tracking/Modification/PinchScalerTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Zinnia.Tracking.Modification;
using Zinnia.Data.Type;
using Zinnia.Tracking.Modification;

namespace Test.Zinnia.Tracking.Modification
{
Expand Down Expand Up @@ -77,6 +78,49 @@ public void ProcessWithMultiplier()
Object.DestroyImmediate(secondaryPoint);
}

[Test]
public void ProcessWithLimits()
{
Vector3EqualityComparer comparer = new Vector3EqualityComparer(0.1f);
GameObject target = new GameObject("PinchScalerTest");
GameObject primaryPoint = new GameObject("PinchScalerTest");
GameObject secondaryPoint = new GameObject("PinchScalerTest");

subject.Target = target;
subject.PrimaryPoint = primaryPoint;
subject.SecondaryPoint = secondaryPoint;
subject.MinimumScaleLimit = Vector3.one * 0.5f;
subject.MaximumScaleLimit = Vector3.one * 2f;

Assert.That(target.transform.localScale, Is.EqualTo(Vector3.one).Using(comparer));

subject.Process();

primaryPoint.transform.position = Vector3.forward * 1f;
secondaryPoint.transform.position = Vector3.forward * -1f;
subject.Process();

Assert.That(target.transform.localScale, Is.EqualTo(Vector3.one * 2f).Using(comparer));

primaryPoint.transform.position = Vector3.forward * 1f;
secondaryPoint.transform.position = Vector3.forward * 1f;
subject.Process();

Assert.That(target.transform.localScale, Is.EqualTo(Vector3.one * 0.5f).Using(comparer));

subject.ApplyScaleOnAxis = Vector3State.XYOnly;

primaryPoint.transform.position = Vector3.forward * 1f;
secondaryPoint.transform.position = Vector3.forward * -1f;
subject.Process();

Assert.That(target.transform.localScale, Is.EqualTo(new Vector3(2f, 2f, 0.5f)).Using(comparer));

Object.DestroyImmediate(target);
Object.DestroyImmediate(primaryPoint);
Object.DestroyImmediate(secondaryPoint);
}

[Test]
public void ProcessNoPrimaryPoint()
{
Expand Down

0 comments on commit 498ff2d

Please sign in to comment.