diff --git a/src/main/java/de/blau/android/resources/DataStyle.java b/src/main/java/de/blau/android/resources/DataStyle.java index f079a414e..9f880e119 100644 --- a/src/main/java/de/blau/android/resources/DataStyle.java +++ b/src/main/java/de/blau/android/resources/DataStyle.java @@ -187,26 +187,26 @@ public final class DataStyle extends DefaultHandler { public class FeatureStyle { - final Map 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 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 cascadedStyles = null; @@ -673,6 +673,13 @@ public int getTextColor() { return textColor; } + /** + * @return the tags + */ + public Map getTags() { + return tags; + } + /** * Dump this Style in XML format, not very abstracted and closely tied to the implementation * @@ -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); @@ -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); @@ -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)); diff --git a/src/main/java/de/blau/android/validation/BaseValidator.java b/src/main/java/de/blau/android/validation/BaseValidator.java index bc1922669..53f0012a6 100644 --- a/src/main/java/de/blau/android/validation/BaseValidator.java +++ b/src/main/java/de/blau/android/validation/BaseValidator.java @@ -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; @@ -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. @@ -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 @@ -188,7 +191,7 @@ 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 @@ -196,8 +199,13 @@ private int validateElement(int status, @NonNull OsmElement e, @NonNull SortedMa * @return new validation status */ public int validateWrongType(int status, @NonNull OsmElement e, @NonNull PresetItem pi) { - List elementType = pi.appliesTo(); - if (!elementType.contains(e.getType())) { + List 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; @@ -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); } } } diff --git a/src/test/java/de/blau/android/resources/DataStyleTaginfoDump.java b/src/test/java/de/blau/android/resources/DataStyleTaginfoDump.java index 817932bb8..e5b69ce03 100644 --- a/src/test/java/de/blau/android/resources/DataStyleTaginfoDump.java +++ b/src/test/java/de/blau/android/resources/DataStyleTaginfoDump.java @@ -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 @@ -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)); } } diff --git a/src/test/java/de/blau/android/validation/BaseValidatorTest.java b/src/test/java/de/blau/android/validation/BaseValidatorTest.java index dca9fcccd..901a97dc1 100644 --- a/src/test/java/de/blau/android/validation/BaseValidatorTest.java +++ b/src/test/java/de/blau/android/validation/BaseValidatorTest.java @@ -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; @@ -24,7 +25,9 @@ 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; @@ -32,10 +35,13 @@ 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 { @@ -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 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)); + } } \ No newline at end of file