package org.myrobotlab.service;
import java.io.IOException;
import java.util.List;
import org.myrobotlab.framework.Service;
import org.myrobotlab.framework.ServiceType;
import org.myrobotlab.kinematics.Point;
import org.myrobotlab.leap.LeapMotionListener;
import org.myrobotlab.logging.Level;
import org.myrobotlab.logging.LoggerFactory;
import org.myrobotlab.logging.Logging;
import org.myrobotlab.logging.LoggingFactory;
import org.myrobotlab.service.data.LeapData;
import org.myrobotlab.service.interfaces.LeapDataListener;
import org.myrobotlab.service.interfaces.LeapDataPublisher;
import org.myrobotlab.service.interfaces.PointPublisher;
import org.slf4j.Logger;
import com.leapmotion.leap.Controller;
import com.leapmotion.leap.Finger;
import com.leapmotion.leap.Frame;
import com.leapmotion.leap.Vector;
public class LeapMotion extends Service implements LeapDataListener, LeapDataPublisher, PointPublisher {
private static final long serialVersionUID = 1L;
public final static Logger log = LoggerFactory.getLogger(LeapMotion.class);
transient LeapMotionListener listener = null;
transient Controller controller = new Controller();
public LeapData lastLeapData = null;
public LeapMotion(String n) {
super(n);
}
public void activateDefaultMode() {
controller.setPolicyFlags(Controller.PolicyFlag.POLICY_DEFAULT);
log.info("default mode active");
return;
}
public void activateVRMode() {
controller.setPolicyFlags(Controller.PolicyFlag.POLICY_OPTIMIZE_HMD);
log.info("virtual reality mode active");
return;
}
public void addFrameListener(Service service) {
addListener("publishFrame", service.getName(), "onFrame");
}
public void addLeapDataListener(Service service) {
addListener("publishLeapData", service.getName(), "onLeapData");
}
public void checkPolicy() {
log.info("controller.policyFlags()");
}
/**
* Return the angle of the finger for the hand specified This computes the
* angle based on the dot product of the palmNormal and the fingerDirection
* Theta = arccos( (V1.V2) / ( |V1| * |V2| )
*
* @param hand
* - "left" or "right"
* @param tip
* - 0 (thumb) / 1 (index) .. etc..
* @return angle in degrees
*/
public double getJointAngle(String hand, Integer tip) {
com.leapmotion.leap.Hand h = null;
if ("left".equalsIgnoreCase(hand)) {
// left hand
h = controller.frame().hands().leftmost();
} else {
// right hand
h = controller.frame().hands().rightmost();
}
// TODO: does this return the correct finger?
Finger f = h.fingers().get(tip);
Vector palmNormal = h.palmNormal();
Vector fDir = f.direction();
// TODO: validate that this is what we actually want.
// otherwise we can directly compute the angleTo in java.
float angleInRadians = palmNormal.angleTo(fDir);
// convert to degrees so it's easy to pass to servos
double angle = Math.toDegrees(angleInRadians);
return angle;
}
public float getLeftStrength() {
Frame frame = controller.frame();
com.leapmotion.leap.Hand hand = frame.hands().leftmost();
float strength = hand.grabStrength();
return strength;
}
public float getRightStrength() {
Frame frame = controller.frame();
com.leapmotion.leap.Hand hand = frame.hands().rightmost();
float strength = hand.grabStrength();
return strength;
}
@Override
public LeapData onLeapData(LeapData data) {
return data;
// TODO Auto-generated method stub
}
public Controller publishConnect(Controller controller) {
return controller;
}
public Controller publishDisconnect(Controller controller) {
return controller;
}
public Controller publishExit(Controller controller) {
return controller;
}
public Frame publishFrame(Frame frame) {
return frame;
}
public Controller publishInit(Controller controller) {
return controller;
}
@Override
public LeapData publishLeapData(LeapData data) {
// if (data != null) {
// log.info("DATA" + data.leftHand.posX);
// }
return data;
}
@Override
public void startService() {
super.startService();
listener = new LeapMotionListener(this);
// we've been asked to start.. we should start tracking !
this.startTracking();
}
public void startTracking() {
controller.addListener(listener);
}
public void stopTracking() {
controller.removeListener(listener);
}
public static void main(String[] args) {
LoggingFactory.init(Level.INFO);
try {
LeapMotion leap = new LeapMotion("leap");
leap.startService();
Runtime.start("gui", "GUIService");
Runtime.start("webgui", "WebGui");
// Have the sample listener receive events from the controller
// leap.startTracking();
// Keep this process running until Enter is pressed
log.info("Press Enter to quit...");
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
// Remove the sample listener when done
} catch (Exception e) {
Logging.logError(e);
}
}
@Override
public List<Point> publishPoints(List<Point> points) {
return points;
}
public void addPointsListener(Service s) {
// TODO - reflect on a public heard method - if doesn't exist error ?
addListener("publishPoints", s.getName(), "onPoints");
}
/**
* This static method returns all the details of the class without it having
* to be constructed. It has description, categories, dependencies, and peer
* definitions.
*
* @return ServiceType - returns all the data
*
*/
static public ServiceType getMetaData() {
ServiceType meta = new ServiceType(LeapMotion.class.getCanonicalName());
meta.addDescription("Leap Motion Service");
meta.addCategory("sensor");
meta.addDependency("com.leapmotion", "2.1.3");
return meta;
}
}