Package de.dfki.km.text20.util.filter.displacement

Source Code of de.dfki.km.text20.util.filter.displacement.MagneticDisplacementFilter

/*
* DisplacementFilter.java
*
* Copyright (c) 2010, Ralf Biedert, DFKI. All rights reserved.
*
* This library 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 library 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 library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301  USA
*
*/
package de.dfki.km.text20.util.filter.displacement;

import java.awt.Point;
import java.awt.Rectangle;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import de.dfki.km.text20.services.pseudorenderer.CoordinatesType;
import de.dfki.km.text20.services.pseudorenderer.RenderElement;
import de.dfki.km.text20.services.pseudorenderer.renderelements.TextualRenderElement;
import de.dfki.km.text20.services.trackingdevices.eyes.EyeTrackingEvent;
import de.dfki.km.text20.services.trackingdevices.eyes.util.wrapper.TrackingEventWrapper;
import de.dfki.km.text20.util.filter.AbstractFilter;
import de.dfki.km.text20.util.filter.displacement.GridEntry.GridStatus;

/**
* Displacement filter, alters the central position based on document information
* @author rb
*/
public class MagneticDisplacementFilter extends AbstractFilter {

    /** offset of the document in the window */
    Point documentOffset = new Point();

    /** Manges the displacement grid */
    final Grid grid = new Grid(100, 100);

    /** Ensures every RE exists only once */
    Map<String, RenderElement> renderElements = new HashMap<String, RenderElement>();

    /** Where the elements are located */
    Rectangle screenPosition = new Rectangle();

    @Override
    public EyeTrackingEvent filterEvent(final EyeTrackingEvent event) {

        // Check if the gaze is inside the document.
        final Point documentPoint = screenToDocumentPoint(event.getGazeCenter());
        if (documentPoint == null) return event;

        // Displacement to apply to the center point
        final Point displacement = new Point();

        // Obtain grid entry for point
        final Point gazeCenter = event.getGazeCenter();
        final GridEntry gridForPoint = this.grid.getGridForPoint(gazeCenter);

        // If we already have a status for the point, return it ... (may not be the best choice ...?)
        // if (gridForPoint.gridStatus.equals(GridStatus.SET)) { return createWrapped(event, gridForPoint.xdisplacement, gridForPoint.ydisplacement); }

        // Get elements near the document gaze point
        final RenderElement bestNear = getBestElementNear(documentPoint);
        if (bestNear == null) return event;

        // Update the displacement
        displacement.y = (int) (bestNear.getGeometry(CoordinatesType.DOCUMENT_BASED).getCenterY() - documentPoint.y);
        // displacement.x = (int) (bestNear.getGeometry().getCenterX() - documentPoint.x);

        // Only return new event if we have a displacement.
        if (displacement.x > 0 || displacement.y > 0) {
            // Update grid for point information
            gridForPoint.xdisplacement = displacement.x;
            gridForPoint.ydisplacement = displacement.y;
            gridForPoint.gridStatus = GridStatus.SET;

            return createWrapped(event, displacement.x, displacement.y);
        }

        return event;
    }

    /**
     * Change document offset
     *
     * @param o
     */
    public void updateDocumentOffset(final Point o) {
        this.documentOffset = o;
    }

    /**
     * Updates a render element inside the filter.
     *
     * @param re
     */
    public void updateRenderElement(final RenderElement re) {
        if (re == null) return;

        this.renderElements.put(re.getIdentifier(), re);
    }

    /**
     * Updates the screen position
     *
     * @param r
     */
    public void updateScreenPosition(final Rectangle r) {
        this.screenPosition = r;
    }

    /**
     * Creates a wrapped tracking event
     *
     * @param event
     * @param dx
     * @param dy
     * @return
     */
    private EyeTrackingEvent createWrapped(final EyeTrackingEvent event, final int dx,
                                           final int dy) {
        return new TrackingEventWrapper(event) {

            @Override
            public Point getGazeCenter() {
                final Point gazeCenter = event.getGazeCenter();
                return new Point(gazeCenter.x + dx, gazeCenter.y + dy);
            }
        };

    }

    /**
     * Returns the 'best'  element close to the gaze point
     * 
     * @param documentPoint
     * @return
     */
    protected RenderElement getBestElementNear(final Point documentPoint) {
        final Set<String> ids = this.renderElements.keySet();

        double distance = Double.MAX_VALUE;
        RenderElement bestGuess = null;

        for (final String id : ids) {
            final RenderElement renderElement = this.renderElements.get(id);

            // Currently we only care for text elements
            if (!(renderElement instanceof TextualRenderElement)) {
                continue;
            }

            final Rectangle geometry = renderElement.getGeometry(CoordinatesType.DOCUMENT_BASED);

            // Elements too large dont give enough information for interesting points ... We alo
            // dont care about the width, as we currently want to displace y-wise only ...
            // TODO: A bit harsh this limit ...
            if (geometry.height > 30) {
                continue;
            }

            // Use point directly above or below gaze.
            final Point p = new Point(documentPoint.x, (int) geometry.getCenterY());
            final double d = documentPoint.distance(p);

            // If the distance is too large, ignore
            // TODO: Check this limit as well
            if (d > 100) {
                continue;
            }

            if (d < distance) {
                distance = d;
                bestGuess = renderElement;
            }

        }

        return bestGuess;
    }

    /**
     *
     * @param p
     * @return
     */
    Point screenToDocumentPoint(final Point p) {
        if (!this.screenPosition.contains(p)) return null;

        final Point rval = (Point) p.clone();
        rval.x -= this.screenPosition.x;
        rval.y -= this.screenPosition.y;
        rval.x += this.documentOffset.x;
        rval.y += this.documentOffset.y;
        return rval;
    }
}
TOP

Related Classes of de.dfki.km.text20.util.filter.displacement.MagneticDisplacementFilter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.