package com.dronecontrol.perceptual.components;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
import com.dronecontrol.perceptual.PerceptualPipeline;
import com.dronecontrol.perceptual.components.filters.BilateralFilter;
import com.dronecontrol.perceptual.components.filters.Filter;
import com.dronecontrol.perceptual.data.DetectionType;
import com.dronecontrol.perceptual.data.body.BodyPart;
import com.dronecontrol.perceptual.data.body.Coordinate;
import com.dronecontrol.perceptual.data.body.Hand;
import com.dronecontrol.perceptual.data.events.DetectionData;
import com.dronecontrol.perceptual.data.events.HandsDetectionData;
import com.dronecontrol.perceptual.listeners.DetectionListener;
import intel.pcsdk.PXCMGesture;
import java.util.Map;
import java.util.Set;
public class DetectionComponent implements PerceptualQueryComponent {
private final Filter leftHandFilter;
private final Filter rightHandFilter;
private Map<DetectionType<?>, Set<DetectionListener<?>>> detectionListeners;
private PXCMGesture.GeoNode leftHandGeoNode;
private PXCMGesture.GeoNode rightHandGeoNode;
@Inject
public DetectionComponent(BilateralFilter leftHandFilter, BilateralFilter rightHandFilter) {
this.leftHandFilter = leftHandFilter;
this.rightHandFilter = rightHandFilter;
detectionListeners = Maps.newHashMap();
}
@Override
public void queryFeatures(PerceptualPipeline pipeline) {
leftHandGeoNode = new PXCMGesture.GeoNode();
rightHandGeoNode = new PXCMGesture.GeoNode();
pipeline.QueryGeoNode(PXCMGesture.GeoNode.LABEL_BODY_HAND_RIGHT, leftHandGeoNode);
pipeline.QueryGeoNode(PXCMGesture.GeoNode.LABEL_BODY_HAND_LEFT, rightHandGeoNode);
}
@Override
public void processFeatures() {
Hand rightHand = new Hand(getSmoothedCoordinate(rightHandFilter, rightHandGeoNode), getCoordinate(rightHandGeoNode), isActive(rightHandGeoNode));
Hand leftHand = new Hand(getSmoothedCoordinate(leftHandFilter, leftHandGeoNode), getCoordinate(leftHandGeoNode), isActive(leftHandGeoNode));
//Sometimes Hands are mixed up. Switch them in case that x-position of right hand is greater than left hands x-position
if (rightHand.isActive() && leftHand.isActive()) {
if (rightHand.getCoordinate().getX() > leftHand.getCoordinate().getX()) {
Hand temporaryRightHand = rightHand;
rightHand = leftHand;
leftHand = temporaryRightHand;
}
}
invokeDetectionListeners(DetectionType.HANDS, new HandsDetectionData(leftHand, rightHand));
}
private Coordinate getSmoothedCoordinate(Filter filter, PXCMGesture.GeoNode handGeoNode) {
return filter.getFilteredCoordinate(getCoordinate(handGeoNode));
}
private Coordinate getCoordinate(PXCMGesture.GeoNode handGeoNode) {
if (handGeoNode.positionWorld != null) {
return new Coordinate(handGeoNode.positionWorld.x, handGeoNode.positionWorld.z, handGeoNode.positionWorld.y);
} else {
return null;
}
}
private boolean isActive(PXCMGesture.GeoNode handGeoNode) {
return handGeoNode.positionWorld != null;
}
public <T extends BodyPart> void addDetectionListener(DetectionType<T> detectionType, DetectionListener<T> listener) {
if (!detectionListeners.containsKey(detectionType)) {
detectionListeners.put(detectionType, Sets.<DetectionListener<?>>newLinkedHashSet());
}
Set<DetectionListener<?>> listeners = detectionListeners.get(detectionType);
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}
public <T extends BodyPart> void removeDetectionListener(DetectionType<T> detectionType, DetectionListener<T> listener) {
if (!detectionListeners.containsKey(detectionType)) {
return;
}
Set<DetectionListener<?>> listeners = detectionListeners.get(detectionType);
if (!listeners.contains(listener)) {
listeners.remove(listener);
}
}
@SuppressWarnings("unchecked")
public <T extends BodyPart> void invokeDetectionListeners(DetectionType<T> detectionType, DetectionData<T> data) {
if (!detectionListeners.containsKey(detectionType)) {
return;
}
Set<DetectionListener<?>> listeners = detectionListeners.get(detectionType);
for (DetectionListener<?> detectionListener : listeners) {
DetectionListener<T> specificListener = (DetectionListener<T>) detectionListener;
specificListener.onDetection(data);
}
}
}