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

org.mechio.api.animation.compiled.CompiledMap 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.compiled;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

/**
 * A HashMap of ServoIDs and corresponding CompiledPath.
 * All CompiledPaths must have the same stepLength.
 * All CompiledPaths are normalized to have the same start and end times;
 * The start and stop times are pulled from the CompiledPaths added.
 *
 * @author Matthew Stevenson 
 */
public class CompiledMap extends HashMap{
    private long myStartTime;
    private long myEndTime;
    private long myStepLength;

    /**
     * Creates an empty CompiledMap with the given stepLength.
     *
     * @param stepLen milliseconds between positions
     */
    public CompiledMap(long stepLen){
        myStepLength = stepLen;
        myEndTime = -1;
    }

    /**
     * Creates an empty CompiledMap with the given stepLength, and time range.
     *
     * @param stepLen milliseconds between positions
     * @param start start time
     * @param end end time
     */
    public CompiledMap(long stepLen, long start, long end){
        myStepLength = stepLen;
        myStartTime = start;
        myEndTime = end;
    }
    /**
     * Returns animation start offset time in milliseconds.
     * This is the length of the expected pause before movement.
     *
     * @return animation start offset time in milliseconds
     */
    public long getStartTime(){
        return myStartTime;
    }
    
    /**
     * Returns the time of the last position contained in the CompiledMap.
     * @return time of the last position contained in the CompiledMap
     */
    public long getEndTime(){
        if(myEndTime != -1){
            return myEndTime;
        }
        long end = myStartTime;
        for(CompiledPath path : values()){
            long pathEnd = path.getEndTime();
            if(pathEnd > end){
                end = pathEnd;
            }
        }
        return end;
    }
    /**
     * Same as HashMap.put() but does not allow null keys or values, and checks
     * the stepLength of the given path.  If the key exists, the paths are
     * combined with the current path taking precedent.
     *
     * @param key logical servo id
     * @param value CompiledPath for the given servo
     * @return resulting CompiledPath for servo id
     * @throws IllegalArgumentException if key or value is null or if the 
     * stepLengths do not match
     */
    @Override
    public CompiledPath put(Integer key, CompiledPath value) throws IllegalArgumentException{
        if(key == null || value == null){
            throw new IllegalArgumentException("CompiledMap does not permit null keys or values.");
        }
        if(myStepLength != value.getStepLength()){
            throw new IllegalArgumentException("Cannot combine CompiledPaths with different step lengths.");
        }
        if(containsKey(key)){
            value = CompiledPath.combine(Arrays.asList(get(key),value));
        }
        CompiledPath p = super.put(key, value);
        //normalizePaths();
        return p;
    }
    /**Same as HashMap.put() but does not allow null keys or values, and checks
     * the stepLength of the given path.  If the key exists, the paths are
     * combined with the current path taking precedent.
     * 
     * @param m map containing servo id and CompiledPath pairs
     * @throws IllegalArgumentException if null key or value is given or if the 
     * stepLengths do not match
     */
    @Override
    public void putAll(Map m) throws IllegalArgumentException{
        if(m.containsKey(null) || m.containsValue(null)){
            throw new IllegalArgumentException("CompiledMap does not permit null keys or values");
        }
        for(Entry e : m.entrySet()){
            if(e.getValue().getStepLength() != myStepLength){
                throw new IllegalArgumentException("Cannot combine CompiledPaths with different step lengths.");
            }
            if(containsKey(e.getKey())){
                CompiledPath cp = CompiledPath.combine(Arrays.asList(get(e.getKey()),e.getValue()));
                ((Entry)e).setValue(cp);
            }
        }
        super.putAll(m);
        normalizePaths();
    }

    /**
     * Finds the earliest start and latest stop times from the paths.  The times
     * are set to multiples of the stepLength.  All the paths are then
     * normalized to the new times.
     */
    private void normalizePaths(){
        long start = myStartTime == -1 ? 0 : myStartTime;
        long end = myEndTime == -1 ? Long.MIN_VALUE : myEndTime;
        for(CompiledPath p : values()){
            if(myEndTime == -1 && p.getEndTime() > end){
                end = p.getEndTime();
            }
        }
        setTimes(start, end, true);
    }
    /**
     * Adjusts all CompiledPaths to use the given times.
     *
     * @param start new start time
     * @param end new end time
     * @param normalizeTimes if true, the start and end times are set to
     * multiples of the stepLength.  If not normalized, some value < stepLength
     * can be added or removed
     */
    public void setTimes(long start, long end, boolean normalizeTimes){
        if(normalizeTimes){
            start -= start%myStepLength;
			long add = myStepLength - end%myStepLength;
			add = add == myStepLength ? 0 : add;
		    end += add;
        }
        for(Entry e : entrySet()){
            CompiledPath p = e.getValue().setTimes(start, end);
            if(!p.equals(e.getValue())){
                e.setValue(p);
            }
        }
        myStartTime = start;
        myEndTime = end;
    }
    
    @Override
    public Object clone(){
        CompiledMap map = new CompiledMap(myStepLength, myStartTime, myEndTime);
        for(Entry e : entrySet()){
            CompiledPath p = e.getValue();
            map.put(e.getKey(), p.clone());
        }
        return map;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy