Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package org.openstreetmap.atlas.checks.event;
import static org.openstreetmap.atlas.geography.geojson.GeoJsonConstants.GEOMETRY;
import static org.openstreetmap.atlas.geography.geojson.GeoJsonConstants.PROPERTIES;
import static org.openstreetmap.atlas.geography.geojson.GeoJsonConstants.TYPE;
import static org.openstreetmap.atlas.geography.geojson.GeoJsonUtils.OSM_IDENTIFIER;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.openstreetmap.atlas.checks.base.Check;
import org.openstreetmap.atlas.checks.flag.CheckFlag;
import org.openstreetmap.atlas.checks.flag.FlaggedObject;
import org.openstreetmap.atlas.checks.flag.FlaggedRelation;
import org.openstreetmap.atlas.geography.geojson.GeoJsonBuilder;
import org.openstreetmap.atlas.geography.geojson.GeoJsonBuilder.GeometryWithProperties;
import org.openstreetmap.atlas.geography.geojson.GeoJsonObject;
import org.openstreetmap.atlas.tags.HighwayTag;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
/**
* Wraps a {@link CheckFlag} for submission to the {@link EventService} for handling {@link Check}
* results
*
* @author mkalender, bbreithaupt
*/
public final class CheckFlagEvent extends Event
{
private static final GeoJsonBuilder GEOJSON_BUILDER = new GeoJsonBuilder();
private static final String GEOMETRY_COLLECTION = "GeometryCollection";
private static final String GEOMETRIES = "geometries";
private static final String FEATURES = "features";
private static final String FEATURE_COLLECTION = "FeatureCollection";
private static final String INSTRUCTIONS = "instructions";
private final String checkName;
private final CheckFlag flag;
/**
* Converts give {@link CheckFlag} to {@link GeoJsonObject} with additional key-value parameters
*
* @param flag
* {@link CheckFlag} to convert to {@link GeoJsonObject}
* @param additionalProperties
* additional key-value parameters to be added in "properties" element of the
* top-level JSON object
* @return {@link GeoJsonObject} created from {@link CheckFlag}
*/
public static JsonObject flagToFeature(final CheckFlag flag,
final Map additionalProperties)
{
final JsonObject flagProperties = new JsonObject();
flagProperties.addProperty(INSTRUCTIONS, flag.getInstructions());
// Add additional properties
additionalProperties.forEach(flagProperties::addProperty);
final JsonObject feature;
final List geometriesWithProperties = flag
.getGeometryWithProperties();
final Set flaggedRelations = flag.getFlaggedRelations();
final JsonArray geometriesJsonArray;
final JsonArray featureProperties = new JsonArray();
final Set featureOsmIds = new HashSet<>();
if (!geometriesWithProperties.isEmpty())
{
if (geometriesWithProperties.size() + flaggedRelations.size() == 1)
{
feature = GEOJSON_BUILDER.create(geometriesWithProperties.get(0));
}
else
{
feature = GEOJSON_BUILDER.createGeometryCollectionFeature(geometriesWithProperties)
.jsonObject();
}
// Geometries with coordinates
geometriesJsonArray = feature.get(GEOMETRY).getAsJsonObject()
.getAsJsonArray(GEOMETRIES);
geometriesWithProperties.forEach(geometry -> Optional
.ofNullable(geometry.getProperties()).ifPresent(propertyMap ->
{
final JsonObject properties = new JsonObject();
propertyMap.forEach(
(key, value) -> properties.addProperty(key, (String) value));
featureProperties.add(properties);
Optional.ofNullable(properties.get(OSM_IDENTIFIER))
.ifPresent(featureOsmIds::add);
}));
}
else
{
feature = new JsonObject();
geometriesJsonArray = new JsonArray();
}
if (!flaggedRelations.isEmpty())
{
if (!feature.has(TYPE))
{
feature.addProperty(TYPE, "Feature");
}
// Get flagged relations as GeoJson features
final List flaggedRelationFeatures = getFlaggedRelationsGeojsonFeatures(
flag);
if (flaggedRelations.size() == 1 && !feature.has(GEOMETRY))
{
feature.add(GEOMETRY, flaggedRelationFeatures.get(0).get(GEOMETRY));
}
else if (flaggedRelations.size() != 1 && !feature.has(GEOMETRY))
{
final JsonObject geometryCollection = new JsonObject();
geometryCollection.add(GEOMETRIES, geometriesJsonArray);
geometryCollection.addProperty(TYPE, GEOMETRY_COLLECTION);
feature.add(GEOMETRY, geometryCollection);
}
// To geometries of flagged objects add geometries of flaggedRelation
geometriesJsonArray.addAll(populateFlaggedRelationGeometries(flaggedRelationFeatures));
// To properties of flagged objects add properties of flaggedRelation
featureProperties
.addAll(populateFlaggedRelationFeatureProperties(flaggedRelationFeatures));
featureOsmIds.addAll(populateFlaggedRelationFeatureOsmIds(flaggedRelationFeatures));
}
final JsonArray uniqueFeatureOsmIds = new JsonArray();
featureOsmIds.forEach(uniqueFeatureOsmIds::add);
// Override name property if able to add a decorator to the name
CheckFlagEvent.featureDecorator(featureProperties)
.ifPresent(decorator -> flagProperties.addProperty("name",
String.format("%s (%s)",
Optional.ofNullable(flagProperties.getAsJsonPrimitive("name"))
.map(JsonPrimitive::getAsString).orElse("Task"),
decorator)));
// Reference properties lost during GeoJson conversion
flagProperties.add("feature_properties", featureProperties);
flagProperties.add("feature_osmids", uniqueFeatureOsmIds);
flagProperties.addProperty("feature_count", featureProperties.size());
feature.addProperty("id", flag.getIdentifier());
feature.add("properties", flagProperties);
return feature;
}
/**
* Converts given {@link CheckFlag} to {@link JsonObject} with additional key-value parameters
*
* @param flag
* {@link CheckFlag} to convert to {@link JsonObject}
* @param additionalProperties
* additional key-value parameters to be added in "properties" element of the
* top-level JSON object
* @return {@link JsonObject} created from {@link CheckFlag}
*/
public static JsonObject flagToJson(final CheckFlag flag,
final Map additionalProperties)
{
JsonObject flagJson = new JsonObject();
if (!flag.getFlaggedObjects().isEmpty())
{
flagJson = GEOJSON_BUILDER
.createFromGeometriesWithProperties(flag.getGeometryWithProperties())
.jsonObject();
}
final Set flaggedRelations = flag.getFlaggedRelations();
// Add features of FlaggedRelation if any
if (!flaggedRelations.isEmpty())
{
// Add type feature collection if not already set.
if (!flagJson.has(FEATURES))
{
flagJson.addProperty(TYPE, FEATURE_COLLECTION);
flagJson.add(FEATURES, new JsonArray());
}
final JsonArray features = flagJson.getAsJsonArray(FEATURES);
// Get features of each flaggedRelations and add it to the flagJson object's FEATURES
// element
flaggedRelations.stream()
.map(flaggedRelation -> flaggedRelation.asGeoJsonFeature(flag.getIdentifier()))
.forEach(features::add);
}
final JsonObject flagPropertiesJson = new JsonObject();
flagPropertiesJson.addProperty("id", flag.getIdentifier());
flagPropertiesJson.addProperty(INSTRUCTIONS, flag.getInstructions());
// Add additional properties
additionalProperties.forEach(flagPropertiesJson::addProperty);
// Add properties to the previously generate geojson
flagJson.add("properties", flagPropertiesJson);
return flagJson;
}
/**
* Extracts a decorator based on the collective features properties. Currently the only
* decoration is the highest class highway tag withing all of the feature properties for flags
* involving Edges.
*/
private static Optional featureDecorator(final JsonArray featureProperties)
{
HighwayTag highestHighwayTag = null;
for (final JsonElement featureProperty : featureProperties)
{
final HighwayTag baslineHighwayTag = highestHighwayTag == null ? HighwayTag.NO
: highestHighwayTag;
try
{
highestHighwayTag = Optional
.ofNullable(
((JsonObject) featureProperty).getAsJsonPrimitive(HighwayTag.KEY))
.map(JsonPrimitive::getAsString).map(String::toUpperCase)
.map(HighwayTag::valueOf).filter(baslineHighwayTag::isLessImportantThan)
.orElse(highestHighwayTag);
}
catch (final IllegalArgumentException badValue)
{
return Optional.empty();
}
}
return Optional.ofNullable(highestHighwayTag)
.map(tag -> String.format("%s=%s", HighwayTag.KEY, tag.getTagValue()));
}
/**
* Get geometry of flagged relation feature.
*
* @param flaggedRelationFeature
* {@link FlaggedRelation} feature
* @return geometry as {@link JsonElement}
*/
private static JsonElement getFlaggedRelationGeometryFromFeature(
final JsonObject flaggedRelationFeature)
{
return flaggedRelationFeature.get(GEOMETRY);
}
/**
* Get property of the flagged relation feature
*
* @param flaggedRelationFeature
* {@link FlaggedRelation} feature
* @return property as {@link JsonElement}
*/
private static JsonElement getFlaggedRelationPropertyFromFeature(
final JsonObject flaggedRelationFeature)
{
return flaggedRelationFeature.get(PROPERTIES);
}
/**
* Converts all {@link FlaggedRelation} to geojson feature
*
* @param flag
* CheckFlag
* @return {@link List} corresponding to geojson feature of {@link FlaggedRelation}
*/
private static List getFlaggedRelationsGeojsonFeatures(final CheckFlag flag)
{
return flag.getFlaggedRelations().stream()
.map(flaggedRelation -> flaggedRelation.asGeoJsonFeature(flag.getIdentifier()))
.collect(Collectors.toList());
}
/**
* Populates osmids of flaggedRelation features to a {@link Set}
*
* @param flaggedRelationFeatures
* flaggedRelationFeatures geojson features of FlaggedRelations
* @return {@link Set} of all osmids of flaggedRelations
*/
private static Set populateFlaggedRelationFeatureOsmIds(
final List flaggedRelationFeatures)
{
// Add osm id
return flaggedRelationFeatures.stream()
.map(CheckFlagEvent::getFlaggedRelationPropertyFromFeature)
.map(jsonElement -> jsonElement.getAsJsonObject().get(OSM_IDENTIFIER))
.collect(Collectors.toSet());
}
/**
* Populates properties of flaggedRelation features to a {@link JsonArray}
*
* @param flaggedRelationFeatures
* geojson features of FlaggedRelations
* @return {@link JsonArray} of properties of flaggedRelations
*/
private static JsonArray populateFlaggedRelationFeatureProperties(
final List flaggedRelationFeatures)
{
final JsonArray featureProperties = new JsonArray();
// Update feature properties from flaggedRelation features
flaggedRelationFeatures.stream().map(CheckFlagEvent::getFlaggedRelationPropertyFromFeature)
.forEach(featureProperties::add);
return featureProperties;
}
/**
* Populates geometries of flaggedRelation features to a {@link JsonArray}
*
* @param flaggedRelationFeatures
* geojson features of FlaggedRelations
* @return {@link JsonArray} of geometries of flaggedRelations
*/
private static JsonArray populateFlaggedRelationGeometries(
final List flaggedRelationFeatures)
{
final JsonArray geometriesOfFlaggedRelations = new JsonArray();
// Add all geometries of flaggedRelations to the json array
flaggedRelationFeatures.stream().map(CheckFlagEvent::getFlaggedRelationGeometryFromFeature)
.forEach(geometriesOfFlaggedRelations::add);
return geometriesOfFlaggedRelations;
}
/**
* Construct a {@link CheckFlagEvent}
*
* @param checkName
* name of the check that created this event
* @param flag
* {@link CheckFlag} generated within this event
*/
public CheckFlagEvent(final String checkName, final CheckFlag flag)
{
this.checkName = checkName;
this.flag = flag;
}
public String asLineDelimitedGeoJsonFeatures()
{
return asLineDelimitedGeoJsonFeatures(jsonObject ->
{
});
}
public String asLineDelimitedGeoJsonFeatures(final Consumer jsonMutator)
{
final JsonObject flagGeoJsonFeature = this.flag.asGeoJsonFeature();
final JsonObject flagGeoJsonProperties = flagGeoJsonFeature.get("properties")
.getAsJsonObject();
flagGeoJsonProperties.addProperty("flag:check", getCheckName());
flagGeoJsonProperties.addProperty("flag:timestamp", getTimestamp().toString());
jsonMutator.accept(flagGeoJsonFeature);
final StringBuilder builder = new StringBuilder().append(flagGeoJsonFeature.toString());
final FlaggedObject[] flaggedObjects = this.flag.getFlaggedObjects()
.toArray(new FlaggedObject[0]);
final int flaggedObjectsSize = flaggedObjects.length;
if (flaggedObjectsSize > 0)
{
builder.append('\n');
// loop through all the flagged objects except the last, give a new line
int index = 0;
for (; index < flaggedObjectsSize - 1; ++index)
{
final JsonObject feature = flaggedObjects[index]
.asGeoJsonFeature(this.flag.getIdentifier());
jsonMutator.accept(feature);
builder.append(feature.toString()).append('\n');
}
// dont give a new line to the last
final JsonObject feature = flaggedObjects[index]
.asGeoJsonFeature(this.flag.getIdentifier());
jsonMutator.accept(feature);
builder.append(feature.toString());
}
return builder.toString();
}
/**
* @return {@link CheckFlag} generated by the check
*/
public CheckFlag getCheckFlag()
{
return this.flag;
}
/**
* @return Name of the check that generated this event
*/
public String getCheckName()
{
return this.checkName;
}
/**
* @return GeoJson Feature representation
*/
public JsonObject toGeoJsonFeature()
{
final Map contextualProperties = new HashMap<>();
contextualProperties.put("name",
this.getCheckFlag().getChallengeName().orElse(this.getCheckName()));
contextualProperties.put("generator", "AtlasChecks");
contextualProperties.put("timestamp", this.getTimestamp().toString());
// Generate json for check flag with given contextual properties
return flagToFeature(this.getCheckFlag(), contextualProperties);
}
/**
* @return {@link JsonObject} form of the GeoJson FeatureCollection representation
*/
public JsonObject toGeoJsonFeatureCollection()
{
final Map contextualProperties = new HashMap<>();
contextualProperties.put("generator", this.getCheckName());
contextualProperties.put("timestamp", this.getTimestamp().toString());
// Generate json for check flag with given contextual properties
return flagToJson(this.getCheckFlag(), contextualProperties);
}
/**
* @return {@link String} form of the GeoJson FeatureCollection representation
*/
@Override
public String toString()
{
return this.toGeoJsonFeatureCollection().toString();
}
}