001 package com.croftsoft.apps.neuro; 002 003 import java.awt.*; 004 import java.awt.event.ComponentAdapter; 005 import java.awt.event.ComponentEvent; 006 import javax.swing.JComponent; 007 008 import com.croftsoft.core.animation.ComponentAnimator; 009 import com.croftsoft.core.animation.animator.FrameRateAnimator; 010 import com.croftsoft.core.lang.NullArgumentException; 011 import com.croftsoft.core.util.mail.Mail; 012 013 /*********************************************************************** 014 * ComponentAnimator. 015 * 016 * @version 017 * $Id: NeuroAnimator.java,v 1.13 2008/08/30 02:36:51 croft Exp $ 018 * @since 019 * 2008-08-17 020 * @author 021 * <a href="https://www.croftsoft.com/">David Wallace Croft</a> 022 ***********************************************************************/ 023 024 public final class NeuroAnimator 025 implements ComponentAnimator 026 //////////////////////////////////////////////////////////////////////// 027 //////////////////////////////////////////////////////////////////////// 028 { 029 030 private final NeuroConfig neuroConfig; 031 032 private final Mail<NeuroMessage> mail; 033 034 private final NeuroModel neuroModel; 035 036 private final Rectangle componentBounds; 037 038 private final FrameRateAnimator frameRateAnimator; 039 040 //////////////////////////////////////////////////////////////////////// 041 // constructor methods 042 //////////////////////////////////////////////////////////////////////// 043 044 /*********************************************************************** 045 * Main constructor. 046 ***********************************************************************/ 047 public NeuroAnimator ( 048 final NeuroConfig neuroConfig, 049 final Mail<NeuroMessage> mail, 050 final NeuroModel neuroModel, 051 final JComponent jComponent ) 052 //////////////////////////////////////////////////////////////////////// 053 { 054 NullArgumentException.checkArgs ( 055 this.neuroConfig = neuroConfig, 056 this.mail = mail, 057 this.neuroModel = neuroModel, 058 jComponent ); 059 060 componentBounds = new Rectangle ( ); 061 062 jComponent.setOpaque ( true ); 063 064 jComponent.setFont ( neuroConfig.getFont ( ) ); 065 066 jComponent.setCursor ( neuroConfig.getCursor ( ) ); 067 068 jComponent.requestFocus ( ); 069 070 jComponent.addComponentListener ( 071 new ComponentAdapter ( ) 072 { 073 @Override 074 public void componentResized ( ComponentEvent componentEvent ) 075 { 076 update ( jComponent ); 077 078 jComponent.repaint ( ); 079 } 080 } ); 081 082 frameRateAnimator = new FrameRateAnimator ( jComponent ); 083 084 frameRateAnimator.toggle ( ); 085 086 update ( jComponent ); 087 } 088 089 //////////////////////////////////////////////////////////////////////// 090 // interface ComponentAnimator methods 091 //////////////////////////////////////////////////////////////////////// 092 093 public void paint ( 094 final JComponent jComponent, 095 final Graphics2D graphics2D ) 096 //////////////////////////////////////////////////////////////////////// 097 { 098 graphics2D.setColor ( neuroConfig.getBackgroundColor ( ) ); 099 100 graphics2D.fill ( componentBounds ); 101 102 graphics2D.setColor ( neuroConfig.getForegroundColor ( ) ); 103 104 final int length = neuroModel.getMembraneVoltageLength ( ); 105 106 final int xMargin = 10; 107 108 final int yMargin = 20; 109 110 final int xOffset = xMargin; 111 112 final int yOffset = componentBounds.height / 2; 113 114 graphics2D.drawLine ( 115 xMargin, yOffset, componentBounds.width - xMargin, yOffset ); 116 117 final double xScale 118 = ( componentBounds.width - 2 * xMargin ) / ( double ) length; 119 120 final double yScale 121 = -( ( componentBounds.height - 2 * yMargin ) / 2 ) 122 / neuroModel.getMembraneVoltageMax ( ); 123 124 // final double timeInterval = neuroModel.getTimeInterval ( ); 125 // 126 // final double timeMin = neuroModel.getTimeMin ( ); 127 128 for ( int i = 0; i < length; i += 100 ) 129 { 130 final int x = xMargin + ( int ) Math.round ( xScale * i ); 131 132 graphics2D.drawLine ( x, yOffset - 10, x, yOffset + 10 ); 133 } 134 135 for ( int i = 0; i < length; i++ ) 136 { 137 final int x = ( int ) Math.round ( i * xScale ) + xOffset; 138 139 final double membraneVoltage = neuroModel.getMembraneVoltage ( i ); 140 141 final int y 142 = ( int ) Math.round ( membraneVoltage * yScale ) + yOffset; 143 144 graphics2D.drawOval ( x - 5, y - 5, 10, 10 ); 145 146 if ( i < length - 1 ) 147 { 148 final double nextMembraneVoltage 149 = neuroModel.getMembraneVoltage ( i + 1 ); 150 151 final int nextX 152 = ( int ) Math.round ( ( i + 1 ) * xScale ) + xOffset; 153 154 final int nextY 155 = ( int ) Math.round ( nextMembraneVoltage * yScale ) + yOffset; 156 157 graphics2D.drawLine ( x, y, nextX, nextY ); 158 } 159 } 160 161 if ( neuroModel.getSpikeCount ( ) > 0 ) 162 { 163 Toolkit.getDefaultToolkit ( ).beep ( ); 164 } 165 166 // final HhNeuron hhNeuron = neuroModel.getHhNeuron ( ); 167 // 168 // System.out.format ( 169 // "v = %1$,1.3f, h = %2$,1.3f, m = %3$,1.3f, n = %4$,1.3f\n", 170 // new Double ( hhNeuron.getMembraneVoltage ( ) ), 171 // new Double ( hhNeuron.getH ( ) ), 172 // new Double ( hhNeuron.getM ( ) ), 173 // new Double ( hhNeuron.getN ( ) ) ); 174 175 frameRateAnimator.paint ( jComponent, graphics2D ); 176 } 177 178 public void update ( final JComponent jComponent ) 179 //////////////////////////////////////////////////////////////////////// 180 { 181 final int size = mail.size ( ); 182 183 for ( int i = 0; i < size; i++ ) 184 { 185 final NeuroMessage neuroMessage = mail.get ( i ); 186 187 final NeuroMessage.Type type = neuroMessage.getType ( ); 188 189 switch ( type ) 190 { 191 case TOGGLE_FRAME_RATE_REQUEST: 192 193 frameRateAnimator.toggle ( ); 194 195 break; 196 197 default: 198 199 // ignore 200 } 201 } 202 203 jComponent.getBounds ( componentBounds ); 204 205 frameRateAnimator.update ( jComponent ); 206 207 jComponent.paintImmediately ( componentBounds ); 208 } 209 210 //////////////////////////////////////////////////////////////////////// 211 //////////////////////////////////////////////////////////////////////// 212 }