dofcalc-commits Mailing List for dofCalc
Status: Beta
Brought to you by:
charly4711
You can subscribe to this list here.
2009 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
(4) |
Nov
|
Dec
|
---|
From: <cha...@us...> - 2009-10-06 20:32:50
|
Revision: 12 http://dofcalc.svn.sourceforge.net/dofcalc/?rev=12&view=rev Author: charly4711 Date: 2009-10-06 20:32:37 +0000 (Tue, 06 Oct 2009) Log Message: ----------- Tagging v1.0 Added Paths: ----------- tags/v1.0/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cha...@us...> - 2009-10-06 13:02:33
|
Revision: 11 http://dofcalc.svn.sourceforge.net/dofcalc/?rev=11&view=rev Author: charly4711 Date: 2009-10-06 12:27:14 +0000 (Tue, 06 Oct 2009) Log Message: ----------- added 35mm and APS-C d/1500 style cocs Modified Paths: -------------- trunk/src/de/olypedia/DofCalculator.java trunk/src/de/olypedia/resources/i18n/messages.properties trunk/src/de/olypedia/resources/i18n/messages_de.properties Modified: trunk/src/de/olypedia/DofCalculator.java =================================================================== --- trunk/src/de/olypedia/DofCalculator.java 2009-10-01 15:57:24 UTC (rev 10) +++ trunk/src/de/olypedia/DofCalculator.java 2009-10-06 12:27:14 UTC (rev 11) @@ -144,6 +144,10 @@ /** Valid choices for the coc list */ private static final String[][] CIRCLE_OF_CONFUSION_CHOICES = new String[][]{ + {LocalizationSupport.getMessage("CHOICE_CIRCLE_OF_CONFUSION_35_TRAD"), + "0.02884"}, + {LocalizationSupport.getMessage("CHOICE_CIRCLE_OF_CONFUSION_APSC_TRAD"), + "0.01803"}, {LocalizationSupport.getMessage("CHOICE_CIRCLE_OF_CONFUSION_FT_TRAD"), "0.0147"}, {LocalizationSupport.getMessage("CHOICE_CIRCLE_OF_CONFUSION_FT_5MP"), Modified: trunk/src/de/olypedia/resources/i18n/messages.properties =================================================================== --- trunk/src/de/olypedia/resources/i18n/messages.properties 2009-10-01 15:57:24 UTC (rev 10) +++ trunk/src/de/olypedia/resources/i18n/messages.properties 2009-10-06 12:27:14 UTC (rev 11) @@ -53,6 +53,8 @@ LIST_TITLE_APERTURES=Aperture Values LIST_TITLE_COC=Typical Circle of Confusion Values +CHOICE_CIRCLE_OF_CONFUSION_35_TRAD=35mm (trad.) +CHOICE_CIRCLE_OF_CONFUSION_APSC_TRAD=APS-C (trad.) CHOICE_CIRCLE_OF_CONFUSION_FT_TRAD=FT (trad.) CHOICE_CIRCLE_OF_CONFUSION_FT_5MP=FT 5MP CHOICE_CIRCLE_OF_CONFUSION_FT_8MP=FT 8MP Modified: trunk/src/de/olypedia/resources/i18n/messages_de.properties =================================================================== --- trunk/src/de/olypedia/resources/i18n/messages_de.properties 2009-10-01 15:57:24 UTC (rev 10) +++ trunk/src/de/olypedia/resources/i18n/messages_de.properties 2009-10-06 12:27:14 UTC (rev 11) @@ -53,6 +53,8 @@ LIST_TITLE_APERTURES=Blenden-Werte LIST_TITLE_COC=Typische Zerstreuungskreise +CHOICE_CIRCLE_OF_CONFUSION_35_TRAD=35mm (trad.) +CHOICE_CIRCLE_OF_CONFUSION_APSC_TRAD=APS-C (trad.) CHOICE_CIRCLE_OF_CONFUSION_FT_TRAD=FT (trad.) CHOICE_CIRCLE_OF_CONFUSION_FT_5MP=FT 5MP CHOICE_CIRCLE_OF_CONFUSION_FT_8MP=FT 8MP This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cha...@us...> - 2009-10-01 15:57:49
|
Revision: 10 http://dofcalc.svn.sourceforge.net/dofcalc/?rev=10&view=rev Author: charly4711 Date: 2009-10-01 15:57:24 +0000 (Thu, 01 Oct 2009) Log Message: ----------- changed order in which commands were added, because the motorola touch emulator does not acknowledge the priority but the order of addition. let's hope other emulators don't look at the order the other way around. Modified Paths: -------------- trunk/src/de/olypedia/DofCalculator.java Modified: trunk/src/de/olypedia/DofCalculator.java =================================================================== --- trunk/src/de/olypedia/DofCalculator.java 2009-10-01 15:12:18 UTC (rev 9) +++ trunk/src/de/olypedia/DofCalculator.java 2009-10-01 15:57:24 UTC (rev 10) @@ -851,8 +851,8 @@ // add commands choiceGroup.addCommand(getHelpCommandSingleton()); + choiceGroup.addCommand(getExitCommandSingleton()); choiceGroup.addCommand(getPreferencesCommandSingleton()); - choiceGroup.addCommand(getExitCommandSingleton()); choiceGroup.setItemCommandListener(app); return choiceGroup; @@ -881,9 +881,9 @@ textField.setLayout(ImageItem.LAYOUT_RIGHT | Item.LAYOUT_EXPAND); // add commands - textField.addCommand(getCalculateCommandSingleton()); textField.addCommand(getHelpCommandSingleton()); textField.addCommand(getExitCommandSingleton()); + textField.addCommand(getCalculateCommandSingleton()); textField.setItemCommandListener(app); return textField; @@ -915,9 +915,9 @@ textField.setLayout(ImageItem.LAYOUT_RIGHT | Item.LAYOUT_EXPAND); // add other commands - textField.addCommand(getCalculateCommandSingleton()); textField.addCommand(getHelpCommandSingleton()); textField.addCommand(getExitCommandSingleton()); + textField.addCommand(getCalculateCommandSingleton()); textField.setItemCommandListener(app); return textField; @@ -946,9 +946,9 @@ textField.setLayout(ImageItem.LAYOUT_RIGHT | Item.LAYOUT_EXPAND); // add commands - textField.addCommand(getCalculateCommandSingleton()); textField.addCommand(getHelpCommandSingleton()); textField.addCommand(getExitCommandSingleton()); + textField.addCommand(getCalculateCommandSingleton()); textField.setItemCommandListener(app); return textField; @@ -977,9 +977,9 @@ textField.setLayout(ImageItem.LAYOUT_RIGHT | Item.LAYOUT_EXPAND); // add commands - textField.addCommand(getCalculateCommandSingleton()); textField.addCommand(getHelpCommandSingleton()); textField.addCommand(getExitCommandSingleton()); + textField.addCommand(getCalculateCommandSingleton()); textField.setItemCommandListener(app); return textField; @@ -1093,7 +1093,7 @@ public static Command getHelpCommandSingleton() { if (helpCommand == null) { helpCommand = new Command(LocalizationSupport.getMessage( - "LBL_CMD_HELP"), Command.HELP, 7); + "LBL_CMD_HELP"), Command.ITEM, 7); } return helpCommand; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <cha...@us...> - 2009-10-01 15:12:44
|
Revision: 9 http://dofcalc.svn.sourceforge.net/dofcalc/?rev=9&view=rev Author: charly4711 Date: 2009-10-01 15:12:18 +0000 (Thu, 01 Oct 2009) Log Message: ----------- adding javadocs Modified Paths: -------------- trunk/src/de/olypedia/DofCalculator.java trunk/src/de/olypedia/ImagingChangeListener.java trunk/src/de/olypedia/ImagingSetting.java trunk/src/de/olypedia/ImagingSettingModel.java trunk/src/de/olypedia/RecordStoreHandler.java trunk/src/de/olypedia/resources/i18n/LocalizationSupport.java Modified: trunk/src/de/olypedia/DofCalculator.java =================================================================== --- trunk/src/de/olypedia/DofCalculator.java 2009-09-30 08:51:34 UTC (rev 8) +++ trunk/src/de/olypedia/DofCalculator.java 2009-10-01 15:12:18 UTC (rev 9) @@ -18,7 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // </editor-fold> - package de.olypedia; import de.olypedia.ImagingSetting.ImagingSettingException; @@ -44,56 +43,105 @@ import org.netbeans.microedition.lcdui.TableItem; /** + * This is the actual MIDlet for the DoF calculator + * * @author khb */ public class DofCalculator extends MIDlet implements CommandListener, ItemCommandListener, ImagingChangeListener, ItemStateListener { + /** The model responsible for managing changes to the underlying data */ private ImagingSettingModel _model; + /** A proxy managing persistent storage of preferences */ private RecordStoreHandler _store; + /** Marker for whether or not the midlet is paused */ private boolean midletPaused = false; + /** + * Reference to the main form. The thing here is, that we need to create + * new forms whenever the calculation target ChoiceGroup is changed, + * because we need to make the selected TextField uneditable. Due to a + * bug in MIDP, making it editable again throws an exception. Therefore, + * we completely recreate the form and all field every time a different + * target is selected. + * For that reason, we also keep references to the currently displayed + * fields here. + * + * @todo: maybe refactor this to always use getters from the DofFormFactory + * and add a switch to the getter for the main form to specify whether or + * not the form and fields should be recreated. + */ private Form form; + /** Reference to the currently used ChoiceGroup for the calculation target */ private ChoiceGroup choiceGroupCalculate; + /** Reference to the currently used TextField for focal length */ private TextField textFieldFocalLength; + /** Reference to the currently used TextField for aperture */ private TextField textFieldAperture; + /** Reference to the currently used TextField for subject distance */ private TextField textFieldDistance; + /** Reference to the currently used TextField for depth-of-field */ private TextField textFieldDepthOfField; + /** Reference to the currently used TableItem for the results */ private TableItem tableResult; + /** + * Reference to the currently used SimpleTableModel used by the + * TableItem above + */ private SimpleTableModel tableModelResult; + /** + * Form to return to from all Alerts or Lists which need to return to + * the main form. + * Other Displayables may open from well-defined locations as the + * preferences screen and return there directly. The Online help can + * be opened from anywhere and therefore needs its own return pointer + * to not interfere with the return path if called from e. g. the + * preferences UI. + */ private Displayable returnTo; + /** The Item to activate/select after returning, if any */ private Item returnToItem; + /** Form to return to when dismissing the online help */ private Displayable helpReturnTo; + /** The Item to activate/select after returning from the online help, if any */ private Item helpReturnToItem; + /** The List display for aperture values to chose from */ private List aperturesList; + /** The List display for circle of confusion values to chose from */ private List cocsList; + /** Reference to the preferences form */ private Form prefForm; + /** Reference to the TextField for coc preference */ private TextField textFieldPrefCoC; + /** Reference to the TextField for default calculation target preference */ private ChoiceGroup choiceGroupPrefDefCalcTarget; + /** Reference to the TextField for aperture stop scale preference */ private ChoiceGroup choiceGroupPrefStopScale; + /** The number of TextFields present on the main display */ private static final int NUM_TEXT_FIELDS = 4; + /** Valid choices for the coc list */ private static final String[][] CIRCLE_OF_CONFUSION_CHOICES = new String[][]{ {LocalizationSupport.getMessage("CHOICE_CIRCLE_OF_CONFUSION_FT_TRAD"), @@ -108,10 +156,13 @@ "0.00855"} }; + /** User wants a full-stop scale in the aperture list */ public static final int APERTURE_FULL_STOPS = 0; + /** User wants a one-half-stop scale in the aperture list */ public static final int APERTURE_HALF_STOPS = 1; + /** User wants a one-third-stop scale in the aperture list */ public static final int APERTURE_THRID_STOPS = 2; // standard hooks @@ -131,17 +182,23 @@ public void destroyApp(boolean unconditional) { } - // hooks as typically created by the visual midlet builder + // hooks as typically created by the Netbeans visual midlet builder public void startMIDlet() { Alert error = null; try { + // create a new record store + // this phyically creates a new record store on the mobile + // device or reads values from one if already present and it + // actually contains any values _store = new RecordStoreHandler(); + // try creating a model with preferences as read above _model = new ImagingSettingModel( _store.getDefaultCalculationTarget(), _store.getCircleOfConfusion(), 54, 3.5, 1000, 33); } catch (ImagingSettingException ie) { + // we could not create the model with the settings above error = new Alert(LocalizationSupport.getMessage( "EXCEPTION_IMAGING_SETTING_TITLE"), LocalizationSupport.getMessage( @@ -151,6 +208,8 @@ e.printStackTrace(); } + // if we could not create the model, that's prolly due to some + // weird setting in the preferences. Let's try a safe combination. if (_model == null) { try { _model = new ImagingSettingModel( @@ -158,6 +217,7 @@ ImagingSetting.DEFAULT_CIRCLE_OF_CONFUSION, 54, 3.5, 1000, 0); } catch (ImagingSettingException ex) { + // we should not ever get here ... I hope ex.printStackTrace(); } } @@ -220,7 +280,7 @@ switchDisplayable(null, DofFormFactory.getHelpScreen(this, displayable)); /* - * we've mad the exit command an item command on every item on the + * we've made the exit command an item command on every item on the * main form to be able to map "Calculate" to the first button * } else if (displayable == form) { @@ -229,15 +289,21 @@ }*/ } else if (displayable == prefForm) { if (command == DofFormFactory.getPrefOKCommandSingleton()) { + // pressing OK in the preferences form ... + + // this will refer to an error message, if we need one Alert error = null; + // if true later on, we will reset the data model to sane values boolean reset = false; + // first get the current values final double coc = Double.parseDouble( textFieldPrefCoC.getString()); int defCalcTarget = getCalculatedModelFromIndex( choiceGroupPrefDefCalcTarget.getSelectedIndex()); int stopScale = choiceGroupPrefStopScale.getSelectedIndex(); + // then try to write them to persistent storage try { _store.updateRecords(coc, defCalcTarget, stopScale); } catch (Exception ex) { @@ -252,6 +318,8 @@ }), null, AlertType.ERROR); } + + // then update the data model try { _model.setCircleOfConfusion(coc); } catch (ImagingSettingException ex) { @@ -266,6 +334,13 @@ } switchDisplayable(error, returnTo); + + // if setting the coc caused the data model to become fishy, + // we reset it to sane values. + // TODO: This is hoping that the new coc alone cannot be the + // problem. Maybe we want to react on a further exception + // and roll back the whole change ... maybe return the user + // the the preferences screen. if (reset) { getDisplay().callSerially(new Runnable() { public void run() { @@ -282,10 +357,14 @@ } } else if (command == DofFormFactory. getPrefCancelCommandSingleton()) { + // cancelling the preferences form ... + switchDisplayable(null, returnTo); } } else if (displayable == aperturesList && command == List.SELECT_COMMAND) { + // selecting a value in the apertures list ... + textFieldAperture.setString(aperturesList.getString(aperturesList. getSelectedIndex())); switchDisplayable(null, returnTo); @@ -296,6 +375,8 @@ }); } else if (displayable == cocsList && command == List.SELECT_COMMAND) { + // selecting a value in the list of cocs ... + int selected = cocsList.getSelectedIndex(); if (selected >= 0 && selected < CIRCLE_OF_CONFUSION_CHOICES.length) { textFieldPrefCoC.setString( @@ -309,6 +390,8 @@ }); } else if (command == DofFormFactory.getHelpOKCommandSingleton() && displayable == DofFormFactory.getHelpScreen()) { + // dismissing the online help ... + switchDisplayable(null, helpReturnTo); if (helpReturnToItem != null) { getDisplay().callSerially(new Runnable() { @@ -319,9 +402,13 @@ } } else if (command == DofFormFactory.getHelpNextCommandSingleton() && displayable == DofFormFactory.getHelpScreen()) { + // pressing next in the online help ... + switchDisplayable(null, DofFormFactory.nextHelpPage(this)); } else if (command == DofFormFactory.getHelpPrevCommandSingleton() && displayable == DofFormFactory.getHelpScreen()) { + // pressing previous in the online help ... + switchDisplayable(null, DofFormFactory.previousHelpPage(this)); } } @@ -336,39 +423,69 @@ public void commandAction(Command command, Item item) { if (command == DofFormFactory.getHelpCommandSingleton()) { + // selecting help on any Item ... + + // this is an item command because we want the Item to be able + // to be context sensitive + + // return to this Displayable helpReturnTo = getDisplay().getCurrent(); + // and this Item helpReturnToItem = item; switchDisplayable(null, DofFormFactory.getHelpScreen(this, item)); } else if (command == DofFormFactory.getExitCommandSingleton()) { + // exit the application ... + + // this is an item command so we can give preference for the + // command layout to the calculate command. If the exit command + // were a form command, it would typically get preference even + // before the highest priority (lowest number) item command. exitMIDlet(); } if (item == textFieldAperture) { if (command == DofFormFactory.getSelectApertureCommandSingleton()) { + // user decided to pick aperture from list ... + returnTo = getDisplay().getCurrent(); aperturesList = DofFormFactory.getApertureList(this); switchDisplayable(null, aperturesList); } } else if (item == choiceGroupCalculate) { if (command == DofFormFactory.getPreferencesCommandSingleton()) { + // opening the prefernces ui ... + + // the preferences can only be opened from the ChoiceGroup + // for the calculation target, at this time. + // TODO: revisit this. Maybe open the preferences from + // everywhere returnTo = getDisplay().getCurrent(); switchDisplayable(null, DofFormFactory.getPreferencesForm(this)); } } else if (item == textFieldPrefCoC) { if (command == DofFormFactory.getSelectCoCCommandSingleton()) { + // user wants to pick coc from list ... + cocsList = DofFormFactory.getCoCList(this); switchDisplayable(null, cocsList); } } if (command == DofFormFactory.getCalculateCommandSingleton()) { + // calculating ... + + // get current values first double fl = Double.parseDouble(textFieldFocalLength.getString()); double a = Double.parseDouble(textFieldAperture.getString()); double g = Double.parseDouble(textFieldDistance.getString()); double dof = Double.parseDouble(textFieldDepthOfField.getString()); try { + // update data model + // note that the data model comes back at the UI through + // the ImagingChangeListener and the imagingSettingChanged + // callback to return the results. _model.updateState(fl, a, g, dof); } catch (ImagingSetting.FocalLengthTooSmallException e) { Alert msg = DofFormFactory.getFocalLengthRangeWarning(); @@ -389,15 +506,28 @@ getDisplay().setCurrentItem(item); } catch (ImagingSetting.ImagingSettingException e) { } + // when an input field is edited, the ChoiceGroup for the + // calculation target is replace by a StringItem to display + // the currently selected target in a non-editable fashion. + // Here we add the ChoiceGroup back. form.delete(0); form.insert(0, choiceGroupCalculate); } } // ItemStateListener + /** + * Called by a system to indicated that an Item has changed. + * @param item the Item that changed. + */ public void itemStateChanged(Item item) { if (item == choiceGroupCalculate) { + // changing the calculation target ... + // first we need to push potentially changed values to the model + // TODO: keeping this in as a reminder in case we put back + // automatic, immediate calculation again, later. + // double fl = Double.parseDouble(textFieldFocalLength.getString()); // double a = Double.parseDouble(textFieldAperture.getString()); // double g = Double.parseDouble(textFieldDistance.getString()); @@ -435,6 +565,10 @@ int selected = choiceGroupCalculate.getSelectedIndex(); switch (selected) { + // TODO: clean this up. The switch and the integer literals + // are only here for the different kind of error handling + // the various alternatives require. This could be done + // differently. case 0: try { _model.setFieldToCalculate(getCalculatedModelFromIndex( @@ -498,13 +632,22 @@ } } else if (item == textFieldFocalLength || item == textFieldAperture || item == textFieldDistance || item == textFieldDepthOfField) { + // editing any of the text input fields in the main form ... + + // replace the ChoiceGroup for the calculation target with a + // non-editable StringItem to display the currently selected target. form.delete(0); form.insert(0, DofFormFactory.getChoiceGroupUneditable( choiceGroupCalculate)); } } - // convert between choiceGroup display and model values + /** + * Sets the ChoiceGroup for the calculation target to the right selected + * value given a target in the data model's terminology. + * @param fieldToCalculate an integer constant + * from ImagingSettingMode.CALCULATE* + */ private void setCalculatedIndexFromModel(int fieldToCalculate) { int select = getCalculatedIndexFromModel(fieldToCalculate); for (int i = 0; i < NUM_TEXT_FIELDS; i++) { @@ -516,7 +659,13 @@ } } - // convert between choiceGroup display and model values + /** + * Converts between selection indexes of the ChoiceGroup for the + * calculation target and targets in the data model's terminology. + * @param fieldToCalculate an integer constant + * from ImagingSettingModel.CALCULATE* + * @return the ChoiceGroup selection that matches the model value. + */ private int getCalculatedIndexFromModel(int fieldToCalculate) { switch (fieldToCalculate) { case ImagingSettingModel.CALCULATE_FOCAL_LENGTH: @@ -531,6 +680,12 @@ } } + /** + * Converts between selection indexes of the ChoiceGroup for the + * calculation target and targets in the data model's terminology. + * @param selected the selection index of the ChoiceGroup + * @return the model value, one of ImagingSettingModel.CALCULATE* + */ private int getCalculatedModelFromIndex(int selected) { switch (selected) { case 0: @@ -545,6 +700,12 @@ } } + /** + * Updates a given TextField, only if the new value is different from the + * current one. + * @param f the field to update + * @param val the new value + */ private void updateTextFieldIfDifferent(TextField f, String val) { if (!f.getString().equals(val)) { @@ -553,12 +714,26 @@ } // ImagingChangeListener + /** + * This is a callback for the model to trigger once it has done it's + * job on an update. The UI can now set its state accordingly. + * @param oldSetting the model before the change + * @param newSetting the new model + */ public void changedImagingSetting(ImagingSettingModel oldSetting, ImagingSettingModel newSetting) { if (oldSetting.getFieldToCalculate() != newSetting.getFieldToCalculate()) { + // the calculation target has changed + // we need a different form (because of the uneditable TextField + // issue) form = DofFormFactory.getForm(this); switchDisplayable(null, form); } else { + // we just did a calculation + // update the TextFields, but only if the values have actually + // changed so as to not trigger a spurious ItemChanged event. + // This is prolly no longer so important since we don't do + // automatic, immediate calculation. updateTextFieldIfDifferent(textFieldFocalLength, _model. getFocalLengthAsString()); updateTextFieldIfDifferent(textFieldAperture, _model. @@ -568,6 +743,7 @@ updateTextFieldIfDifferent(textFieldDepthOfField, _model. getDepthOfFieldAsString()); + // update the results table int n = _model.getNearEdge(); if (n == 0) { tableModelResult.setValue(1, 0, LocalizationSupport.getMessage( @@ -588,22 +764,27 @@ } // form generation + // OK, this is not a real factory implementation, just meant to + // group ui component creation a bit private static class DofFormFactory { + // aperture values by full-stop scale private static final double[] fullStopScale = new double[]{ 1.0, 1.4, 2, 2.8, 4, 5.6, 8, 11, 16, 22 }; + // aperture values by one-half-stop scale private static final double[] oneHalfStopScale = new double[]{ 1.0, 1.2, 1.4, 1.7, 2, 2.4, 2.8, 3.3, 4, 4.8, 5.6, 6.7, 8, 9.5, 11, 13, 16, 19, 22 }; + // aperture values by one-third-stop scale private static final double[] oneThirdStopScale = new double[]{ 1.0, 1.1, 1.2, 1.4, 1.6, 1.8, 2, 2.2, 2.5, 2.8, 3.2, 3.6, 4, 4.5, 5.0, 5.6, 6.3, 7.1, 8, 9, 10, 11, 13, 14, 16, 18, 20, 22 }; - // singleton access + // ui components for singleton access private static Alert apertureMinWarning; private static Alert apertureMaxWarning; @@ -638,23 +819,20 @@ private static Command helpPrevCommand; + // main form first + /** + * Retrieves a ChoiceGroup for calculation target selection. This + * does not follow the singleton pattern, i. e. it creates a new + * Item every time. + * @param app the midlet + * @return the ChoiceGroup Item + */ private static ChoiceGroup getChoiceGroup(DofCalculator app) { - int selected; - switch (app._model.getFieldToCalculate()) { - case ImagingSettingModel.CALCULATE_FOCAL_LENGTH: - selected = 0; - break; - case ImagingSettingModel.CALCULATE_APERTURE: - selected = 1; - break; - case ImagingSettingModel.CALCULATE_DISTANCE: - selected = 2; - break; - case ImagingSettingModel.CALCULATE_DEPTH_OF_FIELD: - default: - selected = 3; - } + // get the choice to select from the data model + int selected = app.getCalculatedIndexFromModel(app._model. + getFieldToCalculate()); + // build the choice group ChoiceGroup choiceGroup = new ChoiceGroup(LocalizationSupport. getMessage("CHOICE_TARGET_TITLE"), Choice.POPUP); choiceGroup.append(LocalizationSupport.getMessage( @@ -671,16 +849,27 @@ (i == selected ? true : false)); } + // add commands choiceGroup.addCommand(getHelpCommandSingleton()); choiceGroup.addCommand(getPreferencesCommandSingleton()); choiceGroup.addCommand(getExitCommandSingleton()); choiceGroup.setItemCommandListener(app); + return choiceGroup; } + /** + * Retrieves a TextField for focal length input. This + * does not follow the singleton pattern, i. e. it creates a new + * Item every time. + * @param app the midlet + * @return the TextField Item + */ private static TextField getTextFieldFocalLength(DofCalculator app) { + // build the TextField String label = LocalizationSupport.getMessage("LBL_TF_FOCAL_LENGTH"); TextField textField; + // it might need to be uneditable if (app._model.getFieldToCalculate() == ImagingSettingModel.CALCULATE_FOCAL_LENGTH) { textField = new TextField(label, null, 32, TextField.NUMERIC | @@ -691,6 +880,7 @@ textField.setString(app._model.getFocalLengthAsString()); textField.setLayout(ImageItem.LAYOUT_RIGHT | Item.LAYOUT_EXPAND); + // add commands textField.addCommand(getCalculateCommandSingleton()); textField.addCommand(getHelpCommandSingleton()); textField.addCommand(getExitCommandSingleton()); @@ -699,21 +889,32 @@ return textField; } + /** + * Retrieves a TextField for aperture input. This + * does not follow the singleton pattern, i. e. it creates a new + * Item every time. + * @param app the midlet + * @return the TextField Item + */ private static TextField getTextFieldAperture(DofCalculator app) { + // build the TextField String label = LocalizationSupport.getMessage("LBL_TF_APERTURE"); TextField textField; + // it might need to be uneditable if (app._model.getFieldToCalculate() == ImagingSettingModel.CALCULATE_APERTURE) { textField = new TextField(label, null, 32, TextField.DECIMAL | TextField.UNEDITABLE); } else { textField = new TextField(label, null, 32, TextField.DECIMAL); + // if it is editable, we add the aperture selection command textField.addCommand(getSelectApertureCommandSingleton()); textField.setItemCommandListener(app); } textField.setString(app._model.getApertureAsString()); textField.setLayout(ImageItem.LAYOUT_RIGHT | Item.LAYOUT_EXPAND); + // add other commands textField.addCommand(getCalculateCommandSingleton()); textField.addCommand(getHelpCommandSingleton()); textField.addCommand(getExitCommandSingleton()); @@ -722,9 +923,18 @@ return textField; } + /** + * Retrieves a TextField for distance input. This + * does not follow the singleton pattern, i. e. it creates a new + * Item every time. + * @param app the midlet + * @return the TextField Item + */ private static TextField getTextFieldDistance(DofCalculator app) { + // build the TextField String label = LocalizationSupport.getMessage("LBL_TF_DISTANCE"); TextField textField; + // it might need to be uneditable if (app._model.getFieldToCalculate() == ImagingSettingModel.CALCULATE_DISTANCE) { textField = new TextField(label, null, 32, TextField.NUMERIC | @@ -735,6 +945,7 @@ textField.setString(app._model.getDistanceAsString()); textField.setLayout(ImageItem.LAYOUT_RIGHT | Item.LAYOUT_EXPAND); + // add commands textField.addCommand(getCalculateCommandSingleton()); textField.addCommand(getHelpCommandSingleton()); textField.addCommand(getExitCommandSingleton()); @@ -743,9 +954,18 @@ return textField; } + /** + * Retrieves a TextField for depth-of-field input. This + * does not follow the singleton pattern, i. e. it creates a new + * Item every time. + * @param app the midlet + * @return the TextField Item + */ private static TextField getTextFieldDepthOfField(DofCalculator app) { + // build the TextField String label = LocalizationSupport.getMessage("LBL_TF_DOF"); TextField textField; + // it might need to be uneditable if (app._model.getFieldToCalculate() == ImagingSettingModel.CALCULATE_DEPTH_OF_FIELD) { textField = new TextField(label, null, 32, TextField.NUMERIC | @@ -756,6 +976,7 @@ textField.setString(app._model.getDepthOfFieldAsString()); textField.setLayout(ImageItem.LAYOUT_RIGHT | Item.LAYOUT_EXPAND); + // add commands textField.addCommand(getCalculateCommandSingleton()); textField.addCommand(getHelpCommandSingleton()); textField.addCommand(getExitCommandSingleton()); @@ -764,7 +985,15 @@ return textField; } + /** + * Retrieves a TableItem to display the results in. This + * does not follow the singleton pattern, i. e. it creates a new + * Item every time. + * @param app the midlet + * @return the TableItem Item + */ private static TableItem getResultsTable(DofCalculator app) { + // first construct the table model app.tableModelResult = new SimpleTableModel( new java.lang.String[][]{ @@ -775,19 +1004,31 @@ "LBL_ROW_DOF_FAR"), app._model.getFarEdgeAsString()}}, null); + // build the TableItem TableItem tableItem = new TableItem(app.getDisplay(), LocalizationSupport.getMessage("LBL_TABLE_RESULT")); tableItem.setLayout(ImageItem.LAYOUT_DEFAULT | Item.LAYOUT_EXPAND); + // set the model tableItem.setModel(app.tableModelResult); + // add commands tableItem.addCommand(getHelpCommandSingleton()); tableItem.addCommand(getExitCommandSingleton()); tableItem.setItemCommandListener(app); + return tableItem; } + /** + * Retrieves a List Displayable with a list of aperture values. This + * does not follow the singleton pattern, i. e. it creates a new + * Item every time. + * @param app the midlet + * @return the List Displayable + */ private static List getApertureList(DofCalculator app) { double[] apertureOptions; + // which stop scale do we want? switch (app._store.getStopScale()) { case APERTURE_FULL_STOPS: apertureOptions = fullStopScale; @@ -800,26 +1041,42 @@ apertureOptions = oneThirdStopScale; } + // build the List List apertures = new List(LocalizationSupport.getMessage( "LIST_TITLE_APERTURES"), Choice.IMPLICIT); + // get the current value to select the closest match in the List double currentApertureVal = Double.parseDouble( app.textFieldAperture.getString()); boolean setSelected = false; for (int i = 0; i < apertureOptions.length; i++) { + // add aperture value apertures.append(Double.toString(apertureOptions[i]), null); if (apertureOptions[i] >= currentApertureVal && !setSelected) { + // if the current candidate matches the currently selected + // aperture or the candidate is larger than the currently + // selected aperture and none has yet been selected (i. e. + // the first larger value), we select it. + // if neither of the two ever matches, the list may be + // left to auto-select the first item setSelected = true; apertures.setSelectedIndex(i, true); } else { apertures.setSelectedIndex(i, false); } } + + // add commands (select is implicit) apertures.addCommand(getHelpCommandSingleton()); apertures.setCommandListener(app); + return apertures; } + /** + * Singleton accessor for the \"Calculate\" command + * @return the Command + */ public static Command getCalculateCommandSingleton() { if (calculateCommand == null) { calculateCommand = new Command(LocalizationSupport.getMessage( @@ -829,6 +1086,10 @@ } + /** + * Singleton accessor for the \"Help\" command + * @return the Command + */ public static Command getHelpCommandSingleton() { if (helpCommand == null) { helpCommand = new Command(LocalizationSupport.getMessage( @@ -837,6 +1098,10 @@ return helpCommand; } + /** + * Singleton accessor for the \"Preferences\" command + * @return the Command + */ public static Command getPreferencesCommandSingleton() { if (preferencesCommand == null) { preferencesCommand = new Command(LocalizationSupport.getMessage( @@ -845,6 +1110,10 @@ return preferencesCommand; } + /** + * Singleton accessor for the \"Select\" command for aperture values + * @return the Command + */ public static Command getSelectApertureCommandSingleton() { if (selectApertureCommand == null) { selectApertureCommand = new Command(LocalizationSupport. @@ -854,6 +1123,10 @@ return selectApertureCommand; } + /** + * Singleton accessor for the \"Exit\" command + * @return the Command + */ public static Command getExitCommandSingleton() { if (exitCommand == null) { exitCommand = new Command(LocalizationSupport.getMessage( @@ -862,13 +1135,27 @@ return exitCommand; } + /** + * Creates an uneditable StringItem to replace the ChoiceGroup for + * calculation target selection. This does not follow the singleton + * pattern and creates a new StringItem every time. + * @param g the ChoiceGroup to replace + * @return the StringItem + */ public static Item getChoiceGroupUneditable(ChoiceGroup g) { return new StringItem(LocalizationSupport.getMessage( - "CHOICE_TARGET_TITLE"), g.getString(g. - getSelectedIndex())); + "CHOICE_TARGET_TITLE"), g.getString(g.getSelectedIndex())); } + /** + * Retrieves a form to display as the main form. This does not follow + * the singleton pattern and creates a new one every time. + * @param app + * @return + */ public static Form getForm(DofCalculator app) { + // first create the individual components and update the + // references in the midlet app.choiceGroupCalculate = getChoiceGroup(app); app.textFieldFocalLength = getTextFieldFocalLength(app); app.textFieldAperture = getTextFieldAperture(app); @@ -876,6 +1163,7 @@ app.textFieldDepthOfField = getTextFieldDepthOfField(app); app.tableResult = getResultsTable(app); + // then create the form itself app.form = new Form( LocalizationSupport.getMessage("FORM_MAIN_TITLE"), new Item[]{ @@ -886,6 +1174,7 @@ app.textFieldDepthOfField, app.tableResult}); + // add commands and wire the listeners // app.form.addCommand(getExitCommandSingleton()); app.form.setCommandListener(app); app.form.setItemStateListener(app); @@ -896,7 +1185,15 @@ /* * preferences stuff */ + /** + * Retrieves a TextField for input of the circle-of-confusion + * preference. This does not follow the singleton pattern, i. e. + * it creates a new Item every time. + * @param app the midlet + * @return the TextField Item + */ private static TextField getTextFieldCoCPref(DofCalculator app) { + // build the Item String label = LocalizationSupport.getMessage("LBL_TF_PREF_COC"); TextField textField = new TextField(label, null, 32, TextField.DECIMAL); @@ -904,6 +1201,7 @@ app._store.getCircleOfConfusion())); textField.setLayout(ImageItem.LAYOUT_RIGHT | Item.LAYOUT_EXPAND); + // add commands textField.addCommand(getSelectCoCCommandSingleton()); textField.addCommand(getHelpCommandSingleton()); textField.setItemCommandListener(app); @@ -911,24 +1209,20 @@ return textField; } + /** + * Retrieves a ChoiceGroup for default calculation target selection. + * This does not follow the singleton pattern, i. e. it creates a new + * Item every time. + * @param app the midlet + * @return the ChoiceGroup Item + */ private static ChoiceGroup getChoiceGroupDefCalcTargetPref( DofCalculator app) { - int selected; - switch (app._store.getDefaultCalculationTarget()) { - case ImagingSettingModel.CALCULATE_FOCAL_LENGTH: - selected = 0; - break; - case ImagingSettingModel.CALCULATE_APERTURE: - selected = 1; - break; - case ImagingSettingModel.CALCULATE_DISTANCE: - selected = 2; - break; - case ImagingSettingModel.CALCULATE_DEPTH_OF_FIELD: - default: - selected = 3; - } + // select the current default choice + int selected = app.getCalculatedIndexFromModel(app._store. + getDefaultCalculationTarget()); + // build the Item ChoiceGroup choiceGroup = new ChoiceGroup(LocalizationSupport. getMessage("CHOICE_DEF_TARGET_TITLE"), Choice.POPUP); choiceGroup.append(LocalizationSupport.getMessage( @@ -944,17 +1238,28 @@ choiceGroup.setSelectedIndex(i, (i == selected ? true : false)); } + + // add commands choiceGroup.addCommand(getHelpCommandSingleton()); choiceGroup.setItemCommandListener(app); + return choiceGroup; } + /** + * Retrieves a ChoiceGroup for stop scale preference selection. This + * does not follow the singleton pattern, i. e. it creates a new + * Item every time. + * @param app the midlet + * @return the ChoiceGroup Item + */ private static ChoiceGroup getChoiceGroupStopScale( DofCalculator app) { - // the following correlates the choicegroup layout (order) and - // the values for the constants! + // FIXME: the following correlates the choicegroup layout (order) + // and the values for the constants, they must be the same! int selected = app._store.getStopScale(); + // build the Item ChoiceGroup choiceGroup = new ChoiceGroup(LocalizationSupport.getMessage( "CHOICE_STOP_SCALE_TITLE"), Choice.POPUP); @@ -969,11 +1274,18 @@ choiceGroup.setSelectedIndex(i, (i == selected ? true : false)); } + + // add commands choiceGroup.addCommand(getHelpCommandSingleton()); choiceGroup.setItemCommandListener(app); + return choiceGroup; } + /** + * Singleton accessor for the \"OK\" command for the preferences form + * @return the Command + */ public static Command getPrefOKCommandSingleton() { if (prefOKCommand == null) { prefOKCommand = new Command(LocalizationSupport.getMessage( @@ -982,6 +1294,11 @@ return prefOKCommand; } + /** + * Singleton accessor for the \"Cancel\" command for the preferences + * form + * @return the Command + */ public static Command getPrefCancelCommandSingleton() { if (prefCancelCommand == null) { prefCancelCommand = new Command(LocalizationSupport.getMessage( @@ -990,7 +1307,15 @@ return prefCancelCommand; } + /** + * Retrieves a List Displayable with sample circle of confusion presets. + * This does not follow the singleton pattern, i. e. it creates a new + * Item every time. + * @param l the midlet + * @return the List Displayable + */ private static List getCoCList(CommandListener l) { + // build the list List cocs = new List(LocalizationSupport.getMessage("LIST_TITLE_COC"), Choice.IMPLICIT); @@ -998,11 +1323,19 @@ cocs.append(CIRCLE_OF_CONFUSION_CHOICES[i][0], null); cocs.setSelectedIndex(i, false); } + + // add commands cocs.addCommand(getHelpCommandSingleton()); cocs.setCommandListener(l); + return cocs; } + /** + * Singleton accessor for the \"Select\" command for the circle of + * confusion in the preferences form + * @return the Command + */ public static Command getSelectCoCCommandSingleton() { if (selectCoCCommand == null) { selectCoCCommand = new Command(LocalizationSupport.getMessage( @@ -1012,12 +1345,20 @@ return selectCoCCommand; } + /** + * Retrieves a form to display as the preferences form. This does not + * follow the singleton pattern and creates a new one every time. + * @param app + * @return + */ public static Form getPreferencesForm(DofCalculator app) { + // first create the fields and update the references in the midlet app.textFieldPrefCoC = getTextFieldCoCPref(app); app.choiceGroupPrefDefCalcTarget = getChoiceGroupDefCalcTargetPref( app); app.choiceGroupPrefStopScale = getChoiceGroupStopScale(app); + // build the form app.prefForm = new Form(LocalizationSupport.getMessage( "FORM_PREFS_TITLE"), new Item[]{ app.textFieldPrefCoC, @@ -1025,6 +1366,7 @@ app.choiceGroupPrefStopScale }); + // add commands app.prefForm.addCommand(getPrefOKCommandSingleton()); app.prefForm.addCommand(getPrefCancelCommandSingleton()); app.prefForm.setCommandListener(app); @@ -1035,6 +1377,7 @@ /* * help */ + /** The help texts in sections with titles */ private static String[][] helpTexts = new String[][]{ {LocalizationSupport.getMessage("HELP_TEXT_OVERVIEW_TITLE"), LocalizationSupport.getMessage("HELP_TEXT_OVERVIEW_TXT")}, @@ -1044,6 +1387,15 @@ LocalizationSupport.getMessage("HELP_TEXT_PREFS_TXT")} }; + /** + * Maps an arbitrary object to a help section to display. This is + * used to implement the context sensitivity of the online help. + * It is typically passed an Item or a Displayable off which the + * help command is executed. + * @param app the midlet + * @param helpAbout the object for which help is requsted + * @return an index into the helpTexts array to the right help section + */ private static int getHelpPageForObject(DofCalculator app, Object helpAbout) { if (helpAbout == app.textFieldPrefCoC || @@ -1058,6 +1410,10 @@ } } + /** + * Singleton accessor for the \"OK\" command in the online help. + * @return the Command + */ public static Command getHelpOKCommandSingleton() { if (helpOKCommand == null) { helpOKCommand = new Command(LocalizationSupport.getMessage( @@ -1066,6 +1422,10 @@ return helpOKCommand; } + /** + * Singleton accessor for the \"Next\" command in the online help. + * @return the Command + */ public static Command getHelpNextCommandSingleton() { if (helpNextCommand == null) { helpNextCommand = new Command(LocalizationSupport.getMessage( @@ -1074,6 +1434,10 @@ return helpNextCommand; } + /** + * Singleton accessor for the \"Previous\" command in the online help. + * @return the Command + */ public static Command getHelpPrevCommandSingleton() { if (helpPrevCommand == null) { helpPrevCommand = new Command(LocalizationSupport.getMessage( @@ -1082,31 +1446,52 @@ return helpPrevCommand; } + /** + * Accessor to the help screen that does not trigger a change, + * just retrieves the current screen. + * @return the Command + */ public static Displayable getHelpScreen() { return helpScreen; } + /** + * Accessor to the help screen for a given object. This creates a + * new help screen for every call. + * @param app the midlet + * @param helpAbout the object for which help is requested + * @return the help screen + */ public static Displayable getHelpScreen(DofCalculator app, Object helpAbout) { + // find the section to display currentHelpPage = getHelpPageForObject(app, helpAbout); + // rebuild the help screen refreshHelpPage(app); return helpScreen; } private static Displayable nextHelpPage(DofCalculator app) { + // increment the section to display currentHelpPage++; + // rebuild the help screen refreshHelpPage(app); + return helpScreen; } private static Displayable previousHelpPage(DofCalculator app) { + // decrement the section to display currentHelpPage--; + // rebuild the help screen refreshHelpPage(app); + return helpScreen; } private static void refreshHelpPage(DofCalculator app) { + // build a new form helpScreen = new Form( LocalizationSupport.getMessage("FORM_HELP_TITLE", new String[]{ @@ -1116,11 +1501,14 @@ new StringItem(null, helpTexts[currentHelpPage][1]) }); + // add OK command helpScreen.addCommand(getHelpOKCommandSingleton()); helpScreen.setCommandListener(app); + // remove next/prev commands helpScreen.removeCommand(getHelpNextCommandSingleton()); helpScreen.removeCommand(getHelpPrevCommandSingleton()); + // add next/prev command if applicable if (currentHelpPage > 0) { helpScreen.addCommand(getHelpPrevCommandSingleton()); } @@ -1133,6 +1521,10 @@ /* * warnings */ + /** + * Singleton accessor for the warning about too small an aperture + * @return the Alert + */ public static Alert getApertureMinWarning() { if (apertureMinWarning == null) { apertureMinWarning = new Alert(LocalizationSupport.getMessage( @@ -1144,6 +1536,10 @@ return apertureMinWarning; } + /** + * Singleton accessor for the warning about too large an aperture + * @return the Alert + */ public static Alert getApertureMaxWarning() { if (apertureMaxWarning == null) { apertureMaxWarning = new Alert(LocalizationSupport.getMessage( @@ -1155,6 +1551,10 @@ return apertureMaxWarning; } + /** + * Singleton accessor for the warning about an invalid focal length + * @return the Alert + */ public static Alert getFocalLengthRangeWarning() { if (focalLengthWarning == null) { focalLengthWarning = new Alert(LocalizationSupport.getMessage( @@ -1166,6 +1566,10 @@ return focalLengthWarning; } + /** + * Singleton accessor for the warning about unachievable infinite dof + * @return the Alert + */ public static Alert getInfinityWarning() { if (infinityWarning == null) { infinityWarning = new Alert(LocalizationSupport.getMessage( Modified: trunk/src/de/olypedia/ImagingChangeListener.java =================================================================== --- trunk/src/de/olypedia/ImagingChangeListener.java 2009-09-30 08:51:34 UTC (rev 8) +++ trunk/src/de/olypedia/ImagingChangeListener.java 2009-10-01 15:12:18 UTC (rev 9) @@ -18,14 +18,22 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // </editor-fold> - package de.olypedia; /** + * An interface that must be implemented to listen for changes on the + * ImagingSettingModel * * @author khb */ public interface ImagingChangeListener { + /** + * Is called from the ImagingSettingModel for each listener in the order + * it was registered + * + * @param oldSetting a copy of the model prior to the change + * @param newSetting a reference to the current model after the change + */ void changedImagingSetting(ImagingSettingModel oldSetting, ImagingSettingModel newSetting); } Modified: trunk/src/de/olypedia/ImagingSetting.java =================================================================== --- trunk/src/de/olypedia/ImagingSetting.java 2009-09-30 08:51:34 UTC (rev 8) +++ trunk/src/de/olypedia/ImagingSetting.java 2009-10-01 15:12:18 UTC (rev 9) @@ -18,42 +18,64 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // </editor-fold> - package de.olypedia; import akme.mobile.util.NumberUtil; /** + * This is the object that implements the features of an imaging situation. + * It does all the mathematics and is used by the model to store the current + * state. The class is implemented as an immutable class. * * @author khb */ public class ImagingSetting { + // the state fields + /** focal length */ private double _focalLength; + /** aperture */ private double _aperture; + /** subject distance */ private double _distance; + /** dof near limit */ private double _nearEdge; + /** dof far limit */ private double _farEdge; + /** circle of confusion */ private final double _circleOfConfusion; + /** maximum valid aperture value */ public static final int MAX_APERTURE = 30; + /** minimum valid aperture value */ public static final int MIN_APERTURE = 1; + /** minimum focal length */ public static final int MIN_FOCAL_LENGTH = 1; + /** default circle of confusion */ public static final double DEFAULT_CIRCLE_OF_CONFUSION = .0147; + // // private constructors // this class is practically immutable + // + /** + * default constructor + */ private ImagingSetting() { _circleOfConfusion = DEFAULT_CIRCLE_OF_CONFUSION; } + /** + * constructor setting a non-standard circle of confusion + * @param circleOfConfusion the circle of confusion to use + */ private ImagingSetting(double circleOfConfusion) { if (circleOfConfusion <= 0 || Double.isInfinite(circleOfConfusion)) { _circleOfConfusion = DEFAULT_CIRCLE_OF_CONFUSION; @@ -62,7 +84,17 @@ } } + // // factory methods + // + /** + * Calculates the depth of field from the other values and a default + * circle of confusion. + * @param focalLength focal length + * @param aperture aperture + * @param distance subject distance + * @return a new ImagingSetting with the dof set + */ public static ImagingSetting calculateDepthOfField(double focalLength, double aperture, double distance) { @@ -70,6 +102,15 @@ aperture, distance); } + /** + * Calculates the depth of field from the other values and a non-standard + * circle of confusion. + * @param circleOfConfusion circle of confusion to use + * @param focalLength focal length + * @param aperture aperture + * @param distance subject distance + * @return a new ImagingSetting with the dof set + */ public static ImagingSetting calculateDepthOfField(double circleOfConfusion, double focalLength, double aperture, @@ -79,12 +120,21 @@ rv._aperture = aperture; rv._distance = distance; + // the dof is implicit in the following rv._nearEdge = rv.doNearEdge(); rv._farEdge = rv.doFarEdge(); return rv; } + /** + * Calculates the subject distance from the other values and a default + * circle of confusion. + * @param focalLength focal length + * @param aperture aperture + * @param dof depth-of-field + * @return a new ImagingSetting with the distance set + */ public static ImagingSetting calculateDistance(double focalLength, double aperture, double dof) { @@ -92,6 +142,15 @@ aperture, dof); } + /** + * Calculates the subject distance from the other values and a non-standard + * circle of confusion. + * @param circleOfConfusion the circle of confusion to use + * @param focalLength focal length + * @param aperture aperture + * @param dof depth-of-field + * @return a new ImagingSetting with the distance set + */ public static ImagingSetting calculateDistance(double circleOfConfusion, double focalLength, double aperture, @@ -100,13 +159,25 @@ rv._focalLength = focalLength; rv._aperture = aperture; + // do the math rv.doDistance(dof); + + // the actual dof achieved is implicit in the following rv._nearEdge = rv.doNearEdge(); rv._farEdge = rv.doFarEdge(); return rv; } + /** + * Calculates the aperture from the other values and a default + * circle of confusion. + * @param focalLength focal length + * @param distance subject distance + * @param dof depth-of-field + * @return a new ImagingSetting with the aperture set + * @throws de.olypedia.ImagingSetting.ImagingSettingException + */ public static ImagingSetting calculateAperture(double focalLength, double distance, double dof) @@ -115,6 +186,16 @@ distance, dof); } + /** + * Calculates the aperture from the other values and a non-standard + * circle of confusion. + * @param circleOfConfusion the circle of confusion to use + * @param focalLength focal length + * @param distance subject distance + * @param dof depth-of-field + * @return a new ImagingSetting with the aperture set + * @throws de.olypedia.ImagingSetting.ImagingSettingException + */ public static ImagingSetting calculateAperture(double circleOfConfusion, double focalLength, double distance, @@ -124,13 +205,25 @@ rv._focalLength = focalLength; rv._distance = distance; + // do the math rv.doAperture(dof); + + // the actual dof achieved is implicit in the following rv._nearEdge = rv.doNearEdge(); rv._farEdge = rv.doFarEdge(); return rv; } + /** + * Calculates the focal length from the other values and a default + * circle of confusion. + * @param aperture aperture + * @param distance subject distance + * @param dof depth-of-field + * @return a new ImagingSetting with the focal length set + * @throws de.olypedia.ImagingSetting.ImagingSettingException + */ public static ImagingSetting calculateFocalLength(double aperture, double distance, double dof) @@ -139,6 +232,16 @@ distance, dof); } + /** + * Calculates the focal length from the other values and a non-standard + * circle of confusion. + * @param circleOfConfusion circle of confusion to use + * @param aperture aperture + * @param distance subject distance + * @param dof depth-of-field + * @return a new ImagingSetting with the focal length set + * @throws de.olypedia.ImagingSetting.ImagingSettingException + */ public static ImagingSetting calculateFocalLength(double circleOfConfusion, double aperture, double distance, @@ -148,38 +251,59 @@ rv._aperture = aperture; rv._distance = distance; + // do the math rv.doFocalLength(dof); + + // the actual dof achieved is implicit in the following rv._nearEdge = rv.doNearEdge(); rv._farEdge = rv.doFarEdge(); return rv; } + // // the real math + // + /** + * Calculates the current dof's near limit + * @return the distance to the near limit + */ private double doNearEdge() { return (_focalLength * _focalLength * _distance) / ((_focalLength * _focalLength) + (_aperture * _circleOfConfusion * (_distance - _focalLength))); } + /** + * Calculates the current dof's far limit + * @return the distance to the far limit + */ private double doFarEdge() { double f = (_focalLength * _focalLength * _distance) / ((_focalLength * _focalLength) - (_aperture * _circleOfConfusion * (_distance - _focalLength))); // make sure we have infinity when we want it - if (f < 0) { + if (f < 0 || Double.isNaN(f)) { f = Double.POSITIVE_INFINITY; } + return f; } + /** + * Calculates the focal length from a specified depth of field and the + * other input values as currently set in the instance. + * @param dof a depth of field. 0 for an infinite dof. + * @throws de.olypedia.ImagingSetting.ImagingSettingException + */ private void doFocalLength(double dof) throws ImagingSettingException { double orig = _focalLength; double a = _aperture; double g = _distance; - if (dof != 0) { + // if requested dof < infinity + if (!Double.isInfinite(dof) && !Double.isNaN(dof) && dof > 0) { // reduce times to calculate some stuff double gTo2 = g * g; double cocTo2 = _circleOfConfusion * _circleOfConfusion; @@ -193,17 +317,28 @@ _circleOfConfusion) / (2.0 * Math.sqrt(dofTo2 + gTo2) - 2.0 * g); + // if the resulting focal length is out of range, throw so the + // model can react if (_focalLength < MIN_FOCAL_LENGTH) { _focalLength = orig; throw new FocalLengthTooSmallException(); } } // if we want infinite dof, we chose the smallest focal length + // TODO: is that a sensible approach? Or do we approach the right + // value from the far end... [truncated message content] |
From: <cha...@us...> - 2009-09-30 08:51:42
|
Revision: 8 http://dofcalc.svn.sourceforge.net/dofcalc/?rev=8&view=rev Author: charly4711 Date: 2009-09-30 08:51:34 +0000 (Wed, 30 Sep 2009) Log Message: ----------- fix for bug #2870548 Modified Paths: -------------- trunk/src/de/olypedia/resources/i18n/messages.properties trunk/src/de/olypedia/resources/i18n/messages_de.properties Modified: trunk/src/de/olypedia/resources/i18n/messages.properties =================================================================== --- trunk/src/de/olypedia/resources/i18n/messages.properties 2009-09-29 20:05:51 UTC (rev 7) +++ trunk/src/de/olypedia/resources/i18n/messages.properties 2009-09-30 08:51:34 UTC (rev 8) @@ -96,7 +96,7 @@ HELP_TEXT_OVERVIEW_TITLE=Overview HELP_TEXT_OVERVIEW_TXT=The Depth-of-Field (DoF) calculator is a small photographer's utility to help him find what depth of field given settings for focal length, aperture, distance will yield. Contrary to other available tools this DoF calculator supports a wide variety of mobile devices and also allows the photographer to determine other targets for the calculation. So, for example, in a situation where the desired depth of field is known you can use the calculator to determine what other settings will be needed to achieve it.\n\nThe DoF calculator 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. HELP_TEXT_OPERATION_TITLE=Principles of Operation -HELP_TEXT_OPERATION_TXT=In the main interface of the calculator, you first select the parameter you want calculated in the drop-down box at the top of the screen. Below that drop-down box are four input controls used to enter the parameters for the calculation. The target parameter of the calculation selected above will become uneditable. Enter the values in the other fields as desired and execute the \"Calculate\" command. As a result, you will find a value in the (uneditable) field for the target parameter and the near and far limit of the depth of field in a table at the bottom of the page.\n\nNote that mobile devices may connect commands to buttons as they see fit. Any command mentioned here may be directly assigned to a soft-button or appear in a menu named e. g. \"Options\" or \"Menu\" in turn assigned to a soft-button.\n\nAlso note that the drop-down box for selecting the target parameter of the calculation will turn uneditable as soon as you start changing input parameters. You need to execute the \"Calculate\" command before you can change the target again. +HELP_TEXT_OPERATION_TXT=In the main interface of the calculator, you first select the parameter you want calculated in the drop-down box at the top of the screen. Below that drop-down box are four input controls used to enter the parameters for the calculation. The target parameter of the calculation selected above will become uneditable. Enter the values in the other fields as desired and execute the \"Calculate\" command. As a result, you will find a value in the (uneditable) field for the target parameter and the near and far limit of the depth of field in a table at the bottom of the page. To request an infinite depth-of-field, enter "0" (zero) in the corresponding text field. If the calculation target is subject distance and you request infinit depth-of-field, the calculator will determine the hyperfocal distance.\n\nNote that mobile devices may connect commands to buttons as they see fit. Any command mentioned here may be directly assigned to a soft-button or appear in a menu named e. g. \"Options\" or \"Menu\" in turn assigned to a soft-button.\n\nAlso note that the drop-down box for selecting the target parameter of the calculation will turn uneditable as soon as you start changing input parameters. You need to execute the \"Calculate\" command before you can change the target again. HELP_TEXT_PREFS_TITLE=Preferences HELP_TEXT_PREFS_TXT=The preferences screen allows the user to specify a number of general settings used by the calculator:\n\n1. Circle of Confusion\nThe circle of confusion is a key parameter for the calculation of the depth of field. It comes in different flavours, though. The traditional (analog) interpretation ignores pixels and defines a degree of sharpness relative to a normal viewing distance of the image diagonal. This, however, ignores the photographer's desire to potentially crop the image. An variant interpretation, therefore, considers the circle of confusion as the size of two pixels.\nThe DoF calculator can work with a user-specified circle of confusion, which can either be entered directly or selected from a list of predefined ones. The formula used to calculate the absolute values is:\nc = 2 * sensor-diagonal / sqrt( form-factor * pixel + pixel / form-factor )\n\n2. Default Calculation Target\nThis is the calculation target the calculator will set on startup.\n\n3. Stop Scale\nWhen selecting an aperture value from the list on the main screen, the list can either show a full-stop f-number scale, a half-stop scale, or a one-third-stop scale. Modified: trunk/src/de/olypedia/resources/i18n/messages_de.properties =================================================================== --- trunk/src/de/olypedia/resources/i18n/messages_de.properties 2009-09-29 20:05:51 UTC (rev 7) +++ trunk/src/de/olypedia/resources/i18n/messages_de.properties 2009-09-30 08:51:34 UTC (rev 8) @@ -96,7 +96,7 @@ HELP_TEXT_OVERVIEW_TITLE=\u00DCberblick HELP_TEXT_OVERVIEW_TXT=Der Sch\u00E4rfentiefe-Rechner ist ein kleines Fotografen-Werkzeug, der es erlaubt zu berechnen, welchen Sch\u00E4rfentiefe-Bereich bestimmte Werte f\u00FCr Brennweite, Blende und Objekt-Entfernung ergeben. Im Gegensatz zu anderen Rechnern unterst\u00FCtzt dieser Sch\u00E4rfentiefe-Rechner eine gro\u00DFe Bandbreite unterschiedlicher mobiler Endger\u00E4te und erlaubt dem Fotografen auch, das Berechnungsziel einzustellen. So kann man in einer Situation, in der z. B. die gew\u00FCnschte Sch\u00E4rfentiefe bekannt ist, der Rechner verwendet werden, um herauszufinden, mit welchen Einstellungen sie erzielt werden kann.\n\nDer Sch\u00E4rfentiefe-Rechner ist freie Software. Sie darf im Rahmen der Bedingungen der GNU General Public License weiterverteilt und ver\u00E4ndert werden, wie sie in Version 2 oder einer sp\u00E4teren Version beschrieben sind. HELP_TEXT_OPERATION_TITLE=Bedienung -HELP_TEXT_OPERATION_TXT=Im Haupt-Bildschirm des Sch\u00E4rfentiefe-Rechners, legen Sie zun\u00E4chst das Berechnungsziel mit Hilfe der Auswahlliste ganz oben fest. Darunter befinden sich vier Eingabe-Felder, in die die Eingangswerte f\u00FCr die Berechnung eingetragen werden. Das Feld f\u00FCr die Zielgr\u00F6\u00DFe ist f\u00FCr die Eingabe gesperrt. Tragen sie in die anderen Felder Werte ein wie ben\u00F6tigt und f\u00FChren Sie dann den Befehl \"Berechnen\" aus. Als Ergebnis finden Sie im nicht-editierbaren Feld einen Wert f\u00FCr die Zielgr\u00F6\u00DFe und den Nah- und Fernpunkt in einer Tabelle am unteren Ende des Bildschirms.\n\nBeachten Sie, dass mobile Endger\u00E4te Befehle nach eigenem Gutd\u00FCnken mit Kn\u00F6pfen verbinden k\u00F6nnen. Jeglicher hier erw\u00E4hnte Befehl k\u00F6nnte entweder direkt einem Knopf zugeordnet sein oder in einem Men\u00FC auftauchen, welches z. B. \"Men\u00FC\" oder \"Optionen\" hei\u00DFen k\u00F6nnte.\n\nBeachten Sie \u00FCberdies, dass die Auswahlliste f\u00FCr das Berechnungsziel gesperrt wird, sobald Sie weitere Eingangsparameter \u00E4ndern. Sie m\u00FCssen dann erst den Befehl \"Berechnen\" ausf\u00FChren, bevor sie das Berechnungsziel wieder \u00E4ndern k\u00F6nnen. +HELP_TEXT_OPERATION_TXT=Im Haupt-Bildschirm des Sch\u00E4rfentiefe-Rechners, legen Sie zun\u00E4chst das Berechnungsziel mit Hilfe der Auswahlliste ganz oben fest. Darunter befinden sich vier Eingabe-Felder, in die die Eingangswerte f\u00FCr die Berechnung eingetragen werden. Das Feld f\u00FCr die Zielgr\u00F6\u00DFe ist f\u00FCr die Eingabe gesperrt. Tragen sie in die anderen Felder Werte ein wie ben\u00F6tigt und f\u00FChren Sie dann den Befehl \"Berechnen\" aus. Als Ergebnis finden Sie im nicht-editierbaren Feld einen Wert f\u00FCr die Zielgr\u00F6\u00DFe und den Nah- und Fernpunkt in einer Tabelle am unteren Ende des Bildschirms. Um eine unendliche Sch\u00E4rfentiefe zu fordern, geben Sie eine "0" (Null) in das entsprechende Feld ein. Bei Objekt-Entfernung als Berechnungsziel und eingestellter unendlicher Sch\u00E4rfentiefe, bestimmt der Sch\u00E4rfentiefe-Rechner die hyperfokale Distanz.\n\nBeachten Sie, dass mobile Endger\u00E4te Befehle nach eigenem Gutd\u00FCnken mit Kn\u00F6pfen verbinden k\u00F6nnen. Jeglicher hier erw\u00E4hnte Befehl k\u00F6nnte entweder direkt einem Knopf zugeordnet sein oder in einem Men\u00FC auftauchen, welches z. B. \"Men\u00FC\" oder \"Optionen\" hei\u00DFen k\u00F6nnte.\n\nBeachten Sie \u00FCberdies, dass die Auswahlliste f\u00FCr das Berechnungsziel gesperrt wird, sobald Sie weitere Eingangsparameter \u00E4ndern. Sie m\u00FCssen dann erst den Befehl \"Berechnen\" ausf\u00FChren, bevor sie das Berechnungsziel wieder \u00E4ndern k\u00F6nnen. HELP_TEXT_PREFS_TITLE=Einstellungen HELP_TEXT_PREFS_TXT=Der Bildschirm \"Einstellungen\" erm\u00F6glicht die Voreinstellung einer Reihe allgemeiner vom Sch\u00E4rfentiefe-Rechner verwendeter Variablen:\n\n1. Zerstreuungskreis\nDer Zerstreuungskreis ist eine zentrale Gr\u00F6\u00DFe f\u00FCr die Berechnung der Sch\u00E4rfentiefe. Sie gibt es jedoch in verschiedenen Geschmacksrichtungen. Die traditionelle (analoge) Deutung ignoriert Pixel und versteht den Zerstreuungskreis als ein Ma\u00DF von Sch\u00E4rfe in Abh\u00E4ngigkeit von einer normalen Betrachtungsentfernung gleich der Bilddiagonalen. Die vernachl\u00E4ssigt jedoch den m\u00F6glichen Wunsch nach Ausschnittsvergr\u00F6\u00DFerungen. Eine alternative Deutung versteht daher den Zertstreuungskreis als zwei Pixel.\nDer Sch\u00E4rfentiefe-Rechner kann mit benutzerdefinierten Zerstreuungskreisen arbeiten, die entweder direkt eingegeben oder aus einer Liste vordefinierter ausgew\u00E4hlt werden k\u00F6nnen. Die Formel zur Berechnung dieser Werte ist:\nk = 2 * Sensor-Diagonale : sqrt( Form-Faktor * Pixel + Pixel : Form-Faktor )\n\n2. Standard Berechnungsziel\nDieses Berechnungsziel verwendet der Sch\u00E4rfentiefe-Rechner beim Start.\n\n3. Blendenreihe\nBei der Auswahl einer Blende aus der Liste vordefinierter Blendenwerte kann die Liste entweder ganze, halbe oder drittel Blendenstufen enthalten. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |