/* * SizesMoA.java * * Copyright (C) 2005-2012 Huseyin Boyaci. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This program 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 2 of the License, or (at your option) any later * version. This program 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 version 2 for more details * (a copy is included in the LICENSE file that accompanied this code) * (also available at http://www.gnu.org) You should have received a copy of * the GNU General Public License along with this program; if not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * */ import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.event.KeyEvent; import java.awt.image.BufferedImage; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import javax.imageio.ImageIO; import psychWithJava.FullScreen; import psychWithJava.Extras; /** * Implements a simple "method of adjustment" experiment. * * In this experiment we investigate the perceived image size * in a complex environment. In each trial observer is presented * a sphere either in FRONT or BACK position and asked to adjust the * size of a 2D disk to match the test object in image size. * * @author Huseyin Boyaci * @since 2012-03-14 * @see FullScreen */ public class SizesMoA extends FullScreen implements Runnable { // Constant values: static final int[] SIZE = {123, 163, 204, 244, 286}; static final String[] SCENE = {"Back", "Front"}; static final int WIDTH = 800; static final int HEIGHT = 600; static final int N_BACK = SIZE.length; static final int SIZE_STEP_PROBE = 4; static final int SIZE_PROBE_MAX = 400; static final int SIZE_PROBE_MIN = 80; static final int N_TRIAL = 5; BufferedImage probe; static PrintWriter outputFile; public static void main(String[] args) { // Open the output file for saving the data try { outputFile = Extras.setOutputFile("data"); } catch (FileNotFoundException e) { e.printStackTrace(); } // Initiate the full-screen mode SizesMoA fs = new SizesMoA(); fs.setNBuffers(1); fs.createProbe(); new Thread(fs).start(); } public void createProbe(){ probe = this.getGraphicsConfiguration(). createCompatibleImage(SIZE_PROBE_MAX, SIZE_PROBE_MAX); RenderingHints hints = new RenderingHints(null); //hints.put(RenderingHints.KEY_ANTIALIASING, // RenderingHints.VALUE_ANTIALIAS_ON); hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); Graphics2D gProbe = probe.createGraphics(); gProbe.setRenderingHints(hints); gProbe.dispose(); } public void updateProbe(int size){ int shift = (SIZE_PROBE_MAX - size)/2; Graphics2D gProbe = probe.createGraphics(); gProbe.setColor(Color.black); gProbe.fillRect(0, 0, SIZE_PROBE_MAX, SIZE_PROBE_MAX); gProbe.setColor(Color.GRAY); gProbe.fillOval(shift, shift, size, size); gProbe.dispose(); } public void run(){ // Display the task and wait for observer's response setFont(new Font("SansSerif", Font.BOLD, 26)); displayText(100, 200, "Task:"); displayText(100, 300, " Adjust the size of the 2-D probe"); displayText(100, 350, " to match the size of the 3-D ball"); displayText(100, 450, " (Up/Down for fine adjustment; Left/Right for fast adjustment)"); displayText(100, 550, " Press space bar to finalize the trial"); displayText(100, 700, "Now press any key to continue"); // Did they press any key? getKeyPressed(-1); // blank the screen using the current background color of the screen blankScreen(); // make the cursor invisible hideCursor(); // To shuffle around the order of presentation we create a list of // 'test' ids List object = new ArrayList(); for (int repeat = 0; repeat < N_TRIAL; repeat++) for(String scene: SCENE) for (int id : SIZE) object.add(scene+"_"+String.valueOf(id)+".jpg"); // put the whole loop inside a try-catch-finally clause. If something // goes wrong the program does not hang our computer. try { int stimulusX = (getWidth() - WIDTH)/3; int stimulusY = (getHeight() - HEIGHT)/2; int probeX = (getWidth() + stimulusX + WIDTH - SIZE_PROBE_MAX ) / 2 ; int probeY = (getHeight() - SIZE_PROBE_MAX) / 2; // A special function of Collections class is invoked to // randomize the order of presentation Collections.shuffle(object); // we show the trials back to back untill we exhaust our list. // Iterator is a fast way of accessing elements of a List of objects. Iterator it = object.listIterator(); while (it.hasNext()) { String fileName = it.next(); String idScene = fileName.split("_")[0]; int size = Integer.valueOf( (fileName.split(".jpg")[0]).split("_")[1]); int sizeProbe = Math.min(SIZE_PROBE_MAX, Math.max(SIZE_PROBE_MIN, size/2 + (int)(Math.random()*size))); BufferedImage stimulus = ImageIO.read(SizesMoA.class.getResource(fileName)); updateProbe(sizeProbe); String message = new String("Ball Size = " + size + ";"); // Show the first images displayImage(stimulusX, stimulusY, stimulus); displayImage(probeX, probeY, probe); updateScreen(); int response; while(true){ response = getKeyPressed(-1).getKey(); if (response == KeyEvent.VK_SPACE){ outputFile.println(idScene + " " + size + " " + sizeProbe); outputFile.flush(); // feedback message = message + new String(" match = " + sizeProbe + " (pixels)"); blankScreen(); displayText(message); updateScreen(); getKeyPressed(-1); blankScreen(); break; } else if (response == KeyEvent.VK_UP) sizeProbe += SIZE_STEP_PROBE; else if (response == KeyEvent.VK_DOWN) sizeProbe -= SIZE_STEP_PROBE; else if (response == KeyEvent.VK_LEFT) sizeProbe -= 5 * SIZE_STEP_PROBE; else if (response == KeyEvent.VK_RIGHT) sizeProbe += 5 * SIZE_STEP_PROBE; else continue; sizeProbe = Math.min(SIZE_PROBE_MAX, Math.max(SIZE_PROBE_MIN, sizeProbe)); updateProbe(sizeProbe); displayImage(probeX,probeY,probe); updateScreen(); } } // Clear the screen and display a thank you message blankScreen(); String message = new String("Thank You!"); displayText(message); java.lang.Thread.sleep(1500); // Here we catch the exceptions. if any of them happens the program // skips the rest of the try block, but always execute finally{...} // so we can be sure that the full-screen display will close. } catch (IOException ef) { System.err.println("cannot open file: "); ef.printStackTrace(); } catch (InterruptedException et) { // In case Tread.sleep() fails. et.printStackTrace(); Thread.currentThread().interrupt(); } finally { // close the full screen mode, and dispose all display components // If you don't do this, the program will hang and you // will have to kill it manually. closeScreen(); } } }