package org.squidy.nodes;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;
import org.squidy.manager.controls.TextField;
import org.squidy.manager.data.Processor;
import org.squidy.manager.data.Property;
import org.squidy.manager.model.AbstractNode;
/**
* <code>HandGesture</code>.
*
* <pre>
* Date: Jul 09, 2007
* Time: 11:27:00 AM
* </pre>
*
* @author Stephanie Foehrenbach, <a
* href="mailto:Stephanie.Foehrenbach@uni-konstanz.de">Stephanie.Foehrenbach@uni-konstanz.de</a>,
* University of Konstanz
*
* @version $Id: HandGesture.java 772 2011-09-16 15:39:44Z raedle $
* @since 1.0.2
*/
@XmlType(name = "HandGesture")
@Processor(
name = "Hand Gesture",
tags = { "hand gesture", "hand", "gesture", "OptiTrack", "ARTracking" },
types = { Processor.Type.FILTER }
)
public class HandGesture extends AbstractNode {
// ################################################################################
// BEGIN OF ADJUSTABLES
// ################################################################################
@XmlAttribute(name = "hand-id")
@Property(
name = "Hand Id",
description = "Id of target on hand (Sf Glove)."
)
@TextField
private String handId = "1";
/**
* @return the handId
*/
public String getHandId() {
return handId;
}
/**
* @param handId
* the handId to set
*/
public void setHandId(String handId) {
this.handId = handId;
}
@XmlAttribute(name = "hand-side-type")
@Property(
name = "Hand side type",
description = "Side of hand (Sf Glove) [left;right]."
)
@TextField
private String handSideType = "right";
/**
* @return the handSideType
*/
public String getHandSideType() {
return handSideType;
}
/**
* @param handSideType
* the handSideType to set
*/
public void setHandSideType(String handSideType) {
this.handSideType = handSideType;
}
@XmlAttribute(name = "number-fingers")
@Property(
name = "Number fingers",
description = "Number of finger marker on hand (Sf Glove)."
)
@TextField
private int numFingersHand = 2;
/**
* @return the numFingersHand
*/
public int getNumFingersHand() {
return numFingersHand;
}
/**
* @param numFingersHand
* the numFingersHand to set
*/
public void setNumFingersHand(int numFingersHand) {
this.numFingersHand = numFingersHand;
// ... unterst�tze Version eingestellt?
if (numFingersHand != 2 && numFingersHand != 4){
// ... wenn nicht als default 2 Finger einstellen
numFingersHand = 2;
}
}
@XmlAttribute(name = "hand-extend")
@Property(
name = "Hand extend",
description = "Maximum extend of hand in mm (Sf Glove)."
)
@TextField
private int handExtend = 200;
/**
* @return the handExtend
*/
public int getHandExtend() {
return handExtend;
}
/**
* @param handExtend
* the handExtend to set
*/
public void setHandExtend(int handExtend) {
this.handExtend = handExtend;
if (handExtend < 0){
handExtend = 0;
}
}
@XmlAttribute(name = "marker-1-target-x")
@Property(
name = "Marker 1 target X",
description = "X Value of marker 1 of hand target (Sf Glove)."
)
@TextField
private Double marker1TargetX = 52.293904;
/**
* @return the marker1TargetX
*/
public Double getMarker1TargetX() {
return marker1TargetX;
}
/**
* @param marker1TargetX
* the marker1TargetX to set
*/
public void setMarker1TargetX(Double marker1TargetX) {
this.marker1TargetX = marker1TargetX;
// setTargetMarker();
}
@XmlAttribute(name = "marker-1-target-y")
@Property(
name = "Marker 1 target Y",
description = "Y Value of marker 1 of hand target (Sf Glove)."
)
@TextField
private Double marker1TargetY = 18.217167;
/**
* @return the marker1TargetY
*/
public Double getMarker1TargetY() {
return marker1TargetY;
}
/**
* @param marker1TargetY
* the marker1TargetY to set
*/
public void setMarker1TargetY(Double marker1TargetY) {
this.marker1TargetY = marker1TargetY;
// setTargetMarker();
}
@XmlAttribute(name = "marker-1-target-z")
@Property(
name = "Marker 1 target Z",
description = "Z Value of marker 1 of hand target (Sf Glove)."
)
@TextField
private Double marker1TargetZ = 42.236839;
/**
* @return the marker1TargetZ
*/
public Double getMarker1TargetZ() {
return marker1TargetZ;
}
/**
* @param marker1TargetZ
* the marker1TargetZ to set
*/
public void setMarker1TargetZ(Double marker1TargetZ) {
this.marker1TargetZ = marker1TargetZ;
// setTargetMarker();
}
@XmlAttribute(name = "marker-2-target-x")
@Property(
name = "Marker 2 target X",
description = "X Value of marker 2 of hand target (Sf Glove)."
)
@TextField
private Double marker2TargetX = 29.04349;
/**
* @return the marker2TargetX
*/
public Double getMarker2TargetX() {
return marker2TargetX;
}
/**
* @param marker2TargetX
* the marker2TargetX to set
*/
public void setMarker2TargetX(Double marker2TargetX) {
this.marker2TargetX = marker2TargetX;
// setTargetMarker();
}
@XmlAttribute(name = "marker-2-target-y")
@Property(
name = "Marker 2 target Y",
description = "Y Value of marker 2 of hand target (Sf Glove)."
)
@TextField
private Double marker2TargetY = 38.460574;
/**
* @return the marker2TargetY
*/
public Double getMarker2TargetY() {
return marker2TargetY;
}
/**
* @param marker2TargetY
* the marker2TargetY to set
*/
public void setMarker2TargetY(Double marker2TargetY) {
this.marker2TargetY = marker2TargetY;
// setTargetMarker();
}
@XmlAttribute(name = "marker-2-target-z")
@Property(
name = "Marker 2 target Z",
description = "Z Value of marker 2 of hand target (Sf Glove)."
)
@TextField
private Double marker2TargetZ = 63.027431;
/**
* @return the marker2TargetZ
*/
public Double getMarker2TargetZ() {
return marker2TargetZ;
}
/**
* @param marker2TargetZ
* the marker2TargetZ to set
*/
public void setMarker2TargetZ(Double marker2TargetZ) {
this.marker2TargetZ = marker2TargetZ;
// setTargetMarker();
}
@XmlAttribute(name = "marker-3-target-x")
@Property(
name = "Marker 3 target X",
description = "X Value of marker 3 of hand target (Sf Glove)."
)
@TextField
private Double marker3TargetX = 74.792438;
/**
* @return the marker3TargetX
*/
public Double getMarker3TargetX() {
return marker3TargetX;
}
/**
* @param marker3TargetX
* the marker3TargetX to set
*/
public void setMarker3TargetX(Double marker3TargetX) {
this.marker3TargetX = marker3TargetX;
// setTargetMarker();
}
@XmlAttribute(name = "marker-3-target-y")
@Property(
name = "Marker 3 target Y",
description = "Y Value of marker 3 of hand target (Sf Glove)."
)
@TextField
private Double marker3TargetY = 71.941399;
/**
* @return the marker3TargetY
*/
public Double getMarker3TargetY() {
return marker3TargetY;
}
/**
* @param marker3TargetY
* the marker3TargetY to set
*/
public void setMarker3TargetY(Double marker3TargetY) {
this.marker3TargetY = marker3TargetY;
// setTargetMarker();
}
@XmlAttribute(name = "marker-3-target-z")
@Property(
name = "Marker 3 target Z",
description = "Z Value of marker 3 of hand target (Sf Glove)."
)
@TextField
private Double marker3TargetZ = 63.394787;
/**
* @return the marker3TargetZ
*/
public Double getMarker3TargetZ() {
return marker3TargetZ;
}
/**
* @param marker3TargetZ
* the marker3TargetZ to set
*/
public void setMarker3TargetZ(Double marker3TargetZ) {
this.marker3TargetZ = marker3TargetZ;
// setTargetMarker();
}
@XmlAttribute(name = "marker-4-target-x")
@Property(
name = "Marker 4 target X",
description = "X Value of marker 4 of hand target (Sf Glove)."
)
@TextField
private Double marker4TargetX = 0.0;
/**
* @return the marker4TargetX
*/
public Double getMarker4TargetX() {
return marker4TargetX;
}
/**
* @param marker4TargetX
* the marker4TargetX to set
*/
public void setMarker4TargetX(Double marker4TargetX) {
this.marker4TargetX = marker4TargetX;
// setTargetMarker();
}
@XmlAttribute(name = "marker-4-target-y")
@Property(
name = "Marker 4 target Y",
description = "Y Value of marker 4 of hand target (Sf Glove)."
)
@TextField
private Double marker4TargetY = 0.0;
/**
* @return the marker4TargetY
*/
public Double getMarker4TargetY() {
return marker4TargetY;
}
/**
* @param marker4TargetY
* the marker4TargetY to set
*/
public void setMarker4TargetY(Double marker4TargetY) {
this.marker4TargetY = marker4TargetY;
// setTargetMarker();
}
@XmlAttribute(name = "marker-4-target-z")
@Property(
name = "Marker 4 target Z",
description = "Z Value of marker 4 of hand target (Sf Glove)."
)
@TextField
private Double marker4TargetZ = 0.0;
/**
* @return the marker4TargetZ
*/
public Double getMarker4TargetZ() {
return marker4TargetZ;
}
/**
* @param marker4TargetZ
* the marker4TargetZ to set
*/
public void setMarker4TargetZ(Double marker4TargetZ) {
this.marker4TargetZ = marker4TargetZ;
// setTargetMarker();
}
@XmlAttribute(name = "marker-5-target-x")
@Property(
name = "Marker 5 target X",
description = "X Value of marker 5 of hand target (Sf Glove)."
)
@TextField
private Double marker5TargetX = 68.685688;
/**
* @return the marker5TargetX
*/
public Double getMarker5TargetX() {
return marker5TargetX;
}
/**
* @param marker5TargetX
* the marker5TargetX to set
*/
public void setMarker5TargetX(Double marker5TargetX) {
this.marker5TargetX = marker5TargetX;
// setTargetMarker();
}
@XmlAttribute(name = "marker-5-target-y")
@Property(
name = "Marker 5 target Y",
description = "Y Value of marker 5 of hand target (Sf Glove)."
)
@TextField
private Double marker5TargetY = -3.94777;
/**
* @return the marker5TargetY
*/
public Double getMarker5TargetY() {
return marker5TargetY;
}
/**
* @param marker5TargetY
* the marker5TargetY to set
*/
public void setMarker5TargetY(Double marker5TargetY) {
this.marker5TargetY = marker5TargetY;
// setTargetMarker();
}
@XmlAttribute(name = "marker-5-target-z")
@Property(
name = "Marker 5 target Z",
description = "Z Value of marker 5 of hand target (Sf Glove)."
)
@TextField
private Double marker5TargetZ = -8.283098;
/**
* @return the marker5TargetZ
*/
public Double getMarker5TargetZ() {
return marker5TargetZ;
}
/**
* @param marker5TargetZ
* the marker5TargetZ to set
*/
public void setMarker5TargetZ(Double marker5TargetZ) {
this.marker5TargetZ = marker5TargetZ;
// setTargetMarker();
}
@XmlAttribute(name = "target-marker-tolerance")
@Property(
name = "Target marker tolerance",
description = "Tolerance for target marker identification in mm (Sf Glove)."
)
@TextField
private int targetMarkerTolerance = 8;
/**
* @return the targetMarkerTolerance
*/
public int getTargetMarkerTolerance() {
return targetMarkerTolerance;
}
/**
* @param targetMarkerTolerance
* the targetMarkerTolerance to set
*/
public void setTargetMarkerTolerance(int targetMarkerTolerance) {
this.targetMarkerTolerance = targetMarkerTolerance;
}
@XmlAttribute(name = "finger-memory")
@Property(
name = "Finger memory",
description = "Use previous finger Ids for classification (Sf Glove) [-1;1])."
)
@TextField
private int fingerMemory = -1;
/**
* @return the fingerMemory
*/
public int getFingerMemory() {
return fingerMemory;
}
/**
* @param fingerMemory
* the fingerMemory to set
*/
public void setFingerMemory(int fingerMemory) {
this.fingerMemory = fingerMemory;
}
// Thresholds for finger classification
@XmlAttribute(name = "min-dist-z-thumb")
@Property(
name = "Minimum distance Z thumb",
description = "Min Distance Z-Thumb in mm (threshold for finger classification)."
)
@TextField
private double minDistZThumb = 4.0;
/**
* @return the minDistZThumb
*/
public double getMinDistZThumb() {
return minDistZThumb;
}
/**
* @param minDistZThumb
* the minDistZThumb to set
*/
public void setMinDistZThumb(double minDistZThumb) {
this.minDistZThumb = minDistZThumb;
}
// Thresholds for finger classification
@XmlAttribute(name = "min-dist-x-indexmiddle")
@Property(
name = "Minimum distance X index middle",
description = "Min Distance X Index-Middlefinger in mm (threshold for finger classification)."
)
@TextField
private double minDistXIndexMiddle = 10.0;
/**
* @return the minDistXIndexMiddle
*/
public double getMinDistXIndexMiddle() {
return minDistXIndexMiddle;
}
/**
* @param minDistXIndexMiddle
* the minDistXIndexMiddle to set
*/
public void setMinDistXIndexMiddle(double minDistXIndexMiddle) {
this.minDistXIndexMiddle = minDistXIndexMiddle;
}
// Thresholds for finger classification
@XmlAttribute(name = "min-dist-y-indexmiddle")
@Property(
name = "Minimum distance Y index middle",
description = "Min Distance Y Index-Middlefinger in mm (threshold for finger classification)."
)
@TextField
private double minDistYIndexMiddle = 16.0;
/**
* @return the minDistYIndexMiddle
*/
public double getMinDistYIndexMiddle() {
return minDistYIndexMiddle;
}
/**
* @param minDistYIndexMiddle
* the minDistYIndexMiddle to set
*/
public void setMinDistYIndexMiddle(double minDistYIndexMiddle) {
this.minDistYIndexMiddle = minDistYIndexMiddle;
}
@XmlAttribute(name = "rotation-angle-DT-y")
@Property(
name = "Rotation angle DT Y",
description = "Rotation angle of target around the y-axis (DTrack Glove)."
)
@TextField
private double rotationAngleDTY = -80.0;
/**
* @return the rotationAngleDTY
*/
public double getRotationAngleDTY() {
return rotationAngleDTY;
}
/**
* @param rotationAngleDTY
* the rotationAngleDTY to set
*/
public void setRotationAngleDTY(double rotationAngleDTY) {
this.rotationAngleDTY = rotationAngleDTY;
}
// ################################################################################
// END OF ADJUSTABLES
// ################################################################################
private static final int NUM_TARGET_MARKER = 5;
private Double targetMarkerPosition[][] = new Double[NUM_TARGET_MARKER][3];
/*
* @TODO: new DataType adoption required. DataPosition6D, DataPosition3D, DataFiner, DataHand
*
*/
// Offsets of hand target from origin - not fully implemented - future adjustables
/* private static double offSetSfX = 0.0;
private static double offSetSfY = 0.0;
private static double offSetSfZ = 0.0;
private Vector<MemoryHelper> vecGroupIdFor3d = new Vector<MemoryHelper>();
private Vector<MemoryHelper> vecGroupIdFor6d = new Vector<MemoryHelper>();
private Vector<String> vecKnownTargetBodyIds = new Vector<String>();
private Vector<DataPosition3D> vec3dCollection = new Vector<DataPosition3D>();
private Vector<DataPosition6D> vec6dCollection = new Vector<DataPosition6D>();
private Vector<DataHand> vecPrevHands = new Vector<DataHand>();
private DataHand hand;
private DataGlove glove;
private DataPosition6D pos6dRot;
private DataPosition6D pos6d;
private DataPosition3D pos3d;
private MemoryHelper objGroupIdFor3dMH;
private MemoryHelper objGroupIdFor6dMH;
private Vector<DataPosition3D> vec3dGroup = new Vector<DataPosition3D>();
private Vector<DataPosition6D> vec6dGroup = new Vector<DataPosition6D>();
private Vector<FingerSet> vecFingerSet = new Vector<FingerSet>();
private FingerSet fingerSet;
private DataFinger fingerRk;
private DataFinger fingerHk;
private int handPositionIndex;
private double extend;
private MathUtility mu = new MathUtility();
private double[][] m6d = new double[3][3];
private double logData[][] = new double [3000][17];
private int logDataIndex;
/*
public HandGesture() {
setTargetMarker();
}
// 3D Positionen der Marker des rechten Targets setzen
private void setTargetMarker(){
// Marker 1
targetMarkerPosition[0][0] = marker1TargetX;
targetMarkerPosition[0][1] = marker1TargetY;
targetMarkerPosition[0][2] = marker1TargetZ;
// Marker 2
targetMarkerPosition[1][0] = marker2TargetX;
targetMarkerPosition[1][1] = marker2TargetY;
targetMarkerPosition[1][2] = marker2TargetZ;
// Marker 3
targetMarkerPosition[2][0] = marker3TargetX;
targetMarkerPosition[2][1] = marker3TargetY;
targetMarkerPosition[2][2] = marker3TargetZ;
// Marker 4
targetMarkerPosition[3][0] = marker4TargetX;
targetMarkerPosition[3][1] = marker4TargetY;
targetMarkerPosition[3][2] = marker4TargetZ;
// Marker 5
targetMarkerPosition[4][0] = marker5TargetX;
targetMarkerPosition[4][1] = marker5TargetY;
targetMarkerPosition[4][2] = marker5TargetZ;
}
public void refreshMemory(){
vecGroupIdFor3d.clear();
vecGroupIdFor6d.clear();
vecKnownTargetBodyIds.clear();
vec3dCollection.clear();
vec6dCollection.clear();
vecPrevHands.clear();
}
/**
* {@inheritDoc}
*/
/*public synchronized IData process(DataPosition3D dataPosition3D) {
boolean elementAdded = false;
pos3d = dataPosition3D;
// Wenn 3d Objekt nicht bereits als Element des Handtargets bekannt
// ist ...
if (isKnownTarget(pos3d) == false) {
// ... der allgemeinen 3d Sammlung als potentieller Finger
// hinzuf�gen
vec3dCollection.add(pos3d);
elementAdded = true;
}
if (countDownGroupMembers(pos3d, elementAdded) == 0) {
if (extractGroup(pos3d.groupID) == true) {
buildHands();
}
}
reduceCollections();
return dataPosition3D;
}
public synchronized IData process(DataPosition6D dataPosition6D) {
boolean elementAdded = false;
pos6d = dataPosition6D;
// Wenn 6d Objekt als Hand bekannt ist ...
if (isKnownHand(pos6d) != -1) {
// ... der allgemeinen 6d Sammlung hinzuf�gen
vec6dCollection.add(pos6d);
elementAdded = true;
}
if (countDownGroupMembers(pos6d, elementAdded) == 0) {
if (extractGroup(pos6d.groupID) == true) {
buildHands();
}
}
reduceCollections();
// Wurde das Element als Hand hinzugef�gt ...
if (elementAdded == true)
// ... kein Element zur�ckgeben
return null;
else
// ... sonst 6DOF zur Cursorpositionierung zur�ck
return dataPosition6D;
}
public synchronized IData process(DataGlove dataGlove) {
return glove2Hand(dataGlove);
}
private int countDownGroupMembers(DataPosition3D data, boolean elementAdded){
// Wenn bereits mit dem Sammeln der Mitglieder von Gruppe data.groupID begonnen wurde ...
for(int i=vecGroupIdFor3d.size()-1; i >= 0 ; i--)
{
if (vecGroupIdFor3d.elementAt(i).identifier == data.groupID)
{
if (elementAdded == true){
// ... Anzahl hinzugef�gter Elemente erh�hen wenn ein Element hinzugef�gt wurde
vecGroupIdFor3d.elementAt(i).collectedMembers++;
}
// ... und verbleibende Anzahl noch zu sammelnder Mitglieder reduzieren und zur�ckgeben
vecGroupIdFor3d.elementAt(i).remainingMembers--;
return vecGroupIdFor3d.elementAt(i).remainingMembers;
}
}
// ... sonst neue Gruppe der Sammelliste hinzuf�gen und noch zu sammelnde Mitglieder setzen
vecGroupIdFor3d.add(new MemoryHelper(data.groupID, data.numGroup-1, 1));
return data.numGroup-1;
}
private int countDownGroupMembers(DataPosition6D data, boolean elementAdded){
// Wenn bereits mit dem Sammeln der Mitglieder von Gruppe data.groupID begonnen wurde ...
int i;
for( i=vecGroupIdFor6d.size()-1; i >= 0 ; i--)
{
if (vecGroupIdFor6d.elementAt(i).identifier == data.groupID)
{
if (elementAdded == true){
// ... Anzahl hinzugef�gter Elemente erh�hen wenn ein Element hinzugef�gt wurde
vecGroupIdFor6d.elementAt(i).collectedMembers++;
}
// ... verbleibende Anzahl noch zu sammelnder Mitglieder reduzieren und zur�ckgeben
vecGroupIdFor6d.elementAt(i).remainingMembers--;
return vecGroupIdFor6d.elementAt(i).remainingMembers;
}
}
// ... sonst neue Gruppe der Sammelliste hinzuf�gen und noch zu sammelnde Mitglieder setzen
vecGroupIdFor6d.add(new MemoryHelper(data.groupID, data.numGroup-1, 1));
return data.numGroup-1;
}
private boolean isKnownTarget(DataPosition3D data){
for(int i=0; i < vecKnownTargetBodyIds.size(); i++)
{
if (data.hasAttribute(DataConstant.IDENTIFIER)) {
if (vecKnownTargetBodyIds.elementAt(i).compareTo((String)
data.getAttribute(DataConstant.IDENTIFIER)) == 0) {
return true;
}
}
}
return false;
}
private int isKnownHand(DataPosition6D data){
if (data.hasAttribute(DataConstant.IDENTIFIER)) {
return (handId.compareTo((String) data.getAttribute(DataConstant.IDENTIFIER)) == 0) ? 1 : -1;
}
return -1;
}
private int lookupHandSide(){
return (handSideType.compareToIgnoreCase("left") == 0)?DataHand.LEFT:DataHand.RIGHT ;
}
private boolean extractGroup(int groupID){
// Wenn alle 3d und 6d Mitglieder der Gruppe gesammelt wurden ...
if (checkGroupIdCollected(groupID) == false) return false;
// ... 6d Mitglieder aus allgemeiner Sammlung extrahieren, sollte es ...
if (extract6dMembers(groupID) == 0) {
// ... keine 6d Mitglieder geben, die 3d Gruppenmitglieder aus allgemeiner Sammlung l�schen
extract3dMembers(groupID, false);
// ... und erfolglose Extraktion zur�ckmelden
return false;
}
else
{
// ... ansonsten 3d Gruppenmitglieder aus allgemeiner Sammlung in Gruppen Sammlung �bernehmen
extract3dMembers(groupID, true);
// ... und erfolgreiche Extraktion zur�ckmelden
return true;
}
}
// Pr�ft ob alle 3d und 6d Mitglieder der Gruppe groupID komplett gesammelt wurden.
// Wenn ja, werden die Z�hler f�r die Gruppe entfernt und true zur�ckgeliefert
// die Daten f�r die Gruppe werden dabei in das Feld objGroupIdFor[6d|3d]MH �bernommen
// Wenn nicht, wird false zur�ckgeliefert und die Z�hler bleiben bestehen
private boolean checkGroupIdCollected(int groupID){
int i;
int index3d = -1;
int index6d = -1;
for(i=vecGroupIdFor6d.size()-1; i >= 0; i--)
{
if (vecGroupIdFor6d.elementAt(i).identifier == groupID)
{
index6d = i;
i = 0;
}
}
for(i=vecGroupIdFor3d.size()-1; i >= 0; i--)
{
if (vecGroupIdFor3d.elementAt(i).identifier == groupID)
{
index3d = i;
i = 0;
}
}
if (index3d > -1 && index6d > -1){
// Wurden alle 3d und 6d der Gruppe groupID gesammelt ...
if (vecGroupIdFor6d.elementAt(index6d).remainingMembers == 0 &&
vecGroupIdFor3d.elementAt(index3d).remainingMembers == 0)
// ... Z�hler entfernen
objGroupIdFor6dMH = vecGroupIdFor6d.remove(index6d);
objGroupIdFor3dMH = vecGroupIdFor3d.remove(index3d);
return true;
}
else
{
return false;
}
}
// Entfernt die 6d Mitglieder der Gruppe groupID aus der allgemeinen Sammlung
// und f�gt sie in die gruppenspezifische Sammlung ein
// R�ckgabewert = Anzahl der �bernommenen 6d Mitglieder
private int extract6dMembers(int groupID){
int anz=0;
vec6dGroup.clear();
if (objGroupIdFor6dMH.collectedMembers == 0) return anz;
for(int i=vec6dCollection.size()-1; i >= 0; i--)
{
if (vec6dCollection.elementAt(i).groupID == groupID)
{
vec6dGroup.add(vec6dCollection.remove(i));
anz++;
if (anz == objGroupIdFor6dMH.collectedMembers){
i = 0;
}
}
}
return anz;
}
// Entfernt die 3d Mitglieder der Gruppe groupID aus der allgemeinen Sammlung
// Ist uebernehmen = true werden die Mitglieder in die gruppenspezifische Sammlung eingef�gt
private int extract3dMembers(int groupID, boolean uebernehmen){
int anz=0;
vec3dGroup.clear();
if (objGroupIdFor3dMH.collectedMembers == 0) return anz;
for(int i=vec3dCollection.size()-1; i >= 0; i--)
{
if (vec3dCollection.elementAt(i).groupID == groupID)
{
if (uebernehmen == true){
vec3dGroup.add(vec3dCollection.remove(i));
}
else{
vec3dCollection.remove(i);
}
anz++;
if (anz == objGroupIdFor3dMH.collectedMembers){
i = 0;
}
}
}
return anz;
}
private void buildHands(){
int handSide;
int fingerType;
int anzClassifiedFingers;
// F�r jedes 6d Objekt der Gruppe eine Hand zusammensetzen
for (int i=0; i<vec6dGroup.size(); i++){
anzClassifiedFingers = 0;
vecFingerSet.clear();
handSide = lookupHandSide();
hand = new DataHand(this.getClass(), handSide,
vec6dGroup.elementAt(i).getX(), vec6dGroup.elementAt(i).getY(), vec6dGroup.elementAt(i).z,
vec6dGroup.elementAt(i).maxX, vec6dGroup.elementAt(i).maxY, vec6dGroup.elementAt(i).maxZ,
vec6dGroup.elementAt(i).rxx, vec6dGroup.elementAt(i).ryx, vec6dGroup.elementAt(i).rzx,
vec6dGroup.elementAt(i).rxy, vec6dGroup.elementAt(i).ryy, vec6dGroup.elementAt(i).rzy,
vec6dGroup.elementAt(i).rxz, vec6dGroup.elementAt(i).ryz, vec6dGroup.elementAt(i).rzz,
vec6dGroup.elementAt(i).groupID, vec6dGroup.elementAt(i).numGroup);
hand.setAttribute(DataConstant.IDENTIFIER, "handSF"+vec6dGroup.elementAt(i).getAttribute(DataConstant.IDENTIFIER));
hand.handType = DataHand.hSF;
extend = handExtend;
lookupPreviousHand(hand);
for (int j=vec3dGroup.size()-1; j>=0; j--){
// Wenn das 3d Objekt zu weit von der aktuell bearbeiteten Hand entfernt ist ...
if (isToRemote(vec3dGroup.elementAt(j), hand) == true){
// ... weiter mit dem n�chsten 3d
continue;
}
fingerSet = obj3d2FingerSet(vec3dGroup.elementAt(j), hand);
// Wenn BodyIDs �bernommen werden soll, wenn diese als fr�here Finger klassifiziert wurden ...
if (fingerMemory == 1){
// ... pruefen ob das 3d Objekt schon als Finger bekannt ist ...
fingerType = isKnownFinger(fingerSet, hand);
if (fingerType != -1){
// ... Finger als schon bekannter Finger sofort der Hand hinzuf�gen ...
setFinger(fingerType, fingerSet, hand, true);
anzClassifiedFingers++;
// ... 3d aus Gruppensammlung l�schen
vec3dGroup.removeElementAt(j);
// ... und weiter mit n�chstem 3d
continue;
}
}
// Wenn das 3d Objekt zum Handtarget geh�rt ...
if (isTarget(fingerSet, hand) == true){
// ... id der Targetliste hinzuf�gen
if (fingerSet.fingerHk.hasAttribute(DataConstant.IDENTIFIER)) {
vecKnownTargetBodyIds.add((String) fingerSet.fingerHk.getAttribute(DataConstant.IDENTIFIER));
}
// ... 3d Objekt aus Gruppensammlung l�schen
vec3dGroup.removeElementAt(j);
// ... und weiter mit n�chstem 3d
continue;
}
// Ist das 3d Objekt ein noch unbekannter Finger der Fingerliste zum sp�teren sortieren hinzuf�gen ...
vecFingerSet.add(fingerSet);
// ... und 3d Objekt aus Gruppensammlung l�schen
vec3dGroup.removeElementAt(j);
}
classifyAndSetFingers(hand, anzClassifiedFingers);
setPreviousHand(hand);
// 2FingerExtendedIndex - 18600
// 2FingerExtendedIndexPanRechtsLinks - 21739
// 2FingerRingImmerWieder - 39938
// 2FingerRingImmerWieder-reserve - 6303
// 2FingerRingPanRechtsLinks - 12914
// 2FingerStatischRechtsLinks - 37482
// 4FingerExtendedIndexImmerWieder - 3842
// 4FingerExtendedIndexPanRechtsLinks - 5774
// 4FingerRingImmerWieder - 8808
// 4FingerRingPanRechtsLinks - 13396
// 4FingerStatischRechtsLinks - 29663
//
// 0_2FingersRingImmerWiederSchraeg - 73000
// 0_2FingerRingImmerWieder - 69262
// 0_2FingersRingPanRechtsLinks - 74925
// 0_2FingersRingPanRechtsLinksSchraeg - 77300
// 0_2FingersExtIndexImmerWiederSchraeg - 86100
// 0_2FingersExtIndexPanRechtsLinksSchraeg - 89901
// logData(hand, 89901);
pushSample(hand);
}
}
private void logData(DataHand hand, int printIndex){
if (hand.thumb != null){
logData[logDataIndex][0] = Integer.parseInt((String) hand.thumb.getAttribute(DataConstant.IDENTIFIER));
logData[logDataIndex][1] = hand.thumb.getX();
logData[logDataIndex][2] = hand.thumb.getY();
logData[logDataIndex][3] = hand.thumb.z;
}
else{
logData[logDataIndex][0] = -1;
logData[logDataIndex][1] = -1;
logData[logDataIndex][2] = -1;
logData[logDataIndex][3] = -1;
}
if (hand.indexFinger != null){
logData[logDataIndex][4+0] = Integer.parseInt((String) hand.indexFinger.getAttribute(DataConstant.IDENTIFIER));
logData[logDataIndex][4+1] = hand.indexFinger.getX();
logData[logDataIndex][4+2] = hand.indexFinger.getY();
logData[logDataIndex][4+3] = hand.indexFinger.z;
}
else{
logData[logDataIndex][4+0] = -1;
logData[logDataIndex][4+1] = -1;
logData[logDataIndex][4+2] = -1;
logData[logDataIndex][4+3] = -1;
}
if (hand.middleFinger != null){
logData[logDataIndex][8+0] = Integer.parseInt((String) hand.middleFinger.getAttribute(DataConstant.IDENTIFIER));
logData[logDataIndex][8+1] = hand.middleFinger.getX();
logData[logDataIndex][8+2] = hand.middleFinger.getY();
logData[logDataIndex][8+3] = hand.middleFinger.z;
}
else{
logData[logDataIndex][8+0] = -1;
logData[logDataIndex][8+1] = -1;
logData[logDataIndex][8+2] = -1;
logData[logDataIndex][8+3] = -1;
}
if (hand.littleFinger != null){
logData[logDataIndex][12+0] = Integer.parseInt((String) hand.littleFinger.getAttribute(DataConstant.IDENTIFIER));
logData[logDataIndex][12+1] = hand.littleFinger.getX();
logData[logDataIndex][12+2] = hand.littleFinger.getY();
logData[logDataIndex][12+3] = hand.littleFinger.z;
}
else{
logData[logDataIndex][12+0] = -1;
logData[logDataIndex][12+1] = -1;
logData[logDataIndex][12+2] = -1;
logData[logDataIndex][12+3] = -1;
}
logData[logDataIndex][16] = hand.groupID;
logDataIndex ++;
if (hand.groupID > printIndex){
System.out.println("Thumb id; Thumb x; Thumb y; Thumb z; Index id; Index x; Index y; Index z; Middle id; Middle x; Middle y; Middle z; Little id; Little x; Little y; Little z; GroupID; ");
for (int i = 0; i<3000; i++){
if(logData[i][12] == 0){
i=3000;
continue;
}
System.out.println(
(int)logData[i][0]+";"+
(int)logData[i][1]+";"+
(int)logData[i][2]+";"+
(int)logData[i][3]+";"+
(int)logData[i][4]+";"+
(int)logData[i][5]+";"+
(int)logData[i][6]+";"+
(int)logData[i][7]+";"+
(int)logData[i][8]+";"+
(int)logData[i][9]+";"+
(int)logData[i][10]+";"+
(int)logData[i][11]+";"+
(int)logData[i][12]+";"+
(int)logData[i][13]+";"+
(int)logData[i][14]+";"+
(int)logData[i][15]+";"+
(int)logData[i][16]+";");
}
}
}
// Pr�ft ob 3d Objekt zu weit entfernt von der hand ist
// R�ckgabewert true = zu weit entfernt, false = nicht zu weit entfernt
private boolean isToRemote(DataPosition3D obj3d, DataHand hand){
return (mu.euclidDist(obj3d.getX(), obj3d.getY(), obj3d.z, hand.getX(), hand.getY(), hand.z) > extend)?true:false;
}
// Legt f�r obj3d ein Finger in den Raumkoordinaten an, rechnet diesen
// in die Handkoordinaten von hand um und gibt beide Finger als FingerSet zur�ck
private FingerSet obj3d2FingerSet (DataPosition3D obj3d, DataHand hand){
fingerRk = new DataFinger(this.getClass(), DataFinger.NOTCLASSIFIED, hand.handSide,
obj3d.getX(), obj3d.getX(), obj3d.z,
obj3d.maxX, obj3d.maxY, obj3d.maxZ,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
obj3d.groupID, obj3d.numGroup);
fingerRk.setAttribute(DataConstant.IDENTIFIER, obj3d.getAttribute(DataConstant.IDENTIFIER));
fingerHk = new DataFinger(this.getClass(), DataFinger.NOTCLASSIFIED, hand.handSide,
obj3d.getX(), obj3d.getY(), obj3d.z,
obj3d.maxX, obj3d.maxY, obj3d.maxZ,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
obj3d.groupID, obj3d.numGroup);
fingerHk.setAttribute(DataConstant.IDENTIFIER, obj3d.getAttribute(DataConstant.IDENTIFIER));
// zu rotierenden Finger in 3d Vektor schreiben
double[] f = new double[3];
f[0] = fingerRk.getX();
f[1] = fingerRk.getY();
f[2] = fingerRk.z;
// Handr�ckenschwerpunkt als Punkt um welchen rotiert wird in 3d Vektor schreiben
double[] o = new double[3];
o[0] = hand.getX();
o[1] = hand.getY();
o[2] = hand.z;
// Meta Rotationsmatrix �bernehmen ? Stimmt das oder m�ssen die Werte da nicht anderst
// �bernommen werden?
// m6d = mu.dataPosition6D2matrix(hand);
m6d[0][0] = hand.rxx;
m6d[0][1] = hand.ryx;
m6d[0][2] = hand.rzx;
m6d[1][0] = hand.rxy;
m6d[1][1] = hand.ryy;
m6d[1][2] = hand.rzy;
m6d[2][0] = hand.rxz;
m6d[2][1] = hand.ryz;
m6d[2][2] = hand.rzz;
// Rotationsmatrix transponieren (-> ergibt inverse, da zur�ckrotiert werden muss)
m6d = mu.transpose(m6d);
// Punkt rotieren und Werte in Bezug auf 0/0/0 Punkt �bernehmen
f = mu.rotatePoint(f, o, m6d, false);
// Rotierten Punkt als Finger �bernehmen ...
fingerHk.setX(f[0]);
fingerHk.setY(f[1]);
fingerHk.z = f[2];
// Offsetwerte verrechnen, damit Ursprung im Indexgelenk liegt
fingerHk.setX(fingerHk.getX() + offSetSfX);
fingerHk.setY(fingerHk.getY() + offSetSfY);
fingerHk.z = fingerHk.z + offSetSfZ;
// Bei linker Hand x-werte drehen
if (hand.handSide == DataHand.LEFT){
fingerHk.setX(fingerHk.getX() * (-1));
fingerHk.setY(fingerHk.getY() * (-1));
fingerHk.z = fingerHk.z * (-1);
}
FingerSet fingerSetNew = new FingerSet(fingerRk, fingerHk);
return fingerSetNew;
}
// Schaut nach ob dieser Finger aus einem vorhergehenden Zusammenbau dieser Hand
// bekannt ist. Wenn ja wird die Identit�t des jeweiligen Fingers zur�ckgeliefert
// ansonsten -1
private int isKnownFinger(FingerSet fingerSet, DataHand hand){
// Raus, wenn's keine vorhergehende Hand gibt
if (handPositionIndex == -1){
return -1;
}
// Raus wenn's keine richtige id (d.h. >0) gibt
if (((String) fingerSet.fingerHk.getAttribute(DataConstant.IDENTIFIER)).compareTo("0") == 0){
return -1;
}
// Auf �bereinstimmung pr�fen und wenn ja Finger in Hand �bernehmen, Finger muss dazu vorher auch als entsprechender Finger
// best�tigt, d.h. als THUMB, ... klassifiziert worden sein
if (vecPrevHands.elementAt(handPositionIndex).thumb != null)
if (((String) vecPrevHands.elementAt(handPositionIndex).thumb.getAttribute(DataConstant.IDENTIFIER)).compareTo((String) fingerSet.fingerHk.getAttribute(DataConstant.IDENTIFIER)) == 0
&& vecPrevHands.elementAt(handPositionIndex).thumb.fingerType == DataFinger.THUMB){
return DataFinger.THUMB;
}
if (vecPrevHands.elementAt(handPositionIndex).indexFinger != null)
if (((String) vecPrevHands.elementAt(handPositionIndex).indexFinger.getAttribute(DataConstant.IDENTIFIER)).compareTo((String) fingerSet.fingerHk.getAttribute(DataConstant.IDENTIFIER)) == 0
&& vecPrevHands.elementAt(handPositionIndex).indexFinger.fingerType == DataFinger.INDEXFINGER){
return DataFinger.INDEXFINGER;
}
if (vecPrevHands.elementAt(handPositionIndex).middleFinger != null)
if (((String) vecPrevHands.elementAt(handPositionIndex).middleFinger.getAttribute(DataConstant.IDENTIFIER)).compareTo((String) fingerSet.fingerHk.getAttribute(DataConstant.IDENTIFIER)) == 0
&& vecPrevHands.elementAt(handPositionIndex).middleFinger.fingerType == DataFinger.MIDDLEFINGER){
return DataFinger.MIDDLEFINGER;
}
if (vecPrevHands.elementAt(handPositionIndex).littleFinger != null)
if(((String) vecPrevHands.elementAt(handPositionIndex).littleFinger.getAttribute(DataConstant.IDENTIFIER)).compareTo((String) fingerSet.fingerHk.getAttribute(DataConstant.IDENTIFIER)) == 0
&& vecPrevHands.elementAt(handPositionIndex).littleFinger.fingerType == DataFinger.LITTLEFINGER){
return DataFinger.LITTLEFINGER;
}
return -1;
}
// F�gt das fingerSet der hand als Finger "fingerType" hinzu. Ist classified = true, wird der
// Finger in der Hand noch als entsprechender Typ klassifiziert/best�tigt.
// Beispiel: der Daumen soll gesetzt werden:
// Unabh�ngig vom classified flag werden die Objekte thumbRk und thumbHk der Hand hand gesetzt
// mit classified = true werden den beiden Fingern dann noch der fingerType = THUMB zugeordnet
// mit classified = false werden den Fingern keine Typen zugeordnet, d.h. es steht was in thumbRk
// und thumbHk aber es ist nicht sicher ob es auch tats�chlich der Daumen ist
private void setFinger(int fingerType, FingerSet fingerSet, DataHand hand, boolean classified){
switch(fingerType){
case(DataFinger.THUMB):
{
hand.thumbRk = fingerSet.fingerRk;
hand.thumb = fingerSet.fingerHk;
if (classified == true){
hand.thumbRk.fingerType = DataFinger.THUMB;
hand.thumb.fingerType = DataFinger.THUMB;
}
break;
}
case(DataFinger.INDEXFINGER):
{
hand.indexFingerRk = fingerSet.fingerRk;
hand.indexFinger = fingerSet.fingerHk;
if (classified == true){
hand.indexFingerRk.fingerType = DataFinger.INDEXFINGER;
hand.indexFinger.fingerType = DataFinger.INDEXFINGER;
}
break;
}
case(DataFinger.MIDDLEFINGER):
{
hand.middleFingerRk = fingerSet.fingerRk;
hand.middleFinger = fingerSet.fingerHk;
if (classified == true){
hand.middleFingerRk.fingerType = DataFinger.MIDDLEFINGER;
hand.middleFinger.fingerType = DataFinger.MIDDLEFINGER;
}
break;
}
case(DataFinger.LITTLEFINGER):
{
hand.littleFingerRk = fingerSet.fingerRk;
hand.littleFinger = fingerSet.fingerHk;
if (classified == true){
hand.littleFingerRk.fingerType = DataFinger.LITTLEFINGER;
hand.littleFinger.fingerType = DataFinger.LITTLEFINGER;
}
break;
}
}
}
// Pr�ft ob der Finger im fingerSet zum Handtarget der Hand hand geh�rt
private boolean isTarget(FingerSet fingerSet, DataHand hand){
if (((String) hand.getAttribute(DataConstant.IDENTIFIER)).compareTo("hand"+handId) == 0)
{
for(int i = 0; i < NUM_TARGET_MARKER; i++){
if (mu.euclidDist(fingerSet.fingerHk.getX(), fingerSet.fingerHk.getY(), fingerSet.fingerHk.z,
targetMarkerPosition[i][0], targetMarkerPosition[i][1], targetMarkerPosition[i][2]) < targetMarkerTolerance ){
return true;
}
}
}
return false;
}
// Klassifiziert die Finger welche noch keinem bestimmten Finger zugeordnet sind
// und legt diese dann in der Hand hand an
private boolean classifyAndSetFingers(DataHand hand, int anzClassifiedFingers){
int anzRemainingFingers = vecFingerSet.size();
// Raus, wenn bereits alle Finger zugeordnet sind
if (anzRemainingFingers == 0) return true;
// Raus, wenn nicht alle Finger erkannt wurden (4er oder 2er Version m�glich
if (anzClassifiedFingers + anzRemainingFingers != numFingersHand) return false;
// Finger werden nur klassifiziert, wenn alle 4 bzw. 2 Finger erkannt wurden, wurden weniger oder mehr erkannt werden nur die
// Finger in die Hand �bernommen, die schon aus vorherigen Durchl�ufen bekannt sind.
// D.h. die erstmalige Neukonfigurierung wird immer mit allen 4 bzw. 2 Fingern durch gef�hrt.
// Die Funktion merkt sich dabei welche BodyIds als welche Finger �bernommen wurden
// Bei nachfolgenden Klassifizierungen werden bereits bekannte BodyIds wieder direkt in den vorhergehenden Finger �bernommen.
// Neue BodyIds (wenn DTrack ein Marker verloren und dann wieder gefunden hat) wird dann eine neue Klassifizierung durchgef�hrt.
// Die Klassifizierung wird dabei nur durchgef�hrt, wenn insgesamt 4 bzw. 2 Fingerb getrackt wurden.
//
// Es ist anzunehmen, da� zu Begin eine entspannte Hand- und Fingerhaltung eingenommen wird, so da� die Klassifikation auf eindeutige
// F�lle zur�ckgreifen kann (z.B. Zeige- und Mittelfinger nebeneinander und nicht �berkreuzt)
// Sollten im Laufe der Interaktion unklarere Klassifikationsf�lle auftauchen, d�rfte das Ged�chtnis der Funktion dazu beitragen trotzdem
// eine hohe Klassifikationsgenauigkeit zu erreichen
// Constrains zur Fingerbestimmung:
// Der kleine Finger kommt nach links nie bis zum Mittelfinger -> ist also immer der am weitesten rechte Finger (-> gr�sster x-Wert)
// Vorgehensweise f�r Kleinen Finger:
// Finger mit gr�sstem x-Wert ist der kleine Finger
// 1. Kleinen Finger zuordnen, wenn 4 Finger Glove im Einsatz ist ...
if (numFingersHand == 4){
// ... und der Finger nicht bereits gesetzt ist
if (hand.littleFinger == null){
int maxXPos = -1;
double maxX = -extend;
for (int i=0; i<anzRemainingFingers; i++){
if (vecFingerSet.elementAt(i).fingerHk.getX() > maxX){
maxX = vecFingerSet.elementAt(i).fingerHk.getX();
maxXPos = i;
}
}
setFinger(DataFinger.LITTLEFINGER, vecFingerSet.remove(maxXPos) , hand, true);
anzRemainingFingers--;
}
}
// Kein Finger kommt direkt unter den Daumen oder noch weiter nach links
// Der Daumen kommt unter den Zeige- und Mittelfinger, aber nie bis direkt unter den Mittelfinger
// Daumen kommt nicht weiter nach rechts als der Mittelfinger
//
// Der Handursprung liegt im, oder knapp �ber dem Zeigefingergelenk,
// die z-Achse liegt im Zeigefinger, und geht zum K�rper hin,
// die x-Achse geht orthogonal vom Zeigefinger in Richtung Mittelfinger weg
// die y-Achse geht zu beiden Achsen orthogonal nach oben hin weg
// -> z-Wert des Zeigefingers- und Mittelfingers kann nicht positiv werden z-Wert = negativ oder 0
// -> z-Wert des Daumens kann nicht negativ werden -> z-Wert = 0 oder positiv
// Ansatz: Daumen ist der Finger mit dem positiven (gr�ssten) z-Wert, Zeige- und Mittelfinger haben negative z-Werte
// -> theoretisch k�nnen die Finger in den Bewegungsgrenzen die gleichen z-Werte erreichen -> der Bereich um 0 ist f�r alle Finger m�glich
// M�gliche Fingerpositionen im Grenzbereich (um 0), sind die F�lle in denen der Zeige- und Mittelfinger stark angewinkelt sind:
// 1. Ann�herungsposition: Daumen unterhalb im Handinnern, beiden anderen Finger gebeugt: (Finger haben nur oberhalb des Daumens Platz)
// Zeige- und Mittelfinger sind �ber dem Daumen -> Daumen hat auch weiterhin den gr�ssten z-Wert
// 2. Ann�herungsposition: Nur Zeige-und/oder Mittelfinger gebeugt, Daumen links beliebig neben dem Zeigefinger (Zeige-Mittelfinger
// k�nnen im �ussersten Gelenk gestreckt sein):
// a) bei Positionierung des Markers auf mittlerem Phalanx des Zeige- und Mittelfingers -> Daumem weiterhin den gr�ssten z-Wert
// b) bei Positionierung des Markers auf �usserem Phalanx des Zeigefingers
// z-Werte der Finger m�glicherweise identisch bzw. mit sehr kleinen Unterschieden, dann ist aber
// der x-Wert des Daumens immer kleiner, da er links neben dem Zeigefinger ist.
// 3. Ann�herungsposition: Zeige-und/oder Mittelfinger gebeugt, Daumen liegt vor dem Zeige-, und/oder Mittelfinger (Zeige-Mittelfinger
// m�ssen im �ussersten Gelenk angewinkelt sein):
// a) bei Positionierung des Markers auf mittlerem Phalanx des Zeige- und Mittelfingers -> Daumen weiterhin den gr�ssten z-Wert
// b) bei Positionierung des Markers auf �usserem Phalanx des Zeigefingers: Positionierung des Daumens nur m�glich auf unterem
// Phalanx des Mittelfingers, dann kommt der Zeigefinger, aber nicht an dem Marker auf dem Daumen vorbei (in Richtung neg->
// positiver z-Richtung -> soweit die Fingerstellung m�glich ist, hat der Daumen den gr�ssten z-Wert
// Vorgehensweise f�r Daumen: (kleiner Finger muss schon weg sein)
// Finger mit gr�sstem z-Wert suchen. Haben z-Werte anderer Finger einen z-Wert > z-Wert-Daumen - 4 (n�her als 4 mm am Daumen-z-Wert)
// ist von den nahen Fingern der mit dem kleinsten x-Wert der Daumen (nur bei Fingerposition 2.b) also mit Marker auf �usserem
// Zeigefingerphalanx )
// Ermittlung des Abstandwertes: Zeigefinger so weit wie m�glich nach unten hinten abgebeugt, �usserstes Gelenk dabei
// gestreckt. Daumen liegt links am Zeigefinger nach vorne. Wert= Wenn Zeigefinger einen gr�sseren Z-Wert als der Daumen hat ->
// Abstand in z-Werten zwischen beiden Fingern (positiv). Hat der Daumen den gr�ssten Z-Wert (trotz DTrack Messschwankungen) ist der Wert = 0;
// Wird ein Wert gesetzt, diesen lieber noch 1-2 mm gr�sser angeben um Messschwankungen zu ber�cksichtigen -> also auch wenn der Daumen
// eigentlich einen gr�sseren z-Wert hat, die DTrack Werte f�r die beiden Finger sich aber nicht eindeutig unterscheiden und mal gr�sser/kleiner
// werden.
// 2. Daumen klassifizieren
if (hand.thumb == null){
int maxZPos = -1;
double maxZ = -extend;
int minXPos = -1;
double minX = extend;
// Groessten z-Wert suchen ...
for (int i= 0; i<anzRemainingFingers; i++){
if (vecFingerSet.elementAt(i).fingerHk.z > maxZ){
maxZ = vecFingerSet.elementAt(i).fingerHk.z;
maxZPos = i;
}
}
// ... den x-Wert und die Position des groessten z-Wert abspeichern
minXPos = maxZPos;
minX = vecFingerSet.elementAt(minXPos).fingerHk.getX();
// Dann die restlichen Finger pruefen, ob da noch einer innerhalb der moeglichen Daumen z-Werte liegt ...
for (int i = 0; i<anzRemainingFingers; i++){
if (i == maxZPos) continue;
// ... liegt der z-Wert des Fingers innerhalb der moeglichen Daumen z-Werte
if (vecFingerSet.elementAt(i).fingerHk.z >= minDistZThumb ){
// ... x-Wert und Position des Fingers speichern, wenn dieser kleiner ist als der bisher kleinste x-Wert
if (vecFingerSet.elementAt(i).fingerHk.getX() < minX){
minX = vecFingerSet.elementAt(i).fingerHk.getX();
minXPos = i;
}
}
}
setFinger(DataFinger.THUMB, vecFingerSet.remove(minXPos) , hand, true);
anzRemainingFingers--;
}
// Zeige- und Mittelfinger
// Es gibt 2 m�gliche Fingerpositionen zu unterscheiden:
// 1. Finger liegen nebeneinander:
// Zu erkennen :
// 1. x-Werte sind mind. 10 mm voneinander entfernt
// (Wert: Abstand zwischen den Markern bei aneinanderliegendem Zeige- und Mittelfinger,
// oder der Abstand den die Marker haben, wenn der Zeigefinger max. unter/�berhalb dem Mittelfinger ist!
// = gr�sserer der beiden Werte ergibt den Schwellwert, nicht kleiner werden, lieber 1-2 mm mehr angeben, den
// sobald der Abstand der Finger gr�sser ist, werden sie nur in Bezug darauf klassifiziert)
// -> kleinerer x-Wert -> Zeigefinger
// 2. x-Werte sind weniger als 10 mm voneinander entfernt -> differenz y-Wert < 16 mm ? (Wert: Fingerdicke+Markerh�he,
// wenn Zeigefingermarker auf mittlerem Phalanx, Fingerdicke wenn Zeigefingermarker auf �usserem Phalanx)
// - zum messen:
// unabh�ngig von Zeigefingermarkerposition: Zeigefinger unter Mittelfinger durch, und dabei so weit wie m�glich
// nach rechts oben mit dem Zeigefinger und Mittelfinger so nah an Zeigefinger beugen wie m�glich.
// Abstand der Marker in dieser Position.
// ergibt den Mindestwert f�r den Abstand, lieber noch 1-2 mm weniger angeben )
// -> ist der Abstand welcher ben�tigt wird um die Marker untereinander zu positionieren)
//
// ja = kleinerer x-Wert -> Zeigefinger
// nein = Finger liegen unter bzw. �bereinander
// 2. Finger liegen unter bzw. �bereinander (Position ist im Idealfall schon durch das Fingerged�chtnis der Funktion abgefangen)
// Tritt nur auf, wenn sowohl Zeige- als auch Mittelfinger gestreckt sind. Markerpositionen sind dann mehrdeutig, keine
// sichere Klassifikation m�glich, evtl. Anwendung der Heuristik: oberer Wert ist der Zeigefinger, da dies evtl. beim Zeigen mit
// dem Zeigefinger als nat�rliche Geste vorkommen k�nnte? -> �bernahme als Zeige- und Mittelfinger aber nicht als classifiziert
// kennzeichnen, damit er beim n�chsten mal nicht einfach �bernommen wird sondern neu klassifiziert wird.
// Wenn die z-Achse vom Zeigefingergelenk parallel zur Zeigerichtung verl�uft (-> entweder entlang dem Zeigefinger, oder etwas links von
// der Fingerkuppe vorbei, kann der x-Wert des Mittelfingers nicht negativ werden, da der Mittelfinger aus seinem Gelenk heraus nicht
// so weit nach links bewegt werden kann (Hand so kalibrieren, da� Ursprung �ber Zeigefingergelenk liegt. Kommt der Mittelfinger in negative
// x-Bereiche den Ursprung noch etwas weiter nach links verschieben. -> geht das nicht, kann evtl. mit einem offset gearbeitet werden?
// 3. Zeigefinger und Mittelfinger setzen wenn noch nicht gesetzt
// es d�rfen nur noch entweder der Zeigefinger- und/oder der Mittelfinger �brig sein
// alle anderen Finger - Daumen+kleiner Finger - m�ssen schon gesetzt sein
// Wenn nur noch ein Finger �brig ist ... (z.B. bei 2 Finger Version, oder bei 4 Finger, wenn vorherige Finger bereits gesetzt wurden)
if (anzRemainingFingers == 1){
// ... den noch fehlenden Finger direkt setzen
if (hand.indexFinger == null){
// ... zuerst den index Finger abpruefen, damit 2 Finger Version immer Indexfinger und nicht den Middlefinger setzt
setFinger(DataFinger.INDEXFINGER, vecFingerSet.remove(0) , hand, true);
anzRemainingFingers--;
}
else if (hand.middleFinger == null){
setFinger(DataFinger.MIDDLEFINGER, vecFingerSet.remove(0) , hand, true);
anzRemainingFingers--;
}
}
// sind noch zwei Finger �brig, diese sortieren
else if (anzRemainingFingers == 2){
int minXPos = (vecFingerSet.elementAt(0).fingerHk.getX() < vecFingerSet.elementAt(1).fingerHk.getX())?0:1;
int maxXPos = (minXPos == 0)?1:0;
// Wenn der Abstand zwischen den beiden Fingern gr�sser ist als der kleinste Abstand bei nebeneinanderliegenden Fingern ...
if ( (vecFingerSet.elementAt(minXPos).fingerHk.getX() - vecFingerSet.elementAt(maxXPos).fingerHk.getX())*(-1.0) > minDistXIndexMiddle ){
// ... ist der Zeigefinger der Finger mit dem kleinsten x-Wert
setFinger(DataFinger.INDEXFINGER, vecFingerSet.elementAt(minXPos) , hand, true);
anzRemainingFingers--;
setFinger(DataFinger.MIDDLEFINGER, vecFingerSet.elementAt(maxXPos) , hand, true);
anzRemainingFingers--;
}
else
{
// ... sonst schauen ob die Differenz in y-Richtung ausreicht um die Finger untereinander zu bringen
int minYPos = (vecFingerSet.elementAt(0).fingerHk.getY() < vecFingerSet.elementAt(1).fingerHk.getY())?0:1;
int maxYPos = (minYPos == 0)?1:0;
// wenn ja ...
if ((vecFingerSet.elementAt(minYPos).fingerHk.getY() - vecFingerSet.elementAt(maxYPos).fingerHk.getY())*(-1.0) > minDistYIndexMiddle ){
// ... ist eine Klassifizierung nicht eindeutig m�glich - Heuristik: oberer Finger ist Zeigefinger (kommt eher vor, da� der
// Zeigefinger oberhalb des Mittelfingers bewegt wird um irgendwo hin zu zeigen, als dass er unterhalb des Mittelfingers gef�hrt
// wird)
// Da dies aber nur eine Annahme ist werden die Finger gesetzt aber nicht als eindeutig klassifiziert/best�tigt gekennzeichnet
// - damit werden sie beim n�chsten Lauf erneut klassifiziert und nicht einfach �bernommen anhand der BodyId
setFinger(DataFinger.INDEXFINGER, vecFingerSet.elementAt(maxYPos) , hand, false);
anzRemainingFingers--;
setFinger(DataFinger.MIDDLEFINGER, vecFingerSet.elementAt(minYPos) , hand, false);
anzRemainingFingers--;
}
// wenn nicht ...
else{
// ... ist der Zeigefinger der Finger mit dem kleinsten x-Wert
setFinger(DataFinger.INDEXFINGER, vecFingerSet.elementAt(minXPos) , hand, true);
anzRemainingFingers--;
setFinger(DataFinger.MIDDLEFINGER, vecFingerSet.elementAt(maxXPos) , hand, true);
anzRemainingFingers--;
}
}
}
return true;
}
private int lookupPreviousHand(DataHand Hand){
// Liste der vorhergehenden H�nde nach Hand durchsuchen
handPositionIndex = -1;
for (int k=0; k<vecPrevHands.size(); k++){
if (((String) vecPrevHands.elementAt(k).getAttribute(DataConstant.IDENTIFIER)).compareTo((String) hand.getAttribute(DataConstant.IDENTIFIER)) == 0)
{
handPositionIndex = k;
k=vecPrevHands.size();
}
}
return handPositionIndex;
}
// F�gt die Hand der Liste der vorhergehenden H�nde hinzu. Ist die Hand dort bereits
// enthalten wird das bisherige Element durch das aktuelle ersetzt.
private void setPreviousHand(DataHand hand){
if(handPositionIndex > -1){
vecPrevHands.set(handPositionIndex, hand);
}
else
{
vecPrevHands.add(hand);
// Groesse des Vektors pruefen ...
if (handPositionIndex > 250){
// ... und wenn zu gross die �ltesten H�nde rausl�schen (Platz f�r 200 individuelle H�nde - sollte gen�gen)
for (int i= 0; i<50; i++){
vecPrevHands.remove(0);
}
}
}
}
// Herausl�schen von Elementen aus den Vektoren vec3dCollection, vec6dCollection, vecGroupIdFor3d, vecGroupIdFor6d
// welche zur allgemeinen Sammlung dienen, um zu verhindern, da� diese Vektoren zu gro� werden
// und �berlaufen, durch Elemente die zwar hinzugef�gt, aber nicht mehr entnommen werden
// Bei DTrack z.B. der Fall, wenn Packete geschickt werden, bei denen entweder
// - eine 3d Zeile aber keine 6d Zeile, bzw. eine 6d Zeile aber 0 Elemente, vorhanden ist
// - eine 6d Zeile aber keine 3d Zeile, bzw. eine 3d Zeile aber 0 Elemente, vorhanden ist
// DTrack sendet mit 60 Hz, d.h. 60 m�gliche Eintr�ge in den GroupId Vectoren pro Sekunde
// 20 Sekunden wird gewartet (dann sind Daten von der Zeit her uninteressant)-> 20x60-> 1000 Elemente
// Annahme: 10 6d pro Paket, 40 6d pro Paket (w�rde bei nur Handdaten f�r 10 H�nde gen�gen)
// 20 Sekunden wird gewartet -> 10x20x60-> 10000 6d Elemente und 40x20x60 -> 40000 3d Elemente
// Um genau zu sein k�nnten auch aus den Collection Vektoren nur die Elemente der im selben
// Schritt gel�schten Gruppen herausfliegen, wird im Moment aber noch nicht gemacht, schauen ob es auch
// mit der schnelleren Heuristik geht.
private void reduceCollections(){
int frequenz = 60;
int wartezeit = 20;
int anz3dproPaket = 40;
int anz6dproPaket = 10;
int loeschIntervall = 500;
// 3d Gruppe reduzieren
if (vecGroupIdFor3d.size() > frequenz*wartezeit+loeschIntervall){
for (int i=0; i<loeschIntervall; i++)
vecGroupIdFor3d.removeElementAt(0);
}
// 6d Gruppe reduzieren
if (vecGroupIdFor6d.size() > frequenz*wartezeit+loeschIntervall){
for (int i=0; i<loeschIntervall; i++)
vecGroupIdFor6d.removeElementAt(0);
}
if (vec3dCollection.size() > frequenz*wartezeit*anz3dproPaket+loeschIntervall){
for (int i=0; i<loeschIntervall; i++)
vec3dCollection.removeElementAt(0);
}
if (vec6dCollection.size() > frequenz*wartezeit*anz6dproPaket+loeschIntervall){
for (int i=0; i<loeschIntervall; i++)
vec6dCollection.removeElementAt(0);
}
if (vecKnownTargetBodyIds.size() > 1000){
for (int i=0; i<500; i++)
vecKnownTargetBodyIds.removeElementAt(0);
}
}
private IData glove2Hand(IData data) {
glove = (DataGlove) data;
hand = new DataHand(this.getClass(), glove.handSide, glove.getX(), glove.getY(), glove.z,
glove.maxX, glove.maxY, glove.maxZ, glove.rxx, glove.ryx, glove.rzx, glove.rxy, glove.ryy, glove.rzy,
glove.rxz, glove.ryz, glove.rzz, glove.groupID, glove.numGroup);
hand.setAttribute(DataConstant.IDENTIFIER, "hand" + glove.getAttribute(DataConstant.IDENTIFIER));
hand.handType = DataHand.hDTRACK;
hand.thumb = glove.thumb;
hand.indexFinger = glove.indexFinger;
hand.middleFinger = glove.middleFinger;
pos6dRot = rotate6d(hand, rotationAngleDTY);
hand.rxx = pos6dRot.rxx;
hand.rxy = pos6dRot.rxy;
hand.rxz = pos6dRot.rxz;
hand.ryx = pos6dRot.ryx;
hand.ryy = pos6dRot.ryy;
hand.ryz = pos6dRot.ryz;
hand.rzx = pos6dRot.rzx;
hand.rzy = pos6dRot.rzy;
hand.rzz = pos6dRot.rzz;
pushSample(hand);
return null;
}
private DataPosition6D rotate6d(DataPosition6D pos6D, double angleAroundY){
m6d = mu.dataPosition6D2matrix(pos6D);
m6d = mu.rotateMatrix(MathUtility.Y_AXIS, m6d, angleAroundY);
return mu.matrix2DataPosition6D(m6d);
}
private void pushSample(DataHand data){
publish(data);
}
private class MemoryHelper{
public int identifier;
public int remainingMembers;
public int collectedMembers;
public MemoryHelper(int identifier, int remainingMembers, int collectedMembers){
this.identifier = identifier;
this.remainingMembers = remainingMembers;
this.collectedMembers = collectedMembers;
}
}
private class FingerSet{
public DataFinger fingerRk;
public DataFinger fingerHk;
public FingerSet(DataFinger fingerRk, DataFinger fingerHk)
{
this.fingerRk = fingerRk;
this.fingerHk = fingerHk;
}
}
*/
}