gt: 		final double n11 = matrixB[ 5 ];
context: /*-
   * #%L
   * Fiji distribution of ImageJ for the life sciences.
   * %%
   * Copyright (C) 2007 - 2021 Fiji developers.
   * %%
   * 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 for more details.
   * 
   * You should have received a copy of the GNU General Public
   * License along with this program.  If not, see
   * <http://www.gnu.org/licenses/gpl-2.0.html>.
   * #L%
   */
  package mpicbg.spim.preprocessing;
  
  import java.util.ArrayList;
  
  import spim.vecmath.Transform3D;
  import spim.vecmath.AxisAngle4d;
  import spim.vecmath.Matrix3d;
  import spim.vecmath.Point3d;
  import spim.vecmath.Vector3d;
  
  import mpicbg.models.AffineModel3D;
  import mpicbg.spim.io.IOFunctions;
  import mpicbg.spim.io.SPIMConfiguration;
  import mpicbg.spim.registration.ViewDataBeads;
  import mpicbg.spim.registration.ViewStructure;
  import mpicbg.util.TransformUtils;
  
  public class AutomaticAngleSetup 
  {
  	public AutomaticAngleSetup( final ViewStructure viewStructure )
  	{		
  		final ArrayList<ViewDataBeads>views = viewStructure.getViews();
  		
  		final ViewDataBeads viewA = views.get( 0 ); 
  		final ViewDataBeads viewB = views.get( 1 );
  		
  		IOFunctions.println("Using view " + viewA.getName() + " and " + viewB.getName() + " for automatic angle setup." );
  		
  		final Vector3d rotationAxis = extractRotationAxis( (AffineModel3D)viewA.getTile().getModel(), (AffineModel3D)viewB.getTile().getModel() );
  		//final float rotationAngle = extractRotationAngle( viewA.getTile().getModel(), viewB.getTile().getModel(), rotationAxis );
  		//IOFunctions.println( "rotation axis: " + rotationAxis + ", angle: " + rotationAngle );
  				
  		IOFunctions.println( "rotation axis: " + rotationAxis );		
  		rotationAxis.normalize();		
  		IOFunctions.println( "rotation axis normed: " + rotationAxis );
  		final Vector3d xAxis = new Vector3d( new double[] { 1, 0, 0 } );
  				
  		IOFunctions.println( "Difference to xAxis: " + distance( rotationAxis, xAxis ) );
  		//testRotationAxis();
  		//getCommonAreaPerpendicularViews( viewA, viewB );
  	}
  	
  	public static double distance( final Vector3d a, final Vector3d b )
  	{
  		final double dx = a.x - b.x;
  		final double dy = a.y - b.y;
  		final double dz = a.z - b.z;
  		
  		return Math.sqrt( dx*dx + dy*dy + dz*dz );
  	}
  	
  	public static void testRotationAxis()
  	{
  		Transform3D a = new Transform3D();
  		Transform3D b = new Transform3D();
  
  		a.setRotation( new AxisAngle4d( new Vector3d( 1, 2, 3), Math.toRadians( 45 ) ) );
  		b.setRotation( new AxisAngle4d( new Vector3d( 1, 2, 3), Math.toRadians( 90 ) ) );
  		
  		Transform3D c = new Transform3D( a );
  		
  		c.mul( a );
  		
  		IOFunctions.println(c);
  		IOFunctions.println(b);
  				
  		Vector3d roationAxis = extractRotationAxis ( TransformUtils.getAffineModel3D( a ), TransformUtils.getAffineModel3D( b )  );
  
  		IOFunctions.println( roationAxis );				
  		IOFunctions.println( extractRotationAngle( TransformUtils.getAffineModel3D( a ), TransformUtils.getAffineModel3D( b ), roationAxis) );		
  		
  	}
  
  	public static double extractRotationAngle( final AffineModel3D modelA, final AffineModel3D modelB, final Vector3d rotationAxis )
  	{
  		final Transform3D transformA = TransformUtils.getTransform3D( modelA );
  		final Transform3D transformB = TransformUtils.getTransform3D( modelB );
  
  		// reset translational components
  		transformA.setTranslation( new Vector3d() );
  		transformB.setTranslation( new Vector3d() );
  		
  		final Transform3D connectingTransform = new Transform3D();
  		final Transform3D tmp = new Transform3D();
  		
  		final Matrix3d matrix1 = new Matrix3d();
  		final Matrix3d matrix2 = new Matrix3d();
  		
  		transformB.get( matrix2 );
  		
  		double minError = Float.MAX_VALUE;
  		double minAngle = -1;
  		
  		for ( double angle = 0f; angle < 360.0f; angle += 1f )
  		{
  			connectingTransform.setIdentity();
  			connectingTransform.setRotation( new AxisAngle4d( rotationAxis, Math.toRadians( angle ) ) );
  		
  			tmp.set( transformA );
  			tmp.mul( connectingTransform );
  			
  			tmp.get( matrix1 );
  			
  			matrix1.sub( matrix2 );
  			
  			final double diff = matrix1.m00 * matrix1.m00 + matrix1.m01 * matrix1.m01 + matrix1.m02 * matrix1.m02 +
  							   matrix1.m10 * matrix1.m10 + matrix1.m11 * matrix1.m11 + matrix1.m12 * matrix1.m12 +
  							   matrix1.m20 * matrix1.m20 + matrix1.m21 * matrix1.m21 + matrix1.m22 * matrix1.m22;
  
  			IOFunctions.println( angle + " " + diff );
  			
  			if ( diff < minError )
  			{
  				minError = diff;
  				minAngle = angle;
  			}
  		}
  		
  		return minAngle;
  	}
  	
  	/**
  	 * Computes the rotation axis between two affine matrices, assuming that the first affine transform is the identity transform E. 
  	 * The rotation axis is just a relative ratio between x,y and z, so x is set to 1.
  	 * @param model - the second affine transformation 
  	 * @return - the Vector containing the rotation axis
  	 */
  	public static Vector3d extractRotationAxis( final AffineModel3D model )
  	{
  		final double[] matrix = model.getMatrix( null );
  				
  		final double m00 = matrix[ 0 ];
  		final double m01 = matrix[ 1 ];
  		final double m02 = matrix[ 2 ];
  		final double m10 = matrix[ 4 ];
  		final double m11 = matrix[ 5 ];
  		final double m12 = matrix[ 6 ];
  		final double m20 = matrix[ 8 ];
  		final double m21 = matrix[ 9 ];
  		final double m22 = matrix[ 10 ];
  		
  		final Vector3d rotationAxis = new Vector3d( 1, 0, 0 );
  		
  		final double x = rotationAxis.x;		
  		rotationAxis.y = ( ( 1 - m00 ) * ( 1 - m22 ) * x - m20 * m02 * x ) / ( m01 * ( 1 - m22 ) + m21 * m02 );
  		rotationAxis.z = ( ( 1 - m00 ) * ( 1 - m11 ) * x - m10 * m01 * x ) / ( m02 * ( 1 - m11 ) + m12 * m01 );
  		
  		return rotationAxis;
  		
  		/*
  		IOFunctions.println( modelA );
  		IOFunctions.println( modelB );
  		
  		final float[] v1 = new float[ 3 ];
  		v1[ 0 ] = -1;
  		v1[ 1 ] = 0;
  		v1[ 2 ] = 0;
  		
  		final float[] v2 = v1.clone();
  		
  		modelA.applyInPlace( v1 );
  		modelB.applyInPlace( v2 );
  		
  		float sum = 0;
  		for ( int j = 0; j < 3; ++j )
  			sum += (v1[ j ] - v2[ j ]) * (v1[ j ] - v2[ j ]);
  			
  		IOFunctions.println( sum );
  		*/
  	}
  
  	/**
  	 * Computes the rotation axis between two affine matrices. 
  	 * The rotation axis is just a relative ratio between x,y and z, so x is set to 1.
  	 * @param modelA - the first affine transformation 
  	 * @param modelB - the second affine transformation 
  	 * @return - the Vector containing the rotation axis
  	 */
  	public static Vector3d extractRotationAxis( final AffineModel3D modelA, final AffineModel3D modelB )
  	{
  		final double[] matrixA = modelA.getMatrix( null );
  		final double[] matrixB = modelB.getMatrix( null );
  				
  		final double m00 = matrixA[ 0 ];
  		final double m01 = matrixA[ 1 ];
  		final double m02 = matrixA[ 2 ];
  		final double m10 = matrixA[ 4 ];
  		final double m11 = matrixA[ 5 ];
  		final double m12 = matrixA[ 6 ];
  		final double m20 = matrixA[ 8 ];
  		final double m21 = matrixA[ 9 ];
  		final double m22 = matrixA[ 10 ];
  
  		final double n00 = matrixB[ 0 ];
  		final double n01 = matrixB[ 1 ];
  		final double n02 = matrixB[ 2 ];
  		final double n10 = matrixB[ 4 ];
  