Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use area tags to improve type result from presets for validation #2769

Merged
merged 2 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 29 additions & 28 deletions src/main/java/de/blau/android/resources/DataStyle.java
Original file line number Diff line number Diff line change
Expand Up @@ -187,26 +187,26 @@ public final class DataStyle extends DefaultHandler {

public class FeatureStyle {

final Map<String, String> tags;
private int minVisibleZoom = DEFAULT_MIN_VISIBLE_ZOOM;
private boolean area = false;
boolean dontrender = false;
boolean updateWidth = true;
final Paint paint;
float widthFactor;
float offset = 0f;
DashPath dashPath = null;
private FontMetrics fontMetrics = null;
private PathPattern pathPattern = null;
private boolean pathPatternSupported;
private FeatureStyle arrowStyle = null;
private FeatureStyle casingStyle = null;
private boolean oneway = false;
private Boolean closed = null;
private String labelKey = null;
private String iconPath = null;
private int labelZoomLimit = Integer.MAX_VALUE;
private int textColor;
private final Map<String, String> tags;
private int minVisibleZoom = DEFAULT_MIN_VISIBLE_ZOOM;
private boolean area = false;
boolean dontrender = false;
boolean updateWidth = true;
final Paint paint;
float widthFactor;
float offset = 0f;
DashPath dashPath = null;
private FontMetrics fontMetrics = null;
private PathPattern pathPattern = null;
private boolean pathPatternSupported;
private FeatureStyle arrowStyle = null;
private FeatureStyle casingStyle = null;
private boolean oneway = false;
private Boolean closed = null;
private String labelKey = null;
private String iconPath = null;
private int labelZoomLimit = Integer.MAX_VALUE;
private int textColor;

List<FeatureStyle> cascadedStyles = null;

Expand Down Expand Up @@ -673,6 +673,13 @@ public int getTextColor() {
return textColor;
}

/**
* @return the tags
*/
public Map<String, String> getTags() {
return tags;
}

/**
* Dump this Style in XML format, not very abstracted and closely tied to the implementation
*
Expand Down Expand Up @@ -865,6 +872,8 @@ private void init() {

FeatureStyle baseWayStyle = new FeatureStyle(WAY, standardPath);
baseWayStyle.setColor(Color.BLACK);
baseWayStyle.getPaint().setStrokeCap(Cap.ROUND);
baseWayStyle.getPaint().setStrokeJoin(Join.ROUND);

FeatureStyle fp = new FeatureStyle(PROBLEM_WAY, standardPath);
int problemColor = ContextCompat.getColor(ctx, R.color.problem);
Expand Down Expand Up @@ -936,15 +945,11 @@ private void init() {

fp = new FeatureStyle(GPS_TRACK, baseWayStyle);
fp.setColor(Color.BLUE);
fp.getPaint().setStrokeCap(Cap.ROUND);
fp.getPaint().setStrokeJoin(Join.ROUND);
internalStyles.put(GPS_TRACK, fp);

fp = new FeatureStyle(MVT_DEFAULT, baseWayStyle);
fp.setColor(Color.BLUE);
fp.getPaint().setAlpha(0x7F);
fp.getPaint().setStrokeCap(Cap.ROUND);
fp.getPaint().setStrokeJoin(Join.ROUND);
internalStyles.put(MVT_DEFAULT, fp);

fp = new FeatureStyle(WAY_TOLERANCE, baseWayStyle);
Expand Down Expand Up @@ -1031,16 +1036,12 @@ private void init() {
fp = new FeatureStyle(SELECTED_WAY, baseWayStyle);
fp.setColor(cccBeige);
fp.setWidthFactor(2f);
fp.getPaint().setStrokeCap(Cap.ROUND);
fp.getPaint().setStrokeJoin(Join.ROUND);
internalStyles.put(SELECTED_WAY, fp);

fp = new FeatureStyle(HIDDEN_WAY, baseWayStyle);
fp.setColor(ContextCompat.getColor(ctx, R.color.light_grey));
fp.getPaint().setAlpha(TOLERANCE_ALPHA);
fp.setWidthFactor(0.5f);
fp.getPaint().setStrokeCap(Cap.ROUND);
fp.getPaint().setStrokeJoin(Join.ROUND);
internalStyles.put(HIDDEN_WAY, fp);

fp = new FeatureStyle(SELECTED_RELATION_WAY, internalStyles.get(SELECTED_WAY));
Expand Down
47 changes: 28 additions & 19 deletions src/main/java/de/blau/android/validation/BaseValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import de.blau.android.prefs.Preferences;
import de.blau.android.presets.Preset;
import de.blau.android.presets.PresetItem;
import de.blau.android.util.AreaTags;
import de.blau.android.util.GeoContext;
import de.blau.android.util.GeoMath;
import de.blau.android.util.Geometry;
Expand All @@ -46,6 +47,7 @@ public class BaseValidator implements Validator {

private Preset[] presets;
private GeoContext geoContext;
private AreaTags areaTags;

/**
* Tags for objects that should be re-surveyed regularly.
Expand Down Expand Up @@ -130,6 +132,7 @@ private void init(@NonNull Context ctx) {
// !!!! don't store ctx as that will cause a potential memory leak
presets = App.getCurrentPresets(ctx);
geoContext = App.getGeoContext(ctx);
areaTags = App.getAreaTags(ctx);

// get per validation prefs
Preferences prefs = new Preferences(ctx); // use our own instance as logics one may be out of sync
Expand Down Expand Up @@ -188,16 +191,21 @@ private int validateElement(int status, @NonNull OsmElement e, @NonNull SortedMa
}

/**
* Check if the element is not one of the ElementType required by the PresetItem
* Check if the element is not one of the ElementTypes required by the PresetItem
*
* @param status previous validation status
* @param e the OsmElement
* @param pi the PresetItem
* @return new validation status
*/
public int validateWrongType(int status, @NonNull OsmElement e, @NonNull PresetItem pi) {
List<ElementType> elementType = pi.appliesTo();
if (!elementType.contains(e.getType())) {
List<ElementType> elementTypes = pi.appliesTo();
ElementType type = e.getType();
// presets currently can't model just simple closed ways as areas
if (e instanceof Way && type == ElementType.AREA && elementTypes.contains(ElementType.CLOSEDWAY) && areaTags.isImpliedArea(e.getTags())) {
return status;
}
if (!elementTypes.contains(type)) {
status |= Validator.WRONG_ELEMENT_TYPE;
}
return status;
Expand Down Expand Up @@ -243,22 +251,23 @@ public int validateResurvey(int status, @NonNull OsmElement e, @NonNull SortedMa
long now = System.currentTimeMillis() / 1000;
long timestamp = e.getTimestamp();
for (String key : resurveyTags.getKeys()) {
if (tags.containsKey(key)) {
for (PatternAndAge value : resurveyTags.get(key)) {
if ((value.getValue() == null || "".equals(value.getValue()) || value.matches(tags.get(key)))) {
long age = value.getAge();
// timestamp is too old
if (timestamp >= 0 && (now - timestamp > age)) {
status |= Validator.AGE;
} else if (tags.containsKey(Tags.KEY_CHECK_DATE)) {
// check_date tag is too old
status |= checkAge(tags, now, Tags.KEY_CHECK_DATE, age);
} else {
// key specific check_date tag is too old
final String keyCheckDate = Tags.KEY_CHECK_DATE + ":" + key;
if (tags.containsKey(keyCheckDate)) {
status |= checkAge(tags, now, keyCheckDate, age);
}
if (!tags.containsKey(key)) {
continue;
}
for (PatternAndAge value : resurveyTags.get(key)) {
if ((value.getValue() == null || "".equals(value.getValue()) || value.matches(tags.get(key)))) {
long age = value.getAge();
// timestamp is too old
if (timestamp >= 0 && (now - timestamp > age)) {
status |= Validator.AGE;
} else if (tags.containsKey(Tags.KEY_CHECK_DATE)) {
// check_date tag is too old
status |= checkAge(tags, now, Tags.KEY_CHECK_DATE, age);
} else {
// key specific check_date tag is too old
final String keyCheckDate = Tags.KEY_CHECK_DATE + ":" + key;
if (tags.containsKey(keyCheckDate)) {
status |= checkAge(tags, now, keyCheckDate, age);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.LargeTest;
import de.blau.android.App;
import de.blau.android.prefs.Preferences;

/**
* This is just a convenient way of generating the default preset dump
Expand Down Expand Up @@ -41,7 +42,7 @@ public void dump() { // NOSONAR
File target = manual ? new File(TARGET_FILE) : new File(ctx.getFilesDir(), TARGET_FILE);
DataStyle styles = App.getDataStyle(ApplicationProvider.getApplicationContext());
styles.getStylesFromFiles(ApplicationProvider.getApplicationContext());
styles.switchTo("Color Round Nodes");
styles.switchTo(Preferences.DEFAULT_MAP_STYLE);
assertTrue(styles.generateTaginfoJson(target));
}
}
29 changes: 28 additions & 1 deletion src/test/java/de/blau/android/validation/BaseValidatorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static de.blau.android.osm.DelegatorUtil.toE7;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.util.Arrays;
Expand All @@ -24,18 +25,23 @@
import de.blau.android.Main;
import de.blau.android.R;
import de.blau.android.ShadowWorkManager;
import de.blau.android.osm.DelegatorUtil;
import de.blau.android.osm.Node;
import de.blau.android.osm.OsmElement.ElementType;
import de.blau.android.osm.OsmElementFactory;
import de.blau.android.osm.Relation;
import de.blau.android.osm.RelationMember;
import de.blau.android.osm.StorageDelegator;
import de.blau.android.osm.Tags;
import de.blau.android.osm.Way;
import de.blau.android.prefs.Preferences;
import de.blau.android.presets.Preset;
import de.blau.android.presets.PresetItem;
import de.blau.android.resources.DataStyle;
import de.blau.android.resources.DataStyle.FeatureStyle;

@RunWith(RobolectricTestRunner.class)
@Config(shadows = { ShadowWorkManager.class }, sdk=33)
@Config(shadows = { ShadowWorkManager.class }, sdk = 33)
@LargeTest
public class BaseValidatorTest {

Expand Down Expand Up @@ -136,4 +142,25 @@ public void nonStandardTypeTest() {
assertEquals(1, warnings.size());
assertTrue(warnings.get(0).contains(ctx.getString(R.string.element_type_node)));
}

/**
* Test correct area determination
*/
@Test
public void nonStandardTypeTest2() {
final Context ctx = ApplicationProvider.getApplicationContext();
Validator v = App.getDefaultValidator(ctx);
StorageDelegator d = new StorageDelegator();
Way w = DelegatorUtil.addWayToStorage(d, true);
Map<String, String> tags = new HashMap<>();
tags.put("golf", "bunker");
tags.put(Tags.KEY_NATURAL, "sand");
d.setTags(w, tags);
assertTrue(App.getDataStyle(ctx).switchTo(Preferences.DEFAULT_MAP_STYLE));
FeatureStyle style = App.getDataStyle(ctx).matchStyle(w);
assertTrue(style.isArea());
PresetItem pi = Preset.findBestMatch(App.getCurrentPresets(ctx), tags, null, null);
assertFalse(pi.appliesTo().contains(ElementType.AREA));
assertEquals(Validator.OK, v.validate(w));
}
}
Loading