001 // This class is based on the FishDisplay class, version 1 August 2002 002 // by Julie Zenekski, Alyce Brady, and Chris Nevison 003 004 // Original copyright notice: 005 006 // AP(r) Computer Science Marine Biology Simulation: 007 // The FishDisplay class is copyright(c) 2002 College Entrance 008 // Examination Board (www.collegeboard.com). 009 // 010 // This class is free software; you can redistribute it and/or modify 011 // it under the terms of the GNU General Public License as published by 012 // the Free Software Foundation. 013 // 014 // This class is distributed in the hope that it will be useful, 015 // but WITHOUT ANY WARRANTY; without even the implied warranty of 016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 // GNU General Public License for more details. 018 019 020 package model.fish.display; 021 022 import sysModel.fish.IFishDisplay; 023 024 import java.awt.*; 025 import java.awt.geom.AffineTransform; 026 import java.awt.geom.Ellipse2D; 027 import java.awt.geom.GeneralPath; 028 029 /** 030 * Parameterized fish display. 031 * 032 * @author Mathias Ricken 033 */ 034 public class ParamFishDisplay implements IFishDisplay { 035 private static final double BODY_WIDTH = .55; 036 private static final double BODY_LENGTH = .75; 037 private static final double TAIL_WIDTH = .5; 038 private static final double TAIL_LENGTH = .4; 039 private static final double EYE_SIZE = .08; 040 041 private static final int GRADIENT_SIZE = 50; 042 private static final AffineTransform ATX = AffineTransform.getScaleInstance(GRADIENT_SIZE, GRADIENT_SIZE); 043 044 private Shape bodyAndTail; 045 private Shape eye1; 046 private Shape eye2; 047 048 /** 049 * Make an object that knows how to drawFish simple fish. 050 * 051 * @param bodyWidth width of the body 052 * @param bodyLength length of the body 053 * @param tailWidth width of the tail 054 * @param tailLength length of the tail 055 * @param eyeSize size of the eyes 056 */ 057 public ParamFishDisplay(double bodyWidth, double bodyLength, double tailWidth, double tailLength, double eyeSize) { 058 buildPaths(bodyWidth, bodyLength, tailWidth, tailLength, eyeSize); 059 } 060 061 /** 062 * Default constructor. 063 */ 064 public ParamFishDisplay() { 065 this(BODY_WIDTH, BODY_LENGTH, TAIL_WIDTH, TAIL_LENGTH, EYE_SIZE); 066 } 067 068 /** 069 * Set up the paths used for the fish body, tail, and eyes. Different parameters will change the proportions, and 070 * thereby control the "look" of the fish. The various parameters should be specified assuming the fish will occupy 071 * a cell of size (1, 1). 072 * 073 * @param bodyWidth width of the elliptical body 074 * @param bodyLength length of the elliptical body 075 * @param tailWidth width of the triangular tail 076 * @param tailLength length of the triangular tail 077 * @param eyeSize diameter of the eye 078 */ 079 private void buildPaths(double bodyWidth, double bodyLength, double tailWidth, double tailLength, double eyeSize) { 080 // Build a set of paths for a fish facing North in a unit-length cell. 081 // We will rotate/scale as needed later. 082 083 float halfFishLength = (float)(bodyLength + tailLength / 3) / 2; 084 085 // The fish body is an ellipse of the given body width and length. 086 // The ellipse is horizontally centered and slightly above vertical 087 // center (to leave room for tail). 088 Shape body = new Ellipse2D.Double(-bodyWidth / 2, -halfFishLength, bodyWidth, bodyLength); 089 090 // The fish tail is a triangle overlapping the end of body. 091 GeneralPath tail = new GeneralPath(); 092 tail.moveTo(-(float)tailWidth / 2, halfFishLength); // lower left 093 tail.lineTo(0, halfFishLength - (float)tailLength); // top of tail 094 tail.lineTo((float)tailWidth / 2, halfFishLength); // lower right 095 tail.closePath(); 096 097 // Join body and tail together in one path. 098 tail.append(body, false); 099 bodyAndTail = tail; 100 101 // The fish eyes are circles. 102 eye1 = new Ellipse2D.Double(-bodyWidth / 4, -halfFishLength + bodyLength / 4, eyeSize, eyeSize); 103 eye2 = new Ellipse2D.Double(+bodyWidth / 4 - eyeSize, -halfFishLength + bodyLength / 4, eyeSize, eyeSize); 104 } 105 106 /** 107 * Draw the fish facing north on the Graphics2D object. The Graphics2D object has been prepared such that the center 108 * of the fish is at the origin. 109 * 110 * @param g2 drawing surface 111 * @param comp the component to drawFish on 112 * @param fishColor color of the fish 113 */ 114 public void draw(Graphics2D g2, Component comp, Color fishColor) { 115 Color oldColor = g2.getColor(); 116 117 // Stroke outline of fish body and tail in slightly darker color. 118 g2.setPaint(fishColor.darker()); 119 g2.draw(bodyAndTail); 120 121 // Fill fish body and tail with gradient (scale up temporarily to get smooth dither). 122 g2.scale(1.0 / GRADIENT_SIZE, 1.0 / GRADIENT_SIZE); 123 g2.setPaint(new GradientPaint(-GRADIENT_SIZE / 4, 124 -GRADIENT_SIZE / 2, 125 Color.white, 126 GRADIENT_SIZE / 4, 127 GRADIENT_SIZE / 4, 128 fishColor)); 129 g2.fill(ATX.createTransformedShape(bodyAndTail)); 130 g2.scale(GRADIENT_SIZE, GRADIENT_SIZE); 131 132 // Fill black circles for the eyes. 133 g2.setPaint(Color.black); 134 g2.fill(eye1); 135 g2.fill(eye2); 136 137 g2.setColor(oldColor); 138 } 139 }