Changeset 28163 in osm for applications/editors
- Timestamp:
- 2012-03-28T16:47:09+02:00 (12 years ago)
- Location:
- applications/editors/josm/plugins/conflation
- Files:
-
- 69 added
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/conflation/build.xml
r27968 r28163 40 40 41 41 <!-- Needs to be used after import, otherwise ${plugin.dist.dir} is not defined --> 42 <property name="utilsplugin2" location="${plugin.dist.dir}/utilsplugin2.jar"/> 42 <property name="jtsplugin" location="${plugin.dist.dir}/jts.jar"/> 43 <property name="utilsplugin2" location="${plugin.dist.dir}/utilsplugin2.jar"/> 43 44 44 45 <!-- … … 52 53 <classpath> 53 54 <pathelement path="${josm}"/> 55 <pathelement location="${jtsplugin}"/> 54 56 <pathelement location="${utilsplugin2}"/> 55 57 </classpath> … … 95 97 <attribute name="Plugin-Description" value="(Warning: Experimental!) Tool for conflating (merging) data"/> 96 98 <attribute name="Plugin-Icon" value="images/conflation.png"/> 97 <attribute name="Plugin-Requires" value=" utilsplugin2"/>99 <attribute name="Plugin-Requires" value="jts;utilsplugin2"/> 98 100 <attribute name="Plugin-Link" value="http://wiki.openstreetmap.org/wiki/JOSM/Plugins/Conflation"/> 99 101 <attribute name="Plugin-Mainversion" value="${plugin.main.version}"/> -
applications/editors/josm/plugins/conflation/src/org/openstreetmap/josm/plugins/conflation/ConflationCandidate.java
r27971 r28163 1 1 package org.openstreetmap.josm.plugins.conflation; 2 2 3 import java.util.Iterator;4 import java.util.LinkedList;5 import java.util.List;6 3 import org.openstreetmap.josm.data.osm.OsmPrimitive; 7 import org.openstreetmap.josm.gui.layer.OsmDataLayer;8 4 import static org.openstreetmap.josm.tools.I18n.tr; 9 5 … … 15 11 16 12 OsmPrimitive referenceObject; 17 OsmDataLayer referenceLayer;18 13 OsmPrimitive subjectObject; 19 OsmDataLayer subjectLayer; 20 double cost; 14 double score; 21 15 double distance; 22 16 23 public ConflationCandidate(OsmPrimitive referenceObject, OsmDataLayer referenceLayer,24 OsmPrimitive subjectObject, OsmDataLayer subjectLayer, double cost) {17 public ConflationCandidate(OsmPrimitive referenceObject, 18 OsmPrimitive subjectObject, double score) { 25 19 if (referenceObject == null || subjectObject == null) { 26 20 throw new IllegalArgumentException(tr("Invalid reference or subject")); 27 21 } 28 22 this.referenceObject = referenceObject; 29 this.referenceLayer = referenceLayer;30 23 this.subjectObject = subjectObject; 31 this.subjectLayer = subjectLayer; 32 this.cost = cost; 33 // TODO: use distance calculated in cost function, and make sure it's in meters? 24 this.score = score; 25 // TODO: use distance calculated in score function, and make sure it's in meters? 34 26 this.distance = ConflationUtils.getCenter(referenceObject).distance(ConflationUtils.getCenter(subjectObject)); 35 27 } … … 38 30 return referenceObject; 39 31 } 40 41 public OsmDataLayer getReferenceLayer() {42 return referenceLayer;43 }44 45 public OsmDataLayer getSubjectLayer() {46 return subjectLayer;47 }48 32 49 33 public OsmPrimitive getSubjectObject() { … … 51 35 } 52 36 53 public Object get Cost() {54 return cost;37 public Object getScore() { 38 return score; 55 39 } 56 40 -
applications/editors/josm/plugins/conflation/src/org/openstreetmap/josm/plugins/conflation/ConflationLayer.java
r28036 r28163 12 12 import org.openstreetmap.josm.actions.RenameLayerAction; 13 13 import org.openstreetmap.josm.data.Bounds; 14 import org.openstreetmap.josm.data.osm.DataSet;15 14 import org.openstreetmap.josm.data.osm.Node; 16 15 import org.openstreetmap.josm.data.osm.OsmPrimitive; -
applications/editors/josm/plugins/conflation/src/org/openstreetmap/josm/plugins/conflation/ConflationToggleDialog.java
r28037 r28163 1 1 package org.openstreetmap.josm.plugins.conflation; 2 2 3 import com.vividsolutions.jcs.conflate.polygonmatch.*; 4 import com.vividsolutions.jts.geom.Envelope; 5 import com.vividsolutions.jump.feature.*; 6 import com.vividsolutions.jump.task.TaskMonitor; 3 7 import java.awt.Component; 4 8 import java.awt.Dialog; 5 import java.awt.event.*; 6 import java.util.Arrays; 7 import java.util.Collection; 8 import java.util.List; 9 import java.awt.event.ActionEvent; 10 import java.awt.event.KeyEvent; 11 import java.awt.event.WindowAdapter; 12 import java.awt.event.WindowEvent; 13 import java.awt.geom.Point2D; 14 import java.util.*; 9 15 import javax.swing.*; 10 16 import javax.swing.event.ListSelectionEvent; … … 23 29 import org.openstreetmap.josm.gui.layer.Layer; 24 30 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 25 import org.openstreetmap.josm. plugins.utilsplugin2.replacegeometry.HungarianAlgorithm;31 import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor; 26 32 import org.openstreetmap.josm.plugins.utilsplugin2.replacegeometry.ReplaceGeometryUtils; 27 33 import static org.openstreetmap.josm.tools.I18n.tr; … … 211 217 //FIXME: should layer listen for selection change? 212 218 ConflationCandidate c = conflationLayer.getSelectedCandidate(); 213 if ( c.getReferenceLayer() != c.getSubjectLayer()) {219 if (settings.getReferenceLayer() != settings.getSubjectLayer()) { 214 220 JOptionPane.showMessageDialog(Main.parent, tr("Conflation between layers isn't supported yet."), 215 221 tr("Cannot conflate between layes"), JOptionPane.ERROR_MESSAGE); … … 263 269 } 264 270 271 /** 272 * Create FeatureSchema using union of all keys from all selected primitives 273 * @param prims 274 * @return 275 */ 276 private FeatureSchema createSchema(Collection<OsmPrimitive> prims) { 277 Set<String> keys = new HashSet<String>(); 278 for (OsmPrimitive prim : prims) { 279 keys.addAll(prim.getKeys().keySet()); 280 } 281 FeatureSchema schema = new FeatureSchema(); 282 schema.addAttribute("__GEOMETRY__", AttributeType.GEOMETRY); 283 for (String key : keys) { 284 schema.addAttribute(key, AttributeType.STRING); 285 } 286 return schema; 287 } 288 289 private FeatureCollection createFeatureCollection(Collection<OsmPrimitive> prims) { 290 FeatureDataset dataset = new FeatureDataset(createSchema(prims)); 291 for (OsmPrimitive prim : prims) { 292 dataset.add(new OsmFeature(prim)); 293 } 294 return dataset; 295 } 296 297 /** 298 * Progress monitor for use with JCS 299 */ 300 private class JosmTaskMonitor extends PleaseWaitProgressMonitor implements TaskMonitor { 301 302 @Override 303 public void report(String description) { 304 subTask(description); 305 } 306 307 @Override 308 public void report(int itemsDone, int totalItems, String itemDescription) { 309 subTask(String.format("Processing %d of %d %s", itemsDone, totalItems, itemDescription)); 310 } 311 312 @Override 313 public void report(Exception exception) { 314 throw new UnsupportedOperationException("Not supported yet."); 315 } 316 317 @Override 318 public void allowCancellationRequests() { 319 setCancelable(true); 320 } 321 322 @Override 323 public boolean isCancelRequested() { 324 return isCanceled(); 325 } 326 327 } 328 265 329 private ConflationCandidateList generateCandidates(ConflationSettings settings) { 266 ConflationCandidateList cands = new ConflationCandidateList(); 267 268 // some initialization 269 int n = settings.getSubjectSelection().size(); 270 int m = settings.getReferenceSelection().size(); 271 double[][] cost = new double[n][m]; 272 // calculate cost matrix 273 for (int i = 0; i < n; i++) { 274 for (int j = 0; j < m; j++) { 275 cost[i][j] = ConflationUtils.calcCost( 276 settings.getSubjectSelection().get(i), settings.getReferenceSelection().get(j), settings); 277 } 278 } 279 // perform assignment using Hungarian algorithm 280 int[][] assignment = HungarianAlgorithm.hgAlgorithm(cost, "min"); 281 OsmPrimitive subObject; 282 OsmPrimitive refObject; 283 for (int i = 0; i < n; i++) { 284 int subIdx = assignment[i][0]; 285 int refIdx = assignment[i][1]; 286 if (subIdx < n) { 287 subObject = settings.getSubjectSelection().get(subIdx); 288 } else { 289 subObject = null; 290 } 291 if (refIdx < m) { 292 refObject = settings.getReferenceSelection().get(refIdx); 293 } else { 294 refObject = null; 295 } 296 if (subObject != null && refObject != null) { 297 // TODO: do something! 298 if (!(cands.hasCandidate(refObject, subObject) || cands.hasCandidate(subObject, refObject))) { 299 cands.add(new ConflationCandidate( 300 refObject, settings.getReferenceLayer(), 301 subObject, settings.getSubjectLayer(), cost[subIdx][refIdx])); 302 } 303 } 304 } 305 return cands; 330 JosmTaskMonitor monitor = new JosmTaskMonitor(); 331 monitor.beginTask("Generating conflation candidates"); 332 333 // create Features and collections from primitive selections 334 Set<OsmPrimitive> allPrimitives = new HashSet<OsmPrimitive>(); 335 allPrimitives.addAll(settings.getReferenceSelection()); 336 allPrimitives.addAll(settings.getSubjectSelection()); 337 FeatureCollection allFeatures = createFeatureCollection(allPrimitives); 338 FeatureCollection refColl = new FeatureDataset(allFeatures.getFeatureSchema()); 339 FeatureCollection subColl = new FeatureDataset(allFeatures.getFeatureSchema()); 340 for (Feature f : allFeatures.getFeatures()) { 341 OsmFeature osmFeature = (OsmFeature)f; 342 if (settings.getReferenceSelection().contains(osmFeature.getPrimitive())) 343 refColl.add(osmFeature); 344 if (settings.getSubjectSelection().contains(osmFeature.getPrimitive())) 345 subColl.add(osmFeature); 346 } 347 348 // get maximum possible distance so scores can be scaled (FIXME: not quite accurate) 349 Envelope envelope = refColl.getEnvelope(); 350 envelope.expandToInclude(subColl.getEnvelope()); 351 double maxDistance = Point2D.distance( 352 envelope.getMinX(), 353 envelope.getMinY(), 354 envelope.getMaxX(), 355 envelope.getMaxY()); 356 357 // build matcher 358 CentroidDistanceMatcher centroid = new CentroidDistanceMatcher(); 359 centroid.setMaxDistance(maxDistance); 360 IdenticalFeatureFilter identical = new IdenticalFeatureFilter(); 361 FeatureMatcher[] matchers = {centroid, identical}; 362 ChainMatcher chain = new ChainMatcher(matchers); 363 BasicFCMatchFinder basicFinder = new BasicFCMatchFinder(chain); 364 OneToOneFCMatchFinder finder = new OneToOneFCMatchFinder(basicFinder); 365 366 // FIXME: ignore/filter duplicate objects (i.e. same object in both sets) 367 // FIXME: fix match functions to work on point/linestring features as well 368 // find matches 369 Map<OsmFeature, Matches> map = finder.match(refColl, subColl, monitor); 370 371 monitor.subTask("Finishing conflation candidate list"); 372 373 // convert to simple one-to-one match 374 ConflationCandidateList list = new ConflationCandidateList(); 375 for (Map.Entry<OsmFeature, Matches> entry: map.entrySet()) { 376 OsmFeature target = entry.getKey(); 377 OsmFeature subject = (OsmFeature)entry.getValue().getTopMatch(); 378 list.add(new ConflationCandidate(target.getPrimitive(), subject.getPrimitive(), 379 entry.getValue().getTopScore())); 380 } 381 382 monitor.finishTask(); 383 monitor.close(); 384 return list; 306 385 } 307 386 -
applications/editors/josm/plugins/conflation/src/org/openstreetmap/josm/plugins/conflation/ConflationUtils.java
r28037 r28163 5 5 import org.openstreetmap.josm.data.coor.LatLon; 6 6 import org.openstreetmap.josm.data.osm.OsmPrimitive; 7 import org.openstreetmap.josm.tools.StringMetrics;8 7 9 8 public final class ConflationUtils { 10 private final static double MAX_COST = Double.MAX_VALUE; 11 9 12 10 public static EastNorth getCenter(OsmPrimitive prim) { 13 LatLon center = prim.getBBox().getTopLeft().getCenter(prim.getBBox().getBottomRight()); 14 return Main.map.mapView.getProjection().latlon2eastNorth(center); 15 } 16 17 /** 18 * Calculate the cost of a pair of <code>OsmPrimitive</code>'s. A 19 * simple cost consisting of the Euclidean distance is used 20 * now, later we can also use dissimilarity between tags. 21 * 22 * @param referenceObject the reference <code>OsmPrimitive</code>. 23 * @param subjectObject the non-reference <code>OsmPrimitive</code>. 24 */ 25 public static double calcCost(OsmPrimitive referenceObject, OsmPrimitive subjectObject, ConflationSettings settings) { 26 double cost; 27 28 if (referenceObject==subjectObject) { 29 return MAX_COST; 30 } 31 32 double distance = 0; 33 double stringCost = 1.0; 34 if (settings.distanceWeight != 0) { 35 distance = getCenter(referenceObject).distance(getCenter(subjectObject)); 36 } 37 if (settings.stringWeight != 0) { 38 String referenceString = referenceObject.getKeys().get(settings.keyString); 39 String subjectString = subjectObject.getKeys().get(settings.keyString); 40 41 if (referenceString == null ? subjectString == null : referenceString.equals(subjectString)) 42 stringCost = 0.0; 43 else if (referenceString == null || subjectString == null) 44 stringCost = 1.0; 45 else 46 stringCost = 1.0 - StringMetrics.getByName("levenshtein").getSimilarity(subjectString, referenceString); 47 } 48 49 if (distance > settings.distanceCutoff || stringCost > settings.stringCutoff) 50 cost = MAX_COST; 51 else 52 cost = distance * settings.distanceWeight + stringCost * settings.stringWeight; 53 54 return cost; 11 LatLon center = prim.getBBox().getTopLeft().getCenter(prim.getBBox().getBottomRight()); 12 return Main.map.mapView.getProjection().latlon2eastNorth(center); 55 13 } 56 14 } -
applications/editors/josm/plugins/conflation/src/org/openstreetmap/josm/plugins/conflation/MatchTableModel.java
r27971 r28163 14 14 15 15 private ConflationCandidateList candidates = null; 16 private final static String[] columnNames = {tr("Reference"), tr("Subject"), "Distance (m)", " Cost", "Tags"};16 private final static String[] columnNames = {tr("Reference"), tr("Subject"), "Distance (m)", "Score", "Tags"}; 17 17 18 18 @Override … … 33 33 } 34 34 35 @Override 35 36 public Object getValueAt(int row, int col) { 36 37 if (candidates == null) … … 45 46 return c.getDistance(); 46 47 } else if (col == 3) { 47 return c.get Cost();48 return c.getScore(); 48 49 } 49 50 if (col == 4) { -
applications/editors/josm/plugins/conflation/src/org/openstreetmap/josm/plugins/conflation/SettingsDialog.java
r28037 r28163 1 1 package org.openstreetmap.josm.plugins.conflation; 2 2 3 import java.awt.Component;4 3 import java.awt.GridBagLayout; 5 4 import java.awt.event.ActionEvent; … … 117 116 stringCheckBox = new JCheckBox(); 118 117 stringCheckBox.setSelected(false); 118 stringCheckBox.setEnabled(false); 119 119 stringCheckBox.setText(tr("String")); 120 120 costsPanel.add(stringCheckBox, GBC.std()); … … 126 126 costsPanel.add(stringTextField, GBC.std()); 127 127 128 costsPanel.setEnabled(false); 128 129 pnl.add(costsPanel); 129 130 setContent(pnl);
Note:
See TracChangeset
for help on using the changeset viewer.