/* * Everyone is free to use, modify, and redistribute this code as long as they * retain this comment block near the top of this file, add this comment block * to files containing significant amounts of code copied from this file, and * not remove any text from this comment block. * Text can be appended to the bottom of this comment block as a change log and * credit to the contributors. * * This code is provided "as is" without any warranty. The contributors will * not be held liable for any damages resulting from the use of this code. * * Change Log: * * YYYY/MM/DD - Contributor Name * -change1 * -change2 * * 2007/07/31 - Dylan Hoen * -Created this file named. DepthOfField.java * -Created public class DepthOfField extends Applet implements ActionListener */ import java.applet.Applet; import java.awt.*; import java.awt.event.*; import java.net.*; import java.util.StringTokenizer; public class DepthOfField extends Applet implements ActionListener, AdjustmentListener { BorderLayout borderLayout = null; BufferedCanvas depthOfFieldCanvas = null; Panel leftPanel = null; Panel centerAndBottomPanel = null; Panel bottomPanel = null; Button calculateDepthOfField = null; Button calculateHyperFocalDistance = null; Button calculateAperture = null; Button calculateApertureAndDistance = null; Button calculateApertureAndDistanceWithLargerAperture = null; Button maximizeNearToInfinity = null; Button saveAsUrl = null; Label sensorSizeLabel = null; List sensorSizeList = null; Label apertureLabel = null; TextField apertureBox = null; Label minApertureLabel = null; TextField minApertureBox = null; Label maxApertureLabel = null; TextField maxApertureBox = null; Label xResLabel = null; TextField xResBox = null; Label yResLabel = null; TextField yResBox = null; Label bayerLowPassFilterLabel = null; Checkbox bayerLowPassFilterBox = null; Label focalLengthLabel = null; TextField focalLengthBox = null; CheckboxGroup equivelentFocalLengthGroup = null; Checkbox equivelentActualBox = null; Checkbox equivelent35mmBox = null; Label focalDistanceLabel = null; TextField focalDistanceBox = null; Label nearFocalDistanceLabel = null; TextField nearFocalDistanceBox = null; Label farFocalDistanceLabel = null; TextField farFocalDistanceBox = null; Label minInFocusLinesPerHeightLabel = null; TextField minInFocusLinesPerHeightBox = null; Scrollbar apertureScrollbar = null; Scrollbar focalDistanceScrollbar = null; TextArea leftTextArea = null; TextArea rightTextArea = null; int canvasWidth, canvasHeight; double xmin, xmax, ymin, ymax, xstep, xscale, yscale; int ntext; Color backgroundColor = null; Color graphColor = null; Color axisColor = null; Color textColor = null; Color focalDistanceColor = null; Color farFocalDistanceColor = null; Color bayerLimitColor = null; Color diffractionLimitColor = null; Color circleOfConfusionLimitColor = null; Color minInFocusLinesPerHeightColor = null; Color horizontalFieldOfViewColor = null; Color verticalFieldOfViewColor = null; double sensorWidth; double sensorHeight; double sensorDiagonal; double focalLengthMultiplier; double aperture; double minAperture; double maxAperture; double xRes; double yRes; double pixelCount; double focalLength; double focalDistance; double nearFocalDistance; double farFocalDistance; double diagonalFOV; double horizontalFov; double verticalFov; double pixelWidth; double pixelHeight; double magnification; double pixelsPerMM; double imageDistance; double macroAperture; boolean bayerLowPassFilter; double bayerLowPassPixelSize; double diffractionDiskSize; double minLinesPerHeight; double minInFocusLinesPerHeight; double minInFocusLinesPerHeightLeftCrossing; double minInFocusLinesPerHeightRightCrossing; public void init () { setLayout( new BorderLayout() ); centerAndBottomPanel = new Panel(); centerAndBottomPanel.setLayout( new BorderLayout() ); leftPanel = new Panel(); leftPanel.setLayout( new GridLayout( 0, 1 ) ); leftTextArea = new TextArea( "", 12, 20 ); rightTextArea = new TextArea( "", 13, 20 ); depthOfFieldCanvas = new BufferedCanvas(); centerAndBottomPanel.add( depthOfFieldCanvas, BorderLayout.CENTER ); leftPanel.setLayout( new GridLayout(0, 2)); sensorSizeLabel = new Label( "Sensor Size:" ); leftPanel.add( sensorSizeLabel ); sensorSizeList = new List(4, false); sensorSizeList.add( "1/2.7\", 5.371mm X 4.035mm" ); sensorSizeList.add( "1/2.5\", 5.760mm X 4.290mm" ); sensorSizeList.add( "1/1.8\", 7.176mm X 5.319mm" ); sensorSizeList.add( "1/1.7\", 7.600mm X 5.700mm" ); sensorSizeList.add( "2/3\", 8.80mm X 6.60mm" ); sensorSizeList.add( "4/3\", 17.40mm X 13.10mm" ); sensorSizeList.add( "APS-C, 22.5mm X 15.0mm" ); sensorSizeList.add( "Canon 5D, 36.0mm X 24.0mm" ); sensorSizeList.add( "35mm FF, 36.0mm X 24.0mm" ); sensorSizeList.add( "medium, 48.0mm X 36.0mm" ); sensorSizeList.select( 5 ); leftPanel.add( sensorSizeList ); xResLabel = new Label( "X Resolution (Pixels):" ); leftPanel.add( xResLabel ); xResBox = new TextField( "" ); leftPanel.add( xResBox ); yResLabel = new Label( "Y Resolution (Pixels):" ); leftPanel.add( yResLabel ); yResBox = new TextField( "" ); leftPanel.add( yResBox ); bayerLowPassFilterLabel = new Label( "Bayer Low Pass Filtered:" ); leftPanel.add( bayerLowPassFilterLabel ); bayerLowPassFilterBox = new Checkbox( "", true ); leftPanel.add( bayerLowPassFilterBox ); minApertureLabel = new Label( "Minimum Aperture (F/A):" ); leftPanel.add( minApertureLabel ); minApertureBox = new TextField( "" ); leftPanel.add( minApertureBox ); maxApertureLabel = new Label( "Maximum Aperture (F/A):" ); leftPanel.add( maxApertureLabel ); maxApertureBox = new TextField( "" ); leftPanel.add( maxApertureBox ); apertureLabel = new Label( "Aperture (F/A):" ); leftPanel.add( apertureLabel ); apertureBox = new TextField( "" ); leftPanel.add( apertureBox ); leftPanel.add( new Label( "" ) ); apertureScrollbar = new Scrollbar( Scrollbar.HORIZONTAL, 50, 1, 0, 101 ); apertureScrollbar.addAdjustmentListener( this ); leftPanel.add( apertureScrollbar ); focalLengthLabel = new Label( "Focal Length (mm):" ); leftPanel.add( focalLengthLabel ); focalLengthBox = new TextField( "" ); leftPanel.add( focalLengthBox ); equivelentFocalLengthGroup = new CheckboxGroup(); equivelentActualBox = new Checkbox( "Actual Focal Length", equivelentFocalLengthGroup, true ); leftPanel.add( equivelentActualBox ); equivelent35mmBox = new Checkbox( "35mm Equivelent Focal Length", equivelentFocalLengthGroup, false ); leftPanel.add( equivelent35mmBox ); nearFocalDistanceLabel = new Label( "Subject Near Distance (m):" ); leftPanel.add( nearFocalDistanceLabel ); nearFocalDistanceBox = new TextField( "" ); leftPanel.add( nearFocalDistanceBox ); farFocalDistanceLabel = new Label( "Subject Far Distance (m):" ); leftPanel.add( farFocalDistanceLabel ); farFocalDistanceBox = new TextField( "" ); leftPanel.add( farFocalDistanceBox ); focalDistanceLabel = new Label( "Focal Distance (m):" ); leftPanel.add( focalDistanceLabel ); focalDistanceBox = new TextField( "" ); leftPanel.add( focalDistanceBox ); leftPanel.add( new Label( "" ) ); focalDistanceScrollbar = new Scrollbar( Scrollbar.HORIZONTAL, 50, 1, 0, 101 ); focalDistanceScrollbar.addAdjustmentListener( this ); leftPanel.add( focalDistanceScrollbar ); minInFocusLinesPerHeightLabel = new Label( "Min In-Focus Lines-Per-Height: " ); leftPanel.add( minInFocusLinesPerHeightLabel ); minInFocusLinesPerHeightBox = new TextField( "" ); leftPanel.add( minInFocusLinesPerHeightBox ); calculateDepthOfField = new Button( "Graph Depth Of Field" ); calculateDepthOfField.addActionListener( this ); leftPanel.add( calculateDepthOfField ); calculateHyperFocalDistance = new Button( "Calculate Hyper Focal Distance" ); calculateHyperFocalDistance.addActionListener( this ); leftPanel.add( calculateHyperFocalDistance ); calculateAperture = new Button( "Calculate Aperture" ); calculateAperture.addActionListener( this ); leftPanel.add( calculateAperture ); calculateApertureAndDistance = new Button( "Calculate Aperture and Distance" ); calculateApertureAndDistance.addActionListener( this ); leftPanel.add( calculateApertureAndDistance ); calculateApertureAndDistanceWithLargerAperture = new Button( "Calculate A and D, larger A" ); calculateApertureAndDistanceWithLargerAperture.addActionListener( this ); leftPanel.add( calculateApertureAndDistanceWithLargerAperture ); maximizeNearToInfinity = new Button( "Maximize Near Subject To Infinity" ); maximizeNearToInfinity.addActionListener( this ); leftPanel.add( maximizeNearToInfinity ); saveAsUrl = new Button( "Save As Linkable URL" ); saveAsUrl.addActionListener( this ); leftPanel.add( saveAsUrl ); bottomPanel = new Panel(); bottomPanel.setLayout( new GridLayout( 1, 2 ) ); bottomPanel.add( leftTextArea ); bottomPanel.add( rightTextArea ); centerAndBottomPanel.add( bottomPanel, BorderLayout.SOUTH ); add( centerAndBottomPanel, BorderLayout.CENTER ); add( leftPanel, BorderLayout.WEST ); xmin = -1; xmax = 20; ymin = -.25; ymax = 1; ntext = 0; backgroundColor = Color.BLACK; graphColor = Color.WHITE; axisColor = Color.GRAY; textColor = Color.WHITE; focalDistanceColor = Color.MAGENTA; farFocalDistanceColor = Color.RED; bayerLimitColor = Color.GREEN; diffractionLimitColor = Color.ORANGE; circleOfConfusionLimitColor = Color.CYAN; minInFocusLinesPerHeightColor = Color.YELLOW; horizontalFieldOfViewColor = Color.DARK_GRAY; verticalFieldOfViewColor = Color.DARK_GRAY; setBackground( backgroundColor ); sensorWidth = 18.000 / 1000; sensorHeight = 13.500 / 1000; aperture = 8.0; minAperture = 2.0; maxAperture = 22.0; xRes = 3648; yRes = 2736; bayerLowPassFilter = true; focalLength = 50.0 / 1000; focalDistance = 2.0; nearFocalDistance = 1.0; farFocalDistance = 3.0; minInFocusLinesPerHeight = 864; calcuateNonInputVariables(); writeSettingsToGui(); getSettingsFromGui(); parseUrl(); writeSettingsToGui(); getSettingsFromGui(); repaint(); } public void calcuateNonInputVariables() { sensorDiagonal = Math.sqrt( sensorWidth * sensorWidth + sensorHeight * sensorHeight ); focalLengthMultiplier = Math.sqrt( .036 * .036 + .024 * .024 ) / sensorDiagonal; pixelCount = xRes * yRes; pixelWidth = sensorWidth / xRes; pixelHeight = sensorHeight / yRes; magnification = focalLength / ( focalDistance - focalLength ); imageDistance = focalDistance * focalLength / ( focalDistance - focalLength ); pixelsPerMM = ( magnification / pixelHeight ) / 1000; diagonalFOV = ( 180 / Math.PI ) * ( 2 * Math.atan( sensorDiagonal / ( 2 * imageDistance ) ) ); horizontalFov = ( 180 / Math.PI ) * ( 2 * Math.atan( sensorWidth / ( 2 * imageDistance ) ) ); verticalFov = ( 180 / Math.PI ) * ( 2 * Math.atan( sensorHeight / ( 2 * imageDistance ) ) ); macroAperture = aperture * ( imageDistance / focalLength ); bayerLowPassPixelSize = bayerLowPassFilter ? pixelHeight * Math.sqrt( 2 ) : pixelHeight; diffractionDiskSize = 1.22 * 600e-9 * macroAperture; minLinesPerHeight = Math.min( f( nearFocalDistance ), f( farFocalDistance ) ); calculateMinInFocusLinesPerHeightLeftCrossing(); calculateMinInFocusLinesPerHeightRightCrossing(); } public void calculateMinInFocusLinesPerHeightLeftCrossing() { double minDistance = focalLength + ( nearFocalDistance - focalLength ) / 10; double maxDistance = focalDistance; for( int i = 0; i < 30; i++ ) { double guess = ( minDistance + maxDistance ) / 2; if( f( guess ) < minInFocusLinesPerHeight ) { minDistance = guess; } else { maxDistance = guess; } } minInFocusLinesPerHeightLeftCrossing = ( minDistance + maxDistance ) / 2; } public void calculateMinInFocusLinesPerHeightRightCrossing() { double minDistance = focalDistance; double maxDistance = Math.max( focalDistance * 1000, farFocalDistance * 2 ); for( int i = 0; i < 30; i++ ) { double guess = ( minDistance + maxDistance ) / 2; if( f( guess ) >= minInFocusLinesPerHeight ) { minDistance = guess; } else { maxDistance = guess; } } minInFocusLinesPerHeightRightCrossing = ( minDistance + maxDistance ) / 2; } public double circleOfConfusion( double x ) { //double circleOfConfusion = ( imageDistance / macroAperture ) * magnification * ( x - focalDistance ) / x; return ( Math.abs( x - focalDistance ) / x ) * ( ( focalLength * focalLength ) / ( aperture * ( focalDistance - focalLength ) ) ); } public double f( double x ) { return sensorHeight / Math.sqrt( Math.pow( bayerLowPassPixelSize, 2 ) + Math.pow( diffractionDiskSize, 2 ) + Math.pow( circleOfConfusion( x ), 2) ); } public int xToScreen( double x ) { return (int)Math.round( ( x - xmin ) * xscale ); } public int yToScreen( double y ) { return canvasHeight - (int)Math.round( ( y - ymin ) * yscale ); } public void paint( Graphics page ) { Graphics canvasGraphics = depthOfFieldCanvas.getBufferedGraphics(); try { canvasPaint( canvasGraphics ); } catch( Exception e ) { e.printStackTrace(); } depthOfFieldCanvas.repaint(); } public void canvasPaint( Graphics page ) { leftTextArea.replaceRange( "", 0, 65535 ); rightTextArea.replaceRange( "", 0, 65535 ); calcuateNonInputVariables(); xmin = Math.max( ( nearFocalDistance + focalLength ) / 2, nearFocalDistance - ( farFocalDistance - nearFocalDistance ) / 2 ); xmax = farFocalDistance + ( farFocalDistance - nearFocalDistance ) / 2; ymin = 0; ymax = yRes; canvasWidth = depthOfFieldCanvas.getWidth(); canvasHeight = depthOfFieldCanvas.getHeight(); xstep = xmax / ( canvasWidth * 4 ); xscale = canvasWidth / ( xmax - xmin ); yscale = canvasHeight / ( ymax - ymin ); page.setColor( Color.BLACK ); page.fillRect( 0, 0, canvasWidth, canvasHeight ); double x, y; int xold, xnew, yold, ynew; ntext = 0; // start field of view lines //horizontalFieldOfViewColor = Color.GRAY; //verticalFieldOfViewColor = Color.GRAY; page.setColor( horizontalFieldOfViewColor ); int fovXStart = xToScreen( 0 ); int fovXEnd = xToScreen( xmax ); int fovYStart = yToScreen( yRes / 2 ); //horizontalFov = ( 180 / Math.PI ) * ( 2 * Math.atan( sensorWidth / ( 2 * imageDistance ) ) ); page.drawLine( fovXStart, fovYStart, fovXEnd, fovYStart + (int)Math.round( ( fovXEnd - fovXStart ) * sensorWidth / ( 2 * imageDistance ) ) ); page.drawLine( fovXStart, fovYStart, fovXEnd, fovYStart - (int)Math.round( ( fovXEnd - fovXStart ) * sensorWidth / ( 2 * imageDistance ) ) ); page.setColor( verticalFieldOfViewColor ); //verticalFov = ( 180 / Math.PI ) * ( 2 * Math.atan( sensorHeight / ( 2 * imageDistance ) ) ); page.drawLine( fovXStart, fovYStart, fovXEnd, fovYStart + (int)Math.round( ( fovXEnd - fovXStart ) * sensorHeight / ( 2 * imageDistance ) ) ); page.drawLine( fovXStart, fovYStart, fovXEnd, fovYStart - (int)Math.round( ( fovXEnd - fovXStart ) * sensorHeight / ( 2 * imageDistance ) ) ); // end field of view lines // start axises page.setColor( axisColor ); drawCross( xToScreen( 0 ), yToScreen( 0 ), page ); page.setColor( textColor ); double xIncriment = findNearestOneTwoFiveTen( ( xmax - xmin ) / 12, true ); double minX = xIncriment * Math.ceil( xmin / xIncriment ); for( x = minX; x < xmax + xIncriment / 2; x += xIncriment ) { page.drawLine( xToScreen( x ), canvasHeight, xToScreen( x ), canvasHeight - 20 ); page.drawString( (float)x + " m", xToScreen( x ) + 3, canvasHeight - 3 ); } double yIncriment = findNearestOneTwoFiveTen( ( ymax - ymin ) / 12, true ); double minY = yIncriment * Math.ceil( ymin / yIncriment ); for( y = minY; y < ymax + yIncriment / 2; y += yIncriment ) { page.drawLine( 0, yToScreen( y ), 40, yToScreen( y ) ); page.drawString( (float)y + " LPH", 3, yToScreen( y ) - 3 ); } // end axises // start other lines page.setColor( bayerLimitColor ); drawHorizontalLine( yToScreen( sensorHeight / bayerLowPassPixelSize ), page ); page.setColor( diffractionLimitColor ); drawHorizontalLine( yToScreen( sensorHeight / diffractionDiskSize ), page ); page.setColor( focalDistanceColor ); drawSmallCross( xToScreen( focalDistance ), yToScreen( f( focalDistance ) ), page ); page.setColor( farFocalDistanceColor ); drawSmallCross( xToScreen( nearFocalDistance ), yToScreen( f( nearFocalDistance ) ), page ); drawSmallCross( xToScreen( farFocalDistance ), yToScreen( f( farFocalDistance ) ), page ); page.setColor( minInFocusLinesPerHeightColor ); if( f( focalDistance ) >= minInFocusLinesPerHeight ) { drawSmallCross( xToScreen( minInFocusLinesPerHeightLeftCrossing ), yToScreen( minInFocusLinesPerHeight ), page ); drawSmallCross( xToScreen( minInFocusLinesPerHeightRightCrossing ), yToScreen( minInFocusLinesPerHeight ), page ); page.drawLine( xToScreen( minInFocusLinesPerHeightLeftCrossing ), yToScreen( minInFocusLinesPerHeight ), xToScreen( minInFocusLinesPerHeightRightCrossing ), yToScreen( minInFocusLinesPerHeight ) ); } else { drawHorizontalLine( yToScreen( minInFocusLinesPerHeight ), page ); } // end other lines // start circleOfConfusion graph page.setColor( circleOfConfusionLimitColor ); x = xmin; y = sensorHeight / circleOfConfusion( x ); xold = xToScreen( x ); yold = yToScreen( y ); // Initial point for( x = xmin; x <= xmax; x += xstep ) { y = sensorHeight / circleOfConfusion( x ); xnew = xToScreen( x ); ynew = yToScreen( y ); page.drawLine( xold, yold, xnew, ynew ); xold = xnew; yold = ynew; } // end circleOfConfusion graph // start function graph page.setColor( graphColor ); x = xmin; y = f( x ); xold = xToScreen( x ); yold = yToScreen( y ); // Initial point for( x = xmin; x <= xmax; x += xstep ) { y = f( x ); xnew = xToScreen( x ); ynew = yToScreen( y ); page.drawLine( xold, yold, xnew, ynew ); xold = xnew; yold = ynew; } // end function graph // start text page.setColor( textColor ); leftTextArea.append( "Focal Resolution\t= " + (float)( f( focalDistance ) ) + " lines per height\n" ); leftTextArea.append( "Near Resolution\t= " + (float)( f( nearFocalDistance ) ) + " lines per height\n" ); leftTextArea.append( "Far Resolution\t= " + (float)( f( farFocalDistance ) ) + " lines per height\n" ); leftTextArea.append( "Bayer Low-Pass Limit\t= " + (float)( sensorHeight / bayerLowPassPixelSize ) + " lines per height\n" ); leftTextArea.append( "Diffraction Limit\t= " + (float)( sensorHeight / diffractionDiskSize ) + " lines per height\n" ); leftTextArea.append( "Pixel Count\t= " + (float)( pixelCount / 1000000 ) + " megapixels\n" ); leftTextArea.append( "Focal Pixel Count\t= " + (float)( f( focalDistance ) * f( focalDistance ) * xRes/ yRes / 1000000 ) + " megapixels\n" ); leftTextArea.append( "Min Pixel Count\t= " + (float)( minLinesPerHeight * minLinesPerHeight * xRes / yRes / 1000000 ) + " megapixels\n" ); leftTextArea.append( "Focal Length\t= " + (float)( focalLength * 1000 ) + " mm\n" ); leftTextArea.append( "Focal Length Multiplier\t= " + (float)( focalLengthMultiplier ) + " X\n" ); leftTextArea.append( "Compensated Focal Length\t= " + (float)( imageDistance * 1000 ) + " mm\n" ); leftTextArea.append( "Compensated Aperture\t= " + (float)( macroAperture ) + "\n" ); rightTextArea.append( "Magnification\t= " + (float)( magnification ) + " X\n" ); rightTextArea.append( "Diagonal FOV\t= " + (float)( diagonalFOV ) + " degrees" + "\n" ); rightTextArea.append( "Horizontal FOV\t= " + (float)( horizontalFov ) + " degrees" + "\n" ); rightTextArea.append( "Vertical FOV\t= " + (float)( verticalFov ) + " degrees" + "\n" ); rightTextArea.append( "Focal Plane Width\t= " + (float)( focalDistance / imageDistance * sensorWidth ) + " m" + "\n" ); rightTextArea.append( "Focal Plane Height\t= " + (float)( focalDistance / imageDistance * sensorHeight ) + " m" + "\n" ); rightTextArea.append( "Focal Lines/mm\t= " + (float)( f( focalDistance ) / sensorHeight / 1000 * magnification ) + "\n" ); rightTextArea.append( "Near Lines/mm\t= " + (float)( f( nearFocalDistance ) / sensorHeight / 1000 * magnification * ( focalDistance / nearFocalDistance ) ) + "\n" ); rightTextArea.append( "Far Lines/mm\t= " + (float)( f( farFocalDistance ) / sensorHeight / 1000 * magnification * ( focalDistance / farFocalDistance ) ) + "\n" ); if( f( focalDistance ) >= minInFocusLinesPerHeight ) { rightTextArea.append( "Start of Field\t= " + (float)( minInFocusLinesPerHeightLeftCrossing ) + " m" + "\n" ); if( minInFocusLinesPerHeightRightCrossing < 500 * focalLength ) { rightTextArea.append( "End of Field\t= " + (float)( minInFocusLinesPerHeightRightCrossing ) + " m" + "\n" ); rightTextArea.append( "Depth of Field\t= " + (float)( minInFocusLinesPerHeightRightCrossing - minInFocusLinesPerHeightLeftCrossing ) + " m" + "\n" ); } else { rightTextArea.append( "End of Field\t= infinity m" + "\n" ); rightTextArea.append( "Depth of Field\t= infinity m" + "\n" ); } } else { rightTextArea.append( "Depth of field\t= 0" + "\n" ); rightTextArea.append( "(The whole range is less than " + (float)( minInFocusLinesPerHeight ) + " lines per height)\n" ); } rightTextArea.append( "Sharpness of Infinity\t= " + (float)( f( focalDistance * 1000000 ) ) + " lines per height\n" ); /* double sensorWidth; double sensorHeight; double sensorDiagonal; double focalLengthMultiplier; double aperture; double minAperture; double maxAperture; double xRes; double yRes; double pixelCount; double focalLength; double focalDistance; double nearFocalDistance; double farFocalDistance; double diagonalFOV; double horizontalFov; double verticalFov; double pixelWidth; double pixelHeight; double magnification; double pixelsPerMM; double imageDistance; double macroAperture; boolean bayerLowPassFilter; double bayerLowPassPixelSize; double diffractionDiskSize; double minLinesPerHeight; double minInFocusLinesPerHeight; double minInFocusLinesPerHeightLeftCrossing; double minInFocusLinesPerHeightRightCrossing; */ // emd text } public void drawCross( int x, int y, Graphics page ) { drawVerticalLine( x, page ); drawHorizontalLine( y, page ); } public void drawSmallCross( int x, int y, Graphics page ) { int length = (int)( Math.round( Math.min( canvasWidth, canvasHeight ) / 4.0 ) ); page.drawLine( x, y, x + length, y ); page.drawLine( x, y, x, y + length ); page.drawLine( x, y, x - length, y ); page.drawLine( x, y, x, y - length ); } public void drawVerticalLine( int x, Graphics page ) { page.drawLine( x, 0, x, canvasHeight ); } public void drawHorizontalLine( int y, Graphics page ) { page.drawLine( 0, y, canvasWidth, y ); } public void print( String s, Graphics page ) { ntext++; page.drawString( s, 5, 15 * ntext ); } /** * Finds the nearest [ 1,2,5 ] * 10 ^ n, where n is an integer. * @param input the input to find the nearest [ 1,2,5 ] * 10 ^ n to. * @param higher if true, find the nearest [ 1,2,5 ] * 10 ^ n that is greater than or equal to input, else find the nearest [ 1,2,5 ] * 10 ^ n that is less than or equal to. * @return the nearest [ 1,2,5 ] * 10 ^ n, where n is an integer. */ public static double findNearestOneTwoFiveTen( double input, boolean higher ) { double result = 1; if( input == 0 ) { return 0; } boolean negative = ( input < 0 ); if( negative ) { input = -input; } double power = Math.log( input ) / Math.log( 10 ); int exponent = (int)Math.floor( power ); power -= exponent; if( higher ) { if( power == 0 ) { result = 1 * Math.pow( 10, exponent ); } else if( power <= Math.log( 2 ) / Math.log( 10 ) ) { result = 2 * Math.pow( 10, exponent ); } else if( power <= Math.log( 5 ) / Math.log( 10 ) ) { result = 5 * Math.pow( 10, exponent ); } else { result = 1 * Math.pow( 10, exponent + 1 ); } } else { if( power < Math.log( 2 ) / Math.log( 10 ) ) { result = 1 * Math.pow( 10, exponent ); } else if( power < Math.log( 5 ) / Math.log( 10 ) ) { result = 2 * Math.pow( 10, exponent ); } else { result = 5 * Math.pow( 10, exponent ); } } if( negative ) { result = -result; } return result; } public void adjustmentValueChanged( AdjustmentEvent e ) { if( e.getSource() == apertureScrollbar ) { int breakpoint = 0; int value = apertureScrollbar.getValue(); getSettingsFromGui(); double alpha = value / 100.0; aperture = alpha * maxAperture + ( 1 - alpha ) * minAperture; } if( e.getSource() == focalDistanceScrollbar ) { int breakpoint = 0; int value = focalDistanceScrollbar.getValue(); getSettingsFromGui(); double alpha = value / 100.0; focalDistance = alpha * farFocalDistance + ( 1 - alpha ) * nearFocalDistance; } repaint(); writeSettingsToGui(); } public void actionPerformed( ActionEvent e ) { getSettingsFromGui(); if( e.getSource() == calculateDepthOfField ) { int breakpoint = 0; } if( e.getSource() == calculateHyperFocalDistance ) { int breakpoint = 0; focalDistance = focalLength + focalLength * focalLength / ( aperture * ( bayerLowPassPixelSize / Math.sqrt( 2 ) ) ); nearFocalDistance = focalDistance / 2; farFocalDistance = focalDistance * 5; calcuateNonInputVariables(); focalDistanceBox.requestFocus(); } if( e.getSource() == calculateAperture ) { int breakpoint = 0; calculateOptimalAperture(); apertureBox.requestFocus(); } if( e.getSource() == calculateApertureAndDistance ) { int breakpoint = 0; for( int i = 0; i < 4; i++ ) { calculateOptimalAperture(); calculateOptimalDistance(); } apertureBox.requestFocus(); } if( e.getSource() == calculateApertureAndDistanceWithLargerAperture ) { int breakpoint = 0; for( int i = 0; i < 4; i++ ) { calculateOptimalAperture(); calculateOptimalDistance(); } calculateOptimalAperture2(); apertureBox.requestFocus(); } if( e.getSource() == maximizeNearToInfinity ) { int breakpoint = 0; for( int i = 0; i < 40; i++ ) { calculateOptimalApertureInfinity(); calculateOptimalDistanceInfinity(); } apertureBox.requestFocus(); } /* if( e.getSource() == calculateApertureAndDistanceRoot2 ) { int breakpoint = 0; for( int i = 0; i < 4; i++ ) { calculateOptimalAperture(); calculateOptimalDistance(); } calculateOptimalAperture3(); apertureBox.requestFocus(); } */ if( e.getSource() == saveAsUrl ) { int breakpoint = 0; setUrl(); } repaint(); writeSettingsToGui(); } public void calculateOptimalAperture() { double localMinAperture = minAperture; double localMaxAperture = maxAperture; for( int i = 0; i < 30; i++ ) { double guess = ( localMinAperture + localMaxAperture ) / 2; double highGuess = guess + ( localMaxAperture - localMinAperture ) / 100; aperture = highGuess; calcuateNonInputVariables(); double highGuessResult = minLinesPerHeight; double lowGuess = guess - ( localMaxAperture - localMinAperture ) / 100; aperture = lowGuess; calcuateNonInputVariables(); double lowGuessResult = minLinesPerHeight; if( highGuessResult > lowGuessResult ) { localMinAperture = lowGuess; } else { localMaxAperture = highGuess; } } aperture = ( localMinAperture + localMaxAperture ) / 2; calcuateNonInputVariables(); } public void calculateOptimalApertureInfinity() { double localMinAperture = minAperture; double localMaxAperture = maxAperture; for( int i = 0; i < 30; i++ ) { double guess = ( localMinAperture + localMaxAperture ) / 2; double highGuess = guess + ( localMaxAperture - localMinAperture ) / 100; aperture = highGuess; calcuateNonInputVariables(); double highGuessResult = Math.min( f( nearFocalDistance ), f( focalDistance * 1000000 ) ); double lowGuess = guess - ( localMaxAperture - localMinAperture ) / 100; aperture = lowGuess; calcuateNonInputVariables(); double lowGuessResult = Math.min( f( nearFocalDistance ), f( focalDistance * 1000000 ) ); if( highGuessResult > lowGuessResult ) { localMinAperture = lowGuess; } else { localMaxAperture = highGuess; } } aperture = ( localMinAperture + localMaxAperture ) / 2; calcuateNonInputVariables(); } public void calculateOptimalAperture2() { calculateOptimalAperture(); calcuateNonInputVariables(); double localMinAperture = minAperture; double localMaxAperture = aperture; double targetValue = minLinesPerHeight * .9; for( int i = 0; i < 30; i++ ) { double guess = ( localMinAperture + localMaxAperture ) / 2; aperture = guess; calcuateNonInputVariables(); if( minLinesPerHeight < targetValue ) { localMinAperture = guess; } else { localMaxAperture = guess; } } aperture = ( localMinAperture + localMaxAperture ) / 2; calcuateNonInputVariables(); } public void calculateOptimalAperture3() { double localMinAperture = minAperture; double localMaxAperture = aperture; for( int i = 0; i < 30; i++ ) { double guess = ( localMinAperture + localMaxAperture ) / 2; aperture = guess; calcuateNonInputVariables(); if( minLinesPerHeight * Math.sqrt( 2 ) < f( focalDistance ) ) { localMinAperture = guess; } else { localMaxAperture = guess; } } aperture = ( localMinAperture + localMaxAperture ) / 2; calcuateNonInputVariables(); } public void calculateOptimalDistance() { double minDistance = nearFocalDistance; double maxDistance = farFocalDistance; for( int i = 0; i < 30; i++ ) { double guess = ( minDistance + maxDistance ) / 2; focalDistance = guess; calcuateNonInputVariables(); if( f( nearFocalDistance ) > f( farFocalDistance ) ) { minDistance = guess; } else { maxDistance = guess; } } focalDistance = ( minDistance + maxDistance ) / 2; calcuateNonInputVariables(); } public void calculateOptimalDistanceInfinity() { double minDistance = nearFocalDistance; double maxDistance = focalLength * 1000000; farFocalDistance = focalLength * 1000000; for( int i = 0; i < 40; i++ ) { double guess = ( minDistance + maxDistance ) / 2; double highGuess = guess + ( maxDistance - minDistance ) / 100; focalDistance = highGuess; calcuateNonInputVariables(); double highGuessResult = Math.min( f( nearFocalDistance ), f( focalDistance * 1000000 ) ); double lowGuess = guess - ( maxDistance - minDistance ) / 100; focalDistance = lowGuess; calcuateNonInputVariables(); double lowGuessResult = Math.min( f( nearFocalDistance ), f( focalDistance * 1000000 ) );; if( highGuessResult > lowGuessResult ) { minDistance = lowGuess; } else { maxDistance = highGuess; } } focalDistance = ( minDistance + maxDistance ) / 2; farFocalDistance = focalDistance * 5; calcuateNonInputVariables(); } public void getSensorSize() { switch( sensorSizeList.getSelectedIndex() ) { case 0: sensorWidth = .005371; sensorHeight = .004035; break; case 1: sensorWidth = .005760; sensorHeight = .004290; break; case 2: sensorWidth = .007176; sensorHeight = .005319; break; case 3: sensorWidth = .007600; sensorHeight = .005700; break; case 4: sensorWidth = .008800; sensorHeight = .006600; break; case 5: sensorWidth = .017400; sensorHeight = .013100; break; case 6: sensorWidth = .0225; sensorHeight = .0150; break; case 7: sensorWidth = .036000; sensorHeight = .024000; break; case 8: sensorWidth = .036000; sensorHeight = .024000; break; case 9: sensorWidth = .048000; sensorHeight = .036000; break; default: try { throw new Exception( "This line of code should not be exicuted. Sensor index = " + sensorSizeList.getSelectedIndex() ); } catch( Exception ex ) { ex.printStackTrace(); } break; } } public void getSettingsFromGui() { getSensorSize(); aperture = Double.parseDouble( apertureBox.getText() ); minAperture = Double.parseDouble( minApertureBox.getText() ); maxAperture = Double.parseDouble( maxApertureBox.getText() ); xRes = Double.parseDouble( xResBox.getText() ); yRes = Double.parseDouble( yResBox.getText() ); minInFocusLinesPerHeight = Double.parseDouble( minInFocusLinesPerHeightBox.getText() ); if( minInFocusLinesPerHeight < 4 ) { minInFocusLinesPerHeight = 4; } if( minInFocusLinesPerHeight > yRes / 2 ) { minInFocusLinesPerHeight = yRes / 2; } bayerLowPassFilter = bayerLowPassFilterBox.getState(); focalLength = Double.parseDouble( focalLengthBox.getText() ) / 1000; if( equivelentFocalLengthGroup.getSelectedCheckbox() == equivelent35mmBox ) { double sensorDiagonal = Math.sqrt( sensorWidth * sensorWidth + sensorHeight * sensorHeight ); double focalLengthMultiplier = Math.sqrt( .036 * .036 + .024 * .024 ) / sensorDiagonal; focalLength /= focalLengthMultiplier; } focalDistance = Double.parseDouble( focalDistanceBox.getText() ); nearFocalDistance = Double.parseDouble( nearFocalDistanceBox.getText() ); farFocalDistance = Double.parseDouble( farFocalDistanceBox.getText() ); if( focalLength < .001 ) { focalLength = .001; } if( nearFocalDistance < focalLength * 1.001 ) { nearFocalDistance = focalLength * 1.001; } if( farFocalDistance < nearFocalDistance * 1.0001 ) { farFocalDistance = nearFocalDistance * 1.0001; } if( focalDistance < nearFocalDistance ) { focalDistance = nearFocalDistance; } if( focalDistance > farFocalDistance ) { focalDistance = farFocalDistance; } if( xRes < 2 ) { xRes = 2; } if( yRes < 2 ) { yRes = 2; } if( minAperture < .25 ) { minAperture = .25; } if( minAperture > 1000 ) { minAperture = 1000; } if( maxAperture < .25 ) { maxAperture = .25; } if( maxAperture > 1000 ) { maxAperture = 1000; } if( maxAperture < maxAperture ) { double temp = maxAperture; maxAperture = minAperture; minAperture = temp; } if( aperture > maxAperture ) { aperture = maxAperture; } if( aperture < minAperture ) { aperture = minAperture; } calcuateNonInputVariables(); writeSettingsToGui(); } public void writeSettingsToGui() { apertureBox.setText( aperture + "" ); minApertureBox.setText( minAperture + "" ); maxApertureBox.setText( maxAperture + "" ); xResBox.setText( xRes + "" ); yResBox.setText( yRes + "" ); bayerLowPassFilterBox.setState( bayerLowPassFilter ); if( equivelentFocalLengthGroup.getSelectedCheckbox() == equivelent35mmBox ) { double sensorDiagonal = Math.sqrt( sensorWidth * sensorWidth + sensorHeight * sensorHeight ); double focalLengthMultiplier = Math.sqrt( .036 * .036 + .024 * .024 ) / sensorDiagonal; focalLengthBox.setText( ( focalLength * focalLengthMultiplier * 1000 ) + "" ); } else { focalLengthBox.setText( ( focalLength * 1000 ) + "" ); } focalDistanceBox.setText( focalDistance + "" ); nearFocalDistanceBox.setText( nearFocalDistance + "" ); farFocalDistanceBox.setText( farFocalDistance + "" ); minInFocusLinesPerHeightBox.setText( minInFocusLinesPerHeight + "" ); apertureScrollbar.setValue( (int)Math.round( 100 * ( aperture - minAperture ) / ( maxAperture - minAperture ) ) ); focalDistanceScrollbar.setValue( (int)Math.round( 100 * ( focalDistance - nearFocalDistance ) / ( farFocalDistance - nearFocalDistance ) ) ); } public void setUrl() { String url = this.getDocumentBase().toString(); if( url.lastIndexOf( '?' ) >= 0 ) { url = url.substring( 0, url.indexOf( '?' ) ); } url += "?"; url += "sensorSize=" + sensorSizeList.getSelectedIndex(); url += "&xRes=" + xRes; url += "&yRes=" + yRes; url += "&bayerLowPassFilter=" + bayerLowPassFilter; url += "&aperture=" + aperture; url += "&minAperture=" + minAperture; url += "&maxAperture=" + maxAperture; url += "&focalLength=" + focalLength; url += "&equivelent=" + ( equivelentFocalLengthGroup.getSelectedCheckbox() == equivelent35mmBox ); url += "&focalDistance=" + focalDistance; url += "&nearFocalDistance=" + nearFocalDistance; url += "&farFocalDistance=" + farFocalDistance; url += "&minInFocusLinesPerHeight=" + minInFocusLinesPerHeight; try { this.getAppletContext().showDocument( new URL( url ) ); } catch( Exception e ) { e.printStackTrace(); } } public void parseUrl() { String url = this.getDocumentBase().toString(); //System.out.println( url ); if( url.lastIndexOf( '?' ) >= 0 ) { url = url.substring( url.indexOf( '?' ) + 1 ); //System.out.println( url ); StringTokenizer st = new StringTokenizer( url, "&" ); while( st.hasMoreTokens() ) { String token = st.nextToken(); //System.out.println( token ); StringTokenizer st2 = new StringTokenizer( token, "=" ); if( st2.countTokens() == 2 ) { String variable = st2.nextToken(); String value = st2.nextToken(); //System.out.println( variable ); //System.out.println( value ); if( variable != null && value != null ) { if( variable.equals( "sensorSize" ) ) { sensorSizeList.select( Integer.parseInt( value ) ); getSensorSize(); } else if( variable.equals( "xRes" ) ) { xRes = Double.parseDouble( value ); } else if( variable.equals( "yRes" ) ) { yRes = Double.parseDouble( value ); } else if( variable.equals( "bayerLowPassFilter" ) ) { bayerLowPassFilter = Boolean.parseBoolean( value ); } else if( variable.equals( "aperture" ) ) { aperture = Double.parseDouble( value ); } else if( variable.equals( "minAperture" ) ) { minAperture = Double.parseDouble( value ); } else if( variable.equals( "maxAperture" ) ) { maxAperture = Double.parseDouble( value ); } else if( variable.equals( "focalLength" ) ) { focalLength = Double.parseDouble( value ); } else if( variable.equals( "equivelent" ) ) { if( Boolean.parseBoolean( value ) ) { equivelentFocalLengthGroup.setSelectedCheckbox( equivelent35mmBox ); } else { equivelentFocalLengthGroup.setSelectedCheckbox( equivelentActualBox ); } } else if( variable.equals( "focalDistance" ) ) { focalDistance = Double.parseDouble( value ); } else if( variable.equals( "nearFocalDistance" ) ) { nearFocalDistance = Double.parseDouble( value ); } else if( variable.equals( "farFocalDistance" ) ) { farFocalDistance = Double.parseDouble( value ); } else if( variable.equals( "minInFocusLinesPerHeight" ) ) { minInFocusLinesPerHeight = Double.parseDouble( value ); } else { try { throw new Exception( "This is not a valid paramiter: " + variable ); } catch( Exception e ) { e.printStackTrace(); } } } } } } writeSettingsToGui(); getSettingsFromGui(); } }