Package de.dfki.km.text20.services.pseudorenderer.impl

Source Code of de.dfki.km.text20.services.pseudorenderer.impl.PseudorendererImpl

/*
* Pseudorenderer.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.services.pseudorenderer.impl;

import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import net.xeoh.plugins.base.util.OptionUtils;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
import de.dfki.km.text20.services.pseudorenderer.CoordinatesType;
import de.dfki.km.text20.services.pseudorenderer.Pseudorenderer;
import de.dfki.km.text20.services.pseudorenderer.PseudorendererStatus;
import de.dfki.km.text20.services.pseudorenderer.RenderElement;
import de.dfki.km.text20.services.pseudorenderer.RenderElementMetaAttribute;
import de.dfki.km.text20.services.pseudorenderer.options.GetAllElementsIntersectingOption;
import de.dfki.km.text20.services.pseudorenderer.options.getallelementsintersecting.OptionMagnetic;
import de.dfki.km.text20.services.pseudorenderer.options.getallelementsintersecting.OptionNoIntersections;
import de.dfki.km.text20.services.pseudorenderer.options.getallelementsintersecting.OptionOnlyValid;
import de.dfki.km.text20.services.pseudorenderer.renderelements.GraphicalRenderElement;
import de.dfki.km.text20.services.pseudorenderer.renderelements.TextualRenderElement;

/**
*
* @author rb
*
*/
public class PseudorendererImpl implements Pseudorenderer {

    /** All status flags */
    private final Collection<PseudorendererStatus> allStatus = new ArrayList<PseudorendererStatus>();

    /** Where the renderer is on the screen */
    final Rectangle currentGeometry = new Rectangle();

    /** Prohibits two threads from accessing the element. */
    final Lock elementsLock = new ReentrantLock();

    /** The last change ID we emitted */
    long lastChangeID = 0;

    /** Keeps all render elements created in this context */
    final Collection<RenderElement> renderElements = new ArrayList<RenderElement>();

    /** Where the viewport starts */
    final Point viewportStart = new Point();

    /** Setup the renderer */
    public PseudorendererImpl() {
        // Make us visible
        setStatus(PseudorendererStatus.VISIBLE, true);
    }

    /* (non-Javadoc)
     * @see de.dfki.km.augmentedtext.services.pseudorenderer.Pseudorenderer#convertPoint(java.awt.Point, de.dfki.km.augmentedtext.services.pseudorenderer.CoordinatesType)
     */
    @Override
    public Point convertPoint(final Point p, final CoordinatesType from, CoordinatesType to) {
        if (p == null) return null;

        final Point r = (Point) p.clone();

        if (from == CoordinatesType.SCREEN_BASED) {
            if (this.currentGeometry == null) return null;
            if (!this.currentGeometry.contains(p)) return null; //TODO: Georg: that's the point where a null centerPoint is created

            r.x -= this.currentGeometry.x;
            r.y -= this.currentGeometry.y;
            r.x += this.viewportStart.x;
            r.y += this.viewportStart.y;
        }

        if (to != CoordinatesType.DOCUMENT_BASED) throw new NotImplementedException();

        return r;
    }

    /* (non-Javadoc)
     * @see de.dfki.km.augmentedtext.services.pseudorenderer.Pseudorenderer#createElement()
     */
    @SuppressWarnings("unchecked")
    @Override
    public <T extends RenderElement> T createElement(Class<T> renderElement) {

        RenderElement re = null;

        if (renderElement.isAssignableFrom(TextualRenderElement.class)) {
            re = new TextualRenderElementImpl(this);
        }

        if (renderElement.isAssignableFrom(GraphicalRenderElement.class)) {
            re = new GraphicalRenderElementImpl(this);
        }

        if (re == null && renderElement.isAssignableFrom(RenderElement.class)) {
            re = new RenderElementImpl(this);
        }

        // Sanity check
        if (re == null)
            throw new IllegalStateException("Ups, render element must not be null at this point");

        this.elementsLock.lock();
        try {
            this.renderElements.add(re);
        } finally {
            this.elementsLock.unlock();
        }

        // Make element visible at first
        re.setVisible(true);

        return (T) re;
    }

    /* (non-Javadoc)
     * @see de.dfki.km.augmentedtext.services.pseudorenderer.Pseudorenderer#getAllElementsIntersecting(java.awt.Rectangle, de.dfki.km.augmentedtext.services.pseudorenderer.CoordinatesType, de.dfki.km.augmentedtext.services.pseudorenderer.options.GetAllElementsIntersectingOption[])
     */
    @Override
    public Collection<RenderElement> getAllElementsIntersecting(final Rectangle rectangle,
                                                                final CoordinatesType position,
                                                                final GetAllElementsIntersectingOption... options) {

        Collection<RenderElement> rval = new ArrayList<RenderElement>();

        // Handle our options ...
        final OptionUtils<GetAllElementsIntersectingOption> ou = new OptionUtils<GetAllElementsIntersectingOption>(options);

        // The point w we get is in screen coordinates. We have to calculate document coorinates first.
        final Rectangle r = (Rectangle) rectangle.clone();

        // If the coordinates are given screen-wise, convert to document position.
        if (position == CoordinatesType.SCREEN_BASED) {
            // If the gaze point is not inside the render window, do nothing ...
            if (!this.currentGeometry.intersects(rectangle)) return rval;

            r.x -= this.currentGeometry.x;
            r.y -= this.currentGeometry.y;

            r.x += this.viewportStart.x;
            r.y += this.viewportStart.y;
        }

        Collection<RenderElement> allElements;

        // Make a copy in order not to block other threads accessing the elements
        this.elementsLock.lock();
        try {
            allElements = new ArrayList<RenderElement>(this.renderElements);
        } finally {
            this.elementsLock.unlock();
        }

        // Check which rectangles intersect
        for (final RenderElement re : allElements) {
            final Rectangle geometry = re.getGeometry(CoordinatesType.DOCUMENT_BASED);
            if (geometry.intersects(r)) {
                rval.add(re);
            }
        }

        // In case we have no intersections and we're magnetic
        if (rval.size() == 0 && ou.contains(OptionMagnetic.class)) {
            final Point queryCenter = new Point((int) r.getCenterX(), (int) r.getCenterY());
            final int maxDistance = ou.get(OptionMagnetic.class).getMaxDistance();

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

            // Find best match
            for (final RenderElement re : allElements) {
                final Circle current = new Circle(re.getGeometry(CoordinatesType.DOCUMENT_BASED));
                final double currentDistance = current.borderDistance(queryCenter);

                if (currentDistance < distance && currentDistance <= maxDistance) {
                    distance = currentDistance;
                    bestMatch = re;
                }
            }

            if (bestMatch != null) {
                rval.add(bestMatch);
            }
        }

        // First, filter all invalid data.
        if (ou.contains(OptionOnlyValid.class)) {
            final Collection<RenderElement> _rval = new ArrayList<RenderElement>();

            // Process elements again, only add elements which dont have an INVALID status.
            for (final RenderElement renderElement : rval) {
                if (renderElement.hasMetaAttribute(RenderElementMetaAttribute.INVALID)) {
                    if (renderElement.getMetaAttribute(RenderElementMetaAttribute.INVALID).equals(Boolean.TRUE))
                        continue;
                }

                _rval.add(renderElement);
            }

            // Replace original data
            rval = _rval;
        }

        // Next, remove intersections
        if (ou.contains(OptionNoIntersections.class))
            throw new IllegalArgumentException("Not implemented yet");

        return rval;
    }

    /* (non-Javadoc)
     * @see de.dfki.km.augmentedtext.services.pseudorenderer.Pseudorenderer#getGeometry()
     */
    @Override
    public Rectangle getGeometry() {
        return (Rectangle) this.currentGeometry.clone();
    }

    /* (non-Javadoc)
     * @see de.dfki.km.augmentedtext.services.pseudorenderer.Pseudorenderer#getStatus()
     */
    @Override
    public Collection<PseudorendererStatus> getStatus() {
        return this.allStatus;
    }

    /* (non-Javadoc)
     * @see de.dfki.km.augmentedtext.services.pseudorenderer.Pseudorenderer#getViewport()
     */
    @Override
    public Point getViewport() {
        return (Point) this.viewportStart.clone();
    }

    /* (non-Javadoc)
     * @see de.dfki.km.augmentedtext.services.pseudorenderer.Pseudorenderer#setGeometry(int, int, int, int)
     */
    @Override
    public void setGeometry(final Rectangle g) {
        this.currentGeometry.x = g.x;
        this.currentGeometry.y = g.y;
        this.currentGeometry.width = g.width;
        this.currentGeometry.height = g.height;

        // System.out.println("Updated windowGeometry: (" + screenX + "," + screenY + "," + width + "," + height + ")");
    }

    /* (non-Javadoc)
     * @see de.dfki.km.augmentedtext.services.pseudorenderer.Pseudorenderer#setStatus(de.dfki.km.augmentedtext.services.pseudorenderer.PseudorendererStatus, boolean)
     */
    @Override
    public void setStatus(final PseudorendererStatus status, final boolean value) {
        if (value == false) {
            this.allStatus.remove(status);
            return;
        }

        if (this.allStatus.contains(status)) return;

        this.allStatus.add(status);
    }

    /* (non-Javadoc)
     * @see de.dfki.km.augmentedtext.services.pseudorenderer.Pseudorenderer#setViewport(int, int)
     */
    @Override
    public void setViewport(final Point start) {
        this.viewportStart.x = start.x;
        this.viewportStart.y = start.y;

        // System.out.println("Updated viewport: (" + documentX + "," + documentY + ")");
    }

    /**
     * @return
     */
    protected long getChangeID() {
        return this.lastChangeID++;
    }

    /* (non-Javadoc)
     * @see de.dfki.km.augmentedtext.services.pseudorenderer.Pseudorenderer#removeElement(de.dfki.km.augmentedtext.services.pseudorenderer.RenderElement)
     */
    @Override
    public void removeElement(final RenderElement renderElementImpl) {

        // Hide the element
        renderElementImpl.setVisible(false);

        // Make a copy in order not to block other threads accessing the elements
        this.elementsLock.lock();
        try {

            this.renderElements.remove(renderElementImpl);
        } finally {
            this.elementsLock.unlock();
        }
    }
}
TOP

Related Classes of de.dfki.km.text20.services.pseudorenderer.impl.PseudorendererImpl

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.