package org.openpnp.machine.reference.wizards; import java.awt.Color; import java.awt.event.ActionEvent; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.border.EtchedBorder; import javax.swing.border.TitledBorder; import org.jdesktop.beansbinding.AutoBinding.UpdateStrategy; import org.openpnp.gui.MainFrame; import org.openpnp.gui.components.CameraView; import org.openpnp.gui.components.ComponentDecorators; import org.openpnp.gui.components.LocationButtonsPanel; import org.openpnp.gui.support.AbstractConfigurationWizard; import org.openpnp.gui.support.DoubleConverter; import org.openpnp.gui.support.IntegerConverter; import org.openpnp.gui.support.LengthConverter; import org.openpnp.gui.support.MutableLocationProxy; import org.openpnp.machine.reference.ReferenceCamera; import org.openpnp.model.Configuration; import com.jgoodies.forms.layout.ColumnSpec; import com.jgoodies.forms.layout.FormLayout; import com.jgoodies.forms.layout.FormSpecs; import com.jgoodies.forms.layout.RowSpec; @SuppressWarnings("serial") public class ReferenceCameraConfigurationWizard extends AbstractConfigurationWizard { private final ReferenceCamera referenceCamera; private JTextField textFieldOffX; private JTextField textFieldOffY; private JTextField textFieldOffZ; private JPanel panelOffsets; private JPanel panelGeneral; private JLabel lblRotation; private JTextField textFieldRotation; private JPanel panelLocation; private JLabel lblX; private JLabel lblY; private JLabel lblZ; private JLabel lblRotation_1; private JTextField textFieldLocationX; private JTextField textFieldLocationY; private JTextField textFieldLocationZ; private JTextField textFieldLocationRotation; private LocationButtonsPanel locationButtonsPanel; private JCheckBox chckbxFlipX; private JLabel lblFlipX; private JLabel lblFlipY; private JCheckBox checkBoxFlipY; private JTextField textFieldSafeZ; private JLabel lblOffsetX; private JLabel lblOffsetY; private JTextField textFieldOffsetX; private JTextField textFieldOffsetY; private JPanel panelLensCalibration; private JLabel lblApplyCalibration; private JCheckBox calibrationEnabledChk; public ReferenceCameraConfigurationWizard(ReferenceCamera referenceCamera) { this.referenceCamera = referenceCamera; panelOffsets = new JPanel(); contentPanel.add(panelOffsets); panelOffsets.setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null), "Offsets", TitledBorder.LEADING, TitledBorder.TOP, null, new Color(0, 0, 0))); panelOffsets.setLayout(new FormLayout( new ColumnSpec[] {FormSpecs.RELATED_GAP_COLSPEC, FormSpecs.DEFAULT_COLSPEC, FormSpecs.RELATED_GAP_COLSPEC, FormSpecs.DEFAULT_COLSPEC, FormSpecs.RELATED_GAP_COLSPEC, FormSpecs.DEFAULT_COLSPEC, FormSpecs.RELATED_GAP_COLSPEC, FormSpecs.DEFAULT_COLSPEC,}, new RowSpec[] {FormSpecs.RELATED_GAP_ROWSPEC, FormSpecs.DEFAULT_ROWSPEC, FormSpecs.RELATED_GAP_ROWSPEC, FormSpecs.DEFAULT_ROWSPEC, FormSpecs.RELATED_GAP_ROWSPEC, FormSpecs.DEFAULT_ROWSPEC,})); JLabel olblX = new JLabel("X"); panelOffsets.add(olblX, "2, 2"); JLabel olblY = new JLabel("Y"); panelOffsets.add(olblY, "4, 2"); JLabel olblZ = new JLabel("Z"); panelOffsets.add(olblZ, "6, 2"); textFieldOffX = new JTextField(); panelOffsets.add(textFieldOffX, "2, 4"); textFieldOffX.setColumns(8); textFieldOffY = new JTextField(); panelOffsets.add(textFieldOffY, "4, 4"); textFieldOffY.setColumns(8); textFieldOffZ = new JTextField(); panelOffsets.add(textFieldOffZ, "6, 4"); textFieldOffZ.setColumns(8); JPanel panelSafeZ = new JPanel(); panelSafeZ.setBorder(new TitledBorder(null, "Safe Z", TitledBorder.LEADING, TitledBorder.TOP, null, null)); contentPanel.add(panelSafeZ); panelSafeZ.setLayout(new FormLayout( new ColumnSpec[] {FormSpecs.RELATED_GAP_COLSPEC, FormSpecs.DEFAULT_COLSPEC, FormSpecs.RELATED_GAP_COLSPEC, FormSpecs.DEFAULT_COLSPEC,}, new RowSpec[] {FormSpecs.RELATED_GAP_ROWSPEC, FormSpecs.DEFAULT_ROWSPEC,})); JLabel lblSafeZ = new JLabel("Safe Z"); panelSafeZ.add(lblSafeZ, "2, 2, right, default"); textFieldSafeZ = new JTextField(); panelSafeZ.add(textFieldSafeZ, "4, 2, fill, default"); textFieldSafeZ.setColumns(10); panelGeneral = new JPanel(); panelGeneral.setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null), "Transformation", TitledBorder.LEADING, TitledBorder.TOP, null, new Color(0, 0, 0))); contentPanel.add(panelGeneral); panelGeneral.setLayout(new FormLayout(new ColumnSpec[] { FormSpecs.RELATED_GAP_COLSPEC, FormSpecs.DEFAULT_COLSPEC, FormSpecs.RELATED_GAP_COLSPEC, FormSpecs.DEFAULT_COLSPEC, ColumnSpec.decode("default:grow"),}, new RowSpec[] { FormSpecs.RELATED_GAP_ROWSPEC, FormSpecs.DEFAULT_ROWSPEC, FormSpecs.RELATED_GAP_ROWSPEC, FormSpecs.DEFAULT_ROWSPEC, FormSpecs.RELATED_GAP_ROWSPEC, FormSpecs.DEFAULT_ROWSPEC, FormSpecs.RELATED_GAP_ROWSPEC, FormSpecs.DEFAULT_ROWSPEC, FormSpecs.RELATED_GAP_ROWSPEC, FormSpecs.DEFAULT_ROWSPEC, FormSpecs.RELATED_GAP_ROWSPEC, FormSpecs.DEFAULT_ROWSPEC, FormSpecs.RELATED_GAP_ROWSPEC, FormSpecs.DEFAULT_ROWSPEC,})); lblRotation = new JLabel("Rotation"); panelGeneral.add(lblRotation, "2, 2, right, default"); textFieldRotation = new JTextField(); panelGeneral.add(textFieldRotation, "4, 2"); textFieldRotation.setColumns(10); lblOffsetX = new JLabel("Offset X"); panelGeneral.add(lblOffsetX, "2, 4, right, default"); textFieldOffsetX = new JTextField(); panelGeneral.add(textFieldOffsetX, "4, 4"); textFieldOffsetX.setColumns(10); lblOffsetY = new JLabel("Offset Y"); panelGeneral.add(lblOffsetY, "2, 6, right, default"); textFieldOffsetY = new JTextField(); panelGeneral.add(textFieldOffsetY, "4, 6"); textFieldOffsetY.setColumns(10); lblFlipX = new JLabel("Flip Vertical"); panelGeneral.add(lblFlipX, "2, 8, right, default"); chckbxFlipX = new JCheckBox(""); panelGeneral.add(chckbxFlipX, "4, 8"); lblFlipY = new JLabel("Flip Horizontal"); panelGeneral.add(lblFlipY, "2, 10, right, default"); checkBoxFlipY = new JCheckBox(""); panelGeneral.add(checkBoxFlipY, "4, 10"); lblCropX = new JLabel("Crop Width"); panelGeneral.add(lblCropX, "2, 12, right, default"); cropWidthTextField = new JTextField(); panelGeneral.add(cropWidthTextField, "4, 12"); cropWidthTextField.setColumns(10); lblNewLabel = new JLabel("(Use 0 for no cropping)"); panelGeneral.add(lblNewLabel, "5, 12"); lblCropHeight = new JLabel("Crop Height"); panelGeneral.add(lblCropHeight, "2, 14, right, default"); cropHeightTextField = new JTextField(); panelGeneral.add(cropHeightTextField, "4, 14"); cropHeightTextField.setColumns(10); lblNewLabel_1 = new JLabel("(Use 0 for no cropping)"); panelGeneral.add(lblNewLabel_1, "5, 14"); panelLocation = new JPanel(); panelLocation.setBorder(new TitledBorder(null, "Location", TitledBorder.LEADING, TitledBorder.TOP, null, null)); contentPanel.add(panelLocation); panelLocation.setLayout(new FormLayout( new ColumnSpec[] {FormSpecs.RELATED_GAP_COLSPEC, FormSpecs.DEFAULT_COLSPEC, FormSpecs.RELATED_GAP_COLSPEC, FormSpecs.DEFAULT_COLSPEC, FormSpecs.RELATED_GAP_COLSPEC, FormSpecs.DEFAULT_COLSPEC, FormSpecs.RELATED_GAP_COLSPEC, FormSpecs.DEFAULT_COLSPEC, FormSpecs.RELATED_GAP_COLSPEC, ColumnSpec.decode("default:grow"),}, new RowSpec[] {FormSpecs.RELATED_GAP_ROWSPEC, FormSpecs.DEFAULT_ROWSPEC, FormSpecs.RELATED_GAP_ROWSPEC, RowSpec.decode("default:grow"),})); lblX = new JLabel("X"); panelLocation.add(lblX, "2, 2"); lblY = new JLabel("Y"); panelLocation.add(lblY, "4, 2"); lblZ = new JLabel("Z"); panelLocation.add(lblZ, "6, 2"); lblRotation_1 = new JLabel("Rotation"); panelLocation.add(lblRotation_1, "8, 2"); textFieldLocationX = new JTextField(); panelLocation.add(textFieldLocationX, "2, 4, fill, default"); textFieldLocationX.setColumns(8); textFieldLocationY = new JTextField(); panelLocation.add(textFieldLocationY, "4, 4, fill, default"); textFieldLocationY.setColumns(8); textFieldLocationZ = new JTextField(); panelLocation.add(textFieldLocationZ, "6, 4, fill, default"); textFieldLocationZ.setColumns(8); textFieldLocationRotation = new JTextField(); panelLocation.add(textFieldLocationRotation, "8, 4, fill, default"); textFieldLocationRotation.setColumns(8); panelLensCalibration = new JPanel(); panelLensCalibration.setBorder(new TitledBorder(null, "Lens Calibration", TitledBorder.LEADING, TitledBorder.TOP, null, null)); contentPanel.add(panelLensCalibration); panelLensCalibration.setLayout(new FormLayout( new ColumnSpec[] {FormSpecs.RELATED_GAP_COLSPEC, FormSpecs.DEFAULT_COLSPEC, FormSpecs.RELATED_GAP_COLSPEC, ColumnSpec.decode("default:grow"),}, new RowSpec[] {FormSpecs.RELATED_GAP_ROWSPEC, FormSpecs.DEFAULT_ROWSPEC, FormSpecs.RELATED_GAP_ROWSPEC, FormSpecs.DEFAULT_ROWSPEC, FormSpecs.RELATED_GAP_ROWSPEC, FormSpecs.DEFAULT_ROWSPEC, FormSpecs.RELATED_GAP_ROWSPEC, FormSpecs.DEFAULT_ROWSPEC, FormSpecs.RELATED_GAP_ROWSPEC, FormSpecs.DEFAULT_ROWSPEC, FormSpecs.RELATED_GAP_ROWSPEC, FormSpecs.DEFAULT_ROWSPEC, FormSpecs.RELATED_GAP_ROWSPEC, FormSpecs.DEFAULT_ROWSPEC,})); startLensCalibrationBtn = new JButton(startCalibration); panelLensCalibration.add(startLensCalibrationBtn, "2, 2, 3, 1"); lblApplyCalibration = new JLabel("Apply Calibration?"); panelLensCalibration.add(lblApplyCalibration, "2, 4, right, default"); calibrationEnabledChk = new JCheckBox(""); panelLensCalibration.add(calibrationEnabledChk, "4, 4"); try { // Causes WindowBuilder to fail, so just throw away the error. if (referenceCamera.getHead() == null) { locationButtonsPanel = new LocationButtonsPanel(textFieldLocationX, textFieldLocationY, textFieldLocationZ, textFieldLocationRotation); panelLocation.add(locationButtonsPanel, "10, 4, fill, fill"); panelOffsets.setVisible(false); } else { panelLocation.setVisible(false); } } catch (Exception e) { } } @Override public void createBindings() { IntegerConverter intConverter = new IntegerConverter(); DoubleConverter doubleConverter = new DoubleConverter(Configuration.get().getLengthDisplayFormat()); LengthConverter lengthConverter = new LengthConverter(); if (referenceCamera.getHead() == null) { // fixed camera MutableLocationProxy headOffsets = new MutableLocationProxy(); bind(UpdateStrategy.READ_WRITE, referenceCamera, "headOffsets", headOffsets, "location"); addWrappedBinding(headOffsets, "lengthX", textFieldLocationX, "text", lengthConverter); addWrappedBinding(headOffsets, "lengthY", textFieldLocationY, "text", lengthConverter); addWrappedBinding(headOffsets, "lengthZ", textFieldLocationZ, "text", lengthConverter); addWrappedBinding(headOffsets, "rotation", textFieldLocationRotation, "text", doubleConverter); } else { // moving camera MutableLocationProxy headOffsets = new MutableLocationProxy(); bind(UpdateStrategy.READ_WRITE, referenceCamera, "headOffsets", headOffsets, "location"); addWrappedBinding(headOffsets, "lengthX", textFieldOffX, "text", lengthConverter); addWrappedBinding(headOffsets, "lengthY", textFieldOffY, "text", lengthConverter); addWrappedBinding(headOffsets, "lengthZ", textFieldOffZ, "text", lengthConverter); } addWrappedBinding(referenceCamera, "rotation", textFieldRotation, "text", doubleConverter); addWrappedBinding(referenceCamera, "offsetX", textFieldOffsetX, "text", intConverter); addWrappedBinding(referenceCamera, "offsetY", textFieldOffsetY, "text", intConverter); addWrappedBinding(referenceCamera, "flipX", chckbxFlipX, "selected"); addWrappedBinding(referenceCamera, "flipY", checkBoxFlipY, "selected"); addWrappedBinding(referenceCamera, "safeZ", textFieldSafeZ, "text", lengthConverter); addWrappedBinding(referenceCamera, "cropWidth", cropWidthTextField, "text", intConverter); addWrappedBinding(referenceCamera, "cropHeight", cropHeightTextField, "text", intConverter); bind(UpdateStrategy.READ_WRITE, referenceCamera.getCalibration(), "enabled", calibrationEnabledChk, "selected"); // addWrappedBinding(referenceCamera.getCalibration(), "enabled", calibrationEnabledChk, // "selected"); ComponentDecorators.decorateWithAutoSelect(textFieldRotation); ComponentDecorators.decorateWithAutoSelect(textFieldOffsetX); ComponentDecorators.decorateWithAutoSelect(textFieldOffsetY); ComponentDecorators.decorateWithAutoSelectAndLengthConversion(textFieldOffX); ComponentDecorators.decorateWithAutoSelectAndLengthConversion(textFieldOffY); ComponentDecorators.decorateWithAutoSelectAndLengthConversion(textFieldOffZ); ComponentDecorators.decorateWithAutoSelectAndLengthConversion(textFieldLocationX); ComponentDecorators.decorateWithAutoSelectAndLengthConversion(textFieldLocationY); ComponentDecorators.decorateWithAutoSelectAndLengthConversion(textFieldLocationZ); ComponentDecorators.decorateWithAutoSelectAndLengthConversion(textFieldLocationRotation); ComponentDecorators.decorateWithAutoSelectAndLengthConversion(textFieldSafeZ); ComponentDecorators.decorateWithAutoSelect(cropWidthTextField); ComponentDecorators.decorateWithAutoSelect(cropHeightTextField); } private Action startCalibration = new AbstractAction("Start Lens Calibration") { @Override public void actionPerformed(ActionEvent e) { MainFrame.get().getCameraViews().setSelectedCamera(referenceCamera); startLensCalibrationBtn.setAction(cancelCalibration); CameraView cameraView = MainFrame.get().getCameraViews().getCameraView(referenceCamera); String message = "Go to https://github.com/openpnp/openpnp/wiki/Camera-Lens-Calibration for detailed instructions.\n" + "When you have your calibration card ready, hold it in front of the camera so that the entire card is visible.\n" + "Each time the screen flashes an image is captured. After the flash you should move the card to a new orientation."; cameraView.setText(message); cameraView.flash(); referenceCamera.startCalibration((progressCurrent, progressMax, finished) -> { if (finished) { cameraView.setText(null); startLensCalibrationBtn.setAction(startCalibration); } else { cameraView.setText(String.format( "Captured %d of %d.\nMove the card to a new position and angle each time the screen flashes.", progressCurrent, progressMax)); } cameraView.flash(); }); } }; private Action cancelCalibration = new AbstractAction("Cancel Lens Calibration") { @Override public void actionPerformed(ActionEvent e) { startLensCalibrationBtn.setAction(startCalibration); referenceCamera.cancelCalibration(); CameraView cameraView = MainFrame.get().getCameraViews().getCameraView(referenceCamera); cameraView.setText(null); cameraView.flash(); } }; private JButton startLensCalibrationBtn; private JLabel lblCropX; private JLabel lblCropHeight; private JTextField cropWidthTextField; private JTextField cropHeightTextField; private JLabel lblNewLabel; private JLabel lblNewLabel_1; }