/* * JAME 6.2.1 * http://jame.sourceforge.net * * Copyright 2001, 2016 Andrea Medeghini * * This file is part of JAME. * * JAME is an application for creating fractals and other graphics artifacts. * * JAME is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * JAME 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 for more details. * * You should have received a copy of the GNU General Public License * along with JAME. If not, see <http://www.gnu.org/licenses/>. * */ package net.sf.jame.core.media; import java.awt.*; import java.awt.geom.AffineTransform; import java.awt.geom.PathIterator; public final class ExtendedMotionTweenSequence extends GraphicsSequence { private final AbstractGraphics object; private final Effect effect; private final Shape guide; private final boolean normal; private int frames = 0; private int frame = 0; private float rotation; private float shearx; private float sheary; private final float delta_rotation; private final float delta_shearx; private final float delta_sheary; private final float copy_rotation; private final float copy_shearx; private final float copy_sheary; private final AffineTransform transform; private final Polygon guida = new Polygon(); public ExtendedMotionTweenSequence(final AbstractGraphics object, final int frames, final Shape guide, final boolean normal, final float rotation, final float shearx, final float sheary, final Effect effect) { this.object = object; this.effect = effect; this.frames = frames; this.normal = normal; this.guide = guide; copy_rotation = rotation; copy_shearx = shearx; copy_sheary = sheary; delta_rotation = rotation / (frames - 1); delta_shearx = shearx / (frames - 1); delta_sheary = sheary / (frames - 1); transform = (AffineTransform) object.getTransform().clone(); PathIterator path = guide.getPathIterator(null, 0.0); double total_length = 0; final double[] s1 = new double[6]; final double[] s2 = new double[6]; int type = path.currentSegment(s1); path.next(); while (type != PathIterator.SEG_CLOSE) { type = path.currentSegment(s2); path.next(); if (type != PathIterator.SEG_CLOSE) { total_length += Math.sqrt(((s2[0] - s1[0]) * (s2[0] - s1[0])) + ((s2[1] - s1[1]) * (s2[1] - s1[1]))); s1[0] = s2[0]; s1[1] = s2[1]; } } final double delta_length = total_length / frames; path = guide.getPathIterator(null, 0.0); total_length = 0; double old_length = 0; double segment_length = 0; double length = 0; type = path.currentSegment(s1); path.next(); while (guida.npoints < frames) { while (type != PathIterator.SEG_CLOSE) { type = path.currentSegment(s2); path.next(); if (type != PathIterator.SEG_CLOSE) { segment_length = Math.sqrt(((s2[0] - s1[0]) * (s2[0] - s1[0])) + ((s2[1] - s1[1]) * (s2[1] - s1[1]))); old_length = total_length; total_length += segment_length; if (length < total_length) { break; } s1[0] = s2[0]; s1[1] = s2[1]; } } while (length < total_length) { final double x = s1[0] + (((s2[0] - s1[0]) * (length - old_length)) / segment_length); final double y = s1[1] + (((s2[1] - s1[1]) * (length - old_length)) / segment_length); guida.addPoint((int) Math.rint(x), (int) Math.rint(y)); length += delta_length; } s1[0] = s2[0]; s1[1] = s2[1]; } } @Override public Object clone() throws CloneNotSupportedException { if (effect != null) { return new ExtendedMotionTweenSequence((AbstractGraphics) object.clone(), frames, guide, normal, copy_rotation, copy_shearx, copy_sheary, (Effect) effect.clone()); } else { return new ExtendedMotionTweenSequence((AbstractGraphics) object.clone(), frames, guide, normal, copy_rotation, copy_shearx, copy_sheary, null); } } @Override public AbstractObject getObject() { return object; } @Override public Effect getEffect() { return effect; } @Override public int getFrames() { return frames; } @Override public int getFrame() { return frame; } @Override public boolean isFirstFrame() { return (frame == 0); } @Override public boolean isLastFrame() { return (frame == (frames - 1)); } @Override void build(final Controller controller, final Movie parent, final Layer layer) { if (object != null) { object.build(controller, parent, layer, this); } } @Override void init() { if (effect != null) { effect.init(frames); } if (object != null) { object.init(); } frame = 0; rotation = 0; shearx = 0; sheary = 0; } @Override void kill() { if (object != null) { object.kill(); } } @Override void reset() { if (effect != null) { effect.reset(); } if (object != null) { object.reset(); } frame = 0; rotation = 0; shearx = 0; sheary = 0; } @Override void setFrame(final int frame) { this.frame = frame; if ((this.frame >= 0) && (this.frame < frames)) { final float x = guida.xpoints[frame]; final float y = guida.ypoints[frame]; object.setTransform(transform); object.translate(x, y); float angle = 0; if ((frame > 0) && normal) { final float ox = guida.xpoints[frame - 1]; final float oy = guida.ypoints[frame - 1]; angle = (float) Math.atan2(y - oy, x - ox); } rotation = delta_rotation * frame; shearx = delta_shearx * frame; sheary = delta_sheary * frame; object.rotate(rotation + angle); object.shear(shearx, sheary); if (effect != null) { effect.setFrame(frame); } if (object instanceof Movie) { ((Movie) object).setFrame(frame); } } } @Override void nextFrame() { frame = frame + 1; if ((frame >= 0) && (frame < frames)) { final float x = guida.xpoints[frame]; final float y = guida.ypoints[frame]; object.setTransform(transform); object.translate(x, y); float angle = 0; if ((frame > 0) && normal) { final float ox = guida.xpoints[frame - 1]; final float oy = guida.ypoints[frame - 1]; angle = (float) Math.atan2(y - oy, x - ox); } rotation += delta_rotation; shearx += delta_shearx; sheary += delta_sheary; object.rotate(rotation + angle); object.shear(shearx, sheary); if (effect != null) { effect.nextFrame(); } if (object instanceof Animate) { ((Animate) object).nextFrame(); } } } @Override void prevFrame() { frame = frame - 1; if ((frame >= 0) && (frame < frames)) { final float x = guida.xpoints[frame]; final float y = guida.ypoints[frame]; object.setTransform(transform); object.translate(x, y); float angle = 0; if ((frame > 0) && normal) { final float ox = guida.xpoints[frame - 1]; final float oy = guida.ypoints[frame - 1]; angle = (float) Math.atan2(y - oy, x - ox); } rotation -= delta_rotation; shearx -= delta_shearx; sheary -= delta_sheary; object.rotate(rotation + angle); object.shear(shearx, sheary); if (effect != null) { effect.prevFrame(); } if (object instanceof Animate) { ((Animate) object).prevFrame(); } } } }