All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mechio.api.animation.MotionPath Maven / Gradle / Ivy

/*
 * Copyright 2014 the MechIO Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.mechio.api.animation;

import org.mechio.api.animation.compiled.CompiledPath;
import java.awt.geom.Point2D;
import org.mechio.api.interpolation.InterpolatorDirectory;
import org.mechio.api.interpolation.InterpolatorFactory;

/**
 * An extended PathInterpolator which can generate a CompiledPath from the
 * interpolated positions.
 *
 * @author Matthew Stevenson 
 */
public class MotionPath extends PathInterpolator{
    private CompiledPath myCache = null;
    private String myName;
    private Long myStartTime;
    private Long myStopTime;

    /**
     * Creates an empty MotionPath with the default Interpolator.
     */
    public MotionPath(){
        this(InterpolatorDirectory.instance().getDefaultFactory());
    }
    /**
     * Creates a MotionPath with an Interpolator from the given InterpolatorFactory.
     *
     * @param factory the InterpolatorFactory from which a Motion Path is to be created
     */
    public MotionPath(InterpolatorFactory factory){
        super(factory);
        myName = "path";
    }
    /**
     * Returns the MotionPath's name.  By default this is null.
     * @return the MotionPath's name
     */
    public String getName(){
        return myName;
    }
    /**
     * Sets the name of the MotionPath
     * @param name the name to set
     */
    public void setName(String name){
        if(name == null || name.isEmpty()){
            myName = "path";
            return;
        }
        myName = name.trim();
    }
    /**
     * Sets the start time
     * @param time start time
     */
    public void setStartTime(Long time){
        if(time < 0){
            throw new IllegalArgumentException("start time must be positive");
        }
        myStartTime = time;
    }
    /**
     * Returns the start time
     * @return start time
     */
    public Long getStartTime(){
        return myStartTime;
    }
    /**
     * Sets the stop time
     * @param time stop time
     */
    public void setStopTime(Long time){
        if(time < 0){
            throw new IllegalArgumentException("start time must be positive");
        }
        myStopTime = time;
    }
    /**
     * Returns the stop time
     * @return stop time
     */
    public Long getStopTime(){
        return myStopTime;
    }
    /**
     * Gets a CompiledPath of the full MotionPath.
     * Returns a cached path if available, otherwise generates and caches the
     * path.  The cached path is cleared when the MotionPath is modified.
     *
     * @param stepLength milliseconds between positions
     * @return CompiledPath of the full MotionPath
     */
    public CompiledPath getCompiledPath(long stepLength){
        compilePath(stepLength);
        return myCache;
    }

    /**
     * Generates and caches a CompiledPath for the complete MotionPath.
     *
     * @param stepLength milliseconds between positions
     * @return returns true if cache is changed, otherwise false
     */
    public boolean compilePath(long stepLength){
        interpolate();
        if(myCache != null || getInterpolatedPoints().isEmpty()){
            return false;
        }
        int len = getInterpolatedPoints().size();
        long start = myStartTime != null ? myStartTime :
                (long)getInterpolatedPoints().get(0).getX();
        long end = myStopTime != null ? myStopTime :
                (long)getInterpolatedPoints().get(len-1).getX();
        myCache = compilePath(start, end, stepLength);
        return true;
    }
    /**
     * Creates a CompiledPath from the interpolated points.
     *
     * @param start path start time
     * @param end path end time
     * @param stepLength milliseconds between positions
     * @return CompiledPath from this MotionPath's interpolated points
     */
    public CompiledPath compilePath(long start, long end, long stepLength) {
        interpolate();
        //adjust times to be multiples of stepLength
        start -= start%stepLength;
		long add = stepLength - end%stepLength;
		add = add == stepLength ? 0 : add;
        end += add;
        boolean cached = myCache != null && myCache.matches(start, end, stepLength);
        if(stepLength < 1 || getInterpolatedPoints().isEmpty() || cached){
            return myCache;
        }
        return CompiledPath.compilePath(start, end, getInterpolatedPoints(), stepLength);
    }
    /**
     * Returns a deep copy of the Channel.
     *
     * @return a deep copy of the Channel
     */
    @Override
    public MotionPath clone(){
        MotionPath mp = new MotionPath(myFactory);
        for(Point2D p : getControlPoints()){
            mp.addPoint(p.getX(), p.getY());
        }
        mp.myName = myName;
        mp.myStartTime = myStartTime;
        mp.myStopTime = myStopTime;
        if(myCache != null){
            mp.myCache = myCache.clone();
        }
        return mp;
    }
    /**
     * Calls interpolate for PathInterpolator.  If there is a change, the
     * cached CompiledPath is cleared.
     *
     * @return true if there was an interpolation change, otherwise false
     */
    @Override
    protected boolean interpolate(){
        if(super.interpolate()){
            myCache = null;
            return true;
        }
        return false;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final MotionPath other = (MotionPath) obj;
        if ((this.myName == null) ? (other.myName != null) : !this.myName.equals(other.myName)) {
            return false;
        }
        if (this.myStartTime != other.myStartTime && (this.myStartTime == null || !this.myStartTime.equals(other.myStartTime))) {
            return false;
        }
        if (this.myStopTime != other.myStopTime && (this.myStopTime == null || !this.myStopTime.equals(other.myStopTime))) {
            return false;
        }
        if (this.myXVals != other.myXVals && (this.myXVals == null || !this.myXVals.equals(other.myXVals))) {
            return false;
        }
		if (this.getControlPoints() != other.getControlPoints() && (this.getControlPoints() == null || !this.getControlPoints().equals(other.getControlPoints()))) {
           return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 17 * hash + (this.myName != null ? this.myName.hashCode() : 0);
        hash = 17 * hash + (this.myStartTime != null ? this.myStartTime.hashCode() : 0);
        hash = 17 * hash + (this.myStopTime != null ? this.myStopTime.hashCode() : 0);
        hash = 17 * hash + (this.myXVals != null ? this.myXVals.hashCode() : 0);
        return hash;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy