QString OsmPgCsvWriter::_getTags(const ConstElementPtr& e) { QString buffer; QTextStream stream(&buffer); stream.setCodec("UTF-8"); const Tags& tags = e->getTags(); QRegExp regex("[\"=>, -]"); for (Tags::const_iterator it = tags.constBegin(); it != tags.constEnd(); ++it) { // Comma separated list if (it != tags.constBegin()) stream << ","; // Surround the key with quotes if it contains a special character requiring it if (it.key().contains(regex)) stream << "\"" << QString(it.key()).replace("\"", "\\\"") << "\""; else stream << it.key(); stream<< "=>"; // Surround the value with quotes if it contains a special character requiring it if (it.value().contains(regex)) stream << "\"" << QString(it.value()).replace("\"", "\\\"") << "\""; else stream << it.value(); } return stream.readAll(); }
void TranslatedTagCountVisitor::visit(ElementType type, long id) { shared_ptr<const Element> e = _map->getElement(type, id); if (e->getTags().getInformationCount() > 0) { shared_ptr<Geometry> g = ElementConverter(_map->shared_from_this()).convertToGeometry(e); Tags t = e->getTags(); t["error:circular"] = QString::number(e->getCircularError()); t["hoot:status"] = e->getStatusString(); // remove all the empty tags. for (Tags::const_iterator it = e->getTags().begin(); it != e->getTags().end(); ++it) { if (t[it.key()] == "") { t.remove(it.key()); } } QString layerName; vector<ScriptToOgrTranslator::TranslatedFeature> f = _translator->translateToOgr(t, e->getElementType(), g->getGeometryTypeId()); // only write the feature if it wasn't filtered by the translation script. for (size_t i = 0; i < f.size(); i++) { _countTags(f[i].feature); } } }
void OgrWriter::writeElement(ElementPtr &element, bool debug) { //Unfortunately, this check also has to happen in addition to checking hasMoreElements. See //explanation in ServicesDbReader::readNextElement. if (element.get()) { Tags sourceTags = element->getTags(); Tags destTags; for (Tags::const_iterator it = element->getTags().begin(); it != element->getTags().end(); ++it) { if (sourceTags[it.key()] != "") { destTags.appendValue(it.key(), it.value()); } } // Now that all the empties are gone, update our element element->setTags(destTags); if ( debug == true ) { LOG_DEBUG(element->toString()); } PartialOsmMapWriter::writePartial(element); } }
void OgrWriter::_writePartial(ElementProviderPtr& provider, const ConstElementPtr& e) { if (_translator.get() == 0) { throw HootException("You must call open before attempting to write."); } if (e->getTags().getInformationCount() > 0) { // There is probably a cleaner way of doing this. // convertToGeometry calls getGeometryType which will throw an exception if it gets a relation // that it doesn't know about. E.g. "route", "superroute", " turnlanes:turns" etc shared_ptr<Geometry> g; try { g = ElementConverter(provider).convertToGeometry(e); } catch (IllegalArgumentException& err) { LOG_WARN("Error converting geometry: " << err.getWhat() << " (" << e->toString() << ")"); g.reset((GeometryFactory::getDefaultInstance()->createEmptyGeometry())); } /* LOG_DEBUG("After conversion to geometry, element is now a " << g->getGeometryType() ); */ Tags t = e->getTags(); t["error:circular"] = QString::number(e->getCircularError()); t["hoot:status"] = e->getStatusString(); for (Tags::const_iterator it = e->getTags().begin(); it != e->getTags().end(); ++it) { if (t[it.key()] == "") { t.remove(it.key()); } } vector<ScriptToOgrTranslator::TranslatedFeature> tf = _translator->translateToOgr(t, e->getElementType(), g->getGeometryTypeId()); // only write the feature if it wasn't filtered by the translation script. for (size_t i = 0; i < tf.size(); i++) { OGRLayer* layer = _getLayer(tf[i].tableName); if (layer != 0) { _addFeature(layer, tf[i].feature, g); } } } }
void KeepTagsVisitor::visit(const shared_ptr<Element>& e) { //get a copy of the tags for modifying Tags tags; tags.addTags(e->getTags()); for (Tags::const_iterator it = e->getTags().begin(); it != e->getTags().end(); ++it) { if (!_keys.contains(it.key())) { tags.remove(it.key()); } } e->setTags(tags); }
bool LinearCriterion::isSatisfied(const ConstElementPtr& e) const { bool result = false; if (e->getElementType() == ElementType::Node) { return false; } const Tags& t = e->getTags(); if (e->getElementType() == ElementType::Relation) { ConstRelationPtr r = boost::dynamic_pointer_cast<const Relation>(e); result |= r->getType() == MetadataTags::RelationMultilineString(); result |= r->getType() == MetadataTags::RelationRoute(); result |= r->getType() == MetadataTags::RelationBoundary(); } for (Tags::const_iterator it = t.constBegin(); it != t.constEnd(); ++it) { const SchemaVertex& tv = OsmSchema::getInstance().getTagVertex(it.key() + "=" + it.value()); uint16_t g = tv.geometries; if (g & (OsmGeometries::LineString | OsmGeometries::ClosedWay) && !(g & OsmGeometries::Area)) { result = true; break; } } return result; }
void PertyRemoveTagVisitor::visit(const shared_ptr<Element>& e) { boost::uniform_real<> uni(0.0, 1.0); Tags t = e->getTags(); for (Tags::const_iterator it = t.constBegin(); it != t.constEnd(); ++it) { const QString tagKey = it.key(); if (uni(*_rng) <= _p && !_exemptTagKeys.contains(tagKey)) { if (!_replacementTagKeys.contains(tagKey)) { LOG_DEBUG("Removing tag with key: " << tagKey << " ..."); e->getTags().remove(tagKey); } else { const int tagIndex = _replacementTagKeys.indexOf(tagKey); const QString tagValue = _replacementTagValues.at(tagIndex); LOG_DEBUG("Substituting value: " << tagValue << " for tag with key: " << tagKey); e->getTags().set(tagKey, tagValue); } } } }
void OgrWriter::writeElement(ElementInputStream& inputStream, bool debug) { // Make sure incoming element is in WGS84 assert( inputStream.getProjection()->IsSame(&_wgs84) == true ); ElementPtr nextElement = inputStream.readNextElement(); // TERRY TESTING COULD BE CATASTROPHIC Tags sourceTags = nextElement->getTags(); Tags destTags; for (Tags::const_iterator it = nextElement->getTags().begin(); it != nextElement->getTags().end(); ++it) { if (sourceTags[it.key()] != "") { destTags.appendValue(it.key(), it.value()); } } // Now that all the empties are gone, update our element nextElement->setTags(destTags); if ( debug == true ) { LOG_DEBUG(nextElement->toString()); } PartialOsmMapWriter::writePartial(nextElement); /* if ( nextElement->getElementType().getEnum() == ElementType::Node ) { //LOG_DEBUG("\n" << nextElement->toString()); const long nodeID = nextElement->getId(); if ( (nodeID >= -265198) && (nodeID <= -265167) ) { LOG_DEBUG("\n" << nextElement->toString()); PartialOsmMapWriter::writePartial(nextElement); } } else if ((nextElement->getElementType().getEnum() == ElementType::Way) && (nextElement->getId() == -23189) ) { LOG_DEBUG("Writing Little Mill Creek -23189"); LOG_DEBUG("\n" << nextElement->toString()); PartialOsmMapWriter::writePartial(nextElement); } */ }
void PbfWriter::_writeRelation(const shared_ptr<const hoot::Relation>& r) { _elementsWritten++; if (_pg == 0) { _pg = _d->primitiveBlock.add_primitivegroup(); } pb::Relation* pbr = _pg->add_relations(); pbr->set_id(r->getId() + _relationIdDelta); // From http://wiki.openstreetmap.org/wiki/PBF_Format#Ways_and_Relations // For ways and relations, which contain the ID's of other nodes, I exploit the tendency of // consecutive nodes in a way or relation to have nearby node ID's by using delta compression, // resulting in small integers. (I.E., instead of encoding x_1, x_2, x_3, I encode // x_1, x_2-x_1, x_3-x_2, ...). long lastId = 0; const vector<RelationData::Entry>& entries = r->getMembers(); for (size_t i = 0; i < entries.size(); i++) { long id = entries[i].getElementId().getId() + _nodeIdDelta; pbr->add_memids(id - lastId); lastId = id + _nodeIdDelta; pbr->add_types((hoot::pb::Relation_MemberType) _toRelationMemberType(entries[i].getElementId().getType())); pbr->add_roles_sid(_convertString(entries[i].role)); } // From http://wiki.openstreetmap.org/wiki/PBF_Format#Ways_and_Relations // Tags are encoded as two parallel arrays, one array of string-id's of the keys, and the other // of string-id's of the values. const Tags& tags = r->getTags(); for (Tags::const_iterator it = tags.constBegin(); it != tags.constEnd(); ++it) { const QString& key = it.key(); const QString& value = it.value(); if (!value.isEmpty()) { pbr->add_keys(_convertString(key)); pbr->add_vals(_convertString(value)); } } int kid = _convertString("error:circular"); int vid = _convertString(QString::number(r->getCircularError())); pbr->add_keys(kid); pbr->add_vals(vid); if (r->getStatus() != Status::Invalid) { kid = _convertString("hoot:status"); vid = _convertString(QString::number(r->getStatus().getEnum())); pbr->add_keys(kid); pbr->add_vals(vid); } _dirty = true; }
void compareTags(const Tags& t1, const Tags& t2) { if (t1.size() != t2.size()) { LOG_WARN("t1: " << t1.toString()); LOG_WARN("t2: " << t2.toString()); CPPUNIT_ASSERT_EQUAL(t1.size(), t2.size()); } for (Tags::const_iterator it = t1.begin(); it != t1.end(); it++) { if (t1[it.key()] != t2[it.key()]) { LOG_WARN("t1: " << t1.toString()); LOG_WARN("t2: " << t2.toString()); CPPUNIT_ASSERT_EQUAL(t1[it.key()].toStdString(), t2[it.key()].toStdString()); } } }
void SplitNameVisitor::visit(const shared_ptr<Element>& e) { Tags& t = e->getTags(); QStringList extraNames; Tags copy = t; for (Tags::const_iterator it = copy.begin(); it != copy.end(); ++it) { const QString& k = it.key(); const QString& v = it.value(); if (v.size() > _maxSize && OsmSchema::getInstance().getCategories(it.key()).intersects(OsmSchemaCategory::name())) { QStringList l = _splitNames(v, extraNames); t.setList(k, l); } } _addExtraNames(t, extraNames); }
virtual void visit(const shared_ptr<const Element>& e) { if (e->getElementType() == _type || _type == ElementType::Unknown) { const Tags& tags = e->getTags(); for (Tags::const_iterator it = tags.begin(); it != tags.end(); ++it) { _keys[it.key()]++; } } }
void PbfWriter::_writeNode(const shared_ptr<const hoot::Node>& n) { _elementsWritten++; if (_pg == 0) { _pg = _d->primitiveBlock.add_primitivegroup(); } ::google::protobuf::RepeatedPtrField< ::hoot::pb::Node >* nodes = _pg->mutable_nodes(); _dirty = true; pb::Node* newNode = nodes->Add(); newNode->set_id(n->getId() + _nodeIdDelta); newNode->set_lon(_convertLon(n->getX())); newNode->set_lat(_convertLat(n->getY())); const Tags& tags = n->getTags(); for (Tags::const_iterator it = tags.constBegin(); it != tags.constEnd(); ++it) { const QString& key = it.key(); const QString& value = it.value(); int kid = _convertString(key); int vid = _convertString(value); if (!value.isEmpty()) { newNode->add_keys(kid); newNode->add_vals(vid); } } // if there are tags on the node then record the CE. CE isn't used as part of a way // at this point. Instead the way records the CE for the entire way. No need to waste disk. if (n->getTags().getNonDebugCount() > 0) { int kid = _convertString("error:circular"); int vid = _convertString(QString::number(n->getCircularError())); newNode->add_keys(kid); newNode->add_vals(vid); if (n->getStatus() != Status::Invalid) { kid = _convertString("hoot:status"); vid = _convertString(QString::number(n->getStatus().getEnum())); newNode->add_keys(kid); newNode->add_vals(vid); } } }
bool PoiPolygonMatch::_calculateTypeMatch(ConstElementPtr e1, ConstElementPtr e2) const { bool result = false; const Tags& t1 = e1->getTags(); const Tags& t2 = e2->getTags(); for (Tags::const_iterator it = t1.begin(); it != t1.end(); it++) { // if it is a use or POI category if ((OsmSchema::getInstance().getCategories(it.key(), it.value()) & (OsmSchemaCategory::building() | OsmSchemaCategory::use() | OsmSchemaCategory::poi())) != OsmSchemaCategory::Empty) { result = t2.get(it.key()) == it.value(); if (result) { return result; } } } return result; }
void TagComparator::compareTextTags(const Tags& t1, const Tags& t2, double& score, double& weight) { OsmSchema& schema = OsmSchema::getInstance(); score = 1.0; weight = 0.0; for (Tags::const_iterator it = t1.begin(); it != t1.end(); it++) { const SchemaVertex& tv = schema.getTagVertex(it.key()); if (schema.isAncestor(it.key(), "abstract_name") == false && tv.valueType == Text && t2.contains(it.key())) { score *= LevenshteinDistance::score(it.value(), t2[it.key()]); weight += tv.influence; } } // if the weight is zero don't confuse things with a low score. if (weight == 0.0) { score = 1; } }
void OsmApiDbSqlChangesetFileWriter::_createTags(ConstElementPtr element) { LOG_TRACE("Creating tags for: " << element->getElementId()); QStringList tableNames = _tagTableNamesForElement(element->getElementId()); Tags tags = element->getTags(); if (_includeDebugTags) { tags.set(MetadataTags::HootStatus(), QString::number(element->getStatus().getEnum())); } LOG_VART(tags); if (element->getElementType().getEnum() == ElementType::Relation && !tags.contains("type")) { ConstRelationPtr tmp = boost::dynamic_pointer_cast<const Relation>(element); tags.appendValue("type", tmp->getType()); } for (Tags::const_iterator it = tags.begin(); it != tags.end(); ++it) { QString k = it.key(); QString v = it.value(); if (k != MetadataTags::HootHash()) { const QString currentTagValues = QString("(%1_id, k, v) VALUES (%2, '%3', '%4');\n") .arg(element->getElementId().getType().toString().toLower()) .arg(element->getElementId().getId()) .arg(k.replace('\'', "''")) .arg(v.replace('\'', "''")); const QString tagValues = QString("(%1_id, k, v, version) VALUES (%2, '%3', '%4', %5);\n") .arg(element->getElementId().getType().toString().toLower()) .arg(element->getElementId().getId()) .arg(k.replace('\'', "''")) .arg(v.replace('\'', "''")) .arg(element->getVersion()); _outputSql.write( (QString("INSERT INTO %1 ").arg(tableNames.at(0)) + currentTagValues).toUtf8()); _outputSql.write((QString("INSERT INTO %1 ").arg(tableNames.at(1)) + tagValues).toUtf8()); } } }
QString ServicesDb::_escapeTags(const Tags& tags) const { QStringList l; static QChar f1('\\'), f2('"'), f3('\''); static QChar to('_'); for (Tags::const_iterator it = tags.begin(); it != tags.end(); ++it) { // this doesn't appear to be working, but I think it is implementing the spec as described here: // http://www.postgresql.org/docs/9.0/static/hstore.html // The spec described above does seem to work on the psql command line. Curious. QString k = QString(it.key()).replace(f1, "\\\\").replace(f2, "\\\""); QString v = QString(it.value()).replace(f1, "\\\\").replace(f2, "\\\""); l << QString("\"%1\"=>\"%2\"").arg(k).arg(v); } return l.join(","); }
bool RoundaboutCriterion::isSatisfied(const ConstElementPtr& e) const { // If it's not a highway, it's not a roundabout if (!HighwayCriterion().isSatisfied(e)) { return false; } // Now check some details... bool result = false; Tags::const_iterator tagIt = e->getTags().find("junction"); if (tagIt != e->getTags().end() && tagIt.value().toLower() == "roundabout") { result = true; } if (result) { LOG_TRACE("isRoundabout; key: " << tagIt.key()); } return result; }
void PbfWriter::_writeWay(const shared_ptr<const hoot::Way>& w) { _elementsWritten++; if (_pg == 0) { _pg = _d->primitiveBlock.add_primitivegroup(); } pb::Way* pbw = _pg->add_ways(); pbw->set_id(w->getId() + _wayIdDelta); // if the cached envelope is valid const Envelope& env = w->getApproximateEnvelope(_map); if (env.isNull() == false) { // write the way's approximate bounding box. This is a custom Hoot extension to the format. pbw->mutable_bbox()->set_left(_convertLon(env.getMinX())); pbw->mutable_bbox()->set_right(_convertLon(env.getMaxX())); pbw->mutable_bbox()->set_top(_convertLat(env.getMaxY())); pbw->mutable_bbox()->set_bottom(_convertLat(env.getMinY())); } // From http://wiki.openstreetmap.org/wiki/PBF_Format#Ways_and_Relations // For ways and relations, which contain the ID's of other nodes, I exploit the tendency of // consecutive nodes in a way or relation to have nearby node ID's by using delta compression, // resulting in small integers. (I.E., instead of encoding x_1, x_2, x_3, I encode // x_1, x_2-x_1, x_3-x_2, ...). long lastId = 0; const std::vector<long>& ids = w->getNodeIds(); for (size_t i = 0; i < ids.size(); i++) { pbw->add_refs(ids[i] + _nodeIdDelta - lastId); lastId = ids[i] + _nodeIdDelta; } // From http://wiki.openstreetmap.org/wiki/PBF_Format#Ways_and_Relations // Tags are encoded as two parallel arrays, one array of string-id's of the keys, and the other // of string-id's of the values. const Tags& tags = w->getTags(); for (Tags::const_iterator it = tags.constBegin(); it != tags.constEnd(); ++it) { const QString& key = it.key(); const QString& value = it.value(); if (!value.isEmpty()) { pbw->add_keys(_convertString(key)); pbw->add_vals(_convertString(value)); } } int kid = _convertString("error:circular"); int vid = _convertString(QString::number(w->getCircularError())); pbw->add_keys(kid); pbw->add_vals(vid); if (w->getStatus() != Status::Invalid) { kid = _convertString("hoot:status"); vid = _convertString(QString::number(w->getStatus().getEnum())); pbw->add_keys(kid); pbw->add_vals(vid); } _dirty = true; }
void PbfWriter::_writeNodeDense(const shared_ptr<const hoot::Node>& n) { _elementsWritten++; if (_dn == 0) { _dn = _d->primitiveBlock.add_primitivegroup()->mutable_dense(); } _dirty = true; // From http://wiki.openstreetmap.org/wiki/PBF_Format#Nodes // I store the group 'columnwise', as an array of ID's, array of latitudes, and array of // longitudes. Each column is delta-encoded. This reduces header overheads and allows // delta-coding to work very effectively. long lon = _convertLon(n->getX()); long lat = _convertLat(n->getY()); _dn->add_id(n->getId() + _nodeIdDelta - _lastId); _dn->add_lon(lon - _lastLon); _dn->add_lat(lat - _lastLat); _lastId = n->getId() + _nodeIdDelta; _lastLon = lon; _lastLat = lat; // From http://wiki.openstreetmap.org/wiki/PBF_Format#Nodes // Keys and values for all nodes are encoded as a single array of stringid's. Each node's tags // are encoded in alternating <keyid> <valid>. We use a single stringid of 0 to delimit when the // tags of a node ends and the tags of the next node begin. The storage pattern is: // ((<keyid> <valid>)* '0' )* const Tags& tags = n->getTags(); for (Tags::const_iterator it = tags.constBegin(); it != tags.constEnd(); ++it) { const QString& key = it.key(); const QString& value = it.value(); int kid = _convertString(key); int vid = _convertString(value); if (!value.isEmpty()) { _dn->add_keys_vals(kid); _dn->add_keys_vals(vid); } } // if there are tags on the node then record the CE. CE isn't used as part of a way // at this point. Instead the way records the CE for the entire way. No need to waste disk. if (n->getTags().getNonDebugCount() > 0) { int kid = _convertString("error:circular"); int vid = _convertString(QString::number(n->getCircularError())); _dn->add_keys_vals(kid); _dn->add_keys_vals(vid); if (n->getStatus() != Status::Invalid) { kid = _convertString("hoot:status"); vid = _convertString(QString::number(n->getStatus().getEnum())); _dn->add_keys_vals(kid); _dn->add_keys_vals(vid); } } _dn->add_keys_vals(0); }
shared_ptr<Relation> BuildingPartMergeOp::combineParts(const OsmMapPtr& map, const vector< shared_ptr<Element> >& parts) { assert(parts.size() > 0); shared_ptr<Relation> building(new Relation(parts[0]->getStatus(), map->createNextRelationId(), -1, "building")); OsmSchema& schema = OsmSchema::getInstance(); Tags& t = building->getTags(); for (size_t i = 0; i < parts.size(); i++) { building->addElement("part", parts[i]); Tags pt = parts[i]->getTags(); Tags tCopy = t; Tags names; TagComparator::getInstance().mergeNames(tCopy, pt, names); t.set(names); // go through all the tags. for (Tags::const_iterator it = pt.begin(); it != pt.end(); it++) { // ignore all keys that are building:part specific. if (_buildingPartTagNames.find(it.key()) == _buildingPartTagNames.end()) { // if the tag isn't already in the relation if (t.contains(it.key()) == false) { t[it.key()] = it.value(); } // if this is an arbitrary text value, then concatenate the values. else if (schema.isTextTag(it.key())) { t.appendValueIfUnique(it.key(), it.value()); } // if the tag is in the relation and the tags differ. else if (t[it.key()] != it.value()) { t[it.key()] = ""; } } } } // go through all the keys that were consistent for each of the parts and move them into the // relation. Tags tCopy = t; for (Tags::const_iterator it = tCopy.begin(); it != tCopy.end(); it++) { // if the value is empty, then the tag isn't needed, or it wasn't consistent between multiple // parts. if (it.value() == "") { t.remove(it.key()); } // if the tag isn't empty, remove it from each of the parts. else { for (size_t i = 0; i < parts.size(); i++) { parts[i]->getTags().remove(it.key()); } } } if (t.contains("building") == false) { t["building"] = "yes"; } // replace the building tag with building:part tags. for (size_t i = 0; i < parts.size(); i++) { parts[i]->getTags().remove("building"); parts[i]->getTags()["building:part"] = "yes"; } map->addRelation(building); return building; }
QString AttributeCount::Count(QString input) { QString finalText; int maxAttributes = ConfigOptions().getAttributeCountValues(); OgrReader reader; reader.setTranslationFile(QString(getenv("HOOT_HOME")) + "/translations/quick.js"); QStringList layers; if (input.contains(";")) { QStringList list = input.split(";"); input = list.at(0); layers.append(list.at(1)); } else { layers = reader.getFilteredLayerNames(input); } if (layers.size() == 0) { LOG_WARN("Could not find any valid layers to read from in " + input + "."); } for (int i = 0; i < layers.size(); i++) { AttributeCountHash result; LOG_DEBUG("Reading: " + input + " " + layers[i]); shared_ptr<ElementIterator> iterator(reader.createIterator(input, layers[i])); while(iterator->hasNext()) { shared_ptr<Element> e = iterator->next(); // // Interesting problem: If there are no elements in the file, e == 0 // // Need to look at the ElementIterator.cpp file to fix this. // if (e == 0) // { // LOG_WARN("No features in: " + input + " " + layer); // break; // } Tags t = e->getTags(); for (Tags::const_iterator it = e->getTags().begin(); it != e->getTags().end(); ++it) { if (it.value() == "") // Drop empty values { continue; } // Drop Hoot metadata tags if (it.key() == "source:ingest:datetime") { continue; } // The default is 30 values if (result.value(it.key()).size() < maxAttributes ) { result[it.key()][it.value()]++; } } } // End Layer QString tmpText = _printJSON(layers[i], result); // Skip empty layers if (tmpText == "") { continue; } finalText += tmpText; if (i != (layers.size() - 1)) { finalText += ",\n"; } } // End layer list return finalText; } // End AttributeCount
void OsmWriter::_writeNodes(shared_ptr<const OsmMap> map, QXmlStreamWriter& writer) { QList<long> nids; NodeMap::const_iterator it = map->getNodeMap().begin(); while (it != map->getNodeMap().end()) { nids.append(it->first); ++it; } // sort the values to give consistent results. qSort(nids.begin(), nids.end(), qGreater<long>()); for (int i = 0; i < nids.size(); i++) { const Node* n = map->getNode(nids[i]).get(); writer.writeStartElement("node"); writer.writeAttribute("visible", "true"); writer.writeAttribute("id", QString::number(n->getId())); _writeMetadata(writer, n); writer.writeAttribute("lat", QString::number(n->getY(), 'f', _precision)); writer.writeAttribute("lon", QString::number(n->getX(), 'f', _precision)); const Tags& tags = n->getTags(); for (Tags::const_iterator it = tags.constBegin(); it != tags.constEnd(); it++) { if (it.key().isEmpty() == false && it.value().isEmpty() == false) { writer.writeStartElement("tag"); writer.writeAttribute("k", _e(it.key())); writer.writeAttribute("v", _e(it.value())); writer.writeEndElement(); } } // turn this on when we start using node circularError. if (n->getCircularError() >= 0 && n->getTags().getNonDebugCount() > 0) { writer.writeStartElement("tag"); writer.writeAttribute("k", "error:circular"); writer.writeAttribute("v", QString("%1").arg(n->getCircularError())); writer.writeEndElement(); } if (_includeDebug || _includeIds) { writer.writeStartElement("tag"); writer.writeAttribute("k", "hoot:id"); writer.writeAttribute("v", QString("%1").arg(n->getId())); writer.writeEndElement(); } if (_includeDebug) { writer.writeStartElement("tag"); writer.writeAttribute("k", "hoot:status"); writer.writeAttribute("v", QString("%1").arg(n->getStatus().getEnum())); writer.writeEndElement(); } writer.writeEndElement(); } }
void OsmWriter::_writeWays(shared_ptr<const OsmMap> map, QXmlStreamWriter& writer) { WayMap::const_iterator it = map->getWays().begin(); while (it != map->getWays().end()) { const Way* w = it->second.get(); writer.writeStartElement("way"); writer.writeAttribute("visible", "true"); writer.writeAttribute("id", QString::number(w->getId())); _writeMetadata(writer, w); for (size_t j = 0; j < w->getNodeCount(); j++) { writer.writeStartElement("nd"); long nid = w->getNodeId(j); writer.writeAttribute("ref", QString::number(w->getNodeId(j))); if (_includePointInWays) { shared_ptr<const Node> n = map->getNode(nid); writer.writeAttribute("x", QString::number(n->getX(), 'g', _precision)); writer.writeAttribute("y", QString::number(n->getY(), 'g', _precision)); } writer.writeEndElement(); } const Tags& tags = w->getTags(); for (Tags::const_iterator tit = tags.constBegin(); tit != tags.constEnd(); ++tit) { if (tit.key().isEmpty() == false && tit.value().isEmpty() == false) { writer.writeStartElement("tag"); writer.writeAttribute("k", _e(tit.key())); writer.writeAttribute("v", _e(tit.value())); writer.writeEndElement(); } } if (w->getCircularError() >= 0) { writer.writeStartElement("tag"); writer.writeAttribute("k", "error:circular"); writer.writeAttribute("v", QString("%1").arg(w->getCircularError())); writer.writeEndElement(); } if (_includeDebug || _includeIds) { writer.writeStartElement("tag"); writer.writeAttribute("k", "hoot:id"); writer.writeAttribute("v", QString("%1").arg(w->getId())); writer.writeEndElement(); } if (_includeDebug) { writer.writeStartElement("tag"); writer.writeAttribute("k", "hoot:status"); writer.writeAttribute("v", QString("%1").arg(w->getStatus().getEnum())); writer.writeEndElement(); } writer.writeEndElement(); ++it; } }
void OsmWriter::_writeRelations(shared_ptr<const OsmMap> map, QXmlStreamWriter& writer) { RelationMap::const_iterator it = map->getRelationMap().begin(); while (it != map->getRelationMap().end()) { const shared_ptr<Relation>& r = it->second; writer.writeStartElement("relation"); writer.writeAttribute("visible", "true"); writer.writeAttribute("id", QString::number(r->getId())); _writeMetadata(writer, r.get()); const vector<RelationData::Entry>& members = r->getMembers(); for (size_t j = 0; j < members.size(); j++) { const RelationData::Entry& e = members[j]; writer.writeStartElement("member"); writer.writeAttribute("type", _typeName(e.getElementId().getType())); writer.writeAttribute("ref", QString::number(e.getElementId().getId())); writer.writeAttribute("role", _e(e.role)); writer.writeEndElement(); } const Tags& tags = r->getTags(); for (Tags::const_iterator tit = tags.constBegin(); tit != tags.constEnd(); ++tit) { if (tit.key().isEmpty() == false && tit.value().isEmpty() == false) { writer.writeStartElement("tag"); writer.writeAttribute("k", _e(tit.key())); writer.writeAttribute("v", _e(tit.value())); writer.writeEndElement(); } } if (r->getType() != "") { writer.writeStartElement("tag"); writer.writeAttribute("k", "type"); writer.writeAttribute("v", _e(r->getType())); writer.writeEndElement(); } if (r->getCircularError() >= 0) { writer.writeStartElement("tag"); writer.writeAttribute("k", "error:circular"); writer.writeAttribute("v", QString("%1").arg(r->getCircularError())); writer.writeEndElement(); } if (_includeDebug || _includeIds) { writer.writeStartElement("tag"); writer.writeAttribute("k", "hoot:id"); writer.writeAttribute("v", QString("%1").arg(r->getId())); writer.writeEndElement(); } if (_includeDebug) { writer.writeStartElement("tag"); writer.writeAttribute("k", "hoot:status"); writer.writeAttribute("v", QString("%1").arg(r->getStatus().getEnum())); writer.writeEndElement(); } writer.writeEndElement(); ++it; } }
QList<ElementPhoneNumber> PhoneNumberParser::parsePhoneNumbers(const Element& element) const { //phone=* is the standard OSM tag, but have seen many others over time...keeping the allowed tags //fairly loose for now QList<ElementPhoneNumber> parsedPhoneNums; for (Tags::const_iterator it = element.getTags().constBegin(); it != element.getTags().constEnd(); ++it) { const QString tagKey = it.key(); LOG_VART(tagKey); if (_additionalTagKeys.contains(tagKey, Qt::CaseInsensitive) || tagKey.contains("phone", Qt::CaseInsensitive)) { const QString tagValue = it.value().toUtf8().trimmed().simplified(); LOG_VART(tagValue); if (_regionCode.isEmpty()) { // If we're not using a region code to see if the number is valid, then just check for at // least one digit (vanity numbers can have letters). // consider getting rid of this, as its too weak of a check if (StringUtils::hasDigit(tagValue)) { _addPhoneNumber(element.getTags().getName(), tagKey, tagValue, parsedPhoneNums); } } else { if (!_searchInText) { // IsPossibleNumber is a fairly quick check (IsValidNumber is more strict and a little // more expensive) if (PhoneNumberUtil::GetInstance()->IsPossibleNumberForString( tagValue.toStdString(), _regionCode.toStdString())) { _addPhoneNumber(element.getTags().getName(), tagKey, tagValue, parsedPhoneNums); } } else { // This lets us search through text that may have other things in it besides phone // numbers. PhoneNumberMatcher numberFinder( *PhoneNumberUtil::GetInstance(), tagValue.toStdString(), _regionCode.toStdString(), PhoneNumberMatcher::Leniency::POSSIBLE, //not sure what a good number is for max tries yet or what that number actually even //means 1); int parserFinds = 0; while (numberFinder.HasNext()) { PhoneNumberMatch match; numberFinder.Next(&match); const QString parsedNum = QString::fromStdString(match.raw_string()); _addPhoneNumber(element.getTags().getName(), tagKey, parsedNum, parsedPhoneNums); parserFinds++; } LOG_TRACE("Number finder found " << parserFinds << " numbers."); } } if (parsedPhoneNums.size() == 0) { LOG_TRACE("Not a phone number: " << tagKey << "=" << tagValue); } } } return parsedPhoneNums; }