package org.andork.bspline;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.andork.bspline.FastFloatBSplineEvaluator;
@SuppressWarnings( "serial" )
public class FastFloatBSplineEvaluatorTest extends JPanel
{
FastFloatBSplineEvaluator evaluator;
float[ ] points;
int pointsStride;
float[ ] knots;
float[ ] out;
int degree;
int dimension;
int mouseoverIndex = -1;
Path2D path;
MouseHandler mouseHandler;
float startParam = 0.3f;
float stepSize = 0.01f;
float endParam = 0.805f;
public static void main( String[ ] args )
{
FastFloatBSplineEvaluatorTest panel = new FastFloatBSplineEvaluatorTest( );
JFrame frame = new JFrame( );
frame.getContentPane( ).add( panel );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.setSize( 400 , 400 );
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
public FastFloatBSplineEvaluatorTest( )
{
init( );
}
private void init( )
{
degree = 3;
dimension = 3;
pointsStride = 3;
knots = new float[ ] { 0 , 0.1f , 0.2f , 0.3f , 0.4f , 0.5f , 0.6f , 0.7f , 0.8f , 0.9f , 1.0f , 1.1f };
points = new float[ ] { 100 , 100 , 1 , 110 , 110 , 1 , 120 , 120 , 1 , 130 , 130 , 1 , 140 , 140 , 1 , 150 , 150 , 1 , 160 , 160 , 1 , 170 , 170 , 1 };
out = new float[ dimension ];
evaluator = new FastFloatBSplineEvaluator( ).points( points ).knots( knots ).dimension( dimension ).degree( degree ).pointsStride( pointsStride );
rebuildPath( );
mouseHandler = new MouseHandler( );
addMouseListener( mouseHandler );
addMouseMotionListener( mouseHandler );
}
private void rebuildPath( )
{
path = new Path2D.Float( );
int i;
for( i = 0 ; startParam + i * stepSize < endParam ; i++ )
{
float param = startParam + i * stepSize;
evaluator.eval( param , out );
if( i == 0 )
{
path.moveTo( out[ 0 ] , out[ 1 ] );
}
else
{
path.lineTo( out[ 0 ] , out[ 1 ] );
}
}
}
@Override
protected void paintComponent( Graphics g )
{
super.paintComponent( g );
Graphics2D g2 = ( Graphics2D ) g;
Rectangle2D r = new Rectangle2D.Float( );
Line2D l = new Line2D.Float( );
for( int i = 0 ; i < points.length ; i += pointsStride )
{
if( i > 0 )
{
g2.setColor( Color.GRAY );
l.setLine( points[ i - pointsStride ] , points[ i - pointsStride + 1 ] , points[ i ] , points[ i + 1 ] );
g2.draw( l );
}
g2.setColor( Color.BLACK );
int radius = i == mouseoverIndex ? 3 : 1;
r.setFrame( points[ i ] - radius , points[ i + 1 ] - radius , radius * 2 + 1 , radius * 2 + 1 );
g2.draw( r );
}
if( path != null )
{
g2.setColor( Color.BLACK );
g2.draw( path );
}
}
private static int findMouseoverPoint( float[ ] points , int pointsStride , float x , float y , double maxDistSq )
{
int result = -1;
double resultDistSq = 0;
for( int i = 0 ; i < points.length ; i += pointsStride )
{
double dx = x - points[ i ];
double dy = y - points[ i + 1 ];
double distSq = dx * dx + dy * dy;
if( distSq < maxDistSq && ( result < 0 || distSq < resultDistSq ) )
{
result = i;
resultDistSq = distSq;
}
}
return result;
}
private class MouseHandler extends MouseAdapter
{
double maxDistSq = 100;
int lastMouseoverIndex = -1;
int pressedIndex = -1;
MouseEvent pressEvent = null;
float[ ] origLocation = new float[ dimension ];
@Override
public void mousePressed( MouseEvent e )
{
mouseMoved( e );
if( e.getModifiersEx( ) == MouseEvent.BUTTON1_DOWN_MASK && mouseoverIndex >= 0 )
{
pressEvent = e;
pressedIndex = mouseoverIndex;
System.arraycopy( points , pressedIndex , origLocation , 0 , dimension );
}
}
@Override
public void mouseReleased( MouseEvent e )
{
if( pressEvent != null && e.getButton( ) == pressEvent.getButton( ) )
{
pressedIndex = -1;
pressEvent = null;
}
}
@Override
public void mouseDragged( MouseEvent e )
{
if( pressedIndex >= 0 )
{
points[ pressedIndex ] = origLocation[ 0 ] + e.getX( ) - pressEvent.getX( );
points[ pressedIndex + 1 ] = origLocation[ 1 ] + e.getY( ) - pressEvent.getY( );
rebuildPath( );
repaint( );
}
}
@Override
public void mouseMoved( MouseEvent e )
{
mouseoverIndex = findMouseoverPoint( points , pointsStride , e.getX( ) , e.getY( ) , maxDistSq );
if( mouseoverIndex != lastMouseoverIndex )
{
lastMouseoverIndex = mouseoverIndex;
repaint( );
}
}
}
}