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        }