001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package org.openimaj.workinprogress; 031 032import java.io.File; 033import java.io.IOException; 034 035import org.openimaj.image.DisplayUtilities; 036import org.openimaj.image.FImage; 037import org.openimaj.image.ImageUtilities; 038import org.openimaj.image.pixel.Pixel; 039import org.openimaj.image.processing.transform.FProjectionProcessor; 040import org.openimaj.math.geometry.point.Point2dImpl; 041import org.openimaj.math.geometry.shape.Circle; 042import org.openimaj.math.geometry.shape.Rectangle; 043import org.openimaj.math.geometry.shape.RotatedRectangle; 044import org.openimaj.math.geometry.shape.Triangle; 045import org.openimaj.math.geometry.transforms.TransformUtilities; 046 047import Jama.Matrix; 048 049public class Pendulum { 050 public static void main(String[] args) throws IOException { 051 052 // background image 053 final FImage background = FImage.randomImage(800, 600); 054 055 final Triangle triangle = new Triangle(new Point2dImpl(400, 100), 056 new Point2dImpl(395, 500), 057 new Point2dImpl(405, 500)); 058 059 final FImage pendulumImage = new FImage(800, 600); 060 final FImage pendulumMask = new FImage(800, 600); 061 for (int y = 0; y < pendulumImage.height; y++) { 062 for (int x = 0; x < pendulumImage.width; x++) { 063 if (triangle.isInside(new Pixel(x, y))) { 064 pendulumImage.pixels[y][x] = (float) Math.random(); 065 pendulumMask.pixels[y][x] = 1; 066 } 067 } 068 } 069 070 final Triangle triangle2 = new Triangle(new Point2dImpl(650, 150), 071 new Point2dImpl(645, 250), 072 new Point2dImpl(655, 250)); 073 074 final FImage clockImage = new FImage(800, 600); 075 final FImage clockMask = new FImage(800, 600); 076 for (int y = 0; y < clockImage.height; y++) { 077 for (int x = 0; x < clockImage.width; x++) { 078 if (triangle2.isInside(new Pixel(x, y))) { 079 clockImage.pixels[y][x] = (float) Math.random(); 080 clockMask.pixels[y][x] = 1; 081 } 082 } 083 } 084 085 final Circle circle = new Circle(50, 50, 25); 086 final FImage linBallImage = new FImage(800, 600); 087 final FImage linBallMask = new FImage(800, 600); 088 for (int y = 0; y < linBallImage.height; y++) { 089 for (int x = 0; x < linBallImage.width; x++) { 090 if (circle.isInside(new Pixel(x, y))) { 091 linBallImage.pixels[y][x] = (float) Math.random(); 092 linBallMask.pixels[y][x] = 1; 093 } 094 } 095 } 096 097 final Circle circle2 = new Circle(50, 550, 25); 098 final FImage accBallImage = new FImage(800, 600); 099 final FImage accBallMask = new FImage(800, 600); 100 for (int y = 0; y < accBallImage.height; y++) { 101 for (int x = 0; x < accBallImage.width; x++) { 102 if (circle2.isInside(new Pixel(x, y))) { 103 accBallImage.pixels[y][x] = (float) Math.random(); 104 accBallMask.pixels[y][x] = 1; 105 } 106 } 107 } 108 109 final File dir = new File("/Users/jon/pendulum+circle"); 110 dir.mkdirs(); 111 int i = 0; 112 final double theta0 = 0.75; 113 final double T = 0.1; 114 double theta; 115 116 final double triMaxSpeed = theta0 * 400; 117 final double clockMaxSpeed = 50 * 100; 118 final double linBallMaxSpeed = 3000; 119 final double accBallMaxSpeed = 30000; 120 121 final double triMaxAcc = theta0 * 400; 122 final double accBallMaxAcc = 500000; 123 124 for (double t = 0; t < 1; t += 0.001, i++) { 125 theta = theta0 * Math.cos(2 * Math.PI * t / T); 126 127 final FImage rotPendulumMask = rotate(pendulumMask, theta, 400, 100); 128 final FImage rotPendulumImage = rotate(pendulumImage, theta, 400, 100); 129 130 // clock - constant angular motion 131 final FImage rotClockMask = rotate(clockMask, t * 50, 650, 150); 132 final FImage rotClockImage = rotate(clockImage, t * 50, 650, 150); 133 DisplayUtilities.displayName(rotClockMask, "foo"); 134 135 // upper circle - linear motion 136 final FImage transLinBallMask = translate(linBallMask, (float) t * 3000, 0f); 137 final FImage transLinBallImage = translate(linBallImage, (float) t * 3000, 0f); 138 139 // lower circle - accel motion 140 final FImage transAccBallMask = translate(accBallMask, (float) (t * t * 500 * 500), 0f); 141 final FImage transAccBallImage = translate(accBallImage, (float) (t * t * 500 * 500), 0f); 142 143 final FImage frame = new FImage(800, 600); 144 final FImage frameVelX = new FImage(800, 600); 145 final FImage frameVelY = new FImage(800, 600); 146 final FImage frameVelMag = new FImage(800, 600); 147 final FImage frameAccX = new FImage(800, 600); 148 final FImage frameAccY = new FImage(800, 600); 149 final FImage frameAccMag = new FImage(800, 600); 150 frameVelX.fill(0.5f); 151 frameVelY.fill(0.5f); 152 frameAccX.fill(0.5f); 153 frameAccY.fill(0.5f); 154 155 frame.drawShapeFilled(new Rectangle(50, 275, 50, 50), 1f); 156 frame.drawShapeFilled(new RotatedRectangle(50, 275, 50, 50, Math.PI / 4), 1f); 157 158 for (int y = 0; y < frame.height; y++) { 159 for (int x = 0; x < frame.width; x++) { 160 161 if (rotPendulumMask.pixels[y][x] > 0.5) { 162 frame.pixels[y][x] = rotPendulumImage.pixels[y][x]; 163 164 // Velocity of the pendulum triangle 165 final double dx = x - 400, dy = y - 100, r = Math.sqrt(dx * dx + dy * dy); 166 final double vt = -r * theta0 * Math.sin(2 * Math.PI * t / T); 167 final double vx = Math.cos(theta) * vt; 168 final double vy = Math.sin(theta) * vt; 169 frameVelX.pixels[y][x] = (float) ((vx + triMaxSpeed) / (2 * triMaxSpeed)); 170 frameVelY.pixels[y][x] = (float) ((vy + triMaxSpeed) / (2 * triMaxSpeed)); 171 frameVelMag.pixels[y][x] = (float) (Math.abs(vt) / (triMaxSpeed)); 172 173 // Acceleration of the pendulum triangle 174 final double at = -r * theta0 * Math.cos(2 * Math.PI * t / T); 175 final double ax = Math.cos(theta) * at; 176 final double ay = Math.sin(theta) * at; 177 frameAccX.pixels[y][x] = (float) ((ax + triMaxAcc) / (2 * triMaxAcc)); 178 frameAccY.pixels[y][x] = (float) ((ay + triMaxAcc) / (2 * triMaxAcc)); 179 frameAccMag.pixels[y][x] = (float) (Math.abs(at) / (triMaxAcc)); 180 } else if (rotClockMask.pixels[y][x] > 0.5) { 181 frame.pixels[y][x] = rotClockImage.pixels[y][x]; 182 183 // velocity of the clock triangle 184 final double dx = x - 650, dy = y - 150, r = Math.sqrt(dx * dx + dy * dy); 185 final double vt = r * 50; 186 final double vx = Math.cos(50 * t) * vt; 187 final double vy = Math.sin(50 * t) * vt; 188 189 frameVelX.pixels[y][x] = (float) ((vx + clockMaxSpeed) / (2 * clockMaxSpeed)); 190 frameVelY.pixels[y][x] = (float) ((vy + clockMaxSpeed) / (2 * clockMaxSpeed)); 191 frameVelMag.pixels[y][x] = (float) (Math.abs(vt) / (clockMaxSpeed)); 192 193 // acceleration of the clock triangle 194 // !!!clock doesn't accelerate!!! 195 } else if (transLinBallMask.pixels[y][x] > 0.5) { 196 frame.pixels[y][x] = transLinBallImage.pixels[y][x]; 197 198 // velocity of the linear ball 199 frameVelX.pixels[y][x] = (float) (3000f / (2 * linBallMaxSpeed)); 200 frameVelMag.pixels[y][x] = (float) (3000f / linBallMaxSpeed); 201 202 // acceleration of the linear ball 203 // !!!ball doesn't accelerate!!! 204 } else if (transAccBallMask.pixels[y][x] > 0.5) { 205 frame.pixels[y][x] = transAccBallImage.pixels[y][x]; 206 207 // velocity of the accelerating ball 208 frameVelX.pixels[y][x] = (float) (500000 * t / (2 * accBallMaxSpeed)); 209 frameVelMag.pixels[y][x] = (float) (500000 * t / accBallMaxSpeed); 210 211 // acceleration of the accelerating ball 212 frameAccX.pixels[y][x] = (float) (500000 / (2 * accBallMaxAcc)); 213 frameAccMag.pixels[y][x] = (float) (500000 / accBallMaxAcc); 214 } else { 215 frame.pixels[y][x] = background.pixels[y][x]; 216 } 217 } 218 } 219 220 DisplayUtilities.displayName(frame, ""); 221 DisplayUtilities.displayName(frameVelX, "Vx"); 222 DisplayUtilities.displayName(frameVelY, "Vy"); 223 DisplayUtilities.displayName(frameVelMag, "Velocity Magnitude"); 224 DisplayUtilities.displayName(frameAccX, "Ax"); 225 DisplayUtilities.displayName(frameAccY, "Ay"); 226 DisplayUtilities.displayName(frameAccMag, "Acceleration Magnitude"); 227 228 ImageUtilities.write(frame, new File(dir, "frame_" + i + 229 ".png")); 230 // ImageUtilities.write(frameVelX, new File(dir, "frame_vx_" + i + 231 // ".png")); 232 // ImageUtilities.write(frameVelY, new File(dir, "frame_vy_" + i + 233 // ".png")); 234 // ImageUtilities.write(frameVelMag, new File(dir, "frame_vm+" + i + 235 // ".png")); 236 // ImageUtilities.write(frameAccX, new File(dir, "frame_ax_" + i + 237 // ".png")); 238 // ImageUtilities.write(frameAccY, new File(dir, "frame_ay_" + i + 239 // ".png")); 240 // ImageUtilities.write(frameAccMag, new File(dir, "frame_am_" + i + 241 // ".png")); 242 } 243 } 244 245 private static FImage rotate(final FImage image, double angle, float px, float py) { 246 final Matrix transform = TransformUtilities.rotationMatrixAboutPoint(angle, px, py); 247 final FProjectionProcessor pp = new FProjectionProcessor(); 248 pp.setMatrix(transform); 249 pp.accumulate(image); 250 return pp.performProjection(true, 0f); 251 } 252 253 private static FImage translate(final FImage image, float x, float y) { 254 final Matrix transform = TransformUtilities.translateMatrix(x, y); 255 final FProjectionProcessor pp = new FProjectionProcessor(); 256 pp.setMatrix(transform); 257 pp.accumulate(image); 258 return pp.performProjection(true, 0f); 259 } 260}