package edu.stanford.rsl.apps.gui; import java.awt.Color; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.LayoutManager; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.ButtonGroup; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JTabbedPane; import javax.swing.JTextField; import javax.swing.SwingUtilities; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import edu.stanford.rsl.conrad.geometry.General; import edu.stanford.rsl.conrad.geometry.Projection.CameraAxisDirection; import edu.stanford.rsl.conrad.geometry.trajectories.CircularTrajectory; import edu.stanford.rsl.conrad.geometry.trajectories.ConfigFileBasedTrajectory; import edu.stanford.rsl.conrad.geometry.trajectories.MultiSweepTrajectory; import edu.stanford.rsl.conrad.geometry.trajectories.Trajectory; import edu.stanford.rsl.conrad.numerics.SimpleVector; import edu.stanford.rsl.conrad.physics.detector.XRayDetector; import edu.stanford.rsl.conrad.utils.CONRAD; import edu.stanford.rsl.conrad.utils.Configuration; import edu.stanford.rsl.conrad.utils.GUIUtil; import edu.stanford.rsl.conrad.utils.UserUtil; /** * This code was edited or generated using CloudGarden's Jigloo * SWT/Swing GUI Builder, which is free for non-commercial * use. If Jigloo is being used commercially (ie, by a corporation, * company or business for any purpose whatever) then you * should purchase a license for each developer using Jigloo. * Please visit www.cloudgarden.com for details. * Use of Jigloo implies acceptance of these licensing terms. * A COMMERCIAL LICENSE HAS NOT BEEN PURCHASED FOR * THIS MACHINE, SO JIGLOO OR THIS CODE CANNOT BE USED * LEGALLY FOR ANY CORPORATE OR COMMERCIAL PURPOSE. */ public class ConfigurationFrame extends JFrame implements ActionListener { /** * */ private static final long serialVersionUID = 979874928758716096L; private JTabbedPane jTabbedPane; private JButton jSaveButton; private boolean exited = false; Configuration config; private UpdateableGUI parentFrame; private RegistryEditor regEditor; private TrajectoryEditor trajEdit; JButton jCenterVolume = new JButton("Center volume"); JButton jDoubleVolumeResolution = new JButton("Resolution *= 2"); JButton jHalfVolumeResolution = new JButton("Resolution /= 2"); JButton jDoubleDetectorResolution = new JButton("Resolution *= 2"); JButton jHalfDetectorResolution = new JButton("Resolution /= 2"); public ConfigurationFrame(){ config = Configuration.getGlobalConfiguration(); regEditor = new RegistryEditor(config); SwingUtilities.invokeLater(new Runnable() { public void run(){ regEditor.initGUI(); }; }); initGUI(); updateValues(); } public boolean isExited() { return exited; } public void exit(){ exited = true; setVisible(false); if (parentFrame != null) parentFrame.updateGUI(); System.out.println("exiting config frame"); } String [] camAxes = new String [] { "points in the direction of detector motion", "points against the direction of detector motion", "points in rotation axis direction", "points against rotation axis direction"}; private CameraAxisDirection getDirection(String str){ CameraAxisDirection dir = CameraAxisDirection.DETECTORMOTION_PLUS; if (str != null){ if (str.equals("points in the direction of detector motion")){ dir = CameraAxisDirection.DETECTORMOTION_PLUS; } else if (str.equals("points against the direction of detector motion")){ dir = CameraAxisDirection.DETECTORMOTION_MINUS; } else if (str.equals("points in rotation axis direction")){ dir = CameraAxisDirection.ROTATIONAXIS_PLUS; } else if (str.equals("points against rotation axis direction")){ dir = CameraAxisDirection.ROTATIONAXIS_MINUS; } } return dir; } private int getDirectionIndex(CameraAxisDirection dir){ int index = -1; if (dir == CameraAxisDirection.DETECTORMOTION_PLUS) { index = 0; } else if (dir == CameraAxisDirection.DETECTORMOTION_MINUS){ index = 1; } else if (dir == CameraAxisDirection.ROTATIONAXIS_PLUS){ index = 2; } else if (dir == CameraAxisDirection.ROTATIONAXIS_MINUS){ index = 3; } return index; } public void actionPerformed(ActionEvent e) { if (e.getSource() != null){ if (e.getSource().equals(jSaveButton)) { readValuesToConfig(); if (config.getImportFromDicomAutomatically()) { try { Trajectory load = Configuration.loadGeometrySource(config); if (load != null){ config.setGeometry(load); } } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } Configuration.setGlobalConfiguration(config); Configuration.saveConfiguration(); exited = true; setVisible(false); if (parentFrame != null) parentFrame.updateGUI(); } if (e.getSource().equals(trajectoryEditorButton)) { startTrajectoryEditor(); } if (e.getSource().equals(jParseGeometry)) { JTextField field = this.projectionTableFileField; Trajectory geom = ConfigFileBasedTrajectory.openAsGeometrySource(field.getText(), config.getGeometry()); if (geom != null){ Configuration config = Configuration.getGlobalConfiguration(); config.setProjectionTableFileName(field.getText()); config.setGeometry(geom); } updateValues(); } if (e.getSource().equals(optionList)){ //System.out.println("Event" + e); trajectoryPanel.remove(trajectoryFromParameters); trajectoryPanel.remove(trajectoryFromFile); if (optionList.getSelectedIndex() == 0){ trajectoryPanel.add(trajectoryFromFile, createConstraints(0, 2, 5, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, 0, 0, 0, 0)); } else { trajectoryPanel.add(trajectoryFromParameters, createConstraints(0, 2, 5, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, 0, 0, 0, 0)); } this.repaint(); } if (e.getSource().equals(jGenerateDetector)) { XRayDetector detector; try { detector = (XRayDetector) UserUtil.queryObject("Select Detector:", "Detector Selection", XRayDetector.class); detector.configure(); Configuration.getGlobalConfiguration().setDetector(detector); jDetectorLabel.setText("Current Detector: " + config.getDetector()); } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } if (e.getSource().equals(jGenerateGeometry)) { readValuesToConfig(); int numProjectionMatrices = config.getGeometry().getProjectionStackSize(); double sourceToAxisDistance = Double.parseDouble(sourceToPatientField.getText()); double averageAngularIncrement = config.getGeometry().getAverageAngularIncrement(); double detectorOffsetU = config.getGeometry().getDetectorOffsetU(); double detectorOffsetV = config.getGeometry().getDetectorOffsetV(); CameraAxisDirection uDirection = config.getGeometry().getDetectorUDirection(); CameraAxisDirection vDirection = config.getGeometry().getDetectorVDirection(); SimpleVector rotationAxis = config.getGeometry().getRotationAxis(); Trajectory geom = new CircularTrajectory(config.getGeometry()); geom.setSecondaryAngleArray(null); ((CircularTrajectory)geom).setTrajectory(numProjectionMatrices, sourceToAxisDistance, averageAngularIncrement, detectorOffsetU, detectorOffsetV, uDirection, vDirection, rotationAxis); if (geom != null){ Configuration config = Configuration.getGlobalConfiguration(); if (config.getNumSweeps() > 1){ MultiSweepTrajectory multi = new MultiSweepTrajectory(geom); multi.extrapolateProjectionGeometry(); geom = new Trajectory(multi); } config.setGeometry(geom); } } if (e.getSource().equals(jCenterVolume)) { centerVolume(); } if (e.getSource().equals(jDoubleVolumeResolution)) { changeVolumeResolution(2.0); } if (e.getSource().equals(jHalfVolumeResolution)) { changeVolumeResolution(0.5); } if (e.getSource().equals(jDoubleDetectorResolution)) { changeDetectorResolution(2.0); } if (e.getSource().equals(jHalfDetectorResolution)) { changeDetectorResolution(0.5); } } } private void startTrajectoryEditor() { if(trajEdit == null) { trajEdit = new TrajectoryEditor(); trajEdit.setVisible(true); trajEdit.setLocation(CONRAD.getWindowTopCorner()); } } /** * creates a 5 x 4 GridBagLayout in ConfigurationFrame SubPanel-Style * @return the sub panel layout */ static LayoutManager createSubPaneLayout(){ GridBagLayout thisLayout = new GridBagLayout(); thisLayout.rowWeights = new double[] {0.0, 0.1, 0.1, 0.0}; thisLayout.rowHeights = new int[] {15, 120, 120, 15}; thisLayout.columnWeights = new double[] {0.1, 0.1, 0.1, 0.1, 0.1}; thisLayout.columnWidths = new int[] {15, 225, 15, 225, 15}; return thisLayout; } private void positionNumericLabelTextFieldPair(JPanel panel, String labelText, JTextField field, int x, int y, int topOffset){ JLabel label = new JLabel(labelText); panel.add(label, createConstraints(x, y, 1, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, topOffset + 3, 0, 0, 0)); panel.add(field, createConstraints(x, y, 1, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, topOffset, 210, 0, 0)); field.setHorizontalAlignment(JTextField.RIGHT); } private void positionLabelTextFieldPair(JPanel panel, String labelText, JTextField field, int x, int y, int width, int topOffset){ JLabel label = new JLabel(labelText); panel.add(label, createConstraints(x, y, width, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, topOffset + 3, 0, 0, 0)); panel.add(field, createConstraints(x, y, width, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, topOffset, 210, 0, 0)); } private void positionLabelTextFieldButton(JPanel panel, String labelText, JTextField field, int x, int y, int width, int topOffset, JButton button){ JLabel label = new JLabel(labelText); panel.add(label, createConstraints(x, y, width, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, topOffset + 3, 0, 0, 0)); panel.add(field, createConstraints(x, y, width, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, topOffset+30, 0, 0, 0)); panel.add(button, createConstraints(x+width-1, y, 1, 1, GridBagConstraints.NORTHEAST, GridBagConstraints.HORIZONTAL, topOffset+60, 100, 0, 0)); } JTextField xDimensionField = new JTextField(); JTextField yDimensionField = new JTextField(); JTextField zDimensionField = new JTextField(); JTextField xOriginVoxel = new JTextField(); JTextField yOriginVoxel = new JTextField(); JTextField zOriginVoxel = new JTextField(); JTextField xOriginWorld = new JTextField(); JTextField yOriginWorld = new JTextField(); JTextField zOriginWorld = new JTextField(); JTextField xSpacingField = new JTextField(); JTextField ySpacingField = new JTextField(); JTextField zSpacingField = new JTextField(); JTextField maxVOIPathField = new JTextField(); private void updateValues(){ // volume Trajectory geometry = config.getGeometry(); if (geometry != null) { xDimensionField.setText("" + geometry.getReconDimensionX()); yDimensionField.setText("" + geometry.getReconDimensionY()); zDimensionField.setText("" + geometry.getReconDimensionZ()); xSpacingField.setText("" + geometry.getVoxelSpacingX()); ySpacingField.setText("" + geometry.getVoxelSpacingY()); zSpacingField.setText("" + geometry.getVoxelSpacingZ()); xOriginWorld.setText("" + geometry.getOriginX()); yOriginWorld.setText("" + geometry.getOriginY()); zOriginWorld.setText("" + geometry.getOriginZ()); xOriginVoxel.setText("" + geometry.getOriginInPixelsX()); yOriginVoxel.setText("" + geometry.getOriginInPixelsY()); zOriginVoxel.setText("" + geometry.getOriginInPixelsZ()); // geometry detectorWidthField.setText("" + geometry.getDetectorWidth()); detectorHeightField.setText("" + geometry.getDetectorHeight()); pixelDimensionXField.setText("" + geometry.getPixelDimensionX()); pixelDimensionYField.setText("" + geometry.getPixelDimensionY()); sourceToDetectorField.setText("" + geometry.getSourceToDetectorDistance()); sourceToPatientField.setText("" + geometry.getSourceToAxisDistance()); projectionStackSizeField.setText("" + geometry.getProjectionStackSize()); // new parameters for trajectory definition averageAngularIncrement.setText("" + geometry.getAverageAngularIncrement()); detectorOffsetU.setText("" + geometry.getDetectorOffsetU()); detectorOffsetV.setText("" + geometry.getDetectorOffsetV()); SimpleVector rotAxis = geometry.getRotationAxis(); if (rotAxis==null) rotAxis = new SimpleVector(0,0,1); rotationAxis.setText("" + rotAxis.toString()); DetectorUDirection.setSelectedIndex(getDirectionIndex(geometry.getDetectorUDirection())); DetectorVDirection.setSelectedIndex(getDirectionIndex(geometry.getDetectorVDirection())); } numSweepsField.setText("" + config.getNumSweeps()); maxVOIPathField.setText(config.getVolumeOfInterestFileName()); projectionTableFileField.setText(config.getProjectionTableFileName()); // other recentFileOneField.setText(config.getRecentFileOne()); recentFileTwoField.setText(config.getRecentFileTwo()); importFromDicom.setSelected(config.getImportFromDicomAutomatically()); extrapolateGeometry.setSelected(config.getUseExtrapolatedGeometry()); houns.setSelected(config.getUseHounsfieldScaling()); if (config.getCitationFormat() == Configuration.BIBTEX_CITATION_FORMAT){ citationFormatGroup.setSelected(bibButton.getModel(), true); } else { citationFormatGroup.setSelected(medlineButton.getModel(), true); } } private String getTextSave(JTextField textField){ String revan = null; if (! textField.getText().equals("")) { revan = textField.getText(); } return revan; } public void setParentFrame(UpdateableGUI parentFrame) { this.parentFrame = parentFrame; } public UpdateableGUI getParentFrame() { return parentFrame; } private void readValuesToConfig() throws NumberFormatException { // volume config.getGeometry().setReconDimensionX((int) Double.parseDouble(xDimensionField.getText())); config.getGeometry().setReconDimensionY((int) Double.parseDouble(yDimensionField.getText())); config.getGeometry().setReconDimensionZ((int) Double.parseDouble(zDimensionField.getText())); config.getGeometry().setVoxelSpacingX(Double.parseDouble(xSpacingField.getText())); config.getGeometry().setVoxelSpacingY(Double.parseDouble(ySpacingField.getText())); config.getGeometry().setVoxelSpacingZ(Double.parseDouble(zSpacingField.getText())); config.getGeometry().setOriginInPixelsX(Double.parseDouble(xOriginVoxel.getText())); config.getGeometry().setOriginInPixelsY(Double.parseDouble(yOriginVoxel.getText())); config.getGeometry().setOriginInPixelsZ(Double.parseDouble(zOriginVoxel.getText())); config.setVolumeOfInterestFileName(getTextSave(maxVOIPathField)); // geometry config.getGeometry().setDetectorWidth((int)Math.floor(Double.parseDouble(detectorWidthField.getText()))); config.getGeometry().setDetectorHeight((int)Math.floor(Double.parseDouble(detectorHeightField.getText()))); config.getGeometry().setPixelDimensionX(Double.parseDouble(pixelDimensionXField.getText())); config.getGeometry().setPixelDimensionY(Double.parseDouble(pixelDimensionYField.getText())); config.getGeometry().setSourceToDetectorDistance(Double.parseDouble(sourceToDetectorField.getText())); config.getGeometry().setSourceToAxisDistance(Double.parseDouble(sourceToPatientField.getText())); config.getGeometry().setProjectionStackSize(Integer.parseInt(projectionStackSizeField.getText())); config.setNumSweeps(Integer.parseInt(numSweepsField.getText())); config.setProjectionTableFileName(getTextSave(projectionTableFileField)); // other config.setRecentFileOne(getTextSave(recentFileOneField)); config.setRecentFileTwo(getTextSave(recentFileTwoField)); config.setImportFromDicomAutomatically(importFromDicom.isSelected()); config.setUseExtrapolatedGeometry(extrapolateGeometry.isSelected()); config.setUseHounsfieldScaling(houns.isSelected()); if (bibButton.isSelected()){ config.setCitationFormat(Configuration.BIBTEX_CITATION_FORMAT); } else { config.setCitationFormat(Configuration.MEDLINE_CITATION_FORMAT); } // new parameters for trajectory definition config.getGeometry().setAverageAngularIncrement(Double.parseDouble(averageAngularIncrement.getText())); config.getGeometry().setDetectorOffsetU(Double.parseDouble(detectorOffsetU.getText())); config.getGeometry().setDetectorOffsetV(Double.parseDouble(detectorOffsetV.getText())); SimpleVector rotAxis = new SimpleVector(); rotAxis.setVectorSerialization(rotationAxis.getText()); config.getGeometry().setRotationAxis(rotAxis); config.getGeometry().setDetectorUDirection(getDirection((String)DetectorUDirection.getSelectedItem())); config.getGeometry().setDetectorVDirection(getDirection((String)DetectorVDirection.getSelectedItem())); regEditor.updateToConfiguration(); } JLabel jDetectorLabel; private JPanel detectorPane(){ JPanel volume = new JPanel(); volume.setBackground(Color.white); volume.setLayout(createSubPaneLayout()); positionNumericLabelTextFieldPair(volume, "Detector size x [pixels]", detectorWidthField, 1, 1, 0); positionNumericLabelTextFieldPair(volume, "Detector size y [pixels]", detectorHeightField, 1, 1, 30); positionNumericLabelTextFieldPair(volume, "Pixel spacing x [mm]", pixelDimensionXField, 3, 1, 0); positionNumericLabelTextFieldPair(volume, "Pixel spacing y [mm]", pixelDimensionYField, 3, 1, 30); volume.add(jDoubleDetectorResolution, createConstraints(1, 1, 3, 1, GridBagConstraints.NORTH, GridBagConstraints.NONE, 200, -150, 0, 0)); jDoubleDetectorResolution.addActionListener(this); volume.add(jHalfDetectorResolution, createConstraints(1, 1, 3, 1, GridBagConstraints.NORTH, GridBagConstraints.NONE, 200, 150, 0, 0)); jHalfDetectorResolution.addActionListener(this); volume.add(jGenerateDetector, createConstraints(1, 1, 3, 1, GridBagConstraints.NORTH, GridBagConstraints.NONE, 90, 0, 0, 0)); jDetectorLabel = new JLabel("Current Detector: " + config.getDetector()); volume.add(jDetectorLabel, createConstraints(1, 1, 3, 1, GridBagConstraints.NORTH, GridBagConstraints.NONE, 60, 0, 0, 0)); jGenerateDetector.addActionListener(this); return volume; } private void changeDetectorResolution(double scale){ testNumericFields(detectorWidthField, detectorHeightField, pixelDimensionXField, pixelDimensionYField); updateNumericFieldValue(pixelDimensionXField, 1.0/scale); updateNumericFieldValue(pixelDimensionYField, 1.0/scale); updateNumericFieldValue(detectorWidthField, scale); updateNumericFieldValue(detectorHeightField, scale); } private void updateNumericFieldValue(JTextField field, double scale){ updateNumericFieldValue(field, scale, false); } private void updateNumericFieldValue(JTextField field, double scale, boolean roundToInteger){ if (!roundToInteger) field.setText(new Double(Double.parseDouble(field.getText()) * scale).toString()); else field.setText(new Integer((int)Math.floor(Double.parseDouble(field.getText()) * scale)).toString()); } /** * Will throw a parsing exception, if the fields contain invalid numbers. * @param fields */ private void testNumericFields(JTextField ... fields){ for (int i=0; i<fields.length; i++){ Double.parseDouble(fields[i].getText()); } } private void changeVolumeResolution(double scale){ testNumericFields(xSpacingField, ySpacingField, zSpacingField, xDimensionField, yDimensionField, zDimensionField); updateNumericFieldValue(xSpacingField, 1.0/scale); updateNumericFieldValue(ySpacingField, 1.0/scale); updateNumericFieldValue(zSpacingField, 1.0/scale); updateNumericFieldValue(xDimensionField, scale); updateNumericFieldValue(yDimensionField, scale); updateNumericFieldValue(zDimensionField, scale); } private JPanel volumePane(){ JPanel volume = new JPanel(); volume.setBackground(Color.white); volume.setLayout(createSubPaneLayout()); positionNumericLabelTextFieldPair(volume, "Size x [voxels]", xDimensionField, 1, 1, 0); positionNumericLabelTextFieldPair(volume, "Spacing x [mm]", xSpacingField, 3, 1, 0); positionNumericLabelTextFieldPair(volume, "Size y [voxels]", yDimensionField, 1, 1, 30); positionNumericLabelTextFieldPair(volume, "Spacing y [mm]", ySpacingField, 3, 1, 30); positionNumericLabelTextFieldPair(volume, "Size z [voxels]", zDimensionField, 1, 1, 60); positionNumericLabelTextFieldPair(volume, "Spacing z [mm]", zSpacingField, 3, 1, 60); positionNumericLabelTextFieldPair(volume, "Index of (0mm/0mm/0mm) x [voxels]", xOriginVoxel, 1, 1, 90); xOriginVoxel.setEnabled(false); positionNumericLabelTextFieldPair(volume, "Index of (0mm/0mm/0mm) y [voxels]", yOriginVoxel, 1, 1, 120); yOriginVoxel.setEnabled(false); positionNumericLabelTextFieldPair(volume, "Index of (0mm/0mm/0mm) z [voxels]", zOriginVoxel, 1, 1, 150); zOriginVoxel.setEnabled(false); positionNumericLabelTextFieldPair(volume, "World coord. of vol. origin (0/0/0) x [mm]", xOriginWorld, 3, 1, 90); positionNumericLabelTextFieldPair(volume, "World coord. of vol. origin (0/0/0) y [mm]", yOriginWorld, 3, 1, 120); positionNumericLabelTextFieldPair(volume, "World coord. of vol. origin (0/0/0) z [mm]", zOriginWorld, 3, 1, 150); xSpacingField.getDocument().addDocumentListener(new VoxelWorldFieldUpdater(xOriginWorld, xOriginVoxel, xSpacingField)); xOriginWorld.getDocument().addDocumentListener(new VoxelWorldFieldUpdater(xOriginWorld, xOriginVoxel, xSpacingField)); ySpacingField.getDocument().addDocumentListener(new VoxelWorldFieldUpdater(yOriginWorld, yOriginVoxel, ySpacingField)); yOriginWorld.getDocument().addDocumentListener(new VoxelWorldFieldUpdater(yOriginWorld, yOriginVoxel, ySpacingField)); zSpacingField.getDocument().addDocumentListener(new VoxelWorldFieldUpdater(zOriginWorld, zOriginVoxel, zSpacingField)); zOriginWorld.getDocument().addDocumentListener(new VoxelWorldFieldUpdater(zOriginWorld, zOriginVoxel, zSpacingField)); volume.add(jCenterVolume, createConstraints(1, 1, 3, 1, GridBagConstraints.NORTH, GridBagConstraints.NONE, 200, 0, 0, 0)); jCenterVolume.addActionListener(this); volume.add(jDoubleVolumeResolution, createConstraints(1, 1, 3, 1, GridBagConstraints.NORTH, GridBagConstraints.NONE, 200, -300, 0, 0)); jDoubleVolumeResolution.addActionListener(this); volume.add(jHalfVolumeResolution, createConstraints(1, 1, 3, 1, GridBagConstraints.NORTH, GridBagConstraints.NONE, 200, 300, 0, 0)); jHalfVolumeResolution.addActionListener(this); positionLabelTextFieldPair(volume, "Maximum VOI file:", maxVOIPathField, 1, 2, 3, 0); GUIUtil.enableDragAndDrop(maxVOIPathField); return volume; } private void centerVolume() { double dimX = Double.parseDouble(xDimensionField.getText()); double dimY = Double.parseDouble(yDimensionField.getText()); double dimZ = Double.parseDouble(zDimensionField.getText()); double spacingX = Double.parseDouble(xSpacingField.getText()); double spacingY = Double.parseDouble(ySpacingField.getText()); double spacingZ = Double.parseDouble(zSpacingField.getText()); xOriginWorld.setText(new Double(-(dimX-1.0)/2.0 * spacingX).toString()); yOriginWorld.setText(new Double(-(dimY-1.0)/2.0 * spacingY).toString()); zOriginWorld.setText(new Double(-(dimZ-1.0)/2.0 * spacingZ).toString()); } JTextField detectorWidthField = new JTextField(); JTextField detectorHeightField = new JTextField(); JTextField pixelDimensionXField = new JTextField(); JTextField pixelDimensionYField = new JTextField(); JButton jGenerateDetector = new JButton("Configure absorption behavior"); JTextField projectionStackSizeField = new JTextField(); JTextField numSweepsField = new JTextField(); JTextField sourceToDetectorField = new JTextField(); JTextField sourceToPatientField = new JTextField(); JTextField projectionTableFileField = new JTextField(); JButton jParseGeometry = new JButton("Import"); JButton jGenerateGeometry = new JButton("Define a trajectory"); // new trajectory parameters JTextField averageAngularIncrement = new JTextField(); JTextField detectorOffsetU = new JTextField(); JTextField detectorOffsetV = new JTextField(); JTextField rotationAxis = new JTextField(); JComboBox DetectorUDirection = new JComboBox(camAxes); JComboBox DetectorVDirection = new JComboBox(camAxes); JComboBox optionList; JPanel trajectoryFromFile; JPanel trajectoryFromParameters; JPanel trajectoryPanel; JButton trajectoryEditorButton; /** * Trajectory Tab * @return */ private JPanel trajectoryPane(){ trajectoryPanel = new JPanel(); trajectoryPanel.setBackground(Color.white); GridBagLayout thisLayout = new GridBagLayout(); thisLayout.rowWeights = new double[] {0.0, 0.1, 0.1, 0.0}; thisLayout.rowHeights = new int[] {15, 30, 120, 15}; thisLayout.columnWeights = new double[] {0.0, 0.1, 0.0, 0.1, 0.0}; thisLayout.columnWidths = new int[] {15, 225, 15, 225, 15}; trajectoryPanel.setLayout(thisLayout); int x = 1; int y = 1; int topOffset = 0; int width = 3; String[] options = { "from file", "from parameters"}; trajectoryEditorButton = new JButton("Edit Trajetory"); trajectoryEditorButton.addActionListener(this); optionList = new JComboBox(options); optionList.addActionListener(this); JLabel label = new JLabel("Define trajectory:"); trajectoryPanel.add(label, createConstraints(x, y, width, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, topOffset + 3, 0, 0, 0)); trajectoryPanel.add(optionList, createConstraints(x, y, width, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, topOffset, 170, 0, 150)); trajectoryPanel.add(trajectoryEditorButton, createConstraints(x, y, width, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, topOffset-2, 470, 0, 30)); trajectoryFromFile = trajectoryFromFile(); trajectoryFromParameters = trajectoryFromParameters(); if (Configuration.getGlobalConfiguration().getProjectionTableFileName() != null){ optionList.setSelectedIndex(0); trajectoryPanel.add(trajectoryFromFile, createConstraints(0, 2, 5, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, 0, 0, 0, 0)); } else { optionList.setSelectedIndex(1); trajectoryPanel.add(trajectoryFromParameters, createConstraints(0, 2, 5, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, 0, 0, 0, 0)); } return trajectoryPanel; } private JPanel trajectoryFromParameters(){ JPanel volume = new JPanel(); volume.setBackground(Color.white); volume.setLayout(createSubPaneLayout()); positionNumericLabelTextFieldPair(volume, "Source to detector distance [mm]", sourceToDetectorField, 1, 1, 00); positionNumericLabelTextFieldPair(volume, "Source to patient distance [mm]", sourceToPatientField, 3, 1, 00); positionNumericLabelTextFieldPair(volume, "Projection stack size", projectionStackSizeField, 1, 1, 30); positionNumericLabelTextFieldPair(volume, "Number of sweeps", numSweepsField, 3, 1, 30); positionNumericLabelTextFieldPair(volume, "Rotation axis", rotationAxis, 1, 1, 60); positionNumericLabelTextFieldPair(volume, "Average angular increment [deg]", averageAngularIncrement, 3, 1, 60); positionNumericLabelTextFieldPair(volume, "Detector offset u [px]", detectorOffsetU, 1, 1, 90); positionNumericLabelTextFieldPair(volume, "Detector offset v [px]", detectorOffsetV, 3, 1, 90); int x = 1; int y = 1; int topOffset = 120; int width = 3; JLabel label = new JLabel("Detector u direction:"); volume.add(label, createConstraints(x, y, width, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, topOffset + 3, 0, 0, 0)); volume.add(DetectorUDirection, createConstraints(x, y, width, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, topOffset, 170, 0, 0)); topOffset = 150; JLabel label2 = new JLabel("Detector v direction:"); volume.add(label2, createConstraints(x, y, width, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, topOffset + 3, 0, 0, 0)); volume.add(DetectorVDirection, createConstraints(x, y, width, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, topOffset, 170, 0, 0)); volume.add(jGenerateGeometry, createConstraints(1, 1, 3, 1, GridBagConstraints.NORTH, GridBagConstraints.NONE, 200, 0, 0, 0)); jGenerateGeometry.addActionListener(this); return volume; } private JPanel trajectoryFromFile(){ JPanel volume = new JPanel(); volume.setBackground(Color.white); volume.setLayout(createSubPaneLayout()); positionLabelTextFieldButton(volume, "Projection geometry source file:", projectionTableFileField, 1, 1, 3, 0, jParseGeometry); jParseGeometry.addActionListener(this); GUIUtil.enableDragAndDrop(projectionTableFileField); return volume; } JTextField recentFileOneField = new JTextField(); JTextField recentFileTwoField = new JTextField(); ButtonGroup citationFormatGroup = new ButtonGroup(); JRadioButton bibButton = new JRadioButton("BibTeX"); JRadioButton medlineButton = new JRadioButton("Medline"); JCheckBox importFromDicom = new JCheckBox("Import geometry automatically from DICOM header"); JCheckBox extrapolateGeometry = new JCheckBox("Extraploate geometry if less than short-scan"); JCheckBox houns = new JCheckBox("Apply Hounsfield scaling"); private JPanel otherPane(){ JPanel volume = new JPanel(); volume.setBackground(Color.white); volume.setLayout(createSubPaneLayout()); medlineButton.setBackground(Color.WHITE); bibButton.setBackground(Color.WHITE); JLabel citationLabel = new JLabel("Citation format:"); volume.add(citationLabel, createConstraints(1, 1, 1, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, 10, 0, 0, 0)); volume.add(bibButton, createConstraints(3, 1, 1, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, 3, 0, 0, 0)); volume.add(medlineButton, createConstraints(3, 1, 1, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, 3, 120, 0, 0)); volume.add(importFromDicom, createConstraints(1, 1, 3, 1, GridBagConstraints.NORTH, GridBagConstraints.NONE, 50, 0, 0, 0)); volume.add(extrapolateGeometry, createConstraints(1, 1, 3, 1, GridBagConstraints.NORTH, GridBagConstraints.NONE, 80, 0, 0, 0)); volume.add(houns, createConstraints(1, 1, 3, 1, GridBagConstraints.NORTH, GridBagConstraints.NONE, 110, 0, 0, 0)); importFromDicom.setBackground(Color.WHITE); extrapolateGeometry.setBackground(Color.WHITE); houns.setBackground(Color.WHITE); citationFormatGroup.add(bibButton); citationFormatGroup.add(medlineButton); positionLabelTextFieldPair(volume, "File for most preferred use:", recentFileOneField, 1, 1, 3, 160); GUIUtil.enableDragAndDrop(recentFileOneField); positionLabelTextFieldPair(volume, "Reference Volume:", recentFileTwoField, 1, 1, 3, 180); GUIUtil.enableDragAndDrop(recentFileTwoField); return volume; } /** * Creates GridBagConstraints * @param x location x * @param y location y * @param width width of the element * @param height height of the element * @param anchor anchor type * @param fill fill type * @param top top inset * @param left left inset * @param bottom bottom inset * @param right right inset * @return the GridBagConstraints */ static GridBagConstraints createConstraints(int x, int y, int width, int height, int anchor, int fill, int top, int left, int bottom, int right){ return new GridBagConstraints(x, y, width, height, 0.0, 0.0, anchor, fill, new Insets(top, left, bottom, right), 0, 0); } private void initGUI() { try { GridBagLayout thisLayout = new GridBagLayout(); thisLayout.rowWeights = new double[] {0.0, 0.1, 0.1, 0.0}; thisLayout.rowHeights = new int[] {15, 150, 150, 15}; thisLayout.columnWeights = new double[] {0.1, 0.1, 0.1, 0.1}; thisLayout.columnWidths = new int[] {15, 300, 300, 15}; setTitle("Configuration"); getContentPane().setLayout(thisLayout); getContentPane().setBackground(Color.WHITE); { jTabbedPane = new JTabbedPane(); getContentPane().add(jTabbedPane, new GridBagConstraints(1, 1, 2, 2, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); } { jSaveButton = new JButton(); getContentPane().add(jSaveButton, new GridBagConstraints(1, 3, 2, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); jSaveButton.setText("save"); jSaveButton.addActionListener(this); } jTabbedPane.add("Volume", volumePane()); jTabbedPane.add("Detector", detectorPane()); jTabbedPane.add("Trajectory", trajectoryPane()); jTabbedPane.add("Other", otherPane()); jTabbedPane.add("Registry", regEditor); pack(); } catch(Exception e) { e.printStackTrace(); } } private class VoxelWorldFieldUpdater implements DocumentListener { private JTextField world; private JTextField voxel; private JTextField spacing; public VoxelWorldFieldUpdater (JTextField world, JTextField voxel, JTextField spacing) { this.world = world; this.voxel = voxel; this.spacing = spacing; } public void changedUpdate(DocumentEvent e) { updateDependentField(); } public void insertUpdate(DocumentEvent e) { updateDependentField(); } public void removeUpdate(DocumentEvent e) { updateDependentField(); } private void updateDependentField(){ SwingUtilities.invokeLater(new Runnable() { public void run() { try{ double spacingDouble = Double.parseDouble(spacing.getText()); double worldDouble = Double.parseDouble(world.getText()); double voxelDouble = General.worldToVoxel(0.0, spacingDouble, worldDouble); voxel.setText(new Double(voxelDouble).toString()); } catch (Exception e) { System.out.println("Could not parse field. Will update as soon as valid number is available."); } } }); } } } /* * Copyright (C) 2010-2014 - Andreas Maier * CONRAD is developed as an Open Source project under the GNU General Public License (GPL). */