// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.plugins.osmrec; import static org.openstreetmap.josm.tools.I18n.tr; import static org.openstreetmap.josm.tools.I18n.trn; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.FlowLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Scanner; import java.util.concurrent.CancellationException; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; import javax.swing.DefaultListModel; import javax.swing.GroupLayout; import javax.swing.GroupLayout.Alignment; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JProgressBar; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.SwingConstants; import javax.swing.border.EtchedBorder; import javax.swing.border.TitledBorder; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.DefaultTableModel; import javax.swing.text.JTextComponent; import org.geotools.geometry.jts.JTS; import org.geotools.referencing.CRS; import org.geotools.referencing.crs.DefaultGeocentricCRS; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.opengis.geometry.MismatchedDimensionException; import org.opengis.referencing.FactoryException; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.TransformException; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.actions.JosmAction; import org.openstreetmap.josm.command.ChangePropertyCommand; import org.openstreetmap.josm.data.osm.Node; import org.openstreetmap.josm.data.osm.OsmPrimitive; import org.openstreetmap.josm.data.osm.Tag; import org.openstreetmap.josm.data.osm.Way; import org.openstreetmap.josm.data.preferences.BooleanProperty; import org.openstreetmap.josm.data.preferences.IntegerProperty; import org.openstreetmap.josm.gui.ExtendedDialog; import org.openstreetmap.josm.gui.mappaint.MapPaintStyles; import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingComboBox; import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionListItem; import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionManager; //import org.openstreetmap.josm.gui.tagging.presets.TaggingPreset; import org.openstreetmap.josm.gui.util.GuiHelper; import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher; import org.openstreetmap.josm.io.XmlWriter; import org.openstreetmap.josm.plugins.osmrec.container.OSMWay; import org.openstreetmap.josm.plugins.osmrec.core.TrainWorker; import org.openstreetmap.josm.plugins.osmrec.extractor.LanguageDetector; import org.openstreetmap.josm.plugins.osmrec.extractor.SampleModelsExtractor; import org.openstreetmap.josm.plugins.osmrec.features.ClassFeatures; import org.openstreetmap.josm.plugins.osmrec.features.GeometryFeatures; import org.openstreetmap.josm.plugins.osmrec.features.OSMClassification; import org.openstreetmap.josm.plugins.osmrec.features.TextualFeatures; import org.openstreetmap.josm.plugins.osmrec.parsers.Mapper; import org.openstreetmap.josm.plugins.osmrec.parsers.OSMParser; import org.openstreetmap.josm.plugins.osmrec.parsers.Ontology; import org.openstreetmap.josm.plugins.osmrec.parsers.TextualStatistics; import org.openstreetmap.josm.plugins.osmrec.personalization.UserDataExtractAndTrainWorker; import org.openstreetmap.josm.tools.GBC; import org.openstreetmap.josm.tools.Shortcut; import org.openstreetmap.josm.tools.WindowGeometry; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.LinearRing; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.geom.Polygon; import de.bwaldvogel.liblinear.FeatureNode; import de.bwaldvogel.liblinear.Linear; import de.bwaldvogel.liblinear.Model; /** * Modified PropertiesDialog(since 5633) to serve the plugin functionality. * * @author imis-nkarag */ class OSMRecPluginHelper { private final DefaultTableModel tagData; private static Collection<String> fileHistory; private Map<File, Double> filesAndWeights = new HashMap<>(); private boolean useCombinedModel; //the most recent file from history. //all necessary files will reside in a directory of this file private static String MAIN_PATH; private static String MODEL_PATH; private static String TEXTUAL_LIST_PATH; private static Map<String, List<String>> indirectClasses; private static Map<String, Integer> indirectClassesWithIDs; private static LanguageDetector languageDetector; private static String bestModelPath; private boolean modelWithClasses; private final String modelWithClassesPath; private boolean useCustomSVMModel = false; private String customSVMModelPath; private final String combinedModelClasses; private final String combinedModel; // Selection that we are editing by using both dialogs Collection<OsmPrimitive> sel; private String changedKey; Comparator<AutoCompletionListItem> defaultACItemComparator = new Comparator<AutoCompletionListItem>() { @Override public int compare(AutoCompletionListItem o1, AutoCompletionListItem o2) { return String.CASE_INSENSITIVE_ORDER.compare(o1.getValue(), o2.getValue()); } }; private String lastAddKey = null; private String lastAddValue = null; public static final int DEFAULT_LRU_TAGS_NUMBER = 5; public static final int MAX_LRU_TAGS_NUMBER = 30; // LRU cache for recently added tags (http://java-planet.blogspot.com/2005/08/how-to-set-up-simple-lru-cache-using.html) private final Map<Tag, Void> recentTags = new LinkedHashMap<Tag, Void>(MAX_LRU_TAGS_NUMBER+1, 1.1f, true) { @Override protected boolean removeEldestEntry(Map.Entry<Tag, Void> eldest) { return size() > MAX_LRU_TAGS_NUMBER; } }; OSMRecPluginHelper(DefaultTableModel propertyData, Map<String, Map<String, Integer>> valueCount) { this.tagData = propertyData; fileHistory = Main.pref.getCollection("file-open.history"); if (!fileHistory.isEmpty()) { MAIN_PATH = (String) fileHistory.toArray()[0]; } else { MAIN_PATH = System.getProperty("user.home"); } MODEL_PATH = new File(MAIN_PATH).getParentFile() + "/OSMRec_models"; TEXTUAL_LIST_PATH = MODEL_PATH + "/textualList.txt"; combinedModelClasses = MODEL_PATH + "/combinedModel.1"; combinedModel = MODEL_PATH + "/combinedModel.0"; bestModelPath = MODEL_PATH + "/best_model"; customSVMModelPath = bestModelPath; modelWithClassesPath = MODEL_PATH + "/model_with_classes"; languageDetector = LanguageDetector.getInstance(MODEL_PATH + "/profiles"); SampleModelsExtractor sampleModelsExtractor = new SampleModelsExtractor(); sampleModelsExtractor.extractSampleSVMmodel("best_model", bestModelPath); sampleModelsExtractor.extractSampleSVMmodel("model_with_classes", modelWithClassesPath); } /** * Open the add selection dialog and add a new key/value to the table (and to the dataset, of course). */ public void addTag() { changedKey = null; sel = Main.main.getInProgressSelection(); if (sel == null || sel.isEmpty()) return; final AddTagsDialog addDialog = new AddTagsDialog(); addDialog.showDialog(); addDialog.destroyActions(); if (addDialog.getValue() == 1) addDialog.performTagAdding(); else addDialog.undoAllTagsAdding(); } /** * Edit the value in the tags table row. * @param row The row of the table from which the value is edited. * @param focusOnKey Determines if the initial focus should be set on key instead of value * @since 5653 */ public void editTag(final int row, boolean focusOnKey) { changedKey = null; sel = Main.main.getInProgressSelection(); String key = ""; @SuppressWarnings("unchecked") Map<String, Integer> dumPar = new HashMap<>(); dumPar.put(" ", -1); final TrainingDialog editDialog = new TrainingDialog(key, row, dumPar, focusOnKey); editDialog.showDialog(); } /** * If during last editProperty call user changed the key name, this key will be returned * Elsewhere, returns null. * @return The modified key, or {@code null} */ public String getChangedKey() { return changedKey; } /** * For a given key k, return a list of keys which are used as keys for * auto-completing values to increase the search space. * @param key the key k * @return a list of keys */ private static List<String> getAutocompletionKeys(String key) { if ("name".equals(key) || "addr:street".equals(key)) return Arrays.asList("addr:street", "name"); else return Arrays.asList(key); } /** * Load recently used tags from preferences if needed. */ public void loadTagsIfNeeded() { if (PROPERTY_REMEMBER_TAGS.get() && recentTags.isEmpty()) { recentTags.clear(); Collection<String> c = Main.pref.getCollection("properties.recent-tags"); Iterator<String> it = c.iterator(); String key, value; while (it.hasNext()) { key = it.next(); value = it.next(); recentTags.put(new Tag(key, value), null); } } } /** * Store recently used tags in preferences if needed. */ public void saveTagsIfNeeded() { if (PROPERTY_REMEMBER_TAGS.get() && !recentTags.isEmpty()) { List<String> c = new ArrayList<>(recentTags.size()*2); for (Tag t: recentTags.keySet()) { c.add(t.getKey()); c.add(t.getValue()); } Main.pref.putCollection("properties.recent-tags", c); } } /** * Warns user about a key being overwritten. * @param action The action done by the user. Must state what key is changed * @param togglePref The preference to save the checkbox state to * @return {@code true} if the user accepts to overwrite key, {@code false} otherwise */ private boolean warnOverwriteKey(String action, String togglePref) { ExtendedDialog ed = new ExtendedDialog( Main.parent, tr("Overwrite key"), new String[]{tr("Replace"), tr("Cancel")}); ed.setButtonIcons(new String[]{"purge", "cancel"}); ed.setContent(action+"\n"+ tr("The new key is already used, overwrite values?")); ed.setCancelButton(2); ed.toggleEnable(togglePref); ed.showDialog(); return ed.getValue() == 1; } public final class TrainingDialog extends AbstractTagsDialog { private static final int FIELD_COLUMNS = 4; private final JTextField inputFileField; private final JLabel inputFileLabel; private final JTextField topKField; private final JTextField cParameterField; private final JTextField frequencyField; private final JButton fileBrowseButton; private final JButton acceptConfigButton; private JRadioButton frequencyButton; private JRadioButton topKButton; private JCheckBox cParameterCheckBox; private final JButton resetConfigButton; private String inputFileValue; private Double cParameterValue = 0.0; private Integer topKvalue = 0; private Integer frequencyValue = 0; private boolean crossValidateFlag; private final JButton startTrainingButton; private final JLabel cErrorMessageLabel; private final JLabel topKErrorMessageLabel; private final JLabel inputFileErrorMessageLabel; private final JLabel frequencyErrorMessageLabel; private final JProgressBar trainingProgressBar; private final JRadioButton byAreaRadioButton; private final JRadioButton byTimeRadioButton; private final JLabel userNameLabel; private final JTextField userNameField; private final JTextField daysField; private final JLabel daysLabel; private final JCheckBox trainFromUserCheckBox; private final JPanel userHistoryPanel; private Integer daysValue; private String usernameValue; private TrainWorker trainWorker; private UserDataExtractAndTrainWorker userDataExtractAndTrainWorker; private TrainingDialog(String key, int row, Map<String, Integer> map, final boolean initialFocusOnKey) { super(Main.parent, tr("Training process configuration"), new String[] {tr("Cancel")}); setButtonIcons(new String[] {"ok", "cancel"}); setCancelButton(2); JPanel mainPanel = new JPanel(new BorderLayout(10, 10)); //6,6 JPanel configPanel = new JPanel(new BorderLayout(10, 10)); //6,6 //at NORTH of mainPanel JPanel inputPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); //NORTH at config panel JPanel paramPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); //WEST at config panel //config panel has EAST free JPanel southPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); //SOUTH at config panel userHistoryPanel = new JPanel(); //CENTER of config trainingProgressBar = new JProgressBar(0, 100); ButtonGroup paramGroup = new ButtonGroup(); ButtonGroup userGroup = new ButtonGroup(); inputFileLabel = new JLabel(); inputFileField = new JTextField(); cParameterField = new JTextField(); topKField = new JTextField(); frequencyField = new JTextField(); cParameterCheckBox = new JCheckBox("Define C parameter"); topKButton = new JRadioButton("Top-K terms"); frequencyButton = new JRadioButton("Max-Frequency"); fileBrowseButton = new JButton(); acceptConfigButton = new JButton("Accept Configuration"); resetConfigButton = new JButton("Reset Configuration/Cancel training"); startTrainingButton = new JButton("Train Model"); inputFileErrorMessageLabel = new JLabel(""); cErrorMessageLabel = new JLabel(""); topKErrorMessageLabel = new JLabel(""); frequencyErrorMessageLabel = new JLabel(""); trainFromUserCheckBox = new JCheckBox("Train Model From User"); byAreaRadioButton = new JRadioButton("By Area"); byTimeRadioButton = new JRadioButton("By Time"); userNameLabel = new JLabel("Username:"); userNameField = new JTextField(); daysLabel = new JLabel("Days: "); daysField = new JTextField(); cParameterCheckBox.setSelected(true); userHistoryPanel.setEnabled(false); byAreaRadioButton.setEnabled(false); byAreaRadioButton.setSelected(true); byTimeRadioButton.setEnabled(false); userNameLabel.setEnabled(false); userNameField.setEnabled(false); daysLabel.setEnabled(false); daysField.setEnabled(false); userNameField.setColumns(FIELD_COLUMNS); daysField.setColumns(FIELD_COLUMNS); Collection<String> fileHistory = Main.pref.getCollection("file-open.history"); if (!fileHistory.isEmpty()) { inputFileField.setText(MAIN_PATH); } fileBrowseButton.setText("..."); inputFileLabel.setText("OSM filepath: "); inputFileErrorMessageLabel.setForeground(Color.RED); inputFileErrorMessageLabel.setText(""); topKField.setText("50"); frequencyField.setText("200"); cParameterField.setText("0.01"); cParameterField.setColumns(FIELD_COLUMNS); cParameterField.setEditable(false); cParameterField.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); cErrorMessageLabel.setForeground(Color.RED); cErrorMessageLabel.setMinimumSize(new Dimension(150, 10)); topKButton.setSelected(true); topKField.setColumns(FIELD_COLUMNS); topKField.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); topKErrorMessageLabel.setForeground(Color.RED); frequencyField.setEditable(false); frequencyField.setColumns(FIELD_COLUMNS); frequencyField.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); frequencyErrorMessageLabel.setForeground(Color.RED); fileBrowseButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { inputFileChooserButtonActionPerformed(evt); } }); topKButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { if (topKButton.isSelected()) { frequencyField.setEditable(false); topKField.setEditable(true); } else { frequencyField.setEditable(true); topKField.setEditable(false); } } }); frequencyButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { if (frequencyButton.isSelected()) { topKField.setEditable(false); frequencyField.setEditable(true); } else { topKField.setEditable(true); frequencyField.setEditable(false); } } }); cParameterCheckBox.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { if (cParameterCheckBox.isSelected()) { cParameterField.setEditable(true); } else { cParameterField.setEditable(false); } } }); acceptConfigButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { acceptConfigButtonActionPerformed(evt); } }); resetConfigButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { resetConfigButtonActionPerformed(); } }); startTrainingButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { if (!acceptConfigButton.isEnabled()) { startTraining(); } else { System.out.println("Set values first!"); } } }); trainFromUserCheckBox.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { if (trainFromUserCheckBox.isSelected()) { userHistoryPanel.setEnabled(true); byAreaRadioButton.setEnabled(true); byTimeRadioButton.setEnabled(true); userNameLabel.setEnabled(true); userNameField.setEnabled(true); daysLabel.setEnabled(true); daysField.setEnabled(true); } else { userHistoryPanel.setEnabled(false); byAreaRadioButton.setEnabled(false); byTimeRadioButton.setEnabled(false); userNameLabel.setEnabled(false); userNameField.setEnabled(false); daysLabel.setEnabled(false); daysField.setEnabled(false); } } }); byAreaRadioButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { if (byAreaRadioButton.isSelected()) { daysField.setEditable(false); } else { daysField.setEditable(true); } } }); byTimeRadioButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { if (byTimeRadioButton.isSelected()) { daysField.setEditable(true); } else { daysField.setEditable(false); } } }); //grouplayout for input panel buildInputPanelGroupLayout(inputPanel); //grouplayout for param panel buildParamPanelGroupLayout(paramPanel); inputPanel.add(inputFileLabel); inputPanel.add(inputFileField); inputPanel.add(fileBrowseButton); inputPanel.add(inputFileErrorMessageLabel); paramGroup.add(topKButton); paramGroup.add(frequencyButton); paramPanel.add(cParameterCheckBox); paramPanel.add(cParameterField); paramPanel.add(cErrorMessageLabel); paramPanel.add(topKButton); paramPanel.add(topKField); paramPanel.add(topKErrorMessageLabel); paramPanel.add(frequencyButton); paramPanel.add(frequencyField); paramPanel.add(frequencyErrorMessageLabel); southPanel.add(acceptConfigButton); southPanel.add(resetConfigButton); southPanel.add(trainFromUserCheckBox); userGroup.add(byAreaRadioButton); userGroup.add(byTimeRadioButton); userHistoryPanel.add(byAreaRadioButton); userHistoryPanel.add(byTimeRadioButton); userHistoryPanel.add(daysLabel); userHistoryPanel.add(daysField); userHistoryPanel.add(userNameLabel); userHistoryPanel.add(userNameField); //grouplayout for user history panel /* userNameLabel userField arearadiobutton timeradiobutton daysLabel daysField */ buildUserHistoryPanelGroupLayout(); configPanel.add(inputPanel, BorderLayout.NORTH); configPanel.add(userHistoryPanel, BorderLayout.EAST); configPanel.add(paramPanel, BorderLayout.WEST); configPanel.add(southPanel, BorderLayout.SOUTH); userHistoryPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory .createEtchedBorder(EtchedBorder.LOWERED, Color.GRAY, Color.WHITE), "Train by user History")); paramPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory .createEtchedBorder(EtchedBorder.LOWERED, Color.GRAY, Color.WHITE), "SVM Configuration")); inputPanel.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED, Color.GRAY, Color.WHITE)); configPanel.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED, Color.GRAY, Color.WHITE)); mainPanel.add(configPanel, BorderLayout.NORTH); mainPanel.add(startTrainingButton, BorderLayout.CENTER); mainPanel.add(trainingProgressBar, BorderLayout.SOUTH); AutoCompletionManager autocomplete = Main.getLayerManager().getEditLayer().data.getAutoCompletionManager(); List<AutoCompletionListItem> keyList = autocomplete.getKeys(); Collections.sort(keyList, defaultACItemComparator); setContent(mainPanel, false); } private void buildInputPanelGroupLayout(JPanel inputPanel) { GroupLayout inputGroupLayout = new GroupLayout(inputPanel); inputPanel.setLayout(inputGroupLayout); inputGroupLayout.setAutoCreateGaps(true); inputGroupLayout.setAutoCreateContainerGaps(true); GroupLayout.SequentialGroup inputHorGroup = inputGroupLayout.createSequentialGroup(); inputHorGroup.addGroup(inputGroupLayout.createParallelGroup().addComponent(inputFileLabel). addComponent(inputFileErrorMessageLabel)); inputHorGroup.addGroup(inputGroupLayout.createParallelGroup().addComponent(inputFileField)); inputHorGroup.addGroup(inputGroupLayout.createParallelGroup().addComponent(fileBrowseButton)); inputGroupLayout.setHorizontalGroup(inputHorGroup); GroupLayout.SequentialGroup inputVerGroup = inputGroupLayout.createSequentialGroup(); inputVerGroup.addGroup(inputGroupLayout.createParallelGroup(Alignment.LEADING).addComponent(inputFileLabel). addComponent(inputFileField).addComponent(fileBrowseButton)); inputVerGroup.addGroup(inputGroupLayout.createParallelGroup(Alignment.LEADING). addComponent(inputFileErrorMessageLabel)); inputGroupLayout.setVerticalGroup(inputVerGroup); } private void buildParamPanelGroupLayout(JPanel paramPanel) { GroupLayout paramGroupLayout = new GroupLayout(paramPanel); paramPanel.setLayout(paramGroupLayout); paramGroupLayout.setAutoCreateGaps(true); paramGroupLayout.setAutoCreateContainerGaps(true); GroupLayout.SequentialGroup paramHorGroup = paramGroupLayout.createSequentialGroup(); paramHorGroup.addGroup(paramGroupLayout.createParallelGroup().addComponent(topKButton). addComponent(frequencyButton).addComponent(cParameterCheckBox)); paramHorGroup.addGroup(paramGroupLayout.createParallelGroup().addComponent(cParameterField). addComponent(topKField).addComponent(frequencyField)); paramHorGroup.addGroup(paramGroupLayout.createParallelGroup().addComponent(cErrorMessageLabel). addComponent(topKErrorMessageLabel).addComponent(frequencyErrorMessageLabel)); paramGroupLayout.setHorizontalGroup(paramHorGroup); GroupLayout.SequentialGroup paramVerGroup = paramGroupLayout.createSequentialGroup(); paramVerGroup.addGroup(paramGroupLayout.createParallelGroup(Alignment.BASELINE). addComponent(cParameterCheckBox).addComponent(cParameterField).addComponent(cErrorMessageLabel)); paramVerGroup.addGroup(paramGroupLayout.createParallelGroup(Alignment.BASELINE).addComponent(topKButton). addComponent(topKField).addComponent(topKErrorMessageLabel)); paramVerGroup.addGroup(paramGroupLayout.createParallelGroup(Alignment.BASELINE). addComponent(frequencyButton).addComponent(frequencyField).addComponent(frequencyErrorMessageLabel)); paramGroupLayout.setVerticalGroup(paramVerGroup); } private void buildUserHistoryPanelGroupLayout() { GroupLayout userHistoryGroupLayout = new GroupLayout(userHistoryPanel); userHistoryPanel.setLayout(userHistoryGroupLayout); userHistoryGroupLayout.setAutoCreateGaps(true); userHistoryGroupLayout.setAutoCreateContainerGaps(true); userHistoryGroupLayout.linkSize(SwingConstants.HORIZONTAL, userNameField, daysLabel, daysField); GroupLayout.SequentialGroup userHistoryHorGroup = userHistoryGroupLayout.createSequentialGroup(); userHistoryHorGroup.addGroup(userHistoryGroupLayout.createParallelGroup().addComponent(userNameLabel) .addComponent(byAreaRadioButton).addComponent(byTimeRadioButton)); userHistoryHorGroup.addGroup(userHistoryGroupLayout.createParallelGroup().addComponent(userNameField) .addComponent(daysLabel)); userHistoryHorGroup.addGroup(userHistoryGroupLayout.createParallelGroup().addComponent(daysField)); userHistoryGroupLayout.setHorizontalGroup(userHistoryHorGroup); GroupLayout.SequentialGroup userHistoryVerGroup = userHistoryGroupLayout.createSequentialGroup(); userHistoryVerGroup.addGroup(userHistoryGroupLayout.createParallelGroup(Alignment.BASELINE). addComponent(userNameLabel).addComponent(userNameField)); userHistoryVerGroup.addGroup(userHistoryGroupLayout.createParallelGroup(Alignment.BASELINE). addComponent(byAreaRadioButton)); userHistoryVerGroup.addGroup(userHistoryGroupLayout.createParallelGroup(Alignment.BASELINE). addComponent(byTimeRadioButton).addComponent(daysLabel).addComponent(daysField)); userHistoryGroupLayout.setVerticalGroup(userHistoryVerGroup); } private void inputFileChooserButtonActionPerformed(ActionEvent evt) { try { final File file = new File(inputFileField.getText()); final JFileChooser fileChooser = new JFileChooser(file); final int returnVal = fileChooser.showOpenDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { inputFileField.setText(fileChooser.getSelectedFile().getAbsolutePath()); } } catch (RuntimeException ex) { Main.warn(ex); } } private void acceptConfigButtonActionPerformed(ActionEvent evt) { //parse values inputFileValue = inputFileField.getText(); if (!new File(inputFileValue).exists()) { inputFileErrorMessageLabel.setText("OSM file does not exist"); resetConfigButtonActionPerformed(); return; } if (cParameterCheckBox.isSelected()) { String c = cParameterField.getText(); try { cParameterValue = Double.parseDouble(c.replace(",", ".")); cErrorMessageLabel.setText(""); } catch (NumberFormatException ex) { cErrorMessageLabel.setText("Must be a number!"); System.out.println("c must be a number!" + ex); //make empty textLabel beside c param to notify errors resetConfigButtonActionPerformed(); return; } crossValidateFlag = false; } else { crossValidateFlag = true; } if (topKButton.isSelected()) { String k = topKField.getText(); try { topKvalue = Integer.parseInt(k); topKErrorMessageLabel.setText(""); } catch (NumberFormatException ex) { topKErrorMessageLabel.setText("Must be an Integer!"); resetConfigButtonActionPerformed(); return; } } else { String f = frequencyField.getText(); try { frequencyValue = Integer.parseInt(f); frequencyErrorMessageLabel.setText(""); } catch (NumberFormatException ex) { frequencyErrorMessageLabel.setText("Must be an Integer!"); resetConfigButtonActionPerformed(); return; } } if (trainFromUserCheckBox.isSelected()) { usernameValue = userNameField.getText(); if (byTimeRadioButton.isSelected()) { try { daysValue = Integer.parseInt(daysField.getText()); } catch (NumberFormatException ex) { daysField.setText("Integer!"); Main.warn(ex); } } userHistoryPanel.setEnabled(false); byAreaRadioButton.setEnabled(false); byTimeRadioButton.setEnabled(false); userNameLabel.setEnabled(false); userNameField.setEnabled(false); daysLabel.setEnabled(false); daysField.setEnabled(false); } System.out.println("Running configuration:" + "\nC parameter: " + cParameterValue +" \ntopK: " + topKvalue + "\nMax Frequency: " + frequencyValue + "\nCross Validate?: " + crossValidateFlag); trainFromUserCheckBox.setEnabled(false); inputFileField.setEditable(false); cParameterField.setEditable(false); topKField.setEditable(false); frequencyField.setEditable(false); cParameterCheckBox.setEnabled(false); topKButton.setEnabled(false); frequencyButton.setEnabled(false); acceptConfigButton.setEnabled(false); fileBrowseButton.setEnabled(false); } private void resetConfigButtonActionPerformed() { if (trainWorker != null) { try { trainWorker.cancel(true); } catch (CancellationException ex) { startTrainingButton.setEnabled(true); System.out.println(ex); } } if (userDataExtractAndTrainWorker != null) { try { userDataExtractAndTrainWorker.cancel(true); } catch (CancellationException ex) { startTrainingButton.setEnabled(true); System.out.println(ex); } } inputFileField.setEditable(true); cParameterField.setEditable(true); topKField.setEditable(true); frequencyField.setEditable(true); cParameterCheckBox.setEnabled(true); topKButton.setEnabled(true); frequencyButton.setEnabled(true); acceptConfigButton.setEnabled(true); fileBrowseButton.setEnabled(true); trainFromUserCheckBox.setEnabled(true); if (trainFromUserCheckBox.isSelected()) { userHistoryPanel.setEnabled(true); byAreaRadioButton.setEnabled(true); byTimeRadioButton.setEnabled(true); userNameLabel.setEnabled(true); userNameField.setEnabled(true); daysLabel.setEnabled(true); daysField.setEnabled(true); } } private void startTraining() { startTrainingButton.setEnabled(false); if (trainFromUserCheckBox.isSelected()) { //if user training. train by area or days EventQueue.invokeLater(new Runnable() { @Override public void run() { userDataExtractAndTrainWorker = new UserDataExtractAndTrainWorker(inputFileValue, usernameValue, daysValue, byAreaRadioButton.isSelected(), crossValidateFlag, cParameterValue, topKvalue, frequencyValue, topKButton.isSelected(), languageDetector); userDataExtractAndTrainWorker.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if ("progress".equals(evt.getPropertyName())) { int progress = (Integer) evt.getNewValue(); trainingProgressBar.setValue(progress); if (progress == 100) { startTrainingButton.setEnabled(true); } } } }); try { System.out.println("executing userDataExtractAndTrainWorker Thread.."); userDataExtractAndTrainWorker.execute(); } catch (Exception ex) { Logger.getLogger(OSMRecPluginHelper.class.getName()).log(Level.SEVERE, null, ex); } } }); } else { EventQueue.invokeLater(new Runnable() { @Override public void run() { trainWorker = new TrainWorker(inputFileValue, crossValidateFlag, cParameterValue, topKvalue, frequencyValue, topKButton.isSelected(), languageDetector); trainWorker.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if ("progress".equals(evt.getPropertyName())) { int progress = (Integer) evt.getNewValue(); trainingProgressBar.setValue(progress); if (progress == 100) { startTrainingButton.setEnabled(true); } } } }); try { trainWorker.execute(); } catch (Exception ex) { Logger.getLogger(OSMRecPluginHelper.class.getName()).log(Level.SEVERE, null, ex); } } }); } } } public static final BooleanProperty PROPERTY_FIX_TAG_LOCALE = new BooleanProperty("properties.fix-tag-combobox-locale", false); public static final BooleanProperty PROPERTY_REMEMBER_TAGS = new BooleanProperty("properties.remember-recently-added-tags", true); public static final IntegerProperty PROPERTY_RECENT_TAGS_NUMBER = new IntegerProperty("properties.recently-added-tags", DEFAULT_LRU_TAGS_NUMBER); abstract static class AbstractTagsDialog extends ExtendedDialog { AutoCompletingComboBox keys; AutoCompletingComboBox values; AbstractTagsDialog(Component parent, String title, String[] buttonTexts) { super(parent, title, buttonTexts); addMouseListener(new PopupMenuLauncher(popupMenu)); } @Override public void setupDialog() { super.setupDialog(); final Dimension size = getSize(); // Set resizable only in width setMinimumSize(size); setPreferredSize(size); // setMaximumSize does not work, and never worked, but still it seems not to bother Oracle to fix this 10-year-old bug // https://bugs.openjdk.java.net/browse/JDK-6200438 // https://bugs.openjdk.java.net/browse/JDK-6464548 setRememberWindowGeometry(getClass().getName() + ".geometry", WindowGeometry.centerInWindow(Main.parent, size)); } @Override public void setVisible(boolean visible) { // Do not want dialog to be resizable in height, as its size may increase each time because of the recently added tags // So need to modify the stored geometry (size part only) in order to use the automatic positioning mechanism if (visible) { WindowGeometry geometry = initWindowGeometry(); Dimension storedSize = geometry.getSize(); Dimension size = getSize(); if (!storedSize.equals(size)) { if (storedSize.width < size.width) { storedSize.width = size.width; } if (storedSize.height != size.height) { storedSize.height = size.height; } rememberWindowGeometry(geometry); } if (keys != null) { keys.setFixedLocale(PROPERTY_FIX_TAG_LOCALE.get()); } } super.setVisible(visible); } /** * Create a focus handling adapter and apply in to the editor component of value * autocompletion box. * @param autocomplete Manager handling the autocompletion * @param comparator Class to decide what values are offered on autocompletion * @return The created adapter */ protected FocusAdapter addFocusAdapter(final AutoCompletionManager autocomplete, final Comparator<AutoCompletionListItem> comparator) { // get the combo box' editor component JTextComponent editor = (JTextComponent) values.getEditor().getEditorComponent(); // Refresh the values model when focus is gained FocusAdapter focus = new FocusAdapter() { @Override public void focusGained(FocusEvent e) { String key = keys.getEditor().getItem().toString(); List<AutoCompletionListItem> valueList = autocomplete.getValues(getAutocompletionKeys(key)); Collections.sort(valueList, comparator); values.setPossibleACItems(valueList); values.getEditor().selectAll(); } }; editor.addFocusListener(focus); return focus; } protected JPopupMenu popupMenu = new JPopupMenu() { JCheckBoxMenuItem fixTagLanguageCb = new JCheckBoxMenuItem( new AbstractAction(tr("Use English language for tag by default")) { @Override public void actionPerformed(ActionEvent e) { boolean sel = ((JCheckBoxMenuItem) e.getSource()).getState(); PROPERTY_FIX_TAG_LOCALE.put(sel); } }); { add(fixTagLanguageCb); fixTagLanguageCb.setState(PROPERTY_FIX_TAG_LOCALE.get()); } }; } class ModelSettingsDialog extends JPanel { private final JLabel chooseModelLabel; private final JButton chooseModelButton; private final JTextField chooseModelTextField; private final DefaultListModel<String> combinationDefaultListModel = new DefaultListModel<>(); private final JList<String> modelCombinationList = new JList<>(combinationDefaultListModel); private final JPanel modelCombinationPanel; private final JPanel weightsPanel; private final JCheckBox useModelCombinationCheckbox; private final JButton acceptWeightsButton; private final JButton resetWeightsButton; private final JButton removeSelectedModelButton; private Map<JTextField, String> weightFieldsAndPaths = new HashMap<>(); private final Map<String, Double> normalizedPathsAndWeights = new HashMap<>(); private final JOptionPane pane; private final JDialog dlg; private final JPanel mainPanel; private final JPanel singleSelectionPanel; private final JPanel setResetWeightsPanel; private final JScrollPane combinationScrollPane; private final JScrollPane singleSelectionScrollPane; private final TitledBorder modelTitle; private final TitledBorder weightTitle; private final TitledBorder combineTitle; private final Dimension singleSelectionDimension; private final Dimension modelCombinationDimension; private final Dimension mainPanelDimension; ModelSettingsDialog(Collection<OsmPrimitive> sel1, final AddTagsDialog addDialog) { loadPreviousCombinedSVMModel(); singleSelectionDimension = new Dimension(470, 70); modelCombinationDimension = new Dimension(450, 250); mainPanelDimension = new Dimension(600, 350); //------- <NORTH of main> ---------// mainPanel = new JPanel(new BorderLayout(10, 10)); singleSelectionPanel = new JPanel(new BorderLayout(10, 10)); setResetWeightsPanel = new JPanel(); chooseModelLabel = new JLabel("Choose a Model:"); chooseModelTextField = new JTextField(); chooseModelButton = new JButton("..."); chooseModelTextField.setText(MODEL_PATH); singleSelectionPanel.add(chooseModelLabel, BorderLayout.NORTH); singleSelectionPanel.add(chooseModelTextField, BorderLayout.WEST); singleSelectionPanel.add(chooseModelButton, BorderLayout.EAST); singleSelectionScrollPane = new JScrollPane(singleSelectionPanel); singleSelectionScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); singleSelectionScrollPane.setPreferredSize(singleSelectionDimension); //------- </NORTH of main> ---------// //------- <WEST of main> ---------// modelCombinationList.setFixedCellHeight(20); modelCombinationList.setEnabled(false); modelCombinationPanel = new JPanel(new BorderLayout(10, 10)); weightsPanel = new JPanel(); weightsPanel.setLayout(new BoxLayout(weightsPanel, BoxLayout.Y_AXIS)); weightsPanel.setEnabled(false); acceptWeightsButton = new JButton("Set Weights/Normalize"); resetWeightsButton = new JButton("Reset Weights"); removeSelectedModelButton = new JButton("Remove Selected"); setResetWeightsPanel.add(acceptWeightsButton); setResetWeightsPanel.add(resetWeightsButton); setResetWeightsPanel.add(removeSelectedModelButton); removeSelectedModelButton.setEnabled(false); acceptWeightsButton.setEnabled(false); resetWeightsButton.setEnabled(false); modelCombinationPanel.add(modelCombinationList, BorderLayout.CENTER); modelCombinationPanel.add(weightsPanel, BorderLayout.EAST); modelCombinationPanel.add(setResetWeightsPanel, BorderLayout.SOUTH); combinationScrollPane = new JScrollPane(modelCombinationPanel); combinationScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); combinationScrollPane.setPreferredSize(modelCombinationDimension); //new Dimension(450, 250) // w/h //------- </WEST of main> ---------// //------- <SOUTH of main> ---------// useModelCombinationCheckbox = new JCheckBox("Combine different models?"); //------- </SOUTH of main> ---------// //------- <Borders> ---------// modelTitle = BorderFactory.createTitledBorder("Models"); weightTitle = BorderFactory.createTitledBorder("W"); combineTitle = BorderFactory.createTitledBorder("Combine Models"); modelCombinationList.setBorder(modelTitle); weightsPanel.setBorder(weightTitle); for (Entry<JTextField, String> entry : weightFieldsAndPaths.entrySet()) { combinationDefaultListModel.addElement(entry.getValue()); JTextField weightTextField = new JTextField("0.00"); weightTextField.setMaximumSize(new Dimension(80, 20)); weightsPanel.add(entry.getKey()); } //modelCombinationPanel.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED, Color.GRAY, Color.WHITE)); modelCombinationPanel.setBorder(combineTitle); singleSelectionPanel.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED, Color.GRAY, Color.WHITE)); //------- </Borders> ---------// chooseModelButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { modelChooserButtonActionPerformed(evt); } }); useModelCombinationCheckbox.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { userCombinationCheckboxActionPerformed(evt); } }); acceptWeightsButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { acceptWeightsButtonActionPerformed(evt); } }); resetWeightsButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { resetWeightsButtonActionPerformed(evt); } }); removeSelectedModelButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { removeSelectedModelButtonActionPerformed(evt); } }); mainPanel.add(singleSelectionScrollPane, BorderLayout.NORTH); mainPanel.add(combinationScrollPane, BorderLayout.CENTER); mainPanel.add(useModelCombinationCheckbox, BorderLayout.SOUTH); mainPanel.setPreferredSize(mainPanelDimension); this.add(mainPanel); pane = new JOptionPane(this, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION) { @Override public void setValue(Object newValue) { super.setValue(newValue); if (newValue instanceof Integer && (int) newValue == 0 && useModelCombinationCheckbox.isSelected()) { System.out.println("model settings button value: " + newValue); System.out.println("\nUSE COMBINED MODEL\n"); useCombinedModel = true; useCustomSVMModel = false; addDialog.loadSVMmodel(); addDialog.createOSMObject(sel); saveCombinedModel(); dlg.setVisible(false); } else if (newValue instanceof Integer && (int) newValue == -1 && useModelCombinationCheckbox.isSelected()) { System.out.println("model settings button value: " + newValue); useCombinedModel = false; useCustomSVMModel = false; System.out.println("Use combined model"); addDialog.loadSVMmodel(); addDialog.createOSMObject(sel); dlg.setVisible(false); } else if (newValue instanceof Integer && (int) newValue == 0 && !useModelCombinationCheckbox.isSelected()) { System.out.println("model settings button value: " + newValue); System.out.println("Don t use combined model, use custom model"); useCombinedModel = false; useCustomSVMModel = true; addDialog.loadSVMmodel(); addDialog.createOSMObject(sel); dlg.setVisible(false); } else if (newValue instanceof Integer && (int) newValue == -1 && !useModelCombinationCheckbox.isSelected()) { System.out.println("model settings button value: " + newValue); System.out.println("Don t use combined model, use custom model"); useCombinedModel = false; useCustomSVMModel = false; addDialog.loadSVMmodel(); addDialog.createOSMObject(sel); dlg.setVisible(false); } else if (newValue == null || newValue.equals("uninitializedValue")) { System.out.println("uninitializedValue, do nothing"); } } }; dlg = pane.createDialog(Main.parent, tr("Model Settings")); dlg.setVisible(true); } public void makeVisible(boolean visible) { dlg.setVisible(true); } private void modelChooserButtonActionPerformed(ActionEvent evt) { try { final File file = new File(chooseModelTextField.getText()); final JFileChooser fileChooser = new JFileChooser(file); final int returnVal = fileChooser.showOpenDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { chooseModelTextField.setText(fileChooser.getSelectedFile().getAbsolutePath()); useCustomSVMModel = true; customSVMModelPath = fileChooser.getSelectedFile().getAbsolutePath(); } if (useModelCombinationCheckbox.isSelected()) { String svmModelPath = fileChooser.getSelectedFile().getAbsolutePath(); String svmModelText; if (System.getProperty("os.name").contains("ux")) { if (svmModelPath.contains("/")) { svmModelText = svmModelPath.substring(svmModelPath.lastIndexOf("/")); } else { svmModelText = svmModelPath; } } else { if (svmModelPath.contains("\\")) { svmModelText = svmModelPath.substring(svmModelPath.lastIndexOf("\\")); } else { svmModelText = svmModelPath; } } combinationDefaultListModel.addElement(svmModelText); JTextField weightTextField = new JTextField("0.00"); weightFieldsAndPaths.put(weightTextField, svmModelPath); System.out.println("weights size: " + weightFieldsAndPaths.size()); weightTextField.setMaximumSize(new Dimension(80, 20)); weightsPanel.add(weightTextField); //add additional textbox } } catch (RuntimeException ex) { Main.warn(ex); } } private void userCombinationCheckboxActionPerformed(java.awt.event.ActionEvent evt) { if (useModelCombinationCheckbox.isSelected()) { useCombinedModel = true; useCustomSVMModel = false; //reseting the selected custom SVM model only here removeSelectedModelButton.setEnabled(true); acceptWeightsButton.setEnabled(true); resetWeightsButton.setEnabled(true); chooseModelTextField.setEnabled(false); modelCombinationList.setEnabled(true); weightsPanel.setEnabled(true); Component[] weightPanelComponents = weightsPanel.getComponents(); for (Component weightPanelComponent : weightPanelComponents) { weightPanelComponent.setEnabled(true); } } else { useCombinedModel = false; useCustomSVMModel = true; removeSelectedModelButton.setEnabled(false); acceptWeightsButton.setEnabled(false); resetWeightsButton.setEnabled(false); chooseModelTextField.setEnabled(true); modelCombinationList.setEnabled(false); weightsPanel.setEnabled(false); Component[] weightPanelComponents = weightsPanel.getComponents(); for (Component weightPanelComponent : weightPanelComponents) { weightPanelComponent.setEnabled(false); } } } private void acceptWeightsButtonActionPerformed(ActionEvent evt) { int weightsCount = 0; removeSelectedModelButton.setEnabled(false); double weightSum = 0; for (JTextField weightField : weightFieldsAndPaths.keySet()) { if (weightField.getText().equals("")) { weightField.setText("0.00"); } try { //TODO replace "," with "." to parse doubles with commas Double weightValue = Double.parseDouble(weightField.getText()); weightValue = Math.abs(weightValue); weightSum += weightValue; } catch (NumberFormatException ex) { Main.warn(ex); } weightsCount++; } if (!filesAndWeights.isEmpty()) { filesAndWeights.clear(); } for (JTextField weightField : weightFieldsAndPaths.keySet()) { try { Double weightValue = Double.parseDouble(weightField.getText()); weightValue = Math.abs(weightValue)/weightSum; //normalize if (weightSum == 0) { weightValue = 1.0/weightsCount; } weightField.setText(new DecimalFormat("#.##").format(weightValue)); normalizedPathsAndWeights.put(weightFieldsAndPaths.get(weightField), weightValue); filesAndWeights.put(new File(weightFieldsAndPaths.get(weightField)), weightValue); System.out.println("normalized: " + weightFieldsAndPaths.get(weightField) + "->" + weightValue); weightField.setEnabled(false); } catch (NumberFormatException ex) { Main.warn(ex); } } useCombinedModel = true; useCustomSVMModel = false; } private void resetWeightsButtonActionPerformed(ActionEvent evt) { removeSelectedModelButton.setEnabled(true); for (JTextField weightField : weightFieldsAndPaths.keySet()) { weightField.setEnabled(true); } } private void removeSelectedModelButtonActionPerformed(ActionEvent evt) { int index = modelCombinationList.getSelectedIndex(); String modelToBeRemoved = combinationDefaultListModel.get(index); combinationDefaultListModel.remove(index); System.out.println("model to be removed: " + modelToBeRemoved); Iterator<Entry<JTextField, String>> it = weightFieldsAndPaths.entrySet().iterator(); while (it.hasNext()) { Entry<JTextField, String> en = it.next(); if (en.getValue().equals(modelToBeRemoved)) { it.remove(); } } System.out.println("model to be removed: " + modelToBeRemoved); weightsPanel.remove(index); weightsPanel.revalidate(); weightsPanel.repaint(); } @SuppressWarnings("unchecked") private void loadPreviousCombinedSVMModel() { File combinedModelClassesFile = new File(combinedModelClasses); if (combinedModelClassesFile.exists()) { FileInputStream fileIn = null; ObjectInputStream in = null; try { fileIn = new FileInputStream(combinedModelClassesFile); in = new ObjectInputStream(fileIn); weightFieldsAndPaths = (Map<JTextField, String>) in.readObject(); } catch (FileNotFoundException ex) { Logger.getLogger(OSMRecPluginHelper.class.getName()).log(Level.SEVERE, null, ex); } catch (IOException | ClassNotFoundException ex) { Logger.getLogger(OSMRecPluginHelper.class.getName()).log(Level.SEVERE, null, ex); } finally { try { if (in != null) { in.close(); } if (fileIn != null) { fileIn.close(); } } catch (IOException ex) { Logger.getLogger(OSMRecPluginHelper.class.getName()).log(Level.SEVERE, null, ex); } } } else { try { combinedModelClassesFile.createNewFile(); } catch (IOException ex) { Logger.getLogger(OSMRecPluginHelper.class.getName()).log(Level.SEVERE, null, ex); } } } private void saveCombinedModel() { try (FileOutputStream fileOut = new FileOutputStream(combinedModelClasses); ObjectOutputStream out = new ObjectOutputStream(fileOut)) { out.writeObject(weightFieldsAndPaths); } catch (IOException e) { System.out.println("serialize error" + e); } } } class AddTagsDialog extends AbstractTagsDialog { List<JosmAction> recentTagsActions = new ArrayList<>(); // Counter of added commands for possible undo private int commandCount; private final JLabel recommendedClassesLabel; private final JButton modelSettingsButton; private final JButton addAndContinueButton; private final DefaultListModel<String> model; private final JList<String> categoryList; private Model modelSVM; private int modelSVMLabelSize; private int[] modelSVMLabels; private Map<String, String> mappings; private Map<String, Integer> mapperWithIDs; private Map<Integer, String> idsWithMappings; private List<String> textualList = new ArrayList<>(); private final JCheckBox useTagsCheckBox; private ModelSettingsDialog modelSettingsDialog; private static final int RECOMMENDATIONS_SIZE = 10; AddTagsDialog() { super(Main.parent, tr("Add value?"), new String[] {tr("OK"), tr("Cancel")}); setButtonIcons(new String[] {"ok", "cancel"}); setCancelButton(2); configureContextsensitiveHelp("/Dialog/AddValue", true /* show help button */); final AddTagsDialog addTagsDialog = this; loadOntology(); //if the user did not train a model by running the training process //the list does not exist in a file and so we load the default list from the jar. System.out.println("path for textual: " + TEXTUAL_LIST_PATH); File textualListFile = new File(TEXTUAL_LIST_PATH); if (textualListFile.exists()) { loadTextualList(textualListFile); } else { loadDefaultTextualList(); } //if training process has not been performed, we use two sample SVM models, extracted from the jar JPanel splitPanel = new JPanel(new BorderLayout(10, 10)); JPanel mainPanel = new JPanel(new GridBagLayout()); //original panel, will be wrapped by the splitPanel JPanel recommendPanel = new JPanel(new BorderLayout(10, 10)); //will contain listPanel, action panel JPanel listPanel = new JPanel(new BorderLayout(10, 10)); //class recommend label, recommendation list JPanel actionsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); //model selection buttons or configuration addAndContinueButton = new JButton("Add and continue"); modelSettingsButton = new JButton("Model Settings"); useTagsCheckBox = new JCheckBox("Predict using tags"); recommendedClassesLabel = new JLabel("Recommended Classes:"); addAndContinueButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { String selectedClass = categoryList.getSelectedValue(); addAndContinueButtonActionPerformed(evt, selectedClass); //reconstruct vector for instance and use the model that was trained with classes here List<OsmPrimitive> osmPrimitiveSelection = new ArrayList<>(sel); OsmPrimitive s; //get a simple selection if (!osmPrimitiveSelection.isEmpty()) { s = osmPrimitiveSelection.get(0); if (s.getInterestingTags().isEmpty()) { //load original model modelWithClasses = false; loadSVMmodel(); createOSMObject(sel); //create object without class features } else { //recommend using tags: set the checkbox selected to avoid confusing the user useTagsCheckBox.setSelected(true); if (useTagsCheckBox.isSelected()) { //load model with classes modelWithClasses = true; loadSVMmodel(); createOSMObject(sel); //create object including class features } else { modelWithClasses = false; loadSVMmodel(); createOSMObject(sel); //create object including class features } } } } }); modelSettingsButton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { if (modelSettingsDialog == null) { System.out.println("new modelSettingsDialog"); modelSettingsDialog = new ModelSettingsDialog(sel, addTagsDialog); } else { System.out.println("set modelSettingsDialog visible"); modelSettingsDialog.makeVisible(true); } } }); useTagsCheckBox.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { List<OsmPrimitive> osmPrimitiveSelection = new ArrayList<>(sel); OsmPrimitive s; if (!osmPrimitiveSelection.isEmpty()) { s = osmPrimitiveSelection.get(0); if (s.getInterestingTags().isEmpty()) { //load original model modelWithClasses = false; loadSVMmodel(); createOSMObject(sel); //create object without class features } else { //useTagsCheckBox if (useTagsCheckBox.isSelected()) { //load model with classes modelWithClasses = true; loadSVMmodel(); createOSMObject(sel); //create object including class features } else { modelWithClasses = false; loadSVMmodel(); createOSMObject(sel); //create object including class features } } } } }); keys = new AutoCompletingComboBox(); values = new AutoCompletingComboBox(); mainPanel.add(new JLabel("<html>"+trn("This will change up to {0} object.", "This will change up to {0} objects.", sel.size(), sel.size()) +"<br><br>"+tr("Please select a key")), GBC.eol().fill(GBC.HORIZONTAL)); AutoCompletionManager autocomplete = Main.getLayerManager().getEditLayer().data.getAutoCompletionManager(); List<AutoCompletionListItem> keyList = autocomplete.getKeys(); AutoCompletionListItem itemToSelect = null; // remove the object's tag keys from the list Iterator<AutoCompletionListItem> iter = keyList.iterator(); while (iter.hasNext()) { AutoCompletionListItem item = iter.next(); if (item.getValue().equals(lastAddKey)) { itemToSelect = item; } for (int i = 0; i < tagData.getRowCount(); ++i) { if (item.getValue().equals(tagData.getValueAt(i, 0))) { if (itemToSelect == item) { itemToSelect = null; } iter.remove(); break; } } } Collections.sort(keyList, defaultACItemComparator); keys.setPossibleACItems(keyList); keys.setEditable(true); mainPanel.add(keys, GBC.eop().fill()); mainPanel.add(new JLabel(tr("Please select a value")), GBC.eol()); model = new DefaultListModel<>(); parseTagsMappedToClasses(); List<OsmPrimitive> osmPrimitiveSelection = new ArrayList<>(sel); OsmPrimitive s; //get a simple selection if (!osmPrimitiveSelection.isEmpty()) { s = osmPrimitiveSelection.get(0); File modelDirectory = new File(MODEL_PATH); String modelWithClassesPath = modelDirectory.getAbsolutePath() + "/model_with_classes"; File modelWithClassesFile = new File(modelWithClassesPath); if (s.getInterestingTags().isEmpty() || !modelWithClassesFile.exists()) { modelWithClasses = false; loadSVMmodel(); //load original model createOSMObject(sel); //create object without class features } else { //recommend using tags: set the checkbox selected to avoid confusing the user useTagsCheckBox.setSelected(true); modelWithClasses = true; loadSVMmodel(); //load model with classes createOSMObject(sel); //create object including class features } } categoryList = new JList<>(model); ListSelectionListener listSelectionListener = new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent listSelectionEvent) { if (!listSelectionEvent.getValueIsAdjusting()) { //This prevents double events String selectedClass = categoryList.getSelectedValue(); if (selectedClass != null) { //null check, because the model is cleared after a new recommendation //tags become unselected if ((selectedClass.indexOf(" ")+1) > 0) { //add both key + value in tags String keyTag = selectedClass.substring(0, selectedClass.indexOf(" ")); String valueTag = selectedClass.substring(selectedClass.indexOf(" ")+1, selectedClass.length()); keys.setSelectedItem(keyTag); //adding selected tags to textBoxes values.setSelectedItem(valueTag); } else { //value does not have a value, add the key tag only String keyTag = selectedClass; //test it keys.setSelectedItem(keyTag); values.setSelectedItem(""); } } } } }; categoryList.addListSelectionListener(listSelectionListener); categoryList.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED, Color.GRAY, Color.WHITE)); categoryList.setModel(model); values.setEditable(true); mainPanel.add(values, GBC.eop().fill()); if (itemToSelect != null) { keys.setSelectedItem(itemToSelect); if (lastAddValue != null) { values.setSelectedItem(lastAddValue); } } FocusAdapter focus = addFocusAdapter(autocomplete, defaultACItemComparator); // fire focus event in advance or otherwise the popup list will be too small at first focus.focusGained(null); int recentTagsToShow = PROPERTY_RECENT_TAGS_NUMBER.get(); if (recentTagsToShow > MAX_LRU_TAGS_NUMBER) { recentTagsToShow = MAX_LRU_TAGS_NUMBER; } suggestRecentlyAddedTags(mainPanel, recentTagsToShow, focus); mainPanel.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED, Color.GRAY, Color.WHITE)); listPanel.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED, Color.GRAY, Color.WHITE)); splitPanel.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED, Color.GRAY, Color.WHITE)); listPanel.add(recommendedClassesLabel, BorderLayout.NORTH); listPanel.add(categoryList, BorderLayout.SOUTH); actionsPanel.add(addAndContinueButton); actionsPanel.add(modelSettingsButton); actionsPanel.add(useTagsCheckBox); recommendPanel.add(actionsPanel, BorderLayout.WEST); recommendPanel.add(listPanel, BorderLayout.NORTH); splitPanel.add(mainPanel, BorderLayout.WEST); splitPanel.add(recommendPanel, BorderLayout.EAST); setContent(splitPanel, false); popupMenu.add(new AbstractAction(tr("Set number of recently added tags")) { @Override public void actionPerformed(ActionEvent e) { selectNumberOfTags(); } }); JCheckBoxMenuItem rememberLastTags = new JCheckBoxMenuItem( new AbstractAction(tr("Remember last used tags after a restart")) { @Override public void actionPerformed(ActionEvent e) { boolean sel = ((JCheckBoxMenuItem) e.getSource()).getState(); PROPERTY_REMEMBER_TAGS.put(sel); if (sel) saveTagsIfNeeded(); } }); rememberLastTags.setState(PROPERTY_REMEMBER_TAGS.get()); popupMenu.add(rememberLastTags); } private void addAndContinueButtonActionPerformed(ActionEvent evt, String selectedClass) { performTagAdding(); } private void selectNumberOfTags() { String s = JOptionPane.showInputDialog(this, tr("Please enter the number of recently added tags to display")); if (s != null) try { int v = Integer.parseInt(s); if (v >= 0 && v <= MAX_LRU_TAGS_NUMBER) { PROPERTY_RECENT_TAGS_NUMBER.put(v); return; } } catch (NumberFormatException ex) { Main.warn(ex); } JOptionPane.showMessageDialog(this, tr("Please enter integer number between 0 and {0}", MAX_LRU_TAGS_NUMBER)); } private void suggestRecentlyAddedTags(JPanel mainPanel, int tagsToShow, final FocusAdapter focus) { if (!(tagsToShow > 0 && !recentTags.isEmpty())) return; mainPanel.add(new JLabel(tr("Recently added tags")), GBC.eol()); int count = 1; // We store the maximum number (9) of recent tags to allow dynamic change of number of tags shown in the preferences. // This implies to iterate in descending order, // as the oldest elements will only be removed after we reach the maximum numbern and not the number of tags to show. // However, as Set does not allow to iterate in descending order, // we need to copy its elements into a List we can access in reverse order. List<Tag> tags = new LinkedList<>(recentTags.keySet()); for (int i = tags.size()-1; i >= 0 && count <= tagsToShow; i--, count++) { final Tag t = tags.get(i); // Create action for reusing the tag, with keyboard shortcut Ctrl+(1-5) String scKey = "properties:recent:"+count; String scsKey = "properties:recent:shift:"+count; Shortcut sc = Shortcut.registerShortcut(scKey, tr("Choose recent tag {0}", count), KeyEvent.VK_0+count, Shortcut.CTRL); final JosmAction action = new JosmAction(scKey, null, tr("Use this tag again"), sc, false) { @Override public void actionPerformed(ActionEvent e) { keys.setSelectedItem(t.getKey()); // fix #7951, #8298 - update list of values before setting value (?) focus.focusGained(null); values.setSelectedItem(t.getValue()); } }; Shortcut scs = Shortcut.registerShortcut(scsKey, tr("Apply recent tag {0}", count), KeyEvent.VK_0+count, Shortcut.CTRL_SHIFT); final JosmAction actionShift = new JosmAction(scsKey, null, tr("Use this tag again"), scs, false) { @Override public void actionPerformed(ActionEvent e) { action.actionPerformed(null); performTagAdding(); } }; recentTagsActions.add(action); recentTagsActions.add(actionShift); disableTagIfNeeded(t, action); // Find and display icon ImageIcon icon = MapPaintStyles.getNodeIcon(t, false); // Filters deprecated icon if (icon == null) { // If no icon found in map style look at presets Map<String, String> map = new HashMap<>(); map.put(t.getKey(), t.getValue()); // If still nothing display an empty icon if (icon == null) { icon = new ImageIcon(new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB)); } } GridBagConstraints gbc = new GridBagConstraints(); gbc.ipadx = 5; mainPanel.add(new JLabel(action.isEnabled() ? icon : GuiHelper.getDisabledIcon(icon)), gbc); // Create tag label final String color = action.isEnabled() ? "" : "; color:gray"; final JLabel tagLabel = new JLabel("<html>" + "<style>td{border:1px solid gray; font-weight:normal"+color+"}</style>" + "<table><tr><td>" + XmlWriter.encode(t.toString(), true) + "</td></tr></table></html>"); if (action.isEnabled()) { // Register action mainPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(sc.getKeyStroke(), scKey); mainPanel.getActionMap().put(scKey, action); mainPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(scs.getKeyStroke(), scsKey); mainPanel.getActionMap().put(scsKey, actionShift); // Make the tag label clickable and set tooltip to the action description (this displays also the keyboard shortcut) tagLabel.setToolTipText((String) action.getValue(Action.SHORT_DESCRIPTION)); tagLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); tagLabel.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { action.actionPerformed(null); // add tags and close window on double-click if (e.getClickCount() > 1) { buttonAction(0, null); // emulate OK click and close the dialog } // add tags on Shift-Click if (e.isShiftDown()) { performTagAdding(); } } }); } else { // Disable tag label tagLabel.setEnabled(false); // Explain in the tooltip why tagLabel.setToolTipText(tr("The key ''{0}'' is already used", t.getKey())); } // Finally add label to the resulting panel JPanel tagPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)); tagPanel.add(tagLabel); mainPanel.add(tagPanel, GBC.eol().fill(GBC.HORIZONTAL)); } } public void destroyActions() { for (JosmAction action : recentTagsActions) { action.destroy(); } } /** * Read tags from comboboxes and add it to all selected objects */ public final void performTagAdding() { String key = Tag.removeWhiteSpaces(keys.getEditor().getItem().toString()); String value = Tag.removeWhiteSpaces(values.getEditor().getItem().toString()); if (key.isEmpty() || value.isEmpty()) return; for (OsmPrimitive osm: sel) { String val = osm.get(key); if (val != null && !val.equals(value)) { if (!warnOverwriteKey(tr("You changed the value of ''{0}'' from ''{1}'' to ''{2}''.", key, val, value), "overwriteAddKey")) return; break; } } lastAddKey = key; lastAddValue = value; recentTags.put(new Tag(key, value), null); AutoCompletionManager.rememberUserInput(key, value, false); commandCount++; Main.main.undoRedo.add(new ChangePropertyCommand(sel, key, value)); changedKey = key; } public void undoAllTagsAdding() { Main.main.undoRedo.undo(commandCount); } private void disableTagIfNeeded(final Tag t, final JosmAction action) { // Disable action if its key is already set on the object (the key being absent from the keys list for this reason // performing this action leads to autocomplete to the next key (see #7671 comments) for (int j = 0; j < tagData.getRowCount(); ++j) { if (t.getKey().equals(tagData.getValueAt(j, 0))) { action.setEnabled(false); break; } } } private void loadSVMmodel() { File modelDirectory = new File(MODEL_PATH); File modelFile; if (useCombinedModel) { if (filesAndWeights.isEmpty()) { System.out.println("No models selected! Loading defaults.."); if (modelWithClasses) { System.out.println("Using default/last model with classes: " + modelDirectory.getAbsolutePath() + "/model_with_classes"); modelFile = new File(modelDirectory.getAbsolutePath() + "/model_with_classes"); try { System.out.println("try to load model: " + modelFile.getAbsolutePath()); modelSVM = Model.load(modelFile); System.out.println("model loaded!"); } catch (IOException ex) { Logger.getLogger(TrainWorker.class.getName()).log(Level.SEVERE, null, ex); } modelSVMLabelSize = modelSVM.getLabels().length; modelSVMLabels = modelSVM.getLabels(); } else { System.out.println("Using default/last model without classes: " + modelDirectory.getAbsolutePath() + "/best_model"); modelFile = new File(modelDirectory.getAbsolutePath() + "/best_model"); try { System.out.println("try to load model: " + modelFile.getAbsolutePath()); modelSVM = Model.load(modelFile); System.out.println("model loaded!"); } catch (IOException ex) { Logger.getLogger(TrainWorker.class.getName()).log(Level.SEVERE, null, ex); } modelSVMLabelSize = modelSVM.getLabels().length; modelSVMLabels = modelSVM.getLabels(); } } if (modelWithClasses) { //check filenames to define if model with classes is selected System.out.println("Using combined model with classes"); useCombinedSVMmodels(sel, true); } else { System.out.println("Using combined model without classes"); useCombinedSVMmodels(sel, false); } } else if (useCustomSVMModel) { System.out.println("custom path: " + customSVMModelPath); File checkExistance = new File(customSVMModelPath); if (checkExistance.exists() && checkExistance.isFile()) { if (modelWithClasses) { System.out.println("Using custom model with classes: "); if (customSVMModelPath.endsWith(".0")) { String customSVMModelPathWithClasses = customSVMModelPath.substring(0, customSVMModelPath.length() - 2) + ".1"; modelFile = new File(customSVMModelPathWithClasses); System.out.println(customSVMModelPathWithClasses); } else { modelFile = new File(customSVMModelPath); } } else { System.out.println("Using custom model without classes"); if (customSVMModelPath.endsWith(".1")) { String customSVMModelPathWithoutClasses = customSVMModelPath.substring(0, customSVMModelPath.length() - 2) + ".0"; modelFile = new File(customSVMModelPathWithoutClasses); System.out.println(customSVMModelPathWithoutClasses); } else { modelFile = new File(customSVMModelPath); } } try { System.out.println("try to load model: " + modelFile.getAbsolutePath()); modelSVM = Model.load(modelFile); System.out.println("model loaded!"); } catch (IOException ex) { Logger.getLogger(TrainWorker.class.getName()).log(Level.SEVERE, null, ex); } modelSVMLabelSize = modelSVM.getLabels().length; modelSVMLabels = modelSVM.getLabels(); } else { //user chose to use a custom model, but did not provide a path to a model: if (modelWithClasses) { System.out.println("Using default/last model with classes"); modelFile = new File(modelDirectory.getAbsolutePath() + "/model_with_classes"); } else { System.out.println("Using default/last model without classes"); modelFile = new File(modelDirectory.getAbsolutePath() + "/best_model"); } try { System.out.println("try to load model: " + modelFile.getAbsolutePath()); modelSVM = Model.load(modelFile); System.out.println("model loaded!"); } catch (IOException ex) { Logger.getLogger(TrainWorker.class.getName()).log(Level.SEVERE, null, ex); } modelSVMLabelSize = modelSVM.getLabels().length; modelSVMLabels = modelSVM.getLabels(); } } else { if (modelWithClasses) { System.out.println("Using default/last model with classes"); modelFile = new File(modelDirectory.getAbsolutePath() + "/model_with_classes"); } else { System.out.println("Using default/last model without classes"); modelFile = new File(modelDirectory.getAbsolutePath() + "/best_model"); } try { System.out.println("try to load model: " + modelFile.getAbsolutePath()); modelSVM = Model.load(modelFile); System.out.println("model loaded!"); } catch (IOException ex) { Logger.getLogger(TrainWorker.class.getName()).log(Level.SEVERE, null, ex); } modelSVMLabelSize = modelSVM.getLabels().length; modelSVMLabels = modelSVM.getLabels(); } } private void useCombinedSVMmodels(Collection<OsmPrimitive> sel, boolean useClassFeatures) { System.out.println("The system will combine " + filesAndWeights.size() + " SVM models."); MathTransform transform = null; GeometryFactory geometryFactory = new GeometryFactory(); CoordinateReferenceSystem sourceCRS = DefaultGeographicCRS.WGS84; CoordinateReferenceSystem targetCRS = DefaultGeocentricCRS.CARTESIAN; try { transform = CRS.findMathTransform(sourceCRS, targetCRS, true); } catch (FactoryException ex) { Logger.getLogger(OSMRecPluginHelper.class.getName()).log(Level.SEVERE, null, ex); } OSMWay selectedInstance; List<OsmPrimitive> osmPrimitiveSelection = new ArrayList<>(sel); OsmPrimitive s; //get a simple selection if (!osmPrimitiveSelection.isEmpty()) { s = osmPrimitiveSelection.get(0); } else { return; } selectedInstance = new OSMWay(); for (Way selectedWay : s.getDataSet().getSelectedWays()) { List<Node> selectedWayNodes = selectedWay.getNodes(); for (Node node : selectedWayNodes) { node.getCoor(); if (node.isLatLonKnown()) { double lat = node.getCoor().lat(); double lon = node.getCoor().lon(); Coordinate sourceCoordinate = new Coordinate(lon, lat); Coordinate targetGeometry = null; try { targetGeometry = JTS.transform(sourceCoordinate, null, transform); } catch (MismatchedDimensionException | TransformException ex) { Logger.getLogger(OSMParser.class.getName()).log(Level.SEVERE, null, ex); } Geometry geom = geometryFactory.createPoint(new Coordinate(targetGeometry)); selectedInstance.addNodeGeometry(geom); } } } Geometry fullGeom = geometryFactory.buildGeometry(selectedInstance.getNodeGeometries()); if ((selectedInstance.getNodeGeometries().size() > 3) && selectedInstance.getNodeGeometries().get(0).equals(selectedInstance.getNodeGeometries() .get(selectedInstance.getNodeGeometries().size()-1))) { //checks if the beginning and ending node are the same and the number of nodes are more than 3. //the nodes must be more than 3, because jts does not allow a construction of a linear ring with less points. LinearRing linear = geometryFactory.createLinearRing(fullGeom.getCoordinates()); Polygon poly = new Polygon(linear, null, geometryFactory); selectedInstance.setGeometry(poly); System.out.println("\n\npolygon"); } else if (selectedInstance.getNodeGeometries().size() > 1) { //it is an open geometry with more than one nodes, make it linestring System.out.println("\n\nlinestring"); LineString lineString = geometryFactory.createLineString(fullGeom.getCoordinates()); selectedInstance.setGeometry(lineString); } else { //we assume all the rest geometries are points System.out.println("\n\npoint"); Point point = geometryFactory.createPoint(fullGeom.getCoordinate()); selectedInstance.setGeometry(point); } Map<String, String> selectedTags = s.getInterestingTags(); selectedInstance.setAllTags(selectedTags); //construct vector if (selectedInstance != null) { int id; OSMClassification classifier = new OSMClassification(); classifier.calculateClasses(selectedInstance, mappings, mapperWithIDs, indirectClasses, indirectClassesWithIDs); if (useClassFeatures) { ClassFeatures classFeatures = new ClassFeatures(); classFeatures.createClassFeatures(selectedInstance, mappings, mapperWithIDs, indirectClasses, indirectClassesWithIDs); id = 1422; } else { id = 1; } GeometryFeatures geometryFeatures = new GeometryFeatures(id); geometryFeatures.createGeometryFeatures(selectedInstance); id = geometryFeatures.getLastID(); TextualFeatures textualFeatures = new TextualFeatures(id, textualList, languageDetector); textualFeatures.createTextualFeatures(selectedInstance); List<FeatureNode> featureNodeList = selectedInstance.getFeatureNodeList(); FeatureNode[] featureNodeArray = new FeatureNode[featureNodeList.size()]; int i = 0; for (FeatureNode featureNode : featureNodeList) { featureNodeArray[i] = featureNode; i++; } FeatureNode[] testInstance2 = featureNodeArray; //compute prediction list for every model int[] ranks = new int[10]; for (int l = 0; l < 10; l++) { ranks[l] = 10-l; //init from 10 to 1 } Map<String, Double> scoreMap = new HashMap<>(); Map<File, Double> alignedFilesAndWeights = getAlignedModels(filesAndWeights); for (File modelFile : alignedFilesAndWeights.keySet()) { try { modelSVM = Model.load(modelFile); } catch (IOException ex) { Logger.getLogger(TrainWorker.class.getName()).log(Level.SEVERE, null, ex); } modelSVMLabelSize = modelSVM.getLabels().length; modelSVMLabels = modelSVM.getLabels(); Map<Integer, Integer> mapLabelsToIDs = new HashMap<>(); for (int h = 0; h < modelSVMLabelSize; h++) { mapLabelsToIDs.put(modelSVMLabels[h], h); } double[] scores = new double[modelSVMLabelSize]; Linear.predictValues(modelSVM, testInstance2, scores); Map<Double, Integer> scoresValues = new HashMap<>(); for (int h = 0; h < scores.length; h++) { scoresValues.put(scores[h], h); } Arrays.sort(scores); int predicted1 = modelSVMLabels[scoresValues.get(scores[scores.length-1])]; int predicted2 = modelSVMLabels[scoresValues.get(scores[scores.length-2])]; int predicted3 = modelSVMLabels[scoresValues.get(scores[scores.length-3])]; int predicted4 = modelSVMLabels[scoresValues.get(scores[scores.length-4])]; int predicted5 = modelSVMLabels[scoresValues.get(scores[scores.length-5])]; int predicted6 = modelSVMLabels[scoresValues.get(scores[scores.length-6])]; int predicted7 = modelSVMLabels[scoresValues.get(scores[scores.length-7])]; int predicted8 = modelSVMLabels[scoresValues.get(scores[scores.length-8])]; int predicted9 = modelSVMLabels[scoresValues.get(scores[scores.length-9])]; int predicted10 = modelSVMLabels[scoresValues.get(scores[scores.length-10])]; String[] predictedTags = new String[10]; for (Map.Entry<String, Integer> entry : mapperWithIDs.entrySet()) { if (entry.getValue().equals(predicted1)) { predictedTags[0] = entry.getKey(); } else if (entry.getValue().equals(predicted2)) { predictedTags[1] = entry.getKey(); } else if (entry.getValue().equals(predicted3)) { predictedTags[2] = entry.getKey(); } else if (entry.getValue().equals(predicted4)) { predictedTags[3] = entry.getKey(); } else if (entry.getValue().equals(predicted5)) { predictedTags[4] = entry.getKey(); } else if (entry.getValue().equals(predicted6)) { predictedTags[5] = entry.getKey(); } else if (entry.getValue().equals(predicted7)) { predictedTags[6] = entry.getKey(); } else if (entry.getValue().equals(predicted8)) { predictedTags[7] = entry.getKey(); } else if (entry.getValue().equals(predicted9)) { predictedTags[8] = entry.getKey(); } else if (entry.getValue().equals(predicted10)) { predictedTags[9] = entry.getKey(); } } //clearing model, to add the new computed classes in jlist model.clear(); for (Map.Entry<String, String> tag : mappings.entrySet()) { for (int k = 0; k < 10; k++) { if (tag.getValue().equals(predictedTags[k])) { predictedTags[k] = tag.getKey(); model.addElement(tag.getKey()); } } } System.out.println("combined, predicted classes: " + Arrays.toString(predictedTags)); for (int r = 0; r < ranks.length; r++) { String predictedTag = predictedTags[r]; Double currentWeight = alignedFilesAndWeights.get(modelFile); double finalRank = ranks[r]*currentWeight; if (scoreMap.containsKey(predictedTag)) { Double scoreToAdd = scoreMap.get(predictedTag); scoreMap.put(predictedTag, finalRank+scoreToAdd); } else { scoreMap.put(predictedTag, finalRank); } //add final weight - predicted tag } } //files iter model.clear(); List<Double> scoresList = new ArrayList<>(scoreMap.values()); Collections.sort(scoresList, Collections.reverseOrder()); for (Double sco : scoresList) { if (model.size() > 9) { break; } for (Map.Entry<String, Double> scoreEntry : scoreMap.entrySet()) { if (scoreEntry.getValue().equals(sco)) { model.addElement(scoreEntry.getKey()); } } } } } private void createOSMObject(Collection<OsmPrimitive> sel) { MathTransform transform = null; GeometryFactory geometryFactory = new GeometryFactory(); CoordinateReferenceSystem sourceCRS = DefaultGeographicCRS.WGS84; CoordinateReferenceSystem targetCRS = DefaultGeocentricCRS.CARTESIAN; try { transform = CRS.findMathTransform(sourceCRS, targetCRS, true); } catch (FactoryException ex) { Logger.getLogger(OSMRecPluginHelper.class.getName()).log(Level.SEVERE, null, ex); } //fire an error to the user if he has multiple selection from map //we consider simple (one instance) selection, so we get the first of the sel list OSMWay selectedInstance; List<OsmPrimitive> osmPrimitiveSelection = new ArrayList<>(sel); OsmPrimitive s; //get a simple selection if (!osmPrimitiveSelection.isEmpty()) { s = osmPrimitiveSelection.get(0); } else { return; } selectedInstance = new OSMWay(); for (Way selectedWay : s.getDataSet().getSelectedWays()) { List<Node> selectedWayNodes = selectedWay.getNodes(); for (Node node : selectedWayNodes) { node.getCoor(); if (node.isLatLonKnown()) { double lat = node.getCoor().lat(); double lon = node.getCoor().lon(); Coordinate sourceCoordinate = new Coordinate(lon, lat); Coordinate targetGeometry = null; try { targetGeometry = JTS.transform(sourceCoordinate, null, transform); } catch (MismatchedDimensionException | TransformException ex) { Logger.getLogger(OSMParser.class.getName()).log(Level.SEVERE, null, ex); } Geometry geom = geometryFactory.createPoint(new Coordinate(targetGeometry)); selectedInstance.addNodeGeometry(geom); } } } Geometry fullGeom = geometryFactory.buildGeometry(selectedInstance.getNodeGeometries()); System.out.println("number of nodes: " + selectedInstance.getNodeGeometries().size()); if ((selectedInstance.getNodeGeometries().size() > 3) && selectedInstance.getNodeGeometries().get(0).equals(selectedInstance.getNodeGeometries() .get(selectedInstance.getNodeGeometries().size()-1))) { //checks if the beginning and ending node are the same and the number of nodes are more than 3. //the nodes must be more than 3, because jts does not allow a construction of a linear ring with less points. LinearRing linear = geometryFactory.createLinearRing(fullGeom.getCoordinates()); Polygon poly = new Polygon(linear, null, geometryFactory); selectedInstance.setGeometry(poly); System.out.println("\n\npolygon"); } else if (selectedInstance.getNodeGeometries().size() > 1) { //it is an open geometry with more than one nodes, make it linestring System.out.println("\n\nlinestring"); LineString lineString = geometryFactory.createLineString(fullGeom.getCoordinates()); selectedInstance.setGeometry(lineString); } else { //we assume all the rest geometries are points System.out.println("\n\npoint"); Point point = geometryFactory.createPoint(fullGeom.getCoordinate()); selectedInstance.setGeometry(point); } Map<String, String> selectedTags = s.getInterestingTags(); selectedInstance.setAllTags(selectedTags); //construct vector here if (selectedInstance != null) { int id; if (mappings == null) { System.out.println("null mappings ERROR"); } OSMClassification classifier = new OSMClassification(); classifier.calculateClasses(selectedInstance, mappings, mapperWithIDs, indirectClasses, indirectClassesWithIDs); if (modelWithClasses) { ClassFeatures classFeatures = new ClassFeatures(); classFeatures.createClassFeatures(selectedInstance, mappings, mapperWithIDs, indirectClasses, indirectClassesWithIDs); id = 1422; } else { id = 1; } GeometryFeatures geometryFeatures = new GeometryFeatures(id); geometryFeatures.createGeometryFeatures(selectedInstance); id = geometryFeatures.getLastID(); TextualFeatures textualFeatures = new TextualFeatures(id, textualList, languageDetector); textualFeatures.createTextualFeatures(selectedInstance); List<FeatureNode> featureNodeList = selectedInstance.getFeatureNodeList(); System.out.println(featureNodeList); FeatureNode[] featureNodeArray = new FeatureNode[featureNodeList.size()]; int i = 0; for (FeatureNode featureNode : featureNodeList) { featureNodeArray[i] = featureNode; i++; } FeatureNode[] testInstance2 = featureNodeArray; Map<Integer, Integer> mapLabelsToIDs = new HashMap<>(); for (int h = 0; h < modelSVMLabelSize; h++) { mapLabelsToIDs.put(modelSVMLabels[h], h); } double[] scores = new double[modelSVMLabelSize]; Linear.predictValues(modelSVM, testInstance2, scores); Map<Double, Integer> scoresValues = new HashMap<>(); for (int h = 0; h < scores.length; h++) { scoresValues.put(scores[h], h); } Arrays.sort(scores); int[] preds = new int[RECOMMENDATIONS_SIZE]; for (int p = 0; p < RECOMMENDATIONS_SIZE; p++) { preds[p] = modelSVMLabels[scoresValues.get(scores[scores.length-(p+1)])]; } String[] predictedTags2 = new String[RECOMMENDATIONS_SIZE]; for (int p = 0; p < RECOMMENDATIONS_SIZE; p++) { if (idsWithMappings.containsKey(preds[p])) { predictedTags2[p] = idsWithMappings.get(preds[p]); } } //clearing model, to add the new computed classes in jlist model.clear(); for (Map.Entry<String, String> tag : mappings.entrySet()) { for (int k = 0; k < 10; k++) { if (tag.getValue().equals(predictedTags2[k])) { predictedTags2[k] = tag.getKey(); model.addElement(tag.getKey()); } } } System.out.println("Optimized - create OSMObject, predicted classes: " + Arrays.toString(predictedTags2)); } } private void parseTagsMappedToClasses() { InputStream tagsToClassesMapping = TrainWorker.class.getResourceAsStream("/resources/files/Map"); Mapper mapper = new Mapper(); try { mapper.parseFile(tagsToClassesMapping); } catch (FileNotFoundException ex) { Logger.getLogger(Mapper.class.getName()).log(Level.SEVERE, null, ex); } mappings = mapper.getMappings(); mapperWithIDs = mapper.getMappingsWithIDs(); idsWithMappings = mapper.getIDsWithMappings(); } private void loadTextualList(File textualListFile) { Scanner input = null; try { input = new Scanner(textualListFile); } catch (FileNotFoundException ex) { Main.warn(ex); } while (input.hasNext()) { String nextLine = input.nextLine(); textualList.add(nextLine); } System.out.println("Textual List parsed from file successfully." + textualList); } private void loadDefaultTextualList() { InputStream textualListStream = TrainWorker.class.getResourceAsStream("/resources/files/textualList.txt"); TextualStatistics textualStatistics = new TextualStatistics(); textualStatistics.parseTextualList(textualListStream); textualList = textualStatistics.getTextualList(); System.out.println("Default Textual List parsed from file successfully." + textualList); } private void loadOntology() { InputStream ontologyStream = TrainWorker.class.getResourceAsStream("/resources/files/owl.xml"); Ontology ontology = new Ontology(ontologyStream); indirectClasses = ontology.getIndirectClasses(); indirectClassesWithIDs = ontology.getIndirectClassesIDs(); } private Map<File, Double> getAlignedModels(Map<File, Double> filesAndWeights) { Map<File, Double> alignedFilesAndWeights = new HashMap<>(); if (modelWithClasses) { for (Entry<File, Double> entry : filesAndWeights.entrySet()) { String absolutePath = entry.getKey().getAbsolutePath(); if (absolutePath.endsWith(".0")) { String newPath = absolutePath.substring(0, absolutePath.length()-2) + ".1"; File alignedFile = new File(newPath); if (alignedFile.exists()) { alignedFilesAndWeights.put(alignedFile, entry.getValue()); } } else { alignedFilesAndWeights.put(entry.getKey(), entry.getValue()); } } } else { for (Entry<File, Double> entry : filesAndWeights.entrySet()) { String absolutePath = entry.getKey().getAbsolutePath(); if (absolutePath.endsWith(".1")) { String newPath = absolutePath.substring(0, absolutePath.length()-2) + ".0"; File alignedFile = new File(newPath); if (alignedFile.exists()) { alignedFilesAndWeights.put(alignedFile, entry.getValue()); } } else { alignedFilesAndWeights.put(entry.getKey(), entry.getValue()); } } } return alignedFilesAndWeights; } } }