WaySublineMatchString::WaySublineMatchString(const WaySublineMatchString& other, const OsmMapPtr& newMap) { _matches.resize(other._matches.size()); for (size_t i = 0; i < other.getMatches().size(); i++) { _matches[i] = WaySublineMatch(other.getMatches()[i], newMap); } }
bool WaySublineMatchString::touches(const WaySublineMatchString& other) const { WaySublineCollection wss1 = getSublineString1(); WaySublineCollection wss2 = getSublineString2(); WaySublineCollection owss1 = other.getSublineString1(); WaySublineCollection owss2 = other.getSublineString2(); return wss1.touches(owss1) || wss2.touches(owss2) || wss1.touches(owss2) || wss2.touches(owss1); }
WaySublineMatchString MaximalSublineStringMatcher::findMatch(const ConstOsmMapPtr& map, const ConstElementPtr& e1, const ConstElementPtr& e2, Meters maxRelevantDistance) const { assert(_maxAngle >= 0); if (maxRelevantDistance == -1) { maxRelevantDistance = e1->getCircularError() + e2->getCircularError(); } // make sure the inputs are legit. If either element isn't legit then throw a NeedsReviewException _validateElement(map, e1->getElementId()); _validateElement(map, e2->getElementId()); // extract the ways from the elements. In most cases it will return a vector of 1, but // multilinestrings may contain multiple ways vector<ConstWayPtr> ways1 = ExtractWaysVisitor::extractWays(map, e1); vector<ConstWayPtr> ways2 = ExtractWaysVisitor::extractWays(map, e2); if ((ways1.size() > 4 && ways2.size() > 4) || (ways1.size() + ways2.size() > 7)) { throw NeedsReviewException("Elements contain too many ways and the computational complexity " "is unreasonable."); } // Try with all combinations of forward and reversed ways. This is very expensive for // multilinestrings with lots of ways in them. Though those shouldn't be common. vector<bool> reversed1(ways1.size(), false), reversed2(ways2.size(), false); ScoredMatch scoredResult = _findBestMatch(map, maxRelevantDistance, ways1, ways2, reversed1, reversed2); // convert the best match into a WaySublineStringMatch and return. try { WaySublineMatchString result = scoredResult.matches; // this likely shouldn't be necessary. See #4593 result.removeEmptyMatches(); return result; } catch(OverlappingMatchesException &e) { throw NeedsReviewException("Internal Error: Multiple overlapping way matches were found within " "one set of ways. Please report this to [email protected]."); } }
bool NetworkDetails::isReversed(ConstNetworkEdgePtr e1, ConstNetworkEdgePtr e2) { assert(e1->getMembers().size() == 1); assert(e2->getMembers().size() == 1); ConstWayPtr w1 = dynamic_pointer_cast<const Way>(e1->getMembers()[0]); ConstWayPtr w2 = dynamic_pointer_cast<const Way>(e2->getMembers()[0]); // calculated the shared sublines WaySublineMatchString sublineMatch = _sublineMatcher->findMatch(_map, w1, w2, ConfigOptions().getSearchRadiusHighway()); if (sublineMatch.getReverseVector2().size() != 1) { throw NotImplementedException(); } return sublineMatch.getReverseVector2()[0]; }
MatchClassification HighwayExpertClassifier::classify(const ConstOsmMapPtr& map, ElementId /*eid1*/, ElementId /*eid2*/, const WaySublineMatchString &match) { // calculate the average classification. Is there a better approach? Max, min, mean? Dunno. MatchClassification result; for (size_t i = 0; i < match.getMatches().size(); i++) { MatchClassification m = classify(map, match.getMatches()[i]); result.setMatchP(m.getMatchP() + result.getMatchP()); result.setMissP(m.getMissP() + result.getMissP()); result.setReviewP(m.getReviewP() + result.getReviewP()); } result.normalize(); return result; }
double NetworkDetails::getPartialEdgeMatchScore(ConstNetworkEdgePtr e1, ConstNetworkEdgePtr e2) { assert(e1->getMembers().size() == 1); assert(e2->getMembers().size() == 1); ConstWayPtr w1 = dynamic_pointer_cast<const Way>(e1->getMembers()[0]); ConstWayPtr w2 = dynamic_pointer_cast<const Way>(e2->getMembers()[0]); //LOG_VAR(ElementConverter(_map).convertToGeometry(w1)->toString()); //LOG_VAR(ElementConverter(_map).convertToGeometry(w2)->toString()); // calculated the shared sublines WaySublineMatchString sublineMatch = _sublineMatcher->findMatch(_map, w1, w2, ConfigOptions().getSearchRadiusHighway()); MatchClassification c; if (sublineMatch.isValid()) { // calculate the match score c = _classifier->classify(_map, w1->getElementId(), w2->getElementId(), sublineMatch); } return c.getMatchP(); }
Handle<Value> SublineStringMatcherJs::extractMatchingSublines(const Arguments& args) { HandleScope scope; SublineStringMatcherJs* smJs = ObjectWrap::Unwrap<SublineStringMatcherJs>(args.This()); SublineStringMatcherPtr sm = smJs->getSublineStringMatcher(); OsmMapJs* mapJs = ObjectWrap::Unwrap<OsmMapJs>(args[0]->ToObject()); ElementJs* e1Js = ObjectWrap::Unwrap<ElementJs>(args[1]->ToObject()); ElementJs* e2Js = ObjectWrap::Unwrap<ElementJs>(args[2]->ToObject()); ConstOsmMapPtr m = mapJs->getConstMap(); ConstElementPtr e1 = e1Js->getConstElement(); ConstElementPtr e2 = e2Js->getConstElement(); Handle<Value> result; try { WaySublineMatchString match = sm->findMatch(m, e1, e2); if (match.isEmpty()) { return Undefined(); } // convert match into elements in a new map. set<ElementId> eids; eids.insert(e1->getElementId()); eids.insert(e2->getElementId()); OsmMapPtr copiedMap(new OsmMap(m->getProjection())); CopySubsetOp(m, eids).apply(copiedMap); WaySublineMatchString copiedMatch(match, copiedMap); // split the shared line based on the matching subline ElementPtr match1, scraps1; ElementPtr match2, scraps2; WaySublineString string1 = copiedMatch.getSublineString1(); WaySublineString string2 = copiedMatch.getSublineString2(); try { MultiLineStringSplitter().split(copiedMap, string1, copiedMatch.getReverseVector1(), match1, scraps1); MultiLineStringSplitter().split(copiedMap, string2, copiedMatch.getReverseVector2(), match2, scraps2); } catch (const IllegalArgumentException& e) { // this is unusual print out some information useful to debugging. MapReprojector::reprojectToWgs84(copiedMap); LOG_WARN(OsmWriter::toString(copiedMap)); throw e; } if (!match1 || !match2) { result = Undefined(); } else { Handle<Object> obj = Object::New(); obj->Set(String::NewSymbol("map"), OsmMapJs::create(copiedMap)); obj->Set(String::NewSymbol("match1"), ElementJs::New(match1)); obj->Set(String::NewSymbol("match2"), ElementJs::New(match2)); result = obj; } } catch (const HootException& e) { return v8::ThrowException(HootExceptionJs::create(e)); } return scope.Close(result); }
MaximalSublineStringMatcher::ScoredMatch MaximalSublineStringMatcher::_evaluateMatch( const ConstOsmMapPtr &map, Meters maxDistance, const vector<ConstWayPtr>& ways1, const vector<ConstWayPtr> &ways2, const vector<bool>& reversed1, const vector<bool> &reversed2) const { vector<WaySublineMatch> matches; // make a copy of the map and the ways we need so we can reverse the ways as needed. set<ElementId> eids; _insertElementIds(ways1, eids); _insertElementIds(ways2, eids); OsmMapPtr copiedMap(new OsmMap(map->getProjection())); CopySubsetOp(map, eids).apply(copiedMap); vector<WayPtr> prep1 = _changeMap(ways1, copiedMap); vector<WayPtr> prep2 = _changeMap(ways2, copiedMap); // reversed ways as appropriate _reverseWays(prep1, reversed1); _reverseWays(prep2, reversed2); double scoreSum = 0; // go through and match each way against every other way for (size_t i = 0; i < prep1.size(); i++) { for (size_t j = 0; j < prep2.size(); j++) { double score; WaySublineMatchString m = _sublineMatcher->findMatch(copiedMap, prep1[i], prep2[j], score, maxDistance); scoreSum += score; matches.insert(matches.end(), m.getMatches().begin(), m.getMatches().end()); } } HashMap<long, bool> wayIdToReversed1, wayIdToReversed2; // create a map from way id to reverse status for (size_t i = 0; i < prep1.size(); i++) { wayIdToReversed1[prep1[i]->getId()] = reversed1[i]; } for (size_t i = 0; i < prep2.size(); i++) { wayIdToReversed2[prep2[i]->getId()] = reversed2[i]; } // go through all the matches for (size_t i = 0; i < matches.size(); i++) { WaySubline ws1, ws2; // if the direction is reversed on one but not both ways then mark the match as reversed. long m1Id = matches[i].getSubline1().getStart().getWay()->getId(); long m2Id = matches[i].getSubline2().getStart().getWay()->getId(); if (wayIdToReversed1[m1Id]) { // make sure the way subline is pointed to the right way (not reversed) ConstWayPtr w = map->getWay(matches[i].getSubline1().getElementId()); ws1 = matches[i].getSubline1().reverse(w); } else { ws1 = WaySubline(matches[i].getSubline1(), map); } if (wayIdToReversed2[m2Id]) { // make sure the way subline is pointed to the right way (not reversed) ConstWayPtr w = map->getWay(matches[i].getSubline2().getElementId()); ws2 = matches[i].getSubline2().reverse(w); } else { ws2 = WaySubline(matches[i].getSubline2(), map); } if (wayIdToReversed1[m1Id] != wayIdToReversed2[m2Id]) { matches[i] = WaySublineMatch(ws1, ws2, true); } else { matches[i] = WaySublineMatch(ws1, ws2, false); } } return ScoredMatch(scoreSum, matches); }