kopia lustrzana https://github.com/JOSM/MapWithAI
Allow users to modify tags (hidden in non-expert mode)
Signed-off-by: Taylor Smock <taylor.smock@kaart.com>pull/1/head
rodzic
df70ac4d4e
commit
f3035d89f2
|
@ -3,28 +3,43 @@ package org.openstreetmap.josm.plugins.mapwithai;
|
|||
import static org.openstreetmap.josm.tools.I18n.tr;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Insets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import javax.swing.Box;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSpinner;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.SpinnerNumberModel;
|
||||
|
||||
import org.openstreetmap.josm.actions.ExpertToggleAction;
|
||||
import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
|
||||
import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting;
|
||||
import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting;
|
||||
import org.openstreetmap.josm.gui.preferences.advanced.PrefEntry;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIPreferenceHelper;
|
||||
import org.openstreetmap.josm.spi.preferences.StringSetting;
|
||||
import org.openstreetmap.josm.tools.GBC;
|
||||
|
||||
public class MapWithAIPreferences implements SubPreferenceSetting {
|
||||
private final JComboBox<String> possibleMapWithAIApiUrl;
|
||||
private final JCheckBox switchLayerCheckBox;
|
||||
private final JCheckBox mergeBuildingAddressCheckBox;
|
||||
private final JSpinner maximumAdditionSpinner;
|
||||
private final ReplacementPreferenceTable table;
|
||||
private final List<PrefEntry> displayData;
|
||||
|
||||
public MapWithAIPreferences() {
|
||||
possibleMapWithAIApiUrl = new JComboBox<>();
|
||||
|
@ -32,6 +47,16 @@ public class MapWithAIPreferences implements SubPreferenceSetting {
|
|||
maximumAdditionSpinner = new JSpinner(
|
||||
new SpinnerNumberModel(MapWithAIPreferenceHelper.getMaximumAddition(), 0, 100, 1));
|
||||
mergeBuildingAddressCheckBox = new JCheckBox();
|
||||
displayData = new ArrayList<>();
|
||||
fillDisplayData(displayData);
|
||||
table = new ReplacementPreferenceTable(displayData);
|
||||
}
|
||||
|
||||
private static void fillDisplayData(List<PrefEntry> list) {
|
||||
Map<String, String> current = new TreeMap<>(MapWithAIPreferenceHelper.getReplacementTags());
|
||||
for (Entry<String, String> entry : current.entrySet()) {
|
||||
list.add(new PrefEntry(entry.getKey(), new StringSetting(entry.getValue()), new StringSetting(null), false));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -40,9 +65,9 @@ public class MapWithAIPreferences implements SubPreferenceSetting {
|
|||
final JLabel switchLayer = new JLabel(tr("Automatically switch layers"));
|
||||
final JLabel maximumAddition = new JLabel(tr("Maximum features (add)"));
|
||||
final JLabel mergeBuildingWithAddress = new JLabel(tr("Merge address nodes and buildings"));
|
||||
final JPanel container = new JPanel(new GridBagLayout());
|
||||
container.setAlignmentY(Component.TOP_ALIGNMENT);
|
||||
final GridBagConstraints constraints = new GridBagConstraints();
|
||||
final JPanel nonExpert = new JPanel(new GridBagLayout());
|
||||
nonExpert.setAlignmentY(Component.TOP_ALIGNMENT);
|
||||
nonExpert.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
|
||||
possibleMapWithAIApiUrl.setEditable(true);
|
||||
possibleMapWithAIApiUrl.setPrototypeDisplayValue("https://example.url/some/end/point");
|
||||
|
@ -58,38 +83,64 @@ public class MapWithAIPreferences implements SubPreferenceSetting {
|
|||
switchLayerCheckBox.setSelected(MapWithAIPreferenceHelper.isSwitchLayers());
|
||||
mergeBuildingAddressCheckBox.setSelected(MapWithAIPreferenceHelper.isMergeBuildingAddress());
|
||||
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = 0;
|
||||
constraints.weightx = .1;
|
||||
constraints.weighty = 0;
|
||||
constraints.insets = new Insets(5, 10, 5, 10);
|
||||
constraints.anchor = GridBagConstraints.EAST;
|
||||
constraints.fill = GridBagConstraints.HORIZONTAL;
|
||||
container.add(mapWithAIApiUrl, constraints);
|
||||
nonExpert.add(mapWithAIApiUrl);
|
||||
|
||||
constraints.gridx++;
|
||||
container.add(possibleMapWithAIApiUrl, constraints);
|
||||
nonExpert.add(possibleMapWithAIApiUrl, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
|
||||
|
||||
constraints.gridx--;
|
||||
constraints.gridy++;
|
||||
container.add(switchLayer, constraints);
|
||||
nonExpert.add(switchLayer);
|
||||
|
||||
constraints.gridx++;
|
||||
container.add(switchLayerCheckBox, constraints);
|
||||
nonExpert.add(switchLayerCheckBox, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
|
||||
|
||||
constraints.gridx--;
|
||||
constraints.gridy++;
|
||||
container.add(maximumAddition, constraints);
|
||||
constraints.gridx++;
|
||||
container.add(maximumAdditionSpinner, constraints);
|
||||
nonExpert.add(maximumAddition);
|
||||
nonExpert.add(maximumAdditionSpinner, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
|
||||
|
||||
constraints.gridx--;
|
||||
constraints.gridy++;
|
||||
container.add(mergeBuildingWithAddress, constraints);
|
||||
constraints.gridx++;
|
||||
container.add(mergeBuildingAddressCheckBox, constraints);
|
||||
nonExpert.add(mergeBuildingWithAddress);
|
||||
nonExpert.add(mergeBuildingAddressCheckBox, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
|
||||
|
||||
getTabPreferenceSetting(gui).addSubTab(this, MapWithAIPlugin.NAME, container);
|
||||
final JPanel expert = new JPanel(new GridBagLayout());
|
||||
expert.add(Box.createHorizontalGlue(), GBC.std().fill(GridBagConstraints.HORIZONTAL));
|
||||
JScrollPane scroll = new JScrollPane(table);
|
||||
expert.add(scroll, GBC.eol().fill(GridBagConstraints.BOTH));
|
||||
scroll.setPreferredSize(new Dimension(400, 200));
|
||||
|
||||
JButton add = new JButton(tr("Add"));
|
||||
expert.add(Box.createHorizontalGlue(), GBC.std().fill(GridBagConstraints.HORIZONTAL));
|
||||
expert.add(add, GBC.std().insets(0, 5, 0, 0));
|
||||
add.addActionListener(e -> {
|
||||
PrefEntry pe = table.addPreference(gui);
|
||||
if (pe != null && pe.getValue() instanceof StringSetting) {
|
||||
displayData.add(pe);
|
||||
Collections.sort(displayData);
|
||||
table.fireDataChanged();
|
||||
}
|
||||
});
|
||||
|
||||
JButton edit = new JButton(tr("Edit"));
|
||||
expert.add(edit, GBC.std().insets(5, 5, 0, 0));
|
||||
edit.addActionListener(e -> {
|
||||
List<PrefEntry> toEdit = table.getSelectedItems();
|
||||
if (toEdit.size() == 1) {
|
||||
table.editPreference(gui);
|
||||
}
|
||||
});
|
||||
|
||||
JButton delete = new JButton(tr("Delete"));
|
||||
expert.add(delete, GBC.std().insets(5, 5, 0, 0));
|
||||
delete.addActionListener(e -> {
|
||||
List<PrefEntry> toRemove = table.getSelectedItems();
|
||||
if (!toRemove.isEmpty()) {
|
||||
displayData.removeAll(toRemove);
|
||||
}
|
||||
table.fireDataChanged();
|
||||
});
|
||||
|
||||
ExpertToggleAction.addVisibilitySwitcher(expert);
|
||||
|
||||
JPanel pane = new JPanel(new GridBagLayout());
|
||||
pane.add(nonExpert, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
|
||||
pane.add(expert);
|
||||
|
||||
getTabPreferenceSetting(gui).addSubTab(this, MapWithAIPlugin.NAME, pane);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -100,9 +151,16 @@ public class MapWithAIPreferences implements SubPreferenceSetting {
|
|||
if (value instanceof Number) {
|
||||
MapWithAIPreferenceHelper.setMaximumAddition(((Number) value).intValue(), true);
|
||||
}
|
||||
MapWithAIPreferenceHelper.setReplacementTags(convertPrefToMap(displayData));
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Map<String, String> convertPrefToMap(List<PrefEntry> displayData) {
|
||||
Map<String, String> returnMap = displayData.isEmpty() ? Collections.emptyMap() : new TreeMap<>();
|
||||
displayData.forEach(entry -> returnMap.put(entry.getKey(), entry.getValue().getValue().toString()));
|
||||
return returnMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExpert() {
|
||||
return false;
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
// License: GPL. For details, see LICENSE file.
|
||||
package org.openstreetmap.josm.plugins.mapwithai;
|
||||
|
||||
import static org.openstreetmap.josm.tools.I18n.tr;
|
||||
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import org.openstreetmap.josm.gui.ExtendedDialog;
|
||||
import org.openstreetmap.josm.gui.preferences.advanced.PrefEntry;
|
||||
import org.openstreetmap.josm.gui.preferences.advanced.PreferencesTable;
|
||||
import org.openstreetmap.josm.gui.widgets.JosmTextField;
|
||||
import org.openstreetmap.josm.spi.preferences.StringSetting;
|
||||
import org.openstreetmap.josm.tools.GBC;
|
||||
|
||||
/**
|
||||
* @author Taylor Smock
|
||||
*/
|
||||
public class ReplacementPreferenceTable extends PreferencesTable {
|
||||
private static final long serialVersionUID = 8057277761625324262L;
|
||||
|
||||
public ReplacementPreferenceTable(List<PrefEntry> displayData) {
|
||||
super(displayData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrefEntry addPreference(final JComponent gui) {
|
||||
JPanel p = new JPanel(new GridBagLayout());
|
||||
p.add(new JLabel(tr("Original Tag")), GBC.std().insets(0, 0, 5, 0));
|
||||
JosmTextField tkey = new JosmTextField("", 50);
|
||||
p.add(tkey, GBC.eop().insets(5, 0, 0, 0).fill(GridBagConstraints.HORIZONTAL));
|
||||
p.add(new JLabel(tr("Replacement Tag")), GBC.std().insets(0, 0, 5, 0));
|
||||
JosmTextField tValue = new JosmTextField("", 50);
|
||||
p.add(tValue, GBC.eop().insets(5, 0, 0, 0).fill(GridBagConstraints.HORIZONTAL));
|
||||
|
||||
PrefEntry pe = null;
|
||||
if (askAddSetting(gui, p)) {
|
||||
pe = new PrefEntry(tkey.getText(), new StringSetting(tValue.getText()), new StringSetting(null), false);
|
||||
}
|
||||
return pe;
|
||||
}
|
||||
|
||||
private static boolean askAddSetting(JComponent gui, JPanel p) {
|
||||
return new ExtendedDialog(gui, tr("Add setting"), tr("OK"), tr("Cancel")).setContent(p)
|
||||
.setButtonIcons("ok", "cancel").showDialog().getValue() == 1;
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@ import org.openstreetmap.josm.data.osm.BBox;
|
|||
import org.openstreetmap.josm.data.osm.DataSet;
|
||||
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.UploadPolicy;
|
||||
import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
|
||||
import org.openstreetmap.josm.gui.progress.ProgressMonitor;
|
||||
|
@ -31,6 +32,7 @@ import org.openstreetmap.josm.plugins.mapwithai.commands.MergeDuplicateWays;
|
|||
import org.openstreetmap.josm.tools.HttpClient;
|
||||
import org.openstreetmap.josm.tools.HttpClient.Response;
|
||||
import org.openstreetmap.josm.tools.Logging;
|
||||
import org.openstreetmap.josm.tools.Pair;
|
||||
|
||||
/**
|
||||
* Get data in a parallel manner
|
||||
|
@ -92,6 +94,7 @@ public class GetDataRunnable extends RecursiveTask<DataSet> {
|
|||
synchronized (LOCK) {
|
||||
/* Microsoft buildings don't have a source, so we add one */
|
||||
MapWithAIDataUtils.addSourceTags(dataSet, "building", "Microsoft");
|
||||
replaceTags(dataSet);
|
||||
removeCommonTags(dataSet);
|
||||
mergeNodes(dataSet);
|
||||
// filterDataSet(dataSet);
|
||||
|
@ -103,6 +106,19 @@ public class GetDataRunnable extends RecursiveTask<DataSet> {
|
|||
return dataSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace tags in a dataset with a set of replacement tags
|
||||
*
|
||||
* @param dataSet The dataset with primitives to change
|
||||
*/
|
||||
public static void replaceTags(DataSet dataSet) {
|
||||
Map<Tag, Tag> replaceTags = MapWithAIPreferenceHelper.getReplacementTags().entrySet().parallelStream()
|
||||
.map(entry -> new Pair<>(Tag.ofString(entry.getKey()), Tag.ofString(entry.getValue())))
|
||||
.collect(Collectors.toMap(pair -> pair.a, pair -> pair.b));
|
||||
replaceTags.forEach((orig, replace) -> dataSet.allNonDeletedPrimitives().parallelStream()
|
||||
.filter(prim -> prim.hasTag(orig.getKey(), orig.getValue())).forEach(prim -> prim.put(replace)));
|
||||
}
|
||||
|
||||
private static void cleanupDataSet(DataSet dataSet) {
|
||||
Map<OsmPrimitive, String> origIds = dataSet.allPrimitives().parallelStream()
|
||||
.filter(prim -> prim.hasKey("orig_id")).distinct()
|
||||
|
|
|
@ -3,8 +3,12 @@ package org.openstreetmap.josm.plugins.mapwithai.backend;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.openstreetmap.josm.data.osm.Tag;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.MapWithAIPlugin;
|
||||
import org.openstreetmap.josm.spi.preferences.Config;
|
||||
|
||||
|
@ -183,7 +187,30 @@ public final class MapWithAIPreferenceHelper {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum distance for a node to be considered a duplicate
|
||||
*
|
||||
* @return The max distance between nodes for duplicates
|
||||
*/
|
||||
public static double getMaxNodeDistance() {
|
||||
return Config.getPref().getDouble(MapWithAIPlugin.NAME.concat(".duplicatenodedistance"), 0.6);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A map of tags to replacement tags (use {@link Tag.ofString} to parse)
|
||||
*/
|
||||
public static Map<String, String> getReplacementTags() {
|
||||
Map<String, String> defaultMap = Collections.emptyMap();
|
||||
List<Map<String, String>> listOfMaps = Config.getPref()
|
||||
.getListOfMaps(MapWithAIPlugin.NAME.concat(".replacementtags"), Arrays.asList(defaultMap));
|
||||
return listOfMaps.isEmpty() ? defaultMap : listOfMaps.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tagsToReplace set the tags to replace
|
||||
*/
|
||||
public static void setReplacementTags(Map<String, String> tagsToReplace) {
|
||||
List<Map<String, String>> tags = tagsToReplace.isEmpty() ? null : Arrays.asList(new TreeMap<>(tagsToReplace));
|
||||
Config.getPref().putListOfMaps(MapWithAIPlugin.NAME.concat(".replacementtags"), tags);
|
||||
}
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue