Skip to content

v0.2.52..v0.2.53 changeset River.js

Garret Voltz edited this page Feb 12, 2020 · 1 revision
diff --git a/rules/River.js b/rules/River.js
new file mode 100644
index 0000000..13909f3
--- /dev/null
+++ b/rules/River.js
@@ -0,0 +1,168 @@
+/**
+ * This script conflates rivers using Generic Conflation.
+ */
+
+"use strict";
+
+exports.description = "Matches linear waterways";
+exports.experimental = false;
+exports.baseFeatureType = "Waterway";
+exports.geometryType = "line";
+
+exports.candidateDistanceSigma = 1.0; // 1.0 * (CE95 + Worst CE95);
+// This matcher only sets match/miss/review values to 1.0, therefore the score thresholds aren't used. 
+// If that ever changes, then the generic score threshold configuration options used below should 
+// be replaced with custom score threshold configuration options.
+exports.matchThreshold = parseFloat(hoot.get("conflate.match.threshold.default"));
+exports.missThreshold = parseFloat(hoot.get("conflate.miss.threshold.default"));
+exports.reviewThreshold = parseFloat(hoot.get("conflate.review.threshold.default"));
+exports.matchCandidateCriterion = "hoot::LinearWaterwayCriterion"; // See #3047
+
+var sublineMatcher =
+  new hoot.MaximalSublineStringMatcher(
+    { "way.matcher.max.angle": hoot.get("waterway.matcher.max.angle"),
+      "way.subline.matcher": hoot.get("waterway.subline.matcher") });
+var sampledAngleHistogramExtractor =
+  new hoot.SampledAngleHistogramExtractor(
+    { "way.angle.sample.distance" : hoot.get("waterway.angle.sample.distance"),
+      "way.matcher.heading.delta" : hoot.get("waterway.matcher.heading.delta") });
+var weightedShapeDistanceExtractor = new hoot.WeightedShapeDistanceExtractor();
+
+/**
+ * Runs before match creation occurs and provides an opportunity to perform custom initialization.
+ */
+exports.calculateSearchRadius = function(map)
+{
+  var autoCalcSearchRadius = (hoot.get("waterway.auto.calc.search.radius") === 'true');
+  if (autoCalcSearchRadius)
+  {
+    hoot.log("Calculating search radius for waterway conflation...");
+    exports.searchRadius =
+      parseFloat(
+        calculateSearchRadiusUsingRubberSheeting(
+          map,
+          hoot.get("waterway.rubber.sheet.ref"),
+          hoot.get("waterway.rubber.sheet.minimum.ties"),
+          exports.matchCandidateCriterion));
+  }
+  else
+  {
+    exports.searchRadius = parseFloat(hoot.get("search.radius.waterway"));
+    hoot.debug("Using specified search radius for waterway conflation: " + exports.searchRadius);
+  }
+}
+
+/**
+ * Returns true if e is a candidate for a match. Implementing this method is
+ * optional, but may dramatically increase speed if you can cull some features
+ * early on. E.g. no need to check nodes for a polygon to polygon match.
+ *
+ * exports.matchCandidateCriterion takes precedence over this function and must
+ * be commented out before using it.
+ * 
+ * @todo This must be left enabled for now despite exports.matchCandidateCriterion being enabled.  See #3047.
+ */
+exports.isMatchCandidate = function(map, e)
+{
+  //return true;
+  return isLinearWaterway(e);
+};
+
+/**
+ * If this function returns true then all overlapping matches will be treated
+ * as a group. For now that means if two matches overlap then the whole group
+ * will be marked as needing review.
+ *
+ * If this function returns false the conflation routines will attempt to
+ * pick the best subset of matches that do not conflict.
+ */
+exports.isWholeGroup = function()
+{
+  return false;
+};
+
+/**
+ * Returns the match score for the three class relationships.
+ * - match
+ * - miss
+ * - review
+ *
+ * The scores should always sum to one. If they don't you will be taunted
+ * mercilessly and we'll normalize it anyway. :P
+ */
+exports.matchScore = function(map, e1, e2)
+{
+  var result = { miss: 1.0, explain:"miss" };
+
+  if (e1.getStatusString() == e2.getStatusString()) 
+  {
+    return result;
+  }
+
+  // extract the sublines needed for matching
+  var sublines = sublineMatcher.extractMatchingSublines(map, e1, e2);
+  if (sublines)
+  {
+    var m = sublines.map;
+    var m1 = sublines.match1;
+    var m2 = sublines.match2;
+
+    var sampledAngleHistogramValue = sampledAngleHistogramExtractor.extract(m, m1, m2);
+    var weightedShapeDistanceValue = weightedShapeDistanceExtractor.extract(m, m1, m2);
+
+    if (sampledAngleHistogramValue == 0 && weightedShapeDistanceValue > 0.861844)
+    {
+      hoot.trace("Found Match!");
+      result = { match: 1.0, explain:"match" };
+    }
+    else if (sampledAngleHistogramValue > 0)
+    {
+      hoot.trace("Found Match!");
+      result = { match: 1.0, explain:"match" };
+    }
+  }
+
+  return result;
+};
+
+/**
+ * The internals of geometry merging can become quite complex. Typically this
+ * method will simply call another hoot method to perform the appropriate merging
+ * of geometries.
+ *
+ * If this method is exported then the mergePair method should not be exported.
+ *
+ * @param map The map that is being conflated
+ * @param pairs An array of ElementId pairs that will be merged.
+ * @param replaced An empty array is passed in, the method should fill the array
+ *      with all the replacements that occur during the merge process (e.g. if two
+ *      elements (way:1 & way:2) are merged into one element (way:3), then the
+ *      replaced array should contain [[way:1, way:3], [way:1, way:3]] where all
+ *      the "way:*" objects are of the ElementId type.
+ */
+exports.mergeSets = function(map, pairs, replaced)
+{
+  // snap the ways in the second input to the first input. Use the default tag
+  // merge method.
+  return snapWays(sublineMatcher, map, pairs, replaced, exports.baseFeatureType);
+};
+
+exports.getMatchFeatureDetails = function(map, e1, e2)
+{
+  var featureDetails = [];
+
+  // extract the sublines needed for matching
+  var sublines = sublineMatcher.extractMatchingSublines(map, e1, e2);
+  if (sublines)
+  {
+    var m = sublines.map;
+    var m1 = sublines.match1;
+    var m2 = sublines.match2;
+
+    featureDetails["sampledAngleHistogramValue"] = sampledAngleHistogramExtractor.extract(m, m1, m2);
+    featureDetails["weightedShapeDistanceValue"] = weightedShapeDistanceExtractor.extract(m, m1, m2);
+  }
+
+  return featureDetails;
+};
+
Clone this wiki locally