Initial release of the Unity plugin.
PiperOrigin-RevId: 425947505
This commit is contained in:
committed by
Saran Tunyasuvunakool
parent
8ec3dd97a4
commit
6de9eafa13
@@ -0,0 +1,239 @@
|
||||
// Copyright 2019 DeepMind Technologies Limited
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Mujoco {
|
||||
|
||||
[TestFixture]
|
||||
public class FindParentComponentTests {
|
||||
public class FakeMjComponent : MjComponent {
|
||||
public override MujocoLib.mjtObj ObjectType => MujocoLib.mjtObj.mjOBJ_GEOM;
|
||||
protected override void OnParseMjcf(XmlElement mjcf) {}
|
||||
protected override XmlElement OnGenerateMjcf(XmlDocument doc) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class FakeGenericComponent : MonoBehaviour {}
|
||||
|
||||
private FakeMjComponent _parent;
|
||||
private FakeMjComponent _child;
|
||||
private FakeMjComponent _secondChild;
|
||||
private FakeGenericComponent _hierarchyBreaker;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() {
|
||||
_parent =
|
||||
new GameObject("parent", typeof(FakeMjComponent)).GetComponent<FakeMjComponent>();
|
||||
_child =
|
||||
new GameObject("child", typeof(FakeMjComponent)).GetComponent<FakeMjComponent>();
|
||||
_secondChild = new GameObject("secondChild", typeof(FakeMjComponent))
|
||||
.GetComponent<FakeMjComponent>();
|
||||
_hierarchyBreaker = new GameObject("hierarchyBreaker", typeof(FakeGenericComponent))
|
||||
.GetComponent<FakeGenericComponent>();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown() {
|
||||
GameObject.DestroyImmediate(_secondChild.gameObject);
|
||||
GameObject.DestroyImmediate(_child.gameObject);
|
||||
GameObject.DestroyImmediate(_hierarchyBreaker.gameObject);
|
||||
GameObject.DestroyImmediate(_parent.gameObject);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FindParentWithMjComponentAsImmediateParent() {
|
||||
_child.transform.parent = _parent.transform;
|
||||
Assert.That(MjHierarchyTool.FindParentComponent(_child), Is.EqualTo(_parent));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FindParentWithHavingToSkipAParent() {
|
||||
_hierarchyBreaker.transform.parent = _parent.transform;
|
||||
_child.transform.parent = _hierarchyBreaker.transform;
|
||||
Assert.That(MjHierarchyTool.FindParentComponent(_child), Is.EqualTo(_parent));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FindParentWitNoMjComponentParent() {
|
||||
_child.transform.parent = _hierarchyBreaker.transform;
|
||||
Assert.That(MjHierarchyTool.FindParentComponent(_child), Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InChainOfThreeTheCorrectImmediateParentIsPicked() {
|
||||
_child.transform.parent = _parent.transform;
|
||||
_secondChild.transform.parent = _child.transform;
|
||||
Assert.That(MjHierarchyTool.FindParentComponent(_secondChild), Is.EqualTo(_child));
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
public class HierachyLinearizationTests {
|
||||
public class FakeMjComponent : MjComponent {
|
||||
public override MujocoLib.mjtObj ObjectType => MujocoLib.mjtObj.mjOBJ_GEOM;
|
||||
protected override void OnParseMjcf(XmlElement mjcf) {}
|
||||
protected override XmlElement OnGenerateMjcf(XmlDocument doc) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class FakeGenericComponent : MonoBehaviour {}
|
||||
|
||||
private FakeMjComponent _root;
|
||||
private FakeMjComponent _node01;
|
||||
private FakeMjComponent _node02;
|
||||
private FakeMjComponent _node11;
|
||||
private FakeMjComponent _node21;
|
||||
private FakeGenericComponent _hierarchyBreaker;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() {
|
||||
_root =
|
||||
new GameObject("root", typeof(FakeMjComponent)).GetComponent<FakeMjComponent>();
|
||||
_node01 =
|
||||
new GameObject("node01", typeof(FakeMjComponent)).GetComponent<FakeMjComponent>();
|
||||
_node02 =
|
||||
new GameObject("node02", typeof(FakeMjComponent)).GetComponent<FakeMjComponent>();
|
||||
_node11 =
|
||||
new GameObject("node11", typeof(FakeMjComponent)).GetComponent<FakeMjComponent>();
|
||||
_node21 =
|
||||
new GameObject("node21", typeof(FakeMjComponent)).GetComponent<FakeMjComponent>();
|
||||
_hierarchyBreaker = new GameObject("hierarchyBreaker", typeof(FakeGenericComponent))
|
||||
.GetComponent<FakeGenericComponent>();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown() {
|
||||
GameObject.DestroyImmediate(_node21.gameObject);
|
||||
GameObject.DestroyImmediate(_node11.gameObject);
|
||||
GameObject.DestroyImmediate(_node02.gameObject);
|
||||
GameObject.DestroyImmediate(_node01.gameObject);
|
||||
GameObject.DestroyImmediate(_hierarchyBreaker.gameObject);
|
||||
GameObject.DestroyImmediate(_root.gameObject);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OneNodeHierarchy() {
|
||||
var hierarchy = MjHierarchyTool.LinearizeHierarchyBFS(_root.transform).ToArray();
|
||||
Assert.That(hierarchy, Has.Length.EqualTo(1));
|
||||
Assert.That(hierarchy[0], Is.EqualTo(_root));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OneLevelDeepTreeExclusivelyWithMjComponents() {
|
||||
_node01.transform.parent = _root.transform;
|
||||
_node02.transform.parent = _root.transform;
|
||||
var hierarchy = MjHierarchyTool.LinearizeHierarchyBFS(_root.transform).ToArray();
|
||||
Assert.That(hierarchy, Has.Length.EqualTo(3));
|
||||
Assert.That(hierarchy[0], Is.EqualTo(_root));
|
||||
Assert.That(hierarchy[1], Is.EqualTo(_node01));
|
||||
Assert.That(hierarchy[2], Is.EqualTo(_node02));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeepTreeExclusivelyWithMjComponents() {
|
||||
_node01.transform.parent = _root.transform;
|
||||
_node02.transform.parent = _root.transform;
|
||||
_node11.transform.parent = _node01.transform;
|
||||
_node21.transform.parent = _node02.transform;
|
||||
var hierarchy = MjHierarchyTool.LinearizeHierarchyBFS(_root.transform).ToArray();
|
||||
Assert.That(hierarchy, Has.Length.EqualTo(5));
|
||||
Assert.That(hierarchy[0], Is.EqualTo(_root));
|
||||
Assert.That(hierarchy[1], Is.EqualTo(_node01));
|
||||
Assert.That(hierarchy[2], Is.EqualTo(_node02));
|
||||
Assert.That(hierarchy[3], Is.EqualTo(_node11));
|
||||
Assert.That(hierarchy[4], Is.EqualTo(_node21));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TreeWithAGenericComponent() {
|
||||
_node01.transform.parent = _root.transform;
|
||||
_hierarchyBreaker.transform.parent = _root.transform;
|
||||
_node02.transform.parent = _hierarchyBreaker.transform;
|
||||
var hierarchy = MjHierarchyTool.LinearizeHierarchyBFS(_root.transform).ToArray();
|
||||
Assert.That(hierarchy, Has.Length.EqualTo(3));
|
||||
Assert.That(hierarchy[0], Is.EqualTo(_root));
|
||||
Assert.That(hierarchy[1], Is.EqualTo(_node01));
|
||||
Assert.That(hierarchy[2], Is.EqualTo(_node02));
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
public class GetComponentsInImmediateChildrenTests {
|
||||
public class FakeComponentA : MonoBehaviour {}
|
||||
public class FakeComponentB : MonoBehaviour {}
|
||||
|
||||
private FakeComponentA _root;
|
||||
private FakeComponentA _validChild;
|
||||
private FakeComponentB _invalidChild;
|
||||
private FakeComponentA _validGrandchild;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() {
|
||||
_root = new GameObject("root", typeof(FakeComponentA)).GetComponent<FakeComponentA>();
|
||||
_validChild =
|
||||
new GameObject("validChild", typeof(FakeComponentA)).GetComponent<FakeComponentA>();
|
||||
_invalidChild =
|
||||
new GameObject("invalidChild", typeof(FakeComponentB)).GetComponent<FakeComponentB>();
|
||||
_validGrandchild =
|
||||
new GameObject("validGrandchild", typeof(FakeComponentA)).GetComponent<FakeComponentA>();
|
||||
_validGrandchild.transform.parent = _validChild.transform;
|
||||
_validChild.transform.parent = _root.transform;
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown() {
|
||||
GameObject.DestroyImmediate(_validGrandchild.gameObject);
|
||||
GameObject.DestroyImmediate(_invalidChild.gameObject);
|
||||
GameObject.DestroyImmediate(_validChild.gameObject);
|
||||
GameObject.DestroyImmediate(_root.gameObject);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RootNodeIsIgnoredInTheSearch() {
|
||||
var components =
|
||||
MjHierarchyTool.GetComponentsInImmediateChildren<FakeComponentA>(_root.transform);
|
||||
Assert.That(components, Has.No.Member(_root));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ImmediateValidChildIsReturned() {
|
||||
var components =
|
||||
MjHierarchyTool.GetComponentsInImmediateChildren<FakeComponentA>(_root.transform);
|
||||
Assert.That(components, Has.Member(_validChild));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ChildWithAnInvalidTypeIsIgnored() {
|
||||
var components =
|
||||
MjHierarchyTool.GetComponentsInImmediateChildren<FakeComponentA>(_root.transform);
|
||||
Assert.That(components, Has.No.Member(_invalidChild));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GrandchildrenAreIgnoredDuringSearch() {
|
||||
var components =
|
||||
MjHierarchyTool.GetComponentsInImmediateChildren<FakeComponentA>(_root.transform);
|
||||
Assert.That(components, Has.No.Member(_validGrandchild));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2eca32299982b4901a0b01568b992fed
|
||||
timeCreated: 1537463659
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,392 @@
|
||||
// Copyright 2019 DeepMind Technologies Limited
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Xml;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools.Utils;
|
||||
|
||||
namespace Mujoco {
|
||||
|
||||
[TestFixture]
|
||||
public class MjEngineToolXmlLoadingTests {
|
||||
|
||||
[Test]
|
||||
public unsafe void LoadingSceneFromAProvidedAsset() {
|
||||
var modelFile = Resources.Load<TextAsset>("ValidModel");
|
||||
var modelPtr = MjEngineTool.LoadModelFromString(modelFile.text);
|
||||
var model =
|
||||
(MujocoLib.mjModel_)Marshal.PtrToStructure(new IntPtr(modelPtr), typeof(MujocoLib.mjModel_));
|
||||
Assert.That(model.nbody, Is.EqualTo(3));
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
public class MjEngineToolTransformHelpersTests {
|
||||
[TestCase(1, 2, 3)]
|
||||
[TestCase(-1, -2, -3)]
|
||||
[TestCase(-1, 2, 3)]
|
||||
[TestCase(1, -2, 3)]
|
||||
[TestCase(1, 2, -3)]
|
||||
public unsafe void RoundrobinConversionOfVector3(float x, float y, float z) {
|
||||
var vec = new Vector3(x, y, z);
|
||||
var MjVec = MjEngineTool.MjVector3(vec);
|
||||
var MjVecAsArray = new double[] { 10, 11, 12, MjVec.x, MjVec.y, MjVec.z };
|
||||
fixed (double* MjArrPtr = MjVecAsArray) {
|
||||
var recreatedVec = MjEngineTool.UnityVector3(MjArrPtr, 1);
|
||||
Assert.That(recreatedVec, Is.EqualTo(vec));
|
||||
}
|
||||
}
|
||||
|
||||
[TestCase(1, 2, 3)]
|
||||
[TestCase(-1, -2, -3)]
|
||||
[TestCase(-1, 2, 3)]
|
||||
[TestCase(1, -2, 3)]
|
||||
[TestCase(1, 2, -3)]
|
||||
public void RoundrobinConversionOfVector3UsingCoreType(float x, float y, float z) {
|
||||
var vec = new Vector3(x, y, z);
|
||||
var MjVec = MjEngineTool.MjVector3(vec);
|
||||
var unityVec = MjEngineTool.UnityVector3(MjVec);
|
||||
Assert.That(unityVec, Is.EqualTo(vec));
|
||||
}
|
||||
|
||||
[TestCase(0.1f, 0.2f, 0.3f, 0.4f)]
|
||||
[TestCase(-0.1f, -0.2f, -0.3f, -0.4f)]
|
||||
[TestCase(-0.1f, 0.2f, 0.3f, 0.4f)]
|
||||
[TestCase(0.1f, -0.2f, 0.3f, 0.4f)]
|
||||
[TestCase(0.1f, 0.2f, -0.3f, 0.4f)]
|
||||
[TestCase(0.1f, 0.2f, 0.3f, -0.4f)]
|
||||
public unsafe void RoundrobinConversionOfQuaternion(float x, float y, float z, float w) {
|
||||
var quat = new Quaternion(x, y, z, w);
|
||||
var MjQuat = MjEngineTool.MjQuaternion(quat);
|
||||
var MjQuatAsArray =
|
||||
new double[] { 10, 20, 30, 40, MjQuat.w, MjQuat.x, MjQuat.y, MjQuat.z };
|
||||
var recreatedQuat = MjEngineTool.UnityQuaternion(MjQuatAsArray, 1);
|
||||
var q1 = new Vector4(quat.x, quat.y, quat.z, quat.w);
|
||||
var q2 = new Vector4(recreatedQuat.x, recreatedQuat.y, recreatedQuat.z, recreatedQuat.w);
|
||||
Assert.That(q1, Is.EqualTo(q2));
|
||||
}
|
||||
|
||||
[TestCase(0.1f, 0.2f, 0.3f, 0.4f)]
|
||||
[TestCase(-0.1f, -0.2f, -0.3f, -0.4f)]
|
||||
[TestCase(-0.1f, 0.2f, 0.3f, 0.4f)]
|
||||
[TestCase(0.1f, -0.2f, 0.3f, 0.4f)]
|
||||
[TestCase(0.1f, 0.2f, -0.3f, 0.4f)]
|
||||
[TestCase(0.1f, 0.2f, 0.3f, -0.4f)]
|
||||
public unsafe void RoundrobinConversionOfQuaternionUsingUnsafeArrays(float x, float y, float z,
|
||||
float w) {
|
||||
var quat = new Quaternion(x, y, z, w);
|
||||
var MjQuat = MjEngineTool.MjQuaternion(quat);
|
||||
var MjQuatAsArray =
|
||||
new double[] { 10, 20, 30, 40, MjQuat.w, MjQuat.x, MjQuat.y, MjQuat.z };
|
||||
fixed (double* MjArrPtr = MjQuatAsArray) {
|
||||
var recreatedQuat = MjEngineTool.UnityQuaternion(MjArrPtr, 1);
|
||||
var q1 = new Vector4(quat.x, quat.y, quat.z, quat.w);
|
||||
var q2 = new Vector4(recreatedQuat.x, recreatedQuat.y, recreatedQuat.z, recreatedQuat.w);
|
||||
Assert.That(q1, Is.EqualTo(q2));
|
||||
}
|
||||
}
|
||||
|
||||
[TestCase(0.1f, 0.2f, 0.3f, 0.4f)]
|
||||
[TestCase(-0.1f, -0.2f, -0.3f, -0.4f)]
|
||||
[TestCase(-0.1f, 0.2f, 0.3f, 0.4f)]
|
||||
[TestCase(0.1f, -0.2f, 0.3f, 0.4f)]
|
||||
[TestCase(0.1f, 0.2f, -0.3f, 0.4f)]
|
||||
[TestCase(0.1f, 0.2f, 0.3f, -0.4f)]
|
||||
public void RoundrobinConversionOfQuaternionUsingCoreType(float x, float y, float z, float w) {
|
||||
var quat = new Quaternion(x, y, z, w);
|
||||
var MjQuat = MjEngineTool.MjQuaternion(quat);
|
||||
var unityQuat = MjEngineTool.UnityQuaternion(MjQuat);
|
||||
Assert.That(unityQuat, Is.EqualTo(quat));
|
||||
}
|
||||
|
||||
[TestCase(1, 2, 3)]
|
||||
[TestCase(-1, -2, -3)]
|
||||
[TestCase(-1, 2, 3)]
|
||||
[TestCase(1, -2, 3)]
|
||||
[TestCase(1, 2, -3)]
|
||||
public void RoundrobinConversionOfExtents(float x, float y, float z) {
|
||||
var extents = new Vector3(x, y, z);
|
||||
var MjExtents = MjEngineTool.MjExtents(extents);
|
||||
var unityExtents = MjEngineTool.UnityExtents(MjExtents);
|
||||
Assert.That(MjExtents, Is.Not.EqualTo(extents));
|
||||
Assert.That(unityExtents, Is.EqualTo(extents));
|
||||
}
|
||||
|
||||
[TestCase(0.1f, 0.2f, 0.3f, 0.4f)]
|
||||
[TestCase(-0.1f, -0.2f, -0.3f, -0.4f)]
|
||||
[TestCase(-0.1f, 0.2f, 0.3f, 0.4f)]
|
||||
[TestCase(0.1f, -0.2f, 0.3f, 0.4f)]
|
||||
[TestCase(0.1f, 0.2f, -0.3f, 0.4f)]
|
||||
[TestCase(0.1f, 0.2f, 0.3f, -0.4f)]
|
||||
public unsafe void SettingAndRetrievingQuaternions(float x, float y, float z, float w) {
|
||||
var quat = new Quaternion(x, y, z, w);
|
||||
var result = Quaternion.identity;
|
||||
var buffer = new double[4];
|
||||
fixed (double* unsafeBuffer = buffer) {
|
||||
MjEngineTool.SetMjQuaternion(unsafeBuffer, quat, entryIndex: 0);
|
||||
result = MjEngineTool.UnityQuaternion(unsafeBuffer, entryIndex: 0);
|
||||
}
|
||||
Assert.That(quat, Is.EqualTo(result));
|
||||
}
|
||||
|
||||
[TestCase(1, 2, 3)]
|
||||
[TestCase(-1, -2, -3)]
|
||||
[TestCase(-1, 2, 3)]
|
||||
[TestCase(1, -2, 3)]
|
||||
[TestCase(1, 2, -3)]
|
||||
public unsafe void SettingAndRetrievingVectors(float x, float y, float z) {
|
||||
var vec = new Vector3(x, y, z);
|
||||
var result = Vector3.zero;
|
||||
double[] buffer = new double[3];
|
||||
fixed (double* unsafeBuffer = buffer) {
|
||||
MjEngineTool.SetMjVector3(unsafeBuffer, vec, entryIndex: 0);
|
||||
result = MjEngineTool.UnityVector3(unsafeBuffer, entryIndex: 0);
|
||||
}
|
||||
Assert.That(vec, Is.EqualTo(result));
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
public class MjEngineToolTransformSerializationTests {
|
||||
public class FakeMjComponent : MjComponent {
|
||||
public override MujocoLib.mjtObj ObjectType => MujocoLib.mjtObj.mjOBJ_GEOM;
|
||||
|
||||
protected override void OnParseMjcf(XmlElement mjcf) {}
|
||||
|
||||
protected override XmlElement OnGenerateMjcf(XmlDocument doc) {
|
||||
return doc.CreateElement("geom");
|
||||
}
|
||||
}
|
||||
|
||||
private GameObject _rootObject;
|
||||
private GameObject _intermediateObject;
|
||||
private FakeMjComponent _component;
|
||||
private Vector3EqualityComparer _vectorComparer;
|
||||
private Vector4EqualityComparer _quaternionComparer;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() {
|
||||
_rootObject = new GameObject("rootObject");
|
||||
_intermediateObject = new GameObject("intermediateObject");
|
||||
_component = new GameObject("component").AddComponent<FakeMjComponent>();
|
||||
var epsilon = 1e-3f;
|
||||
_vectorComparer = new Vector3EqualityComparer(epsilon);
|
||||
_quaternionComparer = new Vector4EqualityComparer(epsilon);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown() {
|
||||
UnityEngine.Object.DestroyImmediate(_component.gameObject);
|
||||
UnityEngine.Object.DestroyImmediate(_intermediateObject);
|
||||
UnityEngine.Object.DestroyImmediate(_rootObject);
|
||||
MjSceneImportSettings.AnglesInDegrees = true;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializingPositionRotationOfRootComponent() {
|
||||
_component.transform.position = new Vector3(1, 2, 3);
|
||||
_component.transform.rotation = Quaternion.AngleAxis(45, Vector3.up);
|
||||
var doc = new XmlDocument();
|
||||
var mjcf = doc.CreateElement("element");
|
||||
MjEngineTool.PositionRotationToMjcf(mjcf, _component);
|
||||
Assert.That(mjcf.GetAttribute("pos"), Is.EqualTo("1 3 2"));
|
||||
Assert.That(mjcf.GetQuaternionAttribute("quat", Quaternion.identity),
|
||||
Is.EqualTo(new Quaternion(w:-0.9238795f, x:0, y:0, z:0.3826835f))
|
||||
.Using(_quaternionComparer));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializingPositionRotationOfRootComponentParentedToGameObject() {
|
||||
_component.transform.parent = _rootObject.transform;
|
||||
_rootObject.transform.position = new Vector3(1, 2, 3);
|
||||
_rootObject.transform.rotation = Quaternion.AngleAxis(45, Vector3.up);
|
||||
var doc = new XmlDocument();
|
||||
var mjcf = doc.CreateElement("element");
|
||||
MjEngineTool.PositionRotationToMjcf(mjcf, _component);
|
||||
Assert.That(mjcf.GetAttribute("pos"), Is.EqualTo("1 3 2"));
|
||||
Assert.That(mjcf.GetQuaternionAttribute("quat", Quaternion.identity),
|
||||
Is.EqualTo(new Quaternion(w:-0.9238795f, x:0, y:0, z:0.3826835f))
|
||||
.Using(_quaternionComparer));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializingPositionRotationOfChildComponentParentedThroughGameObject() {
|
||||
_component.transform.parent = _intermediateObject.transform;
|
||||
_intermediateObject.transform.parent = _rootObject.transform;
|
||||
_intermediateObject.transform.position = new Vector3(1, 2, 3);
|
||||
_intermediateObject.transform.rotation = Quaternion.AngleAxis(45, Vector3.up);
|
||||
var doc = new XmlDocument();
|
||||
var mjcf = doc.CreateElement("element");
|
||||
MjEngineTool.PositionRotationToMjcf(mjcf, _component);
|
||||
Assert.That(mjcf.GetAttribute("pos"), Is.EqualTo("1 3 2"));
|
||||
Assert.That(mjcf.GetQuaternionAttribute("quat", Quaternion.identity),
|
||||
Is.EqualTo(new Quaternion(w:-0.9238795f, x:0, y:0, z:0.3826835f))
|
||||
.Using(_quaternionComparer));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializingPositionAxisOfRootComponent() {
|
||||
_component.transform.position = new Vector3(1, 2, 3);
|
||||
_component.transform.rotation = Quaternion.AngleAxis(45, Vector3.up);
|
||||
var doc = new XmlDocument();
|
||||
var mjcf = doc.CreateElement("element");
|
||||
MjEngineTool.PositionAxisToMjcf(mjcf, _component);
|
||||
Assert.That(mjcf.GetAttribute("pos"), Is.EqualTo("1 3 2"));
|
||||
Assert.That(mjcf.GetVector3Attribute("axis", Vector3.zero),
|
||||
Is.EqualTo(new Vector3(0.7071068f, -0.7071069f, 0)).Using(_vectorComparer));
|
||||
Assert.That(mjcf.GetAttribute("ref"), Is.EqualTo("0"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializingPositionAxisOfRootComponentParentedToGameObject() {
|
||||
_component.transform.parent = _rootObject.transform;
|
||||
_rootObject.transform.position = new Vector3(1, 2, 3);
|
||||
_rootObject.transform.rotation = Quaternion.AngleAxis(45, Vector3.up);
|
||||
var doc = new XmlDocument();
|
||||
var mjcf = doc.CreateElement("element");
|
||||
MjEngineTool.PositionAxisToMjcf(mjcf, _component);
|
||||
Assert.That(mjcf.GetAttribute("pos"), Is.EqualTo("1 3 2"));
|
||||
Assert.That(mjcf.GetVector3Attribute("axis", Vector3.zero),
|
||||
Is.EqualTo(new Vector3(0.7071068f, -0.7071069f, 0)).Using(_vectorComparer));
|
||||
Assert.That(mjcf.GetAttribute("ref"), Is.EqualTo("0"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializingPositionAxisOfChildComponentParentedThroughGameObject() {
|
||||
_component.transform.parent = _intermediateObject.transform;
|
||||
_intermediateObject.transform.parent = _rootObject.transform;
|
||||
_intermediateObject.transform.position = new Vector3(1, 2, 3);
|
||||
_intermediateObject.transform.rotation = Quaternion.AngleAxis(45, Vector3.up);
|
||||
var doc = new XmlDocument();
|
||||
var mjcf = doc.CreateElement("element");
|
||||
MjEngineTool.PositionAxisToMjcf(mjcf, _component);
|
||||
Assert.That(mjcf.GetAttribute("pos"), Is.EqualTo("1 3 2"));
|
||||
Assert.That(mjcf.GetVector3Attribute("axis", Vector3.zero),
|
||||
Is.EqualTo(new Vector3(0.7071068f, -0.7071069f, 0)).Using(_vectorComparer));
|
||||
Assert.That(mjcf.GetAttribute("ref"), Is.EqualTo("0"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParsePosition() {
|
||||
var mjcf = new XmlDocument().CreateElement("element");
|
||||
mjcf.SetAttribute("pos", "1 3 2");
|
||||
MjEngineTool.ParseTransformMjcf(mjcf, _rootObject.transform);
|
||||
Assert.That(_rootObject.transform.position, Is.EqualTo(new Vector3(1, 2, 3)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParseRotationFromQuat() {
|
||||
var mjcf = new XmlDocument().CreateElement("element");
|
||||
mjcf.SetAttribute("quat", "-0.9238795 0 0 0.3826835");
|
||||
MjEngineTool.ParseTransformMjcf(mjcf, _rootObject.transform);
|
||||
var expectedRotation = Quaternion.AngleAxis(45, Vector3.up);
|
||||
Assert.That(_rootObject.transform.rotation.x, Is.EqualTo(expectedRotation.x).Within(1e-5f));
|
||||
Assert.That(_rootObject.transform.rotation.y, Is.EqualTo(expectedRotation.y).Within(1e-5f));
|
||||
Assert.That(_rootObject.transform.rotation.z, Is.EqualTo(expectedRotation.z).Within(1e-5f));
|
||||
Assert.That(_rootObject.transform.rotation.w, Is.EqualTo(expectedRotation.w).Within(1e-5f));
|
||||
// Assert.That(
|
||||
// _rootObject.transform.rotation,
|
||||
// Is.EqualTo(Quaternion.AngleAxis(45, Vector3.up))
|
||||
// .Using(_quaternionComparer));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParseRotationFromZAxis() {
|
||||
var mjcf = new XmlDocument().CreateElement("element");
|
||||
mjcf.SetAttribute("zaxis", "0 1 0");
|
||||
MjEngineTool.ParseTransformMjcf(mjcf, _rootObject.transform);
|
||||
var expectedRotation = Quaternion.AngleAxis(90, Vector3.right);
|
||||
Assert.That(_rootObject.transform.rotation.x, Is.EqualTo(expectedRotation.x).Within(1e-5f));
|
||||
Assert.That(_rootObject.transform.rotation.y, Is.EqualTo(expectedRotation.y).Within(1e-5f));
|
||||
Assert.That(_rootObject.transform.rotation.z, Is.EqualTo(expectedRotation.z).Within(1e-5f));
|
||||
Assert.That(_rootObject.transform.rotation.w, Is.EqualTo(expectedRotation.w).Within(1e-5f));
|
||||
// Assert.That(
|
||||
// _rootObject.transform.rotation,
|
||||
// Is.EqualTo(Quaternion.AngleAxis(90, Vector3.right))
|
||||
// .Using(_quaternionComparer));
|
||||
}
|
||||
|
||||
[TestCase(true, 45, 45)]
|
||||
[TestCase(false, 0.785398f, 45)]
|
||||
[TestCase(true, 90, 90)]
|
||||
[TestCase(false, 1.570796f, 90)]
|
||||
public void ParseRotationFromAxisAngle(bool useDegrees, float MjAngle,
|
||||
float expectedAngle) {
|
||||
MjSceneImportSettings.AnglesInDegrees = useDegrees;
|
||||
var mjcf = new XmlDocument().CreateElement("element");
|
||||
mjcf.SetAttribute("axisangle", $"1 0 0 {MjAngle}");
|
||||
MjEngineTool.ParseTransformMjcf(mjcf, _rootObject.transform);
|
||||
var expectedRotation = Quaternion.AngleAxis(expectedAngle, Vector3.right);
|
||||
Assert.That(_rootObject.transform.rotation.x, Is.EqualTo(expectedRotation.x).Within(1e-5f));
|
||||
Assert.That(_rootObject.transform.rotation.y, Is.EqualTo(expectedRotation.y).Within(1e-5f));
|
||||
Assert.That(_rootObject.transform.rotation.z, Is.EqualTo(expectedRotation.z).Within(1e-5f));
|
||||
Assert.That(_rootObject.transform.rotation.w, Is.EqualTo(expectedRotation.w).Within(1e-5f));
|
||||
// Assert.That(
|
||||
// _rootObject.transform.rotation,
|
||||
// Is.EqualTo(Quaternion.AngleAxis(expectedAngle, Vector3.right))
|
||||
// .Using(_quaternionComparer));
|
||||
}
|
||||
|
||||
[TestCase(true, 0, 45, 0, 0, 0, -45)]
|
||||
[TestCase(false, 0, 0.785398f, 0, 0, 0, -45)]
|
||||
[TestCase(true, 0, 0, 45, 0, 45, 0)]
|
||||
[TestCase(false, 0, 0, 0.785398f, 0, 45, 0)]
|
||||
[TestCase(true, 45, 0, 0, 45, 0, 0)]
|
||||
[TestCase(false, 0.785398f, 0, 0, 45, 0, 0)]
|
||||
public void ParseRotationFromEuler(bool useDegrees, float mx, float my, float mz, float ex,
|
||||
float ey, float ez) {
|
||||
MjSceneImportSettings.AnglesInDegrees = useDegrees;
|
||||
var mjcf = new XmlDocument().CreateElement("element");
|
||||
mjcf.SetAttribute("euler", $"{mx} {my} {mz}");
|
||||
MjEngineTool.ParseTransformMjcf(mjcf, _rootObject.transform);
|
||||
var expectedRotation = Quaternion.Euler(ex, ey, ez);
|
||||
Assert.That(_rootObject.transform.rotation.x, Is.EqualTo(expectedRotation.x).Within(1e-5f));
|
||||
Assert.That(_rootObject.transform.rotation.y, Is.EqualTo(expectedRotation.y).Within(1e-5f));
|
||||
Assert.That(_rootObject.transform.rotation.z, Is.EqualTo(expectedRotation.z).Within(1e-5f));
|
||||
Assert.That(_rootObject.transform.rotation.w, Is.EqualTo(expectedRotation.w).Within(1e-5f));
|
||||
// Assert.That(
|
||||
// _rootObject.transform.rotation,
|
||||
// Is.EqualTo(Quaternion.Euler(ex, ey, ez))
|
||||
// .Using(_quaternionComparer));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParseRotationFromDirectionVector() {
|
||||
var mjcf = new XmlDocument().CreateElement("element");
|
||||
mjcf.SetAttribute("fromto", $"0 0 0 1 1 0");
|
||||
MjEngineTool.ParseTransformMjcf(mjcf, _rootObject.transform);
|
||||
var expectedRotation = new Quaternion(0.5f, 0, -0.5f, 0.7071068f);
|
||||
Assert.That(_rootObject.transform.rotation.x, Is.EqualTo(expectedRotation.x).Within(1e-5f));
|
||||
Assert.That(_rootObject.transform.rotation.y, Is.EqualTo(expectedRotation.y).Within(1e-5f));
|
||||
Assert.That(_rootObject.transform.rotation.z, Is.EqualTo(expectedRotation.z).Within(1e-5f));
|
||||
Assert.That(_rootObject.transform.rotation.w, Is.EqualTo(expectedRotation.w).Within(1e-5f));
|
||||
// Assert.That(
|
||||
// _rootObject.transform.rotation,
|
||||
// Is.EqualTo(new Quaternion(0.5f, 0, -0.5f, 0.7071068f))
|
||||
// .Using(_quaternionComparer));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParsePositionFromDirectionVector() {
|
||||
var mjcf = new XmlDocument().CreateElement("element");
|
||||
mjcf.SetAttribute("fromto", $"1 2 3 5 7 9");
|
||||
MjEngineTool.ParseTransformMjcf(mjcf, _rootObject.transform);
|
||||
Assert.That(_rootObject.transform.position, Is.EqualTo(new Vector3(3, 6, 4.5f)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ff03f770fd9aa43cd95e04660fd82bb3
|
||||
timeCreated: 1536938636
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,159 @@
|
||||
// Copyright 2019 DeepMind Technologies Limited
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Mujoco {
|
||||
|
||||
[TestFixture]
|
||||
public class MjTransformationTests {
|
||||
[Test]
|
||||
public void ConcatenateTranslation() {
|
||||
var t1 = new MjTransformation(new Vector3(10, 0, 0), Quaternion.identity);
|
||||
var t2 = new MjTransformation(new Vector3(0, 20, 0), Quaternion.identity);
|
||||
var result = t1 * t2;
|
||||
var expectedResult = new MjTransformation(new Vector3(10, 20, 0), Quaternion.identity);
|
||||
CompareTransforms(result, expectedResult);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConcatenateRotation() {
|
||||
var t1 = new MjTransformation(Vector3.zero, Quaternion.Euler(0, 45, 0));
|
||||
var t2 = new MjTransformation(Vector3.zero, Quaternion.Euler(0, 15, 0));
|
||||
var result = t1 * t2;
|
||||
var expectedResult = new MjTransformation(Vector3.zero, Quaternion.Euler(0, 60, 0));
|
||||
CompareTransforms(result, expectedResult);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConcatenateTranslationAndRotation() {
|
||||
var t1 = new MjTransformation(new Vector3(10, 0, 0), Quaternion.Euler(0, 45, 0));
|
||||
var t2 = new MjTransformation(new Vector3(20, 0, 0), Quaternion.Euler(0, 15, 0));
|
||||
var result = t1 * t2;
|
||||
// T2 is some translation and rotation in T1's reference frame. We want to learn what that
|
||||
// transform would look like in global space - as if there was no T1.
|
||||
// T1 is located at (10, 0, 0), and rotates its children by 45 deg around the Y axis.
|
||||
// That means it will rotate T2 translation (20, 0, 0) by 45 degrees. Since the rotation
|
||||
// is performed around the Y axis, the X coordinate 20 will be projected onto X and Z axis
|
||||
// in amount [cos(45deg) * 20, -sin(45deg) * 20] = [14.14213, -14.14213].
|
||||
// Next, the rotation will be added to that of the parent: 45 + 15 = 60 deg.
|
||||
var expectedResult = new MjTransformation(new Vector3(24.14213f, 0, -14.14213f),
|
||||
Quaternion.Euler(0, 60, 0));
|
||||
CompareTransforms(result, expectedResult);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConcatenatingRightInverse() {
|
||||
var t1 = new MjTransformation(new Vector3(10, 0, 0), Quaternion.Euler(0, 45, 0));
|
||||
var result = t1 * t1.Inverse();
|
||||
var expectedResult = new MjTransformation(Vector3.zero, Quaternion.identity);
|
||||
CompareTransforms(result, expectedResult);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConcatenatingLeftInverse() {
|
||||
var t1 = new MjTransformation(new Vector3(10, 0, 0), Quaternion.Euler(0, 45, 0));
|
||||
var result = t1.Inverse() * t1;
|
||||
var expectedResult = new MjTransformation(Vector3.zero, Quaternion.identity);
|
||||
CompareTransforms(result, expectedResult);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MjTransformationsConcatenationIsTheSameAsUnitys() {
|
||||
_parent.transform.position = new Vector3(10, 0, 0);
|
||||
_parent.transform.rotation = Quaternion.Euler(0, 45, 0);
|
||||
_child.transform.localPosition = new Vector3(20, 0, 0);
|
||||
_child.transform.localRotation = Quaternion.Euler(0, 15, 0);
|
||||
var t1 = MjTransformation.LoadGlobal(_parent.transform);
|
||||
var t2 = MjTransformation.LoadLocal(_child.transform);
|
||||
var result = t1 * t2;
|
||||
var expectedResult = MjTransformation.LoadGlobal(_child.transform);
|
||||
var expectedExplicitResult = new MjTransformation(new Vector3(24.14213f, 0, -14.14213f),
|
||||
Quaternion.Euler(0, 60, 0));
|
||||
CompareTransforms(result, expectedResult);
|
||||
CompareTransforms(result, expectedExplicitResult);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LoadingGlobalTransform() {
|
||||
var result = MjTransformation.LoadGlobal(_parent.transform);
|
||||
CompareTransforms(result, _parent.transform.position, _parent.transform.rotation);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LoadingLocalTransform() {
|
||||
var result = MjTransformation.LoadLocal(_parent.transform);
|
||||
CompareTransforms(result, _parent.transform.localPosition, _parent.transform.localRotation);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StoringGlobalTransform() {
|
||||
var transform = new MjTransformation(new Vector3(1, 2, 3), Quaternion.Euler(0, 45, 0));
|
||||
transform.StoreGlobal(_parent.transform);
|
||||
CompareTransforms(transform, _parent.transform.position, _parent.transform.rotation);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StoringLocalTransform() {
|
||||
var transform = new MjTransformation(new Vector3(1, 2, 3), Quaternion.Euler(0, 45, 0));
|
||||
transform.StoreGlobal(_parent.transform);
|
||||
CompareTransforms(transform, _parent.transform.localPosition,
|
||||
_parent.transform.localRotation);
|
||||
}
|
||||
|
||||
#region Setup
|
||||
|
||||
private GameObject _parent;
|
||||
private GameObject _child;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() {
|
||||
_parent = new GameObject("parent");
|
||||
_child = new GameObject("child");
|
||||
_child.transform.parent = _parent.transform;
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown() {
|
||||
UnityEngine.Object.DestroyImmediate(_parent);
|
||||
}
|
||||
|
||||
private void CompareTransforms(MjTransformation lhs, MjTransformation rhs) {
|
||||
Assert.That(lhs.Translation.x, Is.EqualTo(rhs.Translation.x).Within(1e-5f));
|
||||
Assert.That(lhs.Translation.y, Is.EqualTo(rhs.Translation.y).Within(1e-5f));
|
||||
Assert.That(lhs.Translation.z, Is.EqualTo(rhs.Translation.z).Within(1e-5f));
|
||||
Assert.That(lhs.Rotation.x, Is.EqualTo(rhs.Rotation.x).Within(1e-5f));
|
||||
Assert.That(lhs.Rotation.y, Is.EqualTo(rhs.Rotation.y).Within(1e-5f));
|
||||
Assert.That(lhs.Rotation.z, Is.EqualTo(rhs.Rotation.z).Within(1e-5f));
|
||||
Assert.That(lhs.Rotation.w, Is.EqualTo(rhs.Rotation.w).Within(1e-5f));
|
||||
}
|
||||
|
||||
private void CompareTransforms(MjTransformation lhs, Vector3 position,
|
||||
Quaternion rotation) {
|
||||
Assert.That(lhs.Translation.x, Is.EqualTo(position.x).Within(1e-5f));
|
||||
Assert.That(lhs.Translation.y, Is.EqualTo(position.y).Within(1e-5f));
|
||||
Assert.That(lhs.Translation.z, Is.EqualTo(position.z).Within(1e-5f));
|
||||
Assert.That(lhs.Rotation.x, Is.EqualTo(rotation.x).Within(1e-5f));
|
||||
Assert.That(lhs.Rotation.y, Is.EqualTo(rotation.y).Within(1e-5f));
|
||||
Assert.That(lhs.Rotation.z, Is.EqualTo(rotation.z).Within(1e-5f));
|
||||
Assert.That(lhs.Rotation.w, Is.EqualTo(rotation.w).Within(1e-5f));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 232da11066f724246bf5b820d6647261
|
||||
timeCreated: 1551107971
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright 2019 DeepMind Technologies Limited
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Mujoco {
|
||||
|
||||
using static MujocoLib;
|
||||
|
||||
[TestFixture]
|
||||
public class MjVfsTests {
|
||||
private MjVfs _vfs;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() {
|
||||
_vfs = new MjVfs();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown() {
|
||||
_vfs.Dispose();
|
||||
_vfs = null;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public unsafe void AddingNewFile() {
|
||||
var filename = "filename";
|
||||
var contents = "contents";
|
||||
_vfs.AddFile(filename, contents);
|
||||
Assert.That(_vfs.FilesCount, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public unsafe void LocatingFileUsingMujocoLib() {
|
||||
var filename = "filename";
|
||||
_vfs.AddFile(filename, "contents");
|
||||
Assert.That(_vfs.FindFile(filename), Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public unsafe void AddedFileContentsAreCorrect() {
|
||||
var filename = "filename";
|
||||
var contents = "contents";
|
||||
_vfs.AddFile(filename, contents);
|
||||
var filedata = Marshal.PtrToStringAnsi(_vfs.Data.filedata[0]);
|
||||
Assert.That(filedata, Is.EqualTo(contents));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 41b2695e2bc7a4317bc759f1eae39ab2
|
||||
timeCreated: 1535647485
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 676e0a086d0ff32f6b91e644a9fc1f23
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,30 @@
|
||||
<!--
|
||||
Copyright 2019 DeepMind Technologies Limited
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<mujoco>
|
||||
<option gravity="0 -9.81 0" />
|
||||
<worldbody>
|
||||
<geom name="ground" type="plane" size="5 5 1" euler="-90 0 0"/>
|
||||
<body name="parent" pos="0 10 0">
|
||||
<geom name="parent_shape" type="sphere" size="0.5"/>
|
||||
<joint type="free" />
|
||||
<body name="child" pos="2 1 0">
|
||||
<geom name="child_shape" type="sphere" size="0.5"/>
|
||||
<joint type="hinge" axis="1 0 0"/>
|
||||
</body>
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4ec05e5bec3e158bb9cf4cc868f75f03
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,193 @@
|
||||
// Copyright 2019 DeepMind Technologies Limited
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Mujoco {
|
||||
|
||||
[TestFixture]
|
||||
public class XmlElementExtensionsEditorTests {
|
||||
public enum TestEnum { ValueDefault, ValueA }
|
||||
|
||||
private XmlElement _element;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() {
|
||||
var doc = new XmlDocument();
|
||||
_element = doc.CreateElement("element");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParsingMissingFloatAttribute() {
|
||||
Assert.That(_element.GetFloatAttribute("attrib", 7.0f), Is.EqualTo(7.0f));
|
||||
}
|
||||
|
||||
[TestCase("5.1", 5.1f)]
|
||||
[TestCase("-4.83", -4.83f)]
|
||||
public void ParsingFloatAttribute(string input, float expected) {
|
||||
_element.SetAttribute("attrib", input);
|
||||
Assert.That(_element.GetFloatAttribute("attrib", 7.0f), Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[TestCase("")]
|
||||
[TestCase("string value")]
|
||||
public void InvalidFloatValueTriggersAnException(string input) {
|
||||
_element.SetAttribute("attrib", input);
|
||||
Assert.That(() => { _element.GetFloatAttribute("attrib", 7.0f); }, Throws.Exception);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParsingMissingEnumAttribute() {
|
||||
Assert.That(_element.GetEnumAttribute<TestEnum>("attrib", TestEnum.ValueDefault),
|
||||
Is.EqualTo(TestEnum.ValueDefault));
|
||||
}
|
||||
|
||||
[TestCase("ValueA", TestEnum.ValueA)]
|
||||
[TestCase("valuea", TestEnum.ValueA)]
|
||||
public void ParsingEnumAttributeIsCaseInsensitive(string input, TestEnum expected) {
|
||||
_element.SetAttribute("attrib", input);
|
||||
Assert.That(_element.GetEnumAttribute<TestEnum>("attrib", TestEnum.ValueDefault, true),
|
||||
Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[TestCase("")]
|
||||
[TestCase("wrong value")]
|
||||
public void InvalidEnumValueTriggersAnException(string input) {
|
||||
_element.SetAttribute("attrib", input);
|
||||
Assert.That(() => { _element.GetEnumAttribute<TestEnum>("attrib", TestEnum.ValueDefault); },
|
||||
Throws.Exception);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParsingMissingStringAttribute() {
|
||||
Assert.That(_element.GetStringAttribute("attrib", "missing"), Is.EqualTo("missing"));
|
||||
}
|
||||
|
||||
[TestCase("value", "value")]
|
||||
[TestCase("", "")]
|
||||
public void ParsingStringAttributes(string input, string expected) {
|
||||
_element.SetAttribute("attrib", input);
|
||||
Assert.That(_element.GetStringAttribute("attrib", "missing"), Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParsingMissingVector3Attribute() {
|
||||
Assert.That(_element.GetVector3Attribute("attrib", Vector3.one), Is.EqualTo(Vector3.one));
|
||||
}
|
||||
|
||||
public void ParsingVector3Attributes() {
|
||||
_element.SetAttribute("attrib", "-1 2 3.5");
|
||||
var expected = new Vector3(-1, 2, 3.5f);
|
||||
Assert.That(_element.GetVector3Attribute("attrib", Vector3.one), Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[TestCase("1 2")]
|
||||
[TestCase("1")]
|
||||
[TestCase("")]
|
||||
public void Vector3WithInsufficientNumberOfComponentsTriggersAnException(string input) {
|
||||
_element.SetAttribute("attrib", input);
|
||||
Assert.That(() => { _element.GetVector3Attribute("attrib", Vector3.one); }, Throws.Exception);
|
||||
}
|
||||
|
||||
[TestCase("a 2 3")]
|
||||
[TestCase("1 b 3")]
|
||||
[TestCase("1 2 c")]
|
||||
public void InvalidVector3ComponentValueTriggersException(string input) {
|
||||
_element.SetAttribute("attrib", input);
|
||||
Assert.That(() => { _element.GetVector3Attribute("attrib", Vector3.one); }, Throws.Exception);
|
||||
}
|
||||
|
||||
public void ParsingVector2Attributes() {
|
||||
_element.SetAttribute("attrib", "-1 2.5");
|
||||
var expected = new Vector3(-1, 2.5f);
|
||||
Assert.That(_element.GetVector2Attribute("attrib", Vector2.one), Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[TestCase("1")]
|
||||
[TestCase("")]
|
||||
public void Vector2WithInsufficientNumberOfComponentsTriggersAnException(string input) {
|
||||
_element.SetAttribute("attrib", input);
|
||||
Assert.That(() => { _element.GetVector2Attribute("attrib", Vector2.one); }, Throws.Exception);
|
||||
}
|
||||
|
||||
[TestCase("a 2")]
|
||||
[TestCase("1 b")]
|
||||
public void InvalidVector2ComponentValueTriggersException(string input) {
|
||||
_element.SetAttribute("attrib", input);
|
||||
Assert.That(() => { _element.GetVector2Attribute("attrib", Vector2.one); }, Throws.Exception);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParsingMissingQuaternionAttribute() {
|
||||
Assert.That(_element.GetQuaternionAttribute("attrib", Quaternion.identity),
|
||||
Is.EqualTo(Quaternion.identity));
|
||||
}
|
||||
|
||||
public void ParsingQuaternionAttributes() {
|
||||
_element.SetAttribute("attrib", "0.1 0.2 0.3 0.4");
|
||||
var expected = new Quaternion(0.1f, 0.2f, 0.3f, 0.4f);
|
||||
Assert.That(_element.GetQuaternionAttribute("attrib", Quaternion.identity),
|
||||
Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[TestCase("1 2 3")]
|
||||
[TestCase("1 2")]
|
||||
[TestCase("1")]
|
||||
[TestCase("")]
|
||||
public void QuaternionWithInsufficientNumberOfComponentsTriggersAnException(string input) {
|
||||
_element.SetAttribute("attrib", input);
|
||||
Assert.That(() => { _element.GetQuaternionAttribute("attrib", Quaternion.identity); },
|
||||
Throws.Exception);
|
||||
}
|
||||
|
||||
[TestCase("a 2 3 4")]
|
||||
[TestCase("1 b 3 4")]
|
||||
[TestCase("1 2 c 4")]
|
||||
[TestCase("1 2 3 d")]
|
||||
public void InvalidQuaternionComponentValueTriggersException(string input) {
|
||||
_element.SetAttribute("attrib", input);
|
||||
Assert.That(() => { _element.GetQuaternionAttribute("attrib", Quaternion.identity); },
|
||||
Throws.Exception);
|
||||
}
|
||||
|
||||
[TestCase("1 2")]
|
||||
[TestCase("1 2 ")]
|
||||
[TestCase(" 1 2")]
|
||||
public void FloatArraysCanContainArbitraryNumberOfWhitespaces(string input) {
|
||||
_element.SetAttribute("attrib", input);
|
||||
Assert.That(_element.GetFloatArrayAttribute("attrib", defaultValue: null),
|
||||
Is.EqualTo(new float[] { 1, 2 }));
|
||||
}
|
||||
|
||||
public void FloatArraysCanBeFilledUpWithDefaultValues() {
|
||||
_element.SetAttribute("attrib", "1 2");
|
||||
var defaultValue = new float[] { 5, 6, 7, 8 };
|
||||
Assert.That(_element.GetFloatArrayAttribute("attrib", defaultValue: defaultValue),
|
||||
Is.EqualTo(new float[] { 1, 2, 7, 8 }));
|
||||
}
|
||||
|
||||
public void FloatArrayDefaultFillingCanBeSwitchedOff() {
|
||||
_element.SetAttribute("attrib", "1 2");
|
||||
var defaultValue = new float[] { 5, 6, 7, 8 };
|
||||
var result = _element.GetFloatArrayAttribute("attrib", defaultValue: defaultValue,
|
||||
fillMissingValues: false);
|
||||
Assert.That(result, Is.EqualTo(new float[] { 1, 2 }));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c5148652c03104473b634d0ec28103d3
|
||||
timeCreated: 1538662593
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user