This is an automated email from the git hooks/post-receive script. sebastic pushed a commit to branch master in repository mkgmap.
commit e042a28f504f79a79a17d00dccace7f64331ebcd Author: Bas Couwenberg <sebas...@xs4all.nl> Date: Tue Mar 3 23:01:06 2015 +0100 Imported Upstream version 0.0.0+svn3478 --- resources/help/en/options | 10 ++ resources/mkgmap-version.properties | 4 +- resources/styles/default/inc/name | 8 + resources/styles/default/lines | 3 +- .../parabola/imgfmt/app/labelenc/Utf8Decoder.java | 1 - src/uk/me/parabola/imgfmt/app/mdr/Mdr20.java | 14 +- src/uk/me/parabola/imgfmt/app/mdr/Mdr22.java | 2 +- src/uk/me/parabola/imgfmt/app/mdr/Mdr2x.java | 41 +++-- src/uk/me/parabola/imgfmt/app/mdr/Mdr7.java | 183 +++++++++++++++++++-- src/uk/me/parabola/imgfmt/app/mdr/Mdr7Record.java | 43 +++++ src/uk/me/parabola/imgfmt/app/mdr/MdrConfig.java | 9 + .../parabola/mkgmap/combiners/GmapsuppBuilder.java | 4 +- .../me/parabola/mkgmap/combiners/MdrBuilder.java | 4 +- .../parabola/mkgmap/osmstyle/RuleFileReader.java | 38 +++-- .../me/parabola/mkgmap/scan/SyntaxException.java | 2 +- test/resources/rules/multi-or-twice.test | 18 ++ test/resources/rules/multi-or-with-and.test | 19 +++ test/resources/rules/or-at-end.test | 30 ++++ .../mkgmap/osmstyle/RuleFileReaderTest.java | 1 + 19 files changed, 376 insertions(+), 58 deletions(-) diff --git a/resources/help/en/options b/resources/help/en/options index f13bef2..5a978e6 100644 --- a/resources/help/en/options +++ b/resources/help/en/options @@ -125,6 +125,16 @@ Address search options: same code page and sorting options (eg. --code-page, --latin1 etc) must be used as were used to compile the individual map tiles. +--x-split-name-index + A temporary option to enable indexing each part of a street name separately. + So for example if the street is "Aleksandra Gryglewskiego" then you will be able to + search for it as both "Aleksandra" and "Gryglewskiego". It will also increase the + size of the index. Useful in countries where searching for the first word in name + is not the right thing to do. + + Note that this option is still experimental and there may be problems. If you find + any let us know! + --bounds=directory|zipfile A directory or a zipfile containing the preprocessed bounds files. Bounds files in a zipfile must be located in the zipfiles root directory. diff --git a/resources/mkgmap-version.properties b/resources/mkgmap-version.properties index 78cc6d5..7a0d191 100644 --- a/resources/mkgmap-version.properties +++ b/resources/mkgmap-version.properties @@ -1,2 +1,2 @@ -svn.version: 3436 -build.timestamp: 2015-02-02T06:43:48+0000 +svn.version: 3478 +build.timestamp: 2015-02-26T07:49:21+0000 diff --git a/resources/styles/default/inc/name b/resources/styles/default/inc/name index f3e9d98..67f0a62 100644 --- a/resources/styles/default/inc/name +++ b/resources/styles/default/inc/name @@ -13,6 +13,7 @@ operator=${name} { delete operator; } brand=${name} { delete brand; } # None of operator, brand given +ref=* & (operator!=* & brand!=*) & (highway=bus_stop | railway=tram_stop | railway=halt | railway=station) { name '${name} ${ref}' | '${ref}' } ref=* & (operator!=* & brand!=*) { name '${ref} ${name}' | '${ref}' } # Both operator and brand given @@ -24,6 +25,13 @@ operator=* & brand=* { } # One of operator or brand given +operator=* & brand!=* & (highway=bus_stop | railway=tram_stop | railway=halt | railway=station) { + name '${name} ${ref} ${operator}' | + '${name} ${operator}' | + '${ref} ${operator}' | + '${operator}' +} + operator=* & brand!=* { name '${operator}: ${ref} ${name}' | '${operator}: ${name}' | diff --git a/resources/styles/default/lines b/resources/styles/default/lines index c43a29c..e2d79c0 100644 --- a/resources/styles/default/lines +++ b/resources/styles/default/lines @@ -163,7 +163,8 @@ power=line [0x29 resolution 21] railway=abandoned [0x0a road_class=0 road_speed=1 resolution 22] railway=platform [0x16 road_class=0 road_speed=0 resolution 23] -railway=* & !(tunnel=yes) [0x14 resolution 22] +# Railway lines, note that many devices display type 0x14 only at resolution 24 +(railway=rail | railway=tram | railway=disused | railway=subway | railway=narrow_gauge | railway=light_rail | railway=preserved) & !(tunnel=yes) [0x14 resolution 22] (man_made=cable|(man_made=* & man_made ~ '.*pipe.*')) & area!=yes & tunnel!=yes & location != underground diff --git a/src/uk/me/parabola/imgfmt/app/labelenc/Utf8Decoder.java b/src/uk/me/parabola/imgfmt/app/labelenc/Utf8Decoder.java index 73345fc..fe0ed56 100644 --- a/src/uk/me/parabola/imgfmt/app/labelenc/Utf8Decoder.java +++ b/src/uk/me/parabola/imgfmt/app/labelenc/Utf8Decoder.java @@ -42,7 +42,6 @@ public class Utf8Decoder implements CharacterDecoder { public boolean addByte(int b) { if (b == 0) { needreset = true; - out.write(0); return true; } diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr20.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr20.java index 3791d31..a2096ca 100644 --- a/src/uk/me/parabola/imgfmt/app/mdr/Mdr20.java +++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr20.java @@ -88,15 +88,17 @@ public class Mdr20 extends Mdr2x { Collator collator = getConfig().getSort().getCollator(); String lastName = null; + String lastPartialName = null; Mdr5Record lastCity = null; int record = 0; - int cityRecord = 0; + int cityRecord = 1; int lastMapNumber = 0; for (SortKey<Mdr7Record> key : keys) { Mdr7Record street = key.getObject(); String name = street.getName(); + String partialName = street.getPartialName(); Mdr5Record city = street.getCity(); boolean citySameByName = city.isSameByName(collator, lastCity); @@ -104,18 +106,24 @@ public class Mdr20 extends Mdr2x { int mapNumber = city.getMapIndex(); // Only save a single copy of each street name. - if (!citySameByName || mapNumber != lastMapNumber || lastName == null || collator.compare(name, lastName) != 0) { + if (!citySameByName || mapNumber != lastMapNumber || lastName == null || lastPartialName == null + || !name.equals(lastName) + || !partialName.equals(lastPartialName)) + { record++; streets.add(street); lastName = name; + lastPartialName = partialName; } // The mdr20 value changes for each new city name if (citySameByName) { + assert cityRecord!=0; city.setMdr20(cityRecord); } else { // New city name, this marks the start of a new section in mdr20 + assert cityRecord != 0; cityRecord = record; city.setMdr20(cityRecord); lastCity = city; @@ -137,6 +145,6 @@ public class Mdr20 extends Mdr2x { * Unknown. */ public int getExtraValue() { - return isForDevice() ? 0xa : 0x8800; + return isForDevice() ? 0xe : 0x8800; } } diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr22.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr22.java index 379d3b4..afd8a35 100644 --- a/src/uk/me/parabola/imgfmt/app/mdr/Mdr22.java +++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr22.java @@ -104,7 +104,7 @@ public class Mdr22 extends Mdr2x { */ public int getExtraValue() { if (isForDevice()) - return 0x600a; + return 0x600e; else return 0x11000; } diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr2x.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr2x.java index bade6d8..d0c1fdf 100644 --- a/src/uk/me/parabola/imgfmt/app/mdr/Mdr2x.java +++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr2x.java @@ -16,7 +16,6 @@ import java.util.ArrayList; import java.util.List; import uk.me.parabola.imgfmt.app.ImgFileWriter; -import uk.me.parabola.imgfmt.app.Label; /** * Common code for 20, 21, 22 which are all lists of streets ordered in @@ -39,30 +38,45 @@ public abstract class Mdr2x extends MdrMapSection implements HasHeaderFlags { int size = getSizes().getStreetSizeFlagged(); boolean hasLabel = hasFlag(0x2); + + String lastPartial = null; int recordNumber = 0; for (Mdr7Record street : streets) { assert street.getMapIndex() == street.getCity().getMapIndex() : street.getMapIndex() + "/" + street.getCity().getMapIndex(); addIndexPointer(street.getMapIndex(), ++recordNumber); int index = street.getIndex(); - String name = Label.stripGarminCodes(street.getName()); - - int flag = 1; + + String name = street.getName(); + + int repeat = 1; if (name.equals(lastName) && sameGroup(street, prev)) - flag = 0; - lastName = name; - prev = street; + repeat = 0; if (hasLabel) { putMapIndex(writer, street.getMapIndex()); int offset = street.getLabelOffset(); - if (flag != 0) + if (repeat != 0) + offset |= 0x800000; + + int trailing = 0; + String partialName = street.getPartialName(); + if (!partialName.equals(lastPartial)) { + trailing |= 1; offset |= 0x800000; + } + writer.put3(offset); - writer.put((byte) flag); - } - else - putN(writer, size, (index << 1) | flag); + writer.put(street.getOutNameOffset()); + + writer.put((byte) trailing); + + lastPartial = partialName; + } else + putN(writer, size, (index << 1) | repeat); + + lastName = name; + prev = street; } } @@ -78,7 +92,8 @@ public abstract class Mdr2x extends MdrMapSection implements HasHeaderFlags { public int getItemSize() { int size; if (isForDevice()) { - size = getSizes().getMapSize() + 3 + 1; + // map-index, label, name-offset, 1byte flag + size = getSizes().getMapSize() + 3 + 1 + 1; } else { size = getSizes().getStreetSizeFlagged(); } diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr7.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr7.java index 6e43a30..e4f1af6 100644 --- a/src/uk/me/parabola/imgfmt/app/mdr/Mdr7.java +++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr7.java @@ -16,8 +16,10 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import uk.me.parabola.imgfmt.MapFailedException; import uk.me.parabola.imgfmt.app.ImgFileWriter; -import uk.me.parabola.imgfmt.app.Label; +import uk.me.parabola.imgfmt.app.srt.MultiSortKey; +import uk.me.parabola.imgfmt.app.srt.Sort; import uk.me.parabola.imgfmt.app.srt.SortKey; /** @@ -27,69 +29,211 @@ import uk.me.parabola.imgfmt.app.srt.SortKey; * @author Steve Ratcliffe */ public class Mdr7 extends MdrMapSection { + public static final int MDR7_HAS_STRING = 0x01; + public static final int MDR7_HAS_NAME_OFFSET = 0x20; + public static final int MDR7_PARTIAL_SHIFT = 6; + public static final int MDR7_U1 = 0x2; + public static final int MDR7_U2 = 0x4; + + private static final int MAX_NAME_OFFSET = 127; + + private final int codepage; + private final boolean isMulti; + private final boolean splitName; + private List<Mdr7Record> allStreets = new ArrayList<>(); private List<Mdr7Record> streets = new ArrayList<>(); + private final int u2size = 1; + public Mdr7(MdrConfig config) { setConfig(config); + Sort sort = config.getSort(); + splitName = config.isSplitName(); + codepage = sort.getCodepage(); + isMulti = sort.isMulti(); } public void addStreet(int mapId, String name, int lblOffset, int strOff, Mdr5Record mdrCity) { + // Find a name prefix, which is either a shield or a word ending 0x1e. We are treating + // a shield as a prefix of length one. + int prefix = 0; + if (name.charAt(0) < 7) + prefix = 1; + int sep = name.indexOf(0x1e); + if (sep > 0) + prefix = sep + 1; + + // Find a name suffix which begins with 0x1f + sep = name.indexOf(0x1f); + int suffix = 0; + if (sep > 0) + suffix = sep; + + // Large values can't actually work. + if (prefix >= MAX_NAME_OFFSET || suffix >= MAX_NAME_OFFSET) + return; + Mdr7Record st = new Mdr7Record(); st.setMapIndex(mapId); st.setLabelOffset(lblOffset); st.setStringOffset(strOff); st.setName(name); st.setCity(mdrCity); + st.setPrefixOffset((byte) prefix); + st.setSuffixOffset((byte) suffix); allStreets.add(st); + + if (!splitName) + return; + + boolean start = false; + boolean inWord = false; + + int c; + int outOffset = 0; + + int end = Math.min((suffix > 0) ? suffix : name.length() - prefix - 1, MAX_NAME_OFFSET); + for (int nameOffset = 0; nameOffset < end; nameOffset += Character.charCount(c)) { + c = name.codePointAt(prefix + nameOffset); + + // Don't use any word after a bracket + if (c == '(') + break; + + if (!Character.isLetterOrDigit(c)) { + start = true; + inWord = false; + } else if (start && Character.isLetterOrDigit(c)) { + inWord = true; + } + + if (start && inWord && outOffset > 0) { + st = new Mdr7Record(); + st.setMapIndex(mapId); + st.setLabelOffset(lblOffset); + st.setStringOffset(strOff); + st.setName(name); + st.setCity(mdrCity); + st.setNameOffset((byte) nameOffset); + st.setOutNameOffset((byte) outOffset); + st.setPrefixOffset((byte) prefix); + st.setSuffixOffset((byte) suffix); + //System.out.println(st.getName() + ": add partial " + st.getPartialName()); + allStreets.add(st); + start = false; + } + + outOffset += outSize(c); + if (outOffset > MAX_NAME_OFFSET) + break; + } + } + + /** + * Return the number of bytes that the given character will consume in the output encoded + * format. + */ + private int outSize(int c) { + if (codepage == 65001) { + // For unicode a simple lookup gives the number of bytes. + if (c < 0x80) { + return 1; + } else if (c <= 0x7FF) { + return 2; + } else if (c <= 0xFFFF) { + return 3; + } else if (c <= 0x10FFFF) { + return 4; + } else { + throw new MapFailedException(String.format("Invalid code point: 0x%x", c)); + } + } else if (!isMulti) { + // The traditional single byte code-pages, always one byte. + return 1; + } else { + // Other multi-byte code-pages (eg ms932); can't currently create index for these anyway. + return 0; + } } /** * Since we change the number of records by removing some after sorting, * we sort and de-duplicate here. + * This is a performance critical part of the index creation process + * as it requires a lot of heap to store the sort keys. */ protected void preWriteImpl() { - List<SortKey<Mdr7Record>> sortedStreets = MdrUtils.sortList(getConfig().getSort(), allStreets); + Sort sort = getConfig().getSort(); + List<SortKey<Mdr7Record>> sortedStreets = new ArrayList<>(allStreets.size()); + for (Mdr7Record m : allStreets) { + String partialName = m.getPartialName(); + String name = m.getName(); + SortKey<Mdr7Record> nameKey = sort.createSortKey(m, m.getName(), m.getMapIndex()); + SortKey<Mdr7Record> partialKey = name.equals(partialName) ? nameKey : sort.createSortKey(m, partialName); + MultiSortKey<Mdr7Record> sortKey = new MultiSortKey<>(partialKey, nameKey, null); + sortedStreets.add(sortKey); + } + Collections.sort(sortedStreets); // De-duplicate the street names so that there is only one entry // per map for the same name. int recordNumber = 0; Mdr7Record last = new Mdr7Record(); - for (SortKey<Mdr7Record> sk : sortedStreets) { + for (int i = 0; i < sortedStreets.size(); i++){ + SortKey<Mdr7Record> sk = sortedStreets.get(i); Mdr7Record r = sk.getObject(); - if (r.getMapIndex() != last.getMapIndex() || !r.getName().equals(last.getName())) { + if (r.getMapIndex() == last.getMapIndex() + && r.getName().equals(last.getName()) // currently think equals is correct, not collator.compare() + && r.getPartialName().equals(last.getPartialName())) + { + // This has the same name (and map number) as the previous one. Save the pointer to that one + // which is going into the file. + r.setIndex(recordNumber); + } else { recordNumber++; last = r; r.setIndex(recordNumber); streets.add(r); - } else { - // This has the same name (and map number) as the previous one. Save the pointer to that one - // which is going into the file. - r.setIndex(recordNumber); } + // release memory + sortedStreets.set(i, null); } } public void writeSectData(ImgFileWriter writer) { String lastName = null; - boolean hasStrings = hasFlag(0x1); + String lastPartial = null; + boolean hasStrings = hasFlag(MDR7_HAS_STRING); + boolean hasNameOffset = hasFlag(MDR7_HAS_NAME_OFFSET); + for (Mdr7Record s : streets) { addIndexPointer(s.getMapIndex(), s.getIndex()); putMapIndex(writer, s.getMapIndex()); int lab = s.getLabelOffset(); - String name = Label.stripGarminCodes(s.getName()); - int trailingFlags = 0; + String name = s.getName(); if (!name.equals(lastName)) { lab |= 0x800000; lastName = name; - trailingFlags = 1; } + + String partialName = s.getPartialName(); + int trailingFlags = 0; + if (!partialName.equals(lastPartial)) { + trailingFlags |= 1; + lab |= 0x800000; // If it is not a partial repeat, then it is not a complete repeat either + } + lastPartial = partialName; + writer.put3(lab); if (hasStrings) putStringOffset(writer, s.getStringOffset()); - - writer.put((byte) trailingFlags); + + if (hasNameOffset) + writer.put(s.getOutNameOffset()); + + putN(writer, u2size, trailingFlags); } } @@ -99,9 +243,11 @@ public class Mdr7 extends MdrMapSection { */ public int getItemSize() { PointerSizes sizes = getSizes(); - int size = sizes.getMapSize() + 3 + 1; + int size = sizes.getMapSize() + 3 + u2size; if (!isForDevice()) size += sizes.getStrOffSize(); + if ((getExtraValue() & MDR7_HAS_NAME_OFFSET) != 0) + size += 1; return size; } @@ -113,11 +259,12 @@ public class Mdr7 extends MdrMapSection { * Value of 3 possibly the existence of the lbl field. */ public int getExtraValue() { - int magic = 0x42; + int magic = MDR7_U1 | MDR7_HAS_NAME_OFFSET | (u2size << MDR7_PARTIAL_SHIFT); + if (isForDevice()) { - magic |= 0x4; + magic |= MDR7_U2; } else { - magic |= 0x1; //strings + magic |= MDR7_HAS_STRING; } return magic; diff --git a/src/uk/me/parabola/imgfmt/app/mdr/Mdr7Record.java b/src/uk/me/parabola/imgfmt/app/mdr/Mdr7Record.java index d26af18..6a3562e 100644 --- a/src/uk/me/parabola/imgfmt/app/mdr/Mdr7Record.java +++ b/src/uk/me/parabola/imgfmt/app/mdr/Mdr7Record.java @@ -23,6 +23,12 @@ public class Mdr7Record extends RecordBase implements NamedRecord { private int index; private Mdr5Record city; + // For searching on partial names + private byte nameOffset; // offset into the name where matching should start + private byte outNameOffset; // offset into the encoded output name + private byte prefixOffset; // offset after 0x1e prefix + private byte suffixOffset; // offset just before 0x1f suffix + public int getLabelOffset() { return labelOffset; } @@ -63,6 +69,43 @@ public class Mdr7Record extends RecordBase implements NamedRecord { return city; } + public void setNameOffset(byte nameOffset) { + this.nameOffset = nameOffset; + } + + public byte getOutNameOffset() { + return outNameOffset; + } + + public void setOutNameOffset(byte outNameOffset) { + this.outNameOffset = outNameOffset; + } + + public void setPrefixOffset(byte prefixOffset) { + this.prefixOffset = prefixOffset; + } + + public void setSuffixOffset(byte suffixOffset) { + this.suffixOffset = suffixOffset; + } + + /** + * Get the name starting at the given nameOffset. + * + * To avoid creating unnecessary objects, a check is made for an offset of zero + * and the original name string is returned. + * + * @return A substring of name, starting at the nameOffset value. + */ + public String getPartialName() { + if (nameOffset == 0 && prefixOffset == 0 && suffixOffset == 0) + return name; + else if ((suffixOffset & 0xff) > 0) + return name.substring((nameOffset & 0xff) + (prefixOffset & 0xff), (suffixOffset & 0xff)); + else + return name.substring((nameOffset & 0xff) + (prefixOffset & 0xff)); + } + public String toString() { return name + " in " + city.getName(); } diff --git a/src/uk/me/parabola/imgfmt/app/mdr/MdrConfig.java b/src/uk/me/parabola/imgfmt/app/mdr/MdrConfig.java index 893e83f..a3bcf6e 100644 --- a/src/uk/me/parabola/imgfmt/app/mdr/MdrConfig.java +++ b/src/uk/me/parabola/imgfmt/app/mdr/MdrConfig.java @@ -32,6 +32,7 @@ public class MdrConfig { private int headerLen = DEFAULT_HEADER_LEN; private Sort sort; private File outputDir; + private boolean splitName; /** * True if we are creating the file, rather than reading it. @@ -87,4 +88,12 @@ public class MdrConfig { if (outputDir != null) this.outputDir = new File(outputDir); } + + public void setSplitName(boolean splitName) { + this.splitName = splitName; + } + + public boolean isSplitName() { + return splitName; + } } diff --git a/src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java b/src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java index f173a2c..8c9005a 100644 --- a/src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java +++ b/src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java @@ -83,6 +83,7 @@ public class GmapsuppBuilder implements Combiner { // There is a separate MDR and SRT file for each family id in the gmapsupp private final Map<Integer, MdrBuilder> mdrBuilderMap = new LinkedHashMap<Integer, MdrBuilder>(); private final Map<Integer, Sort> sortMap = new LinkedHashMap<Integer, Sort>(); + private boolean splitName; public void init(CommandArgs args) { @@ -90,6 +91,7 @@ public class GmapsuppBuilder implements Combiner { mapsetName = args.get("mapset-name", "OSM map set"); overallDescription = args.getDescription(); outputDir = args.getOutputDir(); + splitName = args.get("split-name-index", false); } /** @@ -106,7 +108,7 @@ public class GmapsuppBuilder implements Combiner { return mdrBuilder; mdrBuilder = new MdrBuilder(); - mdrBuilder.initForDevice(sort, outputDir); + mdrBuilder.initForDevice(sort, outputDir, splitName); mdrBuilderMap.put(familyId, mdrBuilder); return mdrBuilder; } diff --git a/src/uk/me/parabola/mkgmap/combiners/MdrBuilder.java b/src/uk/me/parabola/mkgmap/combiners/MdrBuilder.java index 63362bd..487cfc4 100644 --- a/src/uk/me/parabola/mkgmap/combiners/MdrBuilder.java +++ b/src/uk/me/parabola/mkgmap/combiners/MdrBuilder.java @@ -111,6 +111,7 @@ public class MdrBuilder implements Combiner { config.setForDevice(false); config.setOutputDir(outputDir); config.setSort(sort); + config.setSplitName(args.get("split-name-index", false)); // Wrap the MDR channel with the MDRFile object mdrFile = new MDRFile(mdrChan, config); @@ -128,13 +129,14 @@ public class MdrBuilder implements Combiner { } } - void initForDevice(Sort sort, String outputDir) { + void initForDevice(Sort sort, String outputDir, boolean splitName) { // Set the options that we are using for the mdr. MdrConfig config = new MdrConfig(); config.setHeaderLen(568); config.setWritable(true); config.setForDevice(true); config.setSort(sort); + config.setSplitName(splitName); // Wrap the MDR channel with the MDRFile object try { diff --git a/src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java b/src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java index 1d69c56..ff6b4f9 100644 --- a/src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java +++ b/src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java @@ -352,28 +352,34 @@ public class RuleFileReader { // Transform ((first | second) & topSecond) // into (first & topSecond) | (second & topSecond) - Op first = op1.getFirst(); - OrOp orOp = new OrOp(); + return distrubute(op1, top.getSecond()); + } else { + // This shouldn't happen + throw new SyntaxException("X3:" + op1.getType()); + } + return top; + } - Op topSecond = top.getSecond(); + private static OrOp distrubute(Op op1, Op topSecond) { + Op first = op1.getFirst(); + OrOp orOp = new OrOp(); - AndOp and1 = new AndOp(); - and1.setFirst(first); - and1.setSecond(topSecond); + BinaryOp and1 = new AndOp(); + and1.setFirst(first); + and1.setSecond(topSecond); - AndOp and2 = new AndOp(); - Op second = rearrangeExpression(op1.getSecond()); + BinaryOp and2 = new AndOp(); + Op second = rearrangeExpression(op1.getSecond()); + if (second.isType(OR)) { + and2 = distrubute(second, topSecond); + } else { and2.setFirst(second); and2.setSecond(topSecond); - - orOp.setFirst(and1); - orOp.setSecond(and2); - return orOp; - } else { - // This shouldn't happen - throw new SyntaxException("X3:" + op1.getType()); } - return top; + orOp.setFirst(and1); + orOp.setSecond(and2); + + return orOp; } /** diff --git a/src/uk/me/parabola/mkgmap/scan/SyntaxException.java b/src/uk/me/parabola/mkgmap/scan/SyntaxException.java index 66c80da..e533913 100644 --- a/src/uk/me/parabola/mkgmap/scan/SyntaxException.java +++ b/src/uk/me/parabola/mkgmap/scan/SyntaxException.java @@ -47,7 +47,7 @@ public class SyntaxException extends RuntimeException { if (fileName != null) fmt.format("(%s:%d): ", fileName, lineNumber); - fmt.format(super.getMessage()); + fmt.format("%s", super.getMessage()); return fmt.toString(); } } diff --git a/test/resources/rules/multi-or-twice.test b/test/resources/rules/multi-or-twice.test new file mode 100644 index 0000000..30e97df --- /dev/null +++ b/test/resources/rules/multi-or-twice.test @@ -0,0 +1,18 @@ + +WAY +highway=primary +name=b +a=2 +b=5 + +<<<lines>>> + +(highway=secondary | a=2 | b=5) & (highway=service | a=0 | b=5) { set name='a${name}' } + +highway=* [0x2] + +<finalize> +highway=* {name '${name}' } + +<<<results>>> +WAY 1: Line 0x2, labels=[ab, null, null, null], res=24-24 (1/1),(2/2), diff --git a/test/resources/rules/multi-or-with-and.test b/test/resources/rules/multi-or-with-and.test new file mode 100644 index 0000000..e9d3267 --- /dev/null +++ b/test/resources/rules/multi-or-with-and.test @@ -0,0 +1,19 @@ + +WAY +highway=primary +name=b +c=60 +d=50 + +<<<lines>>> + +(highway=primary | name=b | d=50) & highway=primary { + set name='a${name}' +} + +highway=primary [0x2] + +<finalize> +highway=* {name '${name}'} +<<<results>>> +WAY 1: Line 0x2, labels=[ab, null, null, null], res=24-24 (1/1),(2/2), diff --git a/test/resources/rules/or-at-end.test b/test/resources/rules/or-at-end.test new file mode 100644 index 0000000..3ff0d02 --- /dev/null +++ b/test/resources/rules/or-at-end.test @@ -0,0 +1,30 @@ + +WAY +highway=tertiary +name=b +oneway=1 +cycleway=opposite + +WAY 2 +highway=tertiary +name=b +oneway=1 +cycleway=opposite_lane + + +<<<lines>>> +highway ~ '(secondary|tertiary|unclassified|residential|minor|living_street|service)' + & oneway=* + & (cycleway=opposite | cycleway=opposite_lane | cycleway=opposite_track ) + { set name='a${name}' } + [0x2 ] + + +<finalize> +highway=* {name '${name}' } + +<<<results>>> +WAY 1: Line 0x2, labels=[ab, null, null, null], res=24-24 oneway (1/1),(2/2), +WAY 2: Line 0x2, labels=[ab, null, null, null], res=24-24 oneway (1/1),(2/2), + + diff --git a/test/uk/me/parabola/mkgmap/osmstyle/RuleFileReaderTest.java b/test/uk/me/parabola/mkgmap/osmstyle/RuleFileReaderTest.java index c9423b6..99ef40c 100644 --- a/test/uk/me/parabola/mkgmap/osmstyle/RuleFileReaderTest.java +++ b/test/uk/me/parabola/mkgmap/osmstyle/RuleFileReaderTest.java @@ -406,6 +406,7 @@ public class RuleFileReaderTest { type = getFirstType(rs, el); assertNotNull(type); + el = el.copy(); // Copy for LinkedOp which remembers the last matched element el.addTag("cycleway", "opposite_lane"); type = getFirstType(rs, el); assertNotNull(type); -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/mkgmap.git _______________________________________________ Pkg-grass-devel mailing list Pkg-grass-devel@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-grass-devel