/*
JWildfire - an image and animation processor written in Java
Copyright (C) 1995-2015 Andreas Maschke
This is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with this software;
if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jwildfire.create.tina.leapmotion;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import org.jwildfire.base.Prefs;
import org.jwildfire.base.Tools;
import org.jwildfire.create.tina.base.Flame;
import org.jwildfire.create.tina.base.motion.MotionCurve;
import org.jwildfire.create.tina.leapmotion.LeapMotionEditorListenerRecorder.LeapMotionEditorEventWithFrame;
import org.jwildfire.create.tina.swing.StandardDialogs;
import org.jwildfire.create.tina.swing.TinaController;
import org.jwildfire.create.tina.swing.TxtFileChooser;
import org.jwildfire.swing.ErrorHandler;
import com.leapmotion.leap.Controller;
public class LeapMotionControllerHolder {
private final TinaController tinaController;
private final ErrorHandler errorHandler;
private final JPanel rootPanel;
private Controller leapMotionController = null;
private LeapMotionEditorListener listener = null;
private LeapMotionEditorListenerThread leapMotionEditorListenerThread = null;
private LeapMotionEditorListenerRecorder recorder;
private boolean doSave = false;
public LeapMotionControllerHolder(TinaController pTinaController, ErrorHandler pErrorHandler, JPanel pRootPanel) {
tinaController = pTinaController;
errorHandler = pErrorHandler;
rootPanel = pRootPanel;
}
public void stopLeapMotionListener() {
try {
try {
if (leapMotionController != null && listener != null) {
leapMotionController.removeListener(listener);
}
}
finally {
listener = null;
}
if (leapMotionEditorListenerThread != null) {
leapMotionEditorListenerThread.signalCancel();
leapMotionEditorListenerThread = null;
}
if (recorder != null && !recorder.isEmpty()) {
tinaController.undoAction();
applyMotionToFlame(recorder, tinaController.getCurrFlame());
tinaController.refreshUI();
if (doSave && StandardDialogs.confirm(rootPanel, "Do you want to save the recorded motion-data?")) {
Prefs prefs = Prefs.getPrefs();
JFileChooser chooser = new TxtFileChooser(prefs);
if (prefs.getTinaRawMotionDataPath() != null) {
try {
chooser.setCurrentDirectory(new File(prefs.getTinaRawMotionDataPath()));
}
catch (Exception ex) {
ex.printStackTrace();
}
}
else if (prefs.getTinaFlamePath() != null) {
try {
chooser.setCurrentDirectory(new File(prefs.getTinaFlamePath()));
}
catch (Exception ex) {
ex.printStackTrace();
}
}
if (chooser.showOpenDialog(rootPanel) == JFileChooser.APPROVE_OPTION) {
try {
exportMotionToFile(chooser.getSelectedFile());
}
catch (Exception ex) {
errorHandler.handleError(ex);
}
}
}
}
}
catch (Exception ex) {
ex.printStackTrace();
}
}
private void applyMotionToFlame(LeapMotionEditorListenerRecorder pRecorder, Flame pFlame) {
List<LeapMotionEditorEventWithFrame> dataList = pRecorder.getTransformedData();
dataList = compress(dataList);
if (dataList.size() > 1) {
LeapMotionConnectedProperties config = pRecorder.getConfig();
for (LeapMotionConnectedProperty property : config.getProperties()) {
MotionCurve curve = property.getOutputChannel().getMotionCurve(property, pFlame);
if (curve != null) {
int frames[] = new int[dataList.size()];
double amp[] = new double[dataList.size()];
double ampMin = 0.0, ampMax = 0.0;
for (int i = 0; i < dataList.size(); i++) {
LeapMotionEditorEventWithFrame data = dataList.get(i);
double recordedValue = property.getInputChannel().getValue(property.getLeapMotionHand(), data);
double transformedValue = property.transformInputValue(recordedValue);
frames[i] = Tools.FTOI(data.getFrame());
amp[i] = transformedValue;
if (amp[i] < ampMin) {
ampMin = amp[i];
}
else if (amp[i] > ampMax) {
ampMax = amp[i];
}
}
curve.setPoints(frames, amp);
curve.setViewXMin(-10);
curve.setViewXMax(Tools.FTOI(dataList.get(dataList.size() - 1).getFrame()) + 10);
curve.setViewYMin(ampMin + (ampMax - ampMin) / 10.0);
curve.setViewYMax(ampMax + (ampMax - ampMin) / 10.0);
curve.setEnabled(true);
}
}
}
}
private List<LeapMotionEditorEventWithFrame> compress(List<LeapMotionEditorEventWithFrame> pInput) {
Map<Integer, List<LeapMotionEditorEventWithFrame>> map = new HashMap<Integer, List<LeapMotionEditorEventWithFrame>>();
for (LeapMotionEditorEventWithFrame event : pInput) {
int frame = Tools.FTOI(event.getFrame());
List<LeapMotionEditorEventWithFrame> lst = map.get(frame);
if (lst == null) {
lst = new ArrayList<LeapMotionEditorEventWithFrame>();
map.put(frame, lst);
}
lst.add(event);
}
List<Integer> sortedFrames = new ArrayList<Integer>(map.keySet());
Collections.sort(sortedFrames);
List<LeapMotionEditorEventWithFrame> res = new ArrayList<LeapMotionEditorEventWithFrame>();
for (Integer frame : sortedFrames) {
LeapMotionEditorEventWithFrame compressed = new LeapMotionEditorEventWithFrame();
compressed.setFrame(frame);
int cnt = 0;
for (LeapMotionEditorEventWithFrame src : map.get(frame)) {
compressed.getLeftHand().setPosX(compressed.getLeftHand().getPosX() + src.getLeftHand().getPosX());
compressed.getLeftHand().setPosY(compressed.getLeftHand().getPosY() + src.getLeftHand().getPosY());
compressed.getLeftHand().setPosZ(compressed.getLeftHand().getPosZ() + src.getLeftHand().getPosZ());
compressed.getLeftHand().setRoll(compressed.getLeftHand().getRoll() + src.getLeftHand().getRoll());
compressed.getLeftHand().setPitch(compressed.getLeftHand().getPitch() + src.getLeftHand().getPitch());
compressed.getLeftHand().setYaw(compressed.getLeftHand().getYaw() + src.getLeftHand().getYaw());
compressed.getRightHand().setPosX(compressed.getRightHand().getPosX() + src.getRightHand().getPosX());
compressed.getRightHand().setPosY(compressed.getRightHand().getPosY() + src.getRightHand().getPosY());
compressed.getRightHand().setPosZ(compressed.getRightHand().getPosZ() + src.getRightHand().getPosZ());
compressed.getRightHand().setRoll(compressed.getRightHand().getRoll() + src.getRightHand().getRoll());
compressed.getRightHand().setPitch(compressed.getRightHand().getPitch() + src.getRightHand().getPitch());
compressed.getRightHand().setYaw(compressed.getRightHand().getYaw() + src.getRightHand().getYaw());
cnt++;
}
compressed.getLeftHand().setPosX(compressed.getLeftHand().getPosX() / (double) cnt);
compressed.getLeftHand().setPosY(compressed.getLeftHand().getPosY() / (double) cnt);
compressed.getLeftHand().setPosZ(compressed.getLeftHand().getPosZ() / (double) cnt);
compressed.getLeftHand().setRoll(compressed.getLeftHand().getRoll() / (double) cnt);
compressed.getLeftHand().setPitch(compressed.getLeftHand().getPitch() / (double) cnt);
compressed.getLeftHand().setYaw(compressed.getLeftHand().getYaw() / (double) cnt);
compressed.getRightHand().setPosX(compressed.getRightHand().getPosX() / (double) cnt);
compressed.getRightHand().setPosY(compressed.getRightHand().getPosY() / (double) cnt);
compressed.getRightHand().setPosZ(compressed.getRightHand().getPosZ() / (double) cnt);
compressed.getRightHand().setRoll(compressed.getRightHand().getRoll() / (double) cnt);
compressed.getRightHand().setPitch(compressed.getRightHand().getPitch() / (double) cnt);
compressed.getRightHand().setYaw(compressed.getRightHand().getYaw() / (double) cnt);
res.add(compressed);
}
return res;
}
private void exportMotionToFile(File pFile) throws Exception {
Tools.writeUTF8Textfile(pFile.getAbsolutePath(), recorder.getDataAsString());
}
public void startLeapMotionListener(LeapMotionConnectedProperties pConfig, int pFps) {
try {
tinaController.saveUndoPoint();
tinaController.countDown(3);
if (leapMotionController == null) {
leapMotionController = new Controller();
}
recorder = new LeapMotionEditorListenerRecorder(pConfig, pFps);
leapMotionEditorListenerThread = new LeapMotionEditorListenerThread(pConfig, tinaController);
listener = new LeapMotionEditorListener(leapMotionEditorListenerThread, recorder);
new Thread(leapMotionEditorListenerThread).start();
leapMotionController.addListener(listener);
}
catch (Exception ex) {
errorHandler.handleError(ex);
}
}
}