/*@Nonnull*/ private static Point decodeNameless(string str, int firstrec, string extrapostfix, Data mapcoderData) { String result = str; if (mapcoderData.Codex == 22) { result = result.Substring(0, 3) + result.Substring(4); } else { result = result.Substring(0, 2) + result.Substring(3); } int a = Common.CountCityCoordinatesForCountry(mapcoderData.Codex, firstrec, firstrec); if (a < 2) { a = 1; // paranoia } int p = 31 / a; int r = 31 % a; int v = 0; int nrX; bool swapletters = false; if (mapcoderData.Codex != 21 && a <= 31) { int offset = decode_chars[(int) result[0]]; if (offset < r * (p + 1)) { nrX = offset / (p + 1); } else { swapletters = p == 1 && mapcoderData.Codex == 22; nrX = r + (offset - r * (p + 1)) / p; } } else if (mapcoderData.Codex != 21 && a < 62) { nrX = decode_chars[(int) result[0]]; if (nrX < (62 - a)) { swapletters = mapcoderData.Codex == 22; } else { nrX = nrX + nrX - 62 + a; } } else { // codex==21 || A>=62 int basePower = (mapcoderData.Codex == 21) ? 961 * 961 : 961 * 961 * 31; int basePowerA = basePower / a; if (a == 62) { basePowerA++; } else { basePowerA = 961 * (basePowerA / 961); } // decode and determine x v = fastDecode(result); nrX = v / basePowerA; v %= basePowerA; } if (swapletters && !Data.GetIsSpecialShape(firstrec + nrX)) { result = result.Substring(0, 2) + result[3] + result[2] + result[4]; } if (mapcoderData.Codex != 21 && a <= 31) { v = fastDecode(result); if (nrX > 0) { v -= (nrX * p + (nrX < r ? nrX : r)) * 961 * 961; } } else if (mapcoderData.Codex != 21 && a < 62) { v = fastDecode(result.Substring(1)); if (nrX >= (62 - a) && v >= (16 * 961 * 31)) { v -= 16 * 961 * 31; nrX++; } } if (nrX > a) { return Point.undefined(); // return undefined (past end!) } mapcoderData.dataSetup(firstrec + nrX); int side = DataAccess.SmartDiv(firstrec + nrX); int xSIDE = side; int maxy = mapcoderData.MapcoderRect.getMaxY(); int minx = mapcoderData.MapcoderRect.getMinX(); int miny = mapcoderData.MapcoderRect.getMinY(); int dx; int dy; if (mapcoderData.IsSpecialShape) { xSIDE *= side; side = 1 + (maxy - miny) / 90; xSIDE = xSIDE / side; Point d = decode6(v, xSIDE, side); dx = d.getLonMicroDeg(); dy = side - 1 - d.getLatMicroDeg(); } else { dy = v % side; dx = v / side; } if (dx >= xSIDE) // else out-of-range! { return Point.undefined(); // return undefined (out of range!) } int dividerx4 = Common.XDivider(miny, maxy); // 4 times too large! int dividery = 90; int cornerx = minx + (dx * dividerx4) / 4; // FIRST multiply, THEN // divide! int cornery = maxy - dy * dividery; return add2res(cornery, cornerx, dividerx4, dividery, -1, extrapostfix); }
/*@Nonnull*/ private static Point decodeStarpipe(string input, int firstindex, string extrapostfix, /*@Nonnull*/ Data mapcoderData) { // returns Point.isUndefined() in case or error int storageStart = 0; int thiscodexlen = mapcoderData.CodexLen; int value = fastDecode(input); // decode top (before dot) value *= 961 * 31; Point triple = decodeTriple(input.Substring(input.Length - 3)); // decode bottom 3 chars int i; for (i = firstindex; ; i++) { if (Data.CalcCodexLen(i) != thiscodexlen) { return Point.undefined(); // return undefined } if (i > firstindex) { mapcoderData.dataSetup(i); } int maxx = mapcoderData.MapcoderRect.getMaxX(); int maxy = mapcoderData.MapcoderRect.getMaxY(); int minx = mapcoderData.MapcoderRect.getMinX(); int miny = mapcoderData.MapcoderRect.getMinY(); int h = (maxy - miny + 89) / 90; int xdiv = Common.XDivider(miny, maxy); int w = ((maxx - minx) * 4 + xdiv - 1) / xdiv; h = 176 * ((h + 176 - 1) / 176); w = 168 * ((w + 168 - 1) / 168); int product = (w / 168) * (h / 176) * 961 * 31; int goodRounder = mapcoderData.Codex >= 23 ? 961 * 961 * 31 : 961 * 961; if (mapcoderData.PipeType == 8) { // *+ product = ((storageStart + product + goodRounder - 1) / goodRounder) * goodRounder - storageStart; } if (value >= storageStart && value < storageStart + product) { // code belongs here? int dividerx = (maxx - minx + w - 1) / w; int dividery = (maxy - miny + h - 1) / h; value -= storageStart; value = value / (961 * 31); // PIPELETTER DECODE int vx = value / (h / 176); vx = vx * 168 + triple.getLonMicroDeg(); int vy = (value % (h / 176)) * 176 + triple.getLatMicroDeg(); int cornery = maxy - vy * dividery; int cornerx = minx + vx * dividerx; /* * Sri Lanka Defect (v1.1) * { * int c1 = (zonedata == 0) ? -1 : decode_chars[(int) input .charAt(input.length() - 3)]; * Point zd = addzonedata(cornery + (triple.getY() - 176) dividery, * cornerx - triple.getX() * dividerx, 176 * dividery, 168 * dividerx, c1, dividerx, * dividery); * cornery = zd.getY(); * cornerx = zd.getX(); * } */ Point retval = add2res(cornery, cornerx, dividerx << 2, dividery, -1, extrapostfix); return retval; } storageStart += product; } // unreachable }
// throws UnknownMapcodeException /*@Nonnull*/ static Point decode(/*@Nonnull*/ string argMapcode, /*@Nonnull*/ Territory argTerritory) { Trace.TraceInformation("decode: mapcode={0}, territory={1}", argMapcode, argTerritory.ToString()); // JAVA name() string mapcode = argMapcode; Territory territory = argTerritory; // In case of error, result.isDefined() is false. Point result = Point.undefined(); string extrapostfix = string.Empty; int minpos = mapcode.IndexOf('-'); if (minpos > 0) { extrapostfix = mapcode.Substring(minpos + 1).Trim(); if (extrapostfix.Contains("Z")) { throw new UnknownMapcodeException("Invalid character Z"); } mapcode = mapcode.Substring(0, minpos); } mapcode = aeuUnpack(mapcode).Trim(); if (string.IsNullOrEmpty(mapcode)) { return result; // failed to decode! } int incodexlen = mapcode.Length - 1; // *** long codes in states are handled by the country if (incodexlen >= 9) { territory = Territory.territories[Territory.Territories.AAA]; } else { Territory parentTerritory = territory.getParentTerritory(); if (incodexlen >= 8 && (parentTerritory == Territory.territories[Territory.Territories.USA] || parentTerritory == Territory.territories[Territory.Territories.CAN] || parentTerritory == Territory.territories[Territory.Territories.AUS] || parentTerritory == Territory.territories[Territory.Territories.BRA] || parentTerritory == Territory.territories[Territory.Territories.CHN] || parentTerritory == Territory.territories[Territory.Territories.RUS]) || incodexlen >= 7 && (parentTerritory == Territory.territories[Territory.Territories.IND] || parentTerritory == Territory.territories[Territory.Territories.MEX])) { territory = parentTerritory; } } int ccode = territory.getTerritoryCode(); int from = DataAccess.DataFirstRecord(ccode); if (DataAccess.DataFlags(from) == 0) { return Point.undefined(); // this territory is not in the current data } int upto = DataAccess.DataLastRecord(ccode); int incodexhi = mapcode.IndexOf('.'); Data mapcoderData = new Data(); for (int i = from; i <= upto; i++) { mapcoderData.dataSetup(i); if (mapcoderData.PipeType == 0 && !mapcoderData.IsNameless && mapcoderData.CodexLen == incodexlen && mapcoderData.CodexHi == incodexhi) { result = decodeGrid(mapcode, mapcoderData.MapcoderRect.getMinX(), mapcoderData.MapcoderRect .getMinY(), mapcoderData.MapcoderRect.getMaxX(), mapcoderData.MapcoderRect.getMaxY(), i, extrapostfix); // RESTRICTUSELESS if (mapcoderData.IsUseless && result.isDefined()) { bool fitssomewhere = false; int j; for (j = upto - 1; j >= from; j--) { // look in previous // rects mapcoderData.dataSetup(j); if (mapcoderData.IsUseless) { continue; } int xdiv8 = Common.XDivider(mapcoderData.MapcoderRect.getMinY(), mapcoderData.MapcoderRect.getMaxY()) / 4; if (mapcoderData.MapcoderRect.extendBounds(xdiv8, 60).containsPoint(result)) { fitssomewhere = true; break; } } if (!fitssomewhere) { result.setUndefined(); } } break; } else if (mapcoderData.PipeType == 4 && mapcoderData.CodexLen + 1 == incodexlen && mapcoderData.CodexHi + 1 == incodexhi && mapcoderData.PipeLetter[0] == mapcode[0]) { result = decodeGrid(mapcode.Substring(1), mapcoderData.MapcoderRect.getMinX(), mapcoderData .MapcoderRect.getMinY(), mapcoderData.MapcoderRect.getMaxX(), mapcoderData .MapcoderRect.getMaxY(), i, extrapostfix); break; } else if (mapcoderData.IsNameless && (mapcoderData.Codex == 21 && incodexlen == 4 && incodexhi == 2 || mapcoderData.Codex == 22 && incodexlen == 5 && incodexhi == 3 || mapcoderData.Codex == 13 && incodexlen == 5 && incodexhi == 2)) { result = decodeNameless(mapcode, i, extrapostfix, mapcoderData); break; } else if (mapcoderData.PipeType > 4 && incodexlen == incodexhi + 3 && mapcoderData.CodexLen + 1 == incodexlen) { result = decodeStarpipe(mapcode, i, extrapostfix, mapcoderData); break; } } if (result.isDefined()) { if (result.getLonMicroDeg() > 180000000) { result = Point.fromMicroDeg(result.getLatMicroDeg(), result.getLonMicroDeg() - 360000000); } else if (result.getLonMicroDeg() < -180000000) { result = Point.fromMicroDeg(result.getLatMicroDeg(), result.getLonMicroDeg() + 360000000); } // LIMIT_TO_OUTRECT : make sure it fits the country if (ccode != CCODE_EARTH) { SubArea mapcoderRect = SubArea.GetArea(upto); // find // encompassing // rect int xdiv8 = Common.XDivider(mapcoderRect.getMinY(), mapcoderRect.getMaxY()) / 4; // should be /8 but there's some extra margin if (!mapcoderRect.extendBounds(xdiv8, 60).containsPoint(result)) { result.setUndefined(); // decodes outside the official territory // limit } } } Trace.TraceInformation("decode: result=({0}, {1})", result.isDefined() ? result.getLatDeg() : Double.NaN, result.isDefined() ? result.getLonDeg() : Double.NaN); result = Point.restrictLatLon(result); return result; }