Initial Commit

This commit is contained in:
2025-07-04 20:33:06 +03:00
commit 8f09347ae0
9219 changed files with 2447903 additions and 0 deletions
@@ -0,0 +1,188 @@
/*=========================================================================
Library: iMSTK-Unity
Copyright (c) Kitware, Inc.
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.txt
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 UnityEngine;
namespace ImstkUnity
{
/// <summary>
/// GraspingController takes care of some of the higher level aspects of
/// grasping and tool operation, it can manipulate two jaws and open and close
/// them, it can take input from a variety of sources as well
/// </summary>
[RequireComponent(typeof(GraspingManager))]
public class GraspingController : MonoBehaviour
{
// Assumes that the jaws are currently closed, will open
// to the max opening angle
// Rotation is currently just fixed to the Z Axis
public TrackingDevice device;
// TODO disable collision on grasp
/// Drive via Buttons
public int openButton = 0;
public int closeButton = 1;
// Drive via Keys
public string openKey = "]";
public string closeKey = "[";
public bool useSnap = false;
public float transitionTime = 3.0f;
private float openValue = 0.0f;
/// Drive by analog Value
public bool driveWithAnalog = false;
public int analogChannel = 0;
public float analogClosed = 0;
public float analogOpen = 1024;
public GameObject upperJaw;
public GameObject lowerJaw;
[Tooltip("The largest angle between the two jaws")]
public float maxOpenAngle;
GraspingManager _manager;
public GraspingManager manager { get { return _manager; } }
private float _lowerCloseAngle = 0.0f;
private float _upperCloseAngle = 0.0f;
void Start()
{
if (lowerJaw != null)
{
_lowerCloseAngle = lowerJaw.transform.localRotation.eulerAngles.z;
}
if (upperJaw != null)
{
_upperCloseAngle = upperJaw.transform.localRotation.eulerAngles.z;
}
if (!device.isActiveAndEnabled)
{
device = null;
}
// need to check startup order to see if we can initialize the imstk values at this point
// we'd want to do the type check and casting here rather than every frame
_manager = GetComponent<GraspingManager>();
}
// Update is called once per frame
void Update()
{
float newValue = openValue;
if (device == null) return;
if (driveWithAnalog)
{
float input = device.GetAnalog(analogChannel);
#pragma warning disable 1718 // Warning for comparing the same variable
if (input == input)
{
if (analogClosed < analogOpen)
{
newValue = (input - analogClosed) / (analogOpen - analogClosed);
}
else
{
newValue = (analogClosed - input) / (analogClosed - analogOpen);
}
}
#if UNITY_EDITOR
else
{
Debug.LogWarning("Can't read analog from channel: " + analogChannel);
}
#endif
#pragma warning restore 1718
//Debug.Log(Time.realtimeSinceStartup-start + " " + input.ToString());
}
else
{
if (useSnap)
{
if (device.IsButtonDown(openButton) || Input.GetKey(openKey)) newValue = 0.0f;
if (device.IsButtonDown(closeButton) || Input.GetKey(closeKey)) newValue = 1.0f;
}
else
{
// Map buttons to axis, this should probably be in the input _manager
if (device.IsButtonDown(openButton) || Input.GetKey(openKey)) newValue = openValue + Time.deltaTime / transitionTime;
if (device.IsButtonDown(closeButton) || Input.GetKey(closeKey)) newValue = openValue - Time.deltaTime / transitionTime;
}
}
var oldClosed = isClosed();
setOpenValue(Mathf.Clamp01(newValue));
if (isClosed() && !oldClosed)
{
Debug.Log("Start Grasp");
_manager.StartGrasp();
}
if (!isClosed() && oldClosed)
{
_manager.EndGrasp();
}
}
bool isClosed()
{
return openValue < 0.1;
}
void setOpenValue(float value)
{
float half = (maxOpenAngle * value) / 2.0f;
if (upperJaw != null)
{
var rot = upperJaw.transform.localRotation;
var angles = upperJaw.transform.localRotation.eulerAngles;
angles.z = _upperCloseAngle + half;
rot.eulerAngles = angles;
upperJaw.transform.localRotation = rot;
}
if (lowerJaw != null)
{
var rot = lowerJaw.transform.localRotation;
var angles = lowerJaw.transform.localRotation.eulerAngles;
angles.z = _lowerCloseAngle - half;
rot.eulerAngles = angles;
lowerJaw.transform.localRotation = rot;
}
openValue = value;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 484fa8084caf41f4498e3ac6a9a715d1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,120 @@
/*=========================================================================
Library: iMSTK-Unity
Copyright (c) Kitware, Inc.
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.txt
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 UnityEngine;
namespace ImstkUnity
{
/// <summary>
/// Set ups multiple grasping components, handles grasping and upgrasping
/// this set of components. This alleviates the burden to the user to set
/// up multiple grasping components. Plays together with the Grasping Controller
/// that handles the User interaction side of making a tool that can grasp, but
/// can also be used on its own
/// </summary>
public class GraspingManager : MonoBehaviour
{
[Serializable]
public struct GraspingData
{
public bool enabled;
public DynamicalModel target;
public Grasping.GraspType type;
}
public Rigid rigid;
public GeometryFilter graspingGeometry;
public List<GraspingData> graspingData = new List<GraspingData>();
List<Grasping> _graspings = new List<Grasping>();
Coroutine _coroutine;
public double deformableGraspingStiffness = 0.4;
public double rigidGraspingStiffness = 1 / 0.0001;
public
void Awake()
{
// These will be created _before_ the simulation manager searches for
// its component and therefor will participate in the norm imstk-unity
// discovery
foreach (var item in graspingData )
{
if (item.enabled)
{
var grasping = gameObject.AddComponent<Grasping>();
grasping.rigidModel = rigid;
grasping.graspingGeometry = graspingGeometry;
grasping.graspedObject = item.target;
grasping.graspType = item.type;
grasping.deformableGraspingStiffness = deformableGraspingStiffness;
grasping.rigidGraspingStiffness = rigidGraspingStiffness;
_graspings.Add(grasping);
}
}
}
/// <summary>
/// Sets off a corouting to go through all of the graspings that
/// this component created, as it takes a frame to check wether
/// a grasp was successful
/// </summary>
public void StartGrasp()
{
_coroutine = StartCoroutine(CoroutineGrasp());
}
private IEnumerator CoroutineGrasp()
{
foreach (var grasp in _graspings)
{
if (!grasp.enabled) continue;
// It takes a frame for us to detect if the grasp
// has generated constraints, only then do we know
// that something has _actually_ been taken
grasp.StartGrasp();
yield return null;
if (grasp.HasConstraints())
{
yield break;
}
}
}
public void EndGrasp()
{
if (_coroutine != null) {
StopCoroutine(_coroutine);
_coroutine = null;
}
foreach (var grasp in _graspings)
{
grasp.EndGrasp();
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9e4ee5917383f4f4c9fa28352c34a7ee
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,62 @@
/*=========================================================================
Library: iMSTK-Unity
Copyright (c) Kitware, Inc.
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.txt
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 UnityEngine;
namespace ImstkUnity
{
/// <summary>
/// Simple controller for grasping, using a tracking device
/// </summary>
[RequireComponent(typeof(GraspingManager))]
public class SimpleGraspingController : MonoBehaviour
{
public TrackingDevice device;
// Start is called before the first frame update
GraspingManager _manager;
bool _isGrasping = false;
void Start()
{
_manager = GetComponent<GraspingManager>();
Debug.Assert(_manager != null);
}
// Update is called once per frame
void Update()
{
bool doGrasp = device.IsButtonDown(0) || device.IsButtonDown(1);
if (doGrasp && !_isGrasping)
{
Debug.Log("Grasping");
_manager.StartGrasp();
_isGrasping = true;
}
else if (!doGrasp && _isGrasping)
{
Debug.Log("Releasing");
_manager.EndGrasp();
_isGrasping = false;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2a73ab6aebdeb714e9700ee1a1c0c783
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant:
+127
View File
@@ -0,0 +1,127 @@
/*=========================================================================
Library: iMSTK-Unity
Copyright (c) Kitware, Inc.
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.txt
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 UnityEngine;
namespace ImstkUnity
{
/// <summary>
/// High Level interaction that implements suturing. Needs a needle, thread and tissue.
/// It will deal with the needle and the tissue collision as well as the needle puncturing
/// the tissue and the thread being pulled through the tissue.
/// Notes: currently the constraints generated in imstk for the needle/tissue and thread/tissue
/// punctures are only one way. This means that no forces will be exterted on the needle as
/// it violates the constraint.
/// Additionally there is an assumption in ismtk at the moment that the tip of the needle is
/// that _back end_ of the needle mesh.
/// </summary>
public class Suturing : ImstkBehaviour
{
public Rigid needle;
public Deformable thread;
public Deformable tissue;
public string activationKey = "s";
private bool _activated = false;
public float needleSurfaceStiffness = 0.5f;
public float threadSurfaceStiffness = 0.5f;
public float punctureDotThreshold = 0.8f;
Imstk.NeedleInteraction _needleInteraction;
protected override void OnImstkInit()
{
if (needle == null)
{
Debug.LogError("Needle is null");
return;
}
if (thread == null)
{
Debug.LogError("Thread is null");
return;
}
if (tissue == null)
{
Debug.LogError("Tissue is null");
return;
}
// Disable if any of the objects are not active
if (!needle.isActiveAndEnabled || !thread.isActiveAndEnabled || !tissue.isActiveAndEnabled)
{
enabled = false;
return;
}
// Make sure everything is initialized
needle.ImstkInit();
thread.ImstkInit();
tissue.ImstkInit();
var needlePbd = Imstk.Utils.CastTo<Imstk.PbdObject>(needle.GetDynamicObject());
var threadPbd = Imstk.Utils.CastTo<Imstk.PbdObject>(thread.GetDynamicObject());
var tissuePbd = Imstk.Utils.CastTo<Imstk.PbdObject>(tissue.GetDynamicObject());
if (needlePbd == null || threadPbd == null || tissuePbd == null)
{
Debug.LogError("Needle, Thread or Tissue do not have a dynamic Object");
enabled = false;
return;
}
_needleInteraction = new Imstk.NeedleInteraction(tissuePbd, needlePbd, threadPbd);
var ch = Imstk.Utils.CastTo<Imstk.NeedlePbdCH>(_needleInteraction.getCollisionHandlingAB());
if (ch == null)
{
Debug.LogError("Needle interaction does not have a NeedlePbdCH");
enabled = false;
return;
} else
{
ch.setNeedleToSurfaceStiffness(needleSurfaceStiffness);
ch.setSurfaceToNeedleStiffness(needleSurfaceStiffness);
ch.setThreadToSurfaceStiffness(threadSurfaceStiffness);
ch.setSurfaceToThreadStiffness(threadSurfaceStiffness);
ch.setPunctureDotThreshold(punctureDotThreshold);
}
SimulationManager.sceneManager.getActiveScene().addInteraction(_needleInteraction);
}
public void Pull()
{
_needleInteraction.stitch();
}
public void Update()
{
if (!_activated && Input.GetKeyDown(activationKey))
{
Pull();
}
}
public Imstk.NeedlePbdCH.PunctureData GetPunctureData()
{
return _needleInteraction.getPunctureData();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a7a8cdd270f1b2c468a724647826fc16
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 936dbb32eb653d84a9bcbe9caad48547, type: 3}
userData:
assetBundleName:
assetBundleVariant: