FileDocCategorySizeDatePackage
LeafMotionSegment.javaAPI DocphoneME MR2 API (J2ME)7834Wed May 02 18:00:34 BST 2007com.sun.perseus.model

LeafMotionSegment.java

/*
 *
 *
 * Copyright  1990-2007 Sun Microsystems, Inc. All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 only, as published by the Free Software Foundation.
 * 
 * This program 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
 * General Public License version 2 for more details (a copy is
 * included at /legal/license.txt).
 * 
 * You should have received a copy of the GNU General Public License
 * version 2 along with this work; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 * 
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
 * Clara, CA 95054 or visit www.sun.com if you need additional
 * information or have any questions.
 */
package com.sun.perseus.model;

import com.sun.perseus.platform.MathSupport;

/**
 * Represents a time interval in an animation.
 *
 * @version $Id: LeafMotionSegment.java,v 1.3 2006/06/29 10:47:32 ln156897 Exp $
 */
final class LeafMotionSegment implements MotionSegment {
    /**
     * The segment's begin value.
     */
    float[][] start;

    /**
     * The segment's end value.
     */
    float[][] end;

    /**
     * Builds a new motion segment for the given previous segment and 
     * end value.
     *
     * @param prevSegment the preceding segment. Should not be null.
     * @param x2 the motion's end point, on the x-axis
     * @param y2 the motion's end point, on the y-axis
     * @param motion the corresponding AnimateMotion
     */
    public LeafMotionSegment(final LeafMotionSegment prevSegment,
                             final float x2,
                             final float y2,
                             final AnimateMotion motion) {
        start = prevSegment.end;
        end = new float[6][1];
        end[4][0] = x2;
        end[5][0] = y2;

        computeRotate(motion);
    }

    /**
     * Builds a new motion segment for the given start and end 
     * points.
     *
     * @param x1 the motion's starting point on the x-axis
     * @param y1 the motion's stating point, on the y-axis
     * @param x2 the motion's end point, on the x-axis
     * @param y2 the motion's end point, on the y-axis
     * @param motion the corresponding AnimateMotion
     */
    public LeafMotionSegment(final float x1, 
                             final float y1,
                             final float x2,
                             final float y2,
                             final AnimateMotion motion) {
        start = new float[6][1];
        end = new float[6][1];

        start[0][0] = 1;
        start[3][0] = 1;
        start[4][0] = x1;
        start[5][0] = y1;

        end[4][0] = x2;
        end[5][0] = y2;

        computeRotate(motion);
    }

    /**
     * Computes the rotation component on the end value.
     *
     * @param motion the associated AnimateMotion.
     */
    void computeRotate(final AnimateMotion motion) {
        float cosRotate = motion.cosRotate;
        float sinRotate = motion.sinRotate;

        if (motion.rotateType != AnimateMotion.ROTATE_ANGLE) {
            float dx = end[4][0] - start[4][0];
            float dy = end[5][0] - start[5][0];
            float theta = MathSupport.atan2(dy, dx);
            if (motion.rotateType == AnimateMotion.ROTATE_AUTO_REVERSE) {
                theta += MathSupport.PI;
            }

            cosRotate = MathSupport.cos(theta);
            sinRotate = MathSupport.sin(theta);
        } 

        end[0][0] = cosRotate;
        end[1][0] = sinRotate;
        end[2][0] = -sinRotate;
        end[3][0] = cosRotate;
    }

    /**
     * @return the start value.
     */
    public Object[] getStart() {
        return start;
    }

    /**
     * @return set end value.
     */
    public Object[] getEnd() {
        return end;
    }

    /**
     * Computes an interpolated value for the given penetration in the 
     * segment.
     *
     * @param p the segment penetration. Should be in the [0, 1] range.
     * @param w array where the computed value should be stored.
     */
    public void compute(final float p, final float[][] w) {
        // The rotation component is kept in the end value. 
        // The translation is an interpolation of the begin and 
        // end values.
        w[0][0] = end[0][0];
        w[1][0] = end[1][0];
        w[2][0] = end[2][0];
        w[3][0] = end[3][0];
        w[4][0] = p * end[4][0] + (1 - p) * start[4][0];
        w[5][0] = p * end[5][0] + (1 - p) * start[5][0];
    }

    /**
     * Computes the 'motion' length for this segment
     */
    public float getLength() {
        float dx = end[4][0] - start[4][0];
        float dy = end[5][0] - start[5][0];
        
        return MathSupport.sqrt(dx * dx + dy * dy);
    }    

    /**
     * Collapses this segment with the one passed as a parameter.
     * Note that if the input segment is not of the same class
     * as this one, an IllegalArgumentException is thrown. The 
     * method also throws an exception if the input segment's
     * end does not have the same number of components as this 
     * segment's end.
     *
     * After this method is called, this segment's end value
     * is the one of the input <code>seg</code> parameter.
     *
     * @param seg the Segment to collapse with this one.
     * @param anim the Animation this segment is part of.
     */
    public void collapse(final Segment seg, final Animation anim) {
        LeafMotionSegment mseg = (LeafMotionSegment) seg;
        end = mseg.end;
        computeRotate((AnimateMotion) anim);
    }

    /**
     * Adds the input value to this Segment's end value.
     * 
     * @param by the value to add. Throws IllegalArgumentException if this
     * Segment type is not additive or if the input value is incompatible (e.g.,
     * different number of components or different number of dimensions on a
     * component).
     */
    public void addToEnd(Object[] by) {
        float[][] add = (float[][]) by;

        // Adding motion segments is equivalent to concatenating transforms.
        // So the result of adding the input value to the end is equivalent
        // to concatenating the by value matrix to the end value matrix.
        float[][] tmpEnd = new float[6][1];
        tmpEnd[0][0] = end[0][0] * add[0][0] + end[2][0] * add[1][0];
        tmpEnd[1][0] = end[1][0] * add[0][0] + end[3][0] * add[1][0];

        tmpEnd[2][0] = end[0][0] * add[2][0] + end[2][0] * add[3][0];
        tmpEnd[3][0] = end[1][0] * add[2][0] + end[3][0] * add[3][0];

        tmpEnd[4][0] = end[0][0] * add[4][0] + end[2][0] * add[5][0] 
                        + end[4][0];
        tmpEnd[5][0] = end[1][0] * add[4][0] + end[3][0] * add[5][0] 
                        + end[5][0];

        end = tmpEnd;
    }

    /**
     * @return true if this segment type supports addition. false
     * otherwise.
     */
    public boolean isAdditive() {
        return true;
    }

    /**
     * Sets the start value to its notion of 'zero'
     */
    public void setZeroStart() {
        start[4][0] = 0;
        start[5][0] = 0;
    }

    /**
     * Sets the start value. 
     *
     * @param newStart the new segment start value.
     */
    public void setStart(Object[] newStart) {
        start = (float[][]) newStart;
    }

    /**
     * Should be called after the segment's configuration is complete
     * to give the segment's implementation a chance to initialize 
     * internal data and cache values.
     */
    public void initialize() {
    }
}