/* * JaamSim Discrete Event Simulation * Copyright (C) 2013 Ausenco Engineering Canada Inc. * * 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 com.jaamsim.render; import java.util.ArrayList; import com.jaamsim.math.Mat4d; import com.jaamsim.math.Quaternion; import com.jaamsim.math.Vec3d; public class Action { public static class Description { public String name; public double duration; } public static class Queue { public String name; public double time; @Override public boolean equals(Object o) { if (!(o instanceof Queue)) { return false; } Queue q = (Queue)o; return q.name == name && q.time == time; } } /** * Used to bind entity outputs to active actions * @author matt.chudleigh * */ public static class Binding { public String actionName; public String outputName; } public static class RotKey { public double time; public Quaternion rot; } public static class TransKey { public double time; public Vec3d trans; } public static class Channel { public String name; public ArrayList<RotKey> rotKeys; public ArrayList<TransKey> transKeys; } // Actual members of Action public String name; public double duration; public ArrayList<Channel> channels = new ArrayList<>(); // Calculate the interpolated rotation for this channel at time private static Quaternion interpRot(Action.Channel ch, double time) { if (ch.rotKeys == null || ch.rotKeys.size() == 0) { return new Quaternion(); // identity } if (time < ch.rotKeys.get(0).time) { return ch.rotKeys.get(0).rot; // Before the first key, so just take that value } if (time > ch.rotKeys.get(ch.rotKeys.size()-1).time) { return ch.rotKeys.get(ch.rotKeys.size()-1).rot; // past the end } for (int i = 0; i < ch.rotKeys.size() - 1; ++i) { Action.RotKey a = ch.rotKeys.get(i); Action.RotKey b = ch.rotKeys.get(i+1); if (time < a.time || time > b.time) continue; double bWeight = (time-a.time) / (b.time-a.time); Quaternion ret = new Quaternion(); a.rot.slerp(b.rot, bWeight, ret); return ret; } assert(false); return new Quaternion(); } // Calculate the interpolated tranlation for this channel at time private static Vec3d interpTrans(Action.Channel ch, double time) { if (ch.transKeys == null || ch.transKeys.size() == 0) { return new Vec3d(); // identity } if (time < ch.transKeys.get(0).time) { return ch.transKeys.get(0).trans; // Before the first key, so just take that value } if (time > ch.transKeys.get(ch.transKeys.size()-1).time) { return ch.transKeys.get(ch.transKeys.size()-1).trans; // past the end } for (int i = 0; i < ch.transKeys.size()-1; ++i) { Action.TransKey a = ch.transKeys.get(i); Action.TransKey b = ch.transKeys.get(i+1); if (time < a.time || time > b.time) continue; double bw = (time-a.time) / (b.time-a.time); double aw = 1 - bw; Vec3d ret = new Vec3d( a.trans.x*aw + b.trans.x*bw, a.trans.y*aw + b.trans.y*bw, a.trans.z*aw + b.trans.z*bw); return ret; } assert(false); return new Vec3d(); } /** * Returns a Mat4d of the time interpolated value of the rotation and translation defined by Channel ch * @param ch * @param time * @return */ public static Mat4d getChannelMatAtTime(Channel ch, double time) { Mat4d ret = new Mat4d(); ret.setRot3(interpRot(ch, time)); ret.setTranslate3(interpTrans(ch, time)); return ret; } }