[mkgmap] 05/14: Imported Upstream version 0.0.0+svn3366
Bas Couwenberg
sebastic at xs4all.nl
Sun Dec 14 15:39:46 UTC 2014
This is an automated email from the git hooks/post-receive script.
sebastic-guest pushed a commit to branch master
in repository mkgmap.
commit 31ade85724eb1e8d0dd4d51bc655b3916c925772
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date: Sun Dec 14 00:41:13 2014 +0100
Imported Upstream version 0.0.0+svn3366
---
.classpath | 10 +-
.idea/codeStyleSettings.xml | 4 +-
.idea/inspectionProfiles/Mapping.xml | 71 +++++-
.project | 28 ++-
.settings/org.apache.ivyde.eclipse.prefs | 2 +
.settings/org.eclipse.jdt.core.prefs | 100 ++++++++
doc/options.txt | 19 +-
doc/styles/rules-filters.txt | 32 ++-
doc/styles/rules.txt | 10 +-
ivy.xml | 3 +
ivysettings.xml | 2 +-
resources/LocatorConfig.xml | 148 ++++++------
resources/help/en/options | 19 +-
resources/mkgmap-version.properties | 4 +-
resources/styles/default/inc/address | 22 +-
resources/styles/default/inc/water_lines | 1 +
resources/styles/default/points | 14 +-
.../parabola/imgfmt/app/BufferedImgFileReader.java | 11 +-
src/uk/me/parabola/imgfmt/app/Coord.java | 27 ++-
.../me/parabola/imgfmt/app/lbl/LBLFileReader.java | 15 +-
src/uk/me/parabola/imgfmt/app/lbl/POIRecord.java | 39 +--
src/uk/me/parabola/imgfmt/app/net/NODFile.java | 4 +
src/uk/me/parabola/imgfmt/app/net/NODHeader.java | 17 +-
src/uk/me/parabola/imgfmt/app/net/RoadDef.java | 19 +-
.../me/parabola/imgfmt/app/trergn/Subdivision.java | 22 +-
src/uk/me/parabola/imgfmt/app/trergn/TREFile.java | 4 +
.../parabola/imgfmt/app/trergn/TREFileReader.java | 6 +-
.../me/parabola/imgfmt/app/trergn/TREHeader.java | 10 +-
src/uk/me/parabola/mkgmap/CommandArgsReader.java | 17 +-
src/uk/me/parabola/mkgmap/build/LocatorConfig.java | 23 +-
src/uk/me/parabola/mkgmap/build/MapArea.java | 98 +++++---
src/uk/me/parabola/mkgmap/build/MapBuilder.java | 40 +--
src/uk/me/parabola/mkgmap/build/MapSplitter.java | 29 ++-
.../parabola/mkgmap/combiners/GmapsuppBuilder.java | 11 +-
src/uk/me/parabola/mkgmap/main/StyleTester.java | 9 +
src/uk/me/parabola/mkgmap/osmstyle/ActionRule.java | 14 +-
.../parabola/mkgmap/osmstyle/ExpressionRule.java | 16 +-
.../parabola/mkgmap/osmstyle/RuleFileReader.java | 2 +-
src/uk/me/parabola/mkgmap/osmstyle/RuleSet.java | 14 ++
src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java | 8 +
.../parabola/mkgmap/osmstyle/StyledConverter.java | 158 +++++++++---
src/uk/me/parabola/mkgmap/osmstyle/TypeReader.java | 4 +-
.../parabola/mkgmap/osmstyle/WrongAngleFixer.java | 2 +-
.../mkgmap/osmstyle/actions/AddLabelAction.java | 2 +-
.../mkgmap/osmstyle/actions/ConvertFilter.java | 44 +++-
.../mkgmap/osmstyle/actions/CountryISOFilter.java | 38 +++
.../mkgmap/osmstyle/actions/HeightFilter.java | 2 +-
.../mkgmap/osmstyle/actions/NameAction.java | 2 +-
.../mkgmap/osmstyle/actions/SubstringFilter.java | 2 +-
.../mkgmap/osmstyle/actions/ValueBuilder.java | 8 +-
.../mkgmap/osmstyle/eval/UnitConversions.java | 168 +++++++++++--
.../osmstyle/housenumber/HousenumberGenerator.java | 146 ++++++++++-
.../mkgmap/reader/MapperBasedMapDataSource.java | 13 +
.../mkgmap/reader/osm/CoastlineFileLoader.java | 2 -
src/uk/me/parabola/mkgmap/reader/osm/Element.java | 2 +-
src/uk/me/parabola/mkgmap/reader/osm/GType.java | 23 +-
.../mkgmap/reader/osm/MultiPolygonRelation.java | 11 +
.../parabola/mkgmap/reader/osm/OsmConverter.java | 5 +
.../mkgmap/reader/osm/OsmMapDataSource.java | 15 +-
.../mkgmap/reader/osm/RelationStyleHook.java | 7 +-
src/uk/me/parabola/mkgmap/reader/osm/Rule.java | 1 +
.../parabola/mkgmap/reader/osm/SeaGenerator.java | 3 -
src/uk/me/parabola/mkgmap/reader/osm/Style.java | 5 +
src/uk/me/parabola/mkgmap/reader/osm/TagDict.java | 15 +-
.../reader/osm/boundary/BoundaryConverter.java | 5 +
.../mkgmap/reader/osm/boundary/BoundaryDiff.java | 24 +-
.../reader/osm/boundary/BoundaryPreprocessor.java | 16 +-
.../reader/osm/boundary/BoundaryQuadTree.java | 269 ++++++++++++---------
.../mkgmap/reader/osm/boundary/BoundarySaver.java | 164 +++++--------
.../mkgmap/reader/osm/boundary/BoundaryUtil.java | 252 ++++++++++++-------
.../mkgmap/reader/polish/PolishMapDataSource.java | 7 +
src/uk/me/parabola/util/Java2DConverter.java | 39 ++-
src/uk/me/parabola/util/ShapeSplitter.java | 260 ++++++++++++++++++++
test/func/route/SimpleRouteTest.java | 2 +-
test/uk/me/parabola/imgfmt/app/CoordTest.java | 15 ++
.../mkgmap/osmstyle/actions/ConvertFilterTest.java | 151 ++++++++++++
.../osmstyle/actions/CountryISOFilterTest.java | 55 +++++
.../mkgmap/osmstyle/actions/ValueBuilderTest.java | 14 ++
78 files changed, 2144 insertions(+), 751 deletions(-)
diff --git a/.classpath b/.classpath
index cb68169..a9544e7 100644
--- a/.classpath
+++ b/.classpath
@@ -1,14 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
<classpathentry kind="src" path="resources"/>
- <classpathentry kind="src" path="src"/>
+ <classpathentry excluding="uk/me/parabola/mkgmap/reader/dem/optional/" kind="src" path="src"/>
<classpathentry kind="src" path="test"/>
- <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/junit"/>
- <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/resource"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
- <classpathentry kind="lib" path="lib/compile/protobuf-java-2.4.1.jar"/>
- <classpathentry kind="lib" path="lib/compile/osmpbf-1.1.1-754a33af.jar"/>
- <classpathentry kind="lib" path="lib/compile/fastutil-6.5.2-mkg.1.jar"/>
+ <classpathentry kind="con" path="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=mkgmap&ivyXmlPath=ivy.xml&confs=*"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml
index d96c3e2..34644f1 100644
--- a/.idea/codeStyleSettings.xml
+++ b/.idea/codeStyleSettings.xml
@@ -118,7 +118,6 @@
<option name="METHOD_BRACE_STYLE" value="5" />
<option name="INDENT_CASE_FROM_SWITCH" value="false" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
- <option name="WRAP_COMMENTS" value="true" />
<option name="PARENT_SETTINGS_INSTALLED" value="true" />
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />
@@ -176,5 +175,4 @@
</option>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</component>
-</project>
-
+</project>
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Mapping.xml b/.idea/inspectionProfiles/Mapping.xml
index c999530..bd0f371 100644
--- a/.idea/inspectionProfiles/Mapping.xml
+++ b/.idea/inspectionProfiles/Mapping.xml
@@ -26,9 +26,13 @@
<inspection_tool class="AndroidDomInspection" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidElementNotAllowed" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintAaptCrash" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintAccidentalOctal" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintAdapterViewChildren" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintAddJavascriptInterface" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintAllowBackup" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintAlwaysShowAction" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintAppCompatMethod" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintAppCompatResource" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintAssert" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintBackButton" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintButtonCase" enabled="false" level="WARNING" enabled_by_default="false" />
@@ -37,7 +41,9 @@
<inspection_tool class="AndroidLintByteOrderMark" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintCommitPrefEdits" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintContentDescription" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintCustomViewStyleable" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintCutPasteId" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintDeprecated" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintDeviceAdmin" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintDisableBaselineAlignment" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintDrawAllocation" enabled="false" level="WARNING" enabled_by_default="false" />
@@ -49,13 +55,17 @@
<inspection_tool class="AndroidLintEasterEgg" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintEnforceUTF8" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintExportedContentProvider" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintExportedPreferenceActivity" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintExportedReceiver" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintExportedService" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintExtraText" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintExtraTranslation" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintGetInstance" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintGifUsage" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintGradleCompatible" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintGradleCompatiblePlugin" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintGradleDependency" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintGradleDeprecated" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintGradleDynamicVersion" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintGradleGetter" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintGradleIdeError" enabled="false" level="ERROR" enabled_by_default="true" />
@@ -79,6 +89,7 @@
<inspection_tool class="AndroidLintIconNoDpi" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintIconXmlAndPng" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintIllegalResourceRef" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintImpliedQuantity" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintInOrMmUsage" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintIncludeLayoutParam" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintInconsistentArrays" enabled="false" level="WARNING" enabled_by_default="false" />
@@ -91,6 +102,7 @@
<inspection_tool class="AndroidLintLabelFor" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintLibraryCustomView" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="AndroidLintLocalSuppress" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintLocaleFolder" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintMangledCRLF" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintManifestOrder" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintMenuTitle" enabled="false" level="WARNING" enabled_by_default="true" />
@@ -107,6 +119,7 @@
<inspection_tool class="AndroidLintNestedScrolling" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintNestedWeights" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintNewApi" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintNewerVersionAvailable" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintNfcTechWhitespace" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintNotSibling" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintObsoleteLayoutParam" enabled="false" level="WARNING" enabled_by_default="false" />
@@ -114,7 +127,9 @@
<inspection_tool class="AndroidLintOrientation" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintOverdraw" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintOverride" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintOverrideAbstract" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintPackagedPrivateKey" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintParcelCreator" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintPrivateResource" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="AndroidLintProguard" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintProguardSplit" enabled="false" level="WARNING" enabled_by_default="true" />
@@ -124,10 +139,12 @@
<inspection_tool class="AndroidLintPxUsage" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintReferenceType" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintRegistered" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintRelativeOverlap" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintRequiredSize" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintResAuto" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintResourceAsColor" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="AndroidLintResourceCycle" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintResourceName" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintRtlCompat" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="AndroidLintRtlEnabled" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintRtlHardcoded" enabled="false" level="WARNING" enabled_by_default="false" />
@@ -139,6 +156,7 @@
<inspection_tool class="AndroidLintServiceCast" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintSetJavaScriptEnabled" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintShowToast" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintSignatureOrSystemPermissions" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintSmallSp" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintSpUsage" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintSparseArray" enabled="false" level="WARNING" enabled_by_default="false" />
@@ -147,6 +165,7 @@
<inspection_tool class="AndroidLintStringFormatCount" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintStringFormatInvalid" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintStringFormatMatches" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintStringShouldBeInt" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintStyleCycle" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="AndroidLintSuspicious0dp" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintSuspiciousImport" enabled="false" level="WARNING" enabled_by_default="false" />
@@ -175,10 +194,13 @@
<inspection_tool class="AndroidLintUselessLeaf" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintUselessParent" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintUsesMinSdkAttributes" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintValidFragment" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="AndroidLintViewConstructor" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintViewHolder" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintWebViewLayout" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintWorldReadableFiles" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintWorldWriteableFiles" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AndroidLintWrongCall" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintWrongCase" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintWrongFolder" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AndroidLintWrongViewCast" enabled="false" level="ERROR" enabled_by_default="false" />
@@ -242,6 +264,7 @@
</inspection_tool>
<inspection_tool class="AssignmentToForLoopParameterJS" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AssignmentToFunctionParameterJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="AssignmentToLambdaParameter" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AssignmentToMethodParameter" enabled="false" level="WARNING" enabled_by_default="false">
<option name="ignoreTransformationOfOriginalParameter" value="false" />
</inspection_tool>
@@ -284,7 +307,10 @@
<inspection_tool class="BeforeClassOrAfterClassIsPublicStaticVoidNoArg" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="BeforeOrAfterIsPublicVoidNoArg" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="BigDecimalEquals" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="BigDecimalLegacyMethod" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="BigDecimalMethodWithoutRoundingCalled" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="BindingAnnotationWithoutInject" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="BlockMarkerComments" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="BlockStatementJS" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="BooleanConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="BooleanMethodIsAlwaysInverted" enabled="false" level="WARNING" enabled_by_default="false" />
@@ -343,6 +369,7 @@
<inspection_tool class="CdiManagedBeanInconsistencyInspection" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="CdiNormalScopeInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CdiObservesInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CdiScopeInspection" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CdiSpecializesInspection" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="CdiStereotypeInspection" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="CdiStereotypeRestrictionsInspection" enabled="true" level="ERROR" enabled_by_default="true" />
@@ -373,6 +400,7 @@
<inspection_tool class="CheckXmlFileWithXercesValidator" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="CheckedExceptionClass" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ClashingGetters" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ClashingTraitMethods" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ClassComplexity" enabled="false" level="WARNING" enabled_by_default="false">
<option name="m_limit" value="80" />
</inspection_tool>
@@ -419,6 +447,7 @@
<inspection_tool class="ClassWithMultipleLoggers" enabled="false" level="WARNING" enabled_by_default="false">
<option name="loggerNamesString" value="java.util.logging.Logger,org.slf4j.Logger,org.apache.commons.logging.Log,org.apache.log4j.Logger" />
</inspection_tool>
+ <inspection_tool class="ClassWithOnlyPrivateConstructors" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ClassWithTooManyDependencies" enabled="false" level="WARNING" enabled_by_default="false">
<option name="limit" value="10" />
</inspection_tool>
@@ -519,6 +548,7 @@
<inspection_tool class="ContinueStatementJS" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ContinueStatementWithLabel" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ContinueStatementWithLabelJS" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="Contract" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ControlFlowStatementWithoutBraces" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="Convert2Diamond" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="Convert2Lambda" enabled="false" level="WARNING" enabled_by_default="false" />
@@ -537,10 +567,13 @@
<inspection_tool class="CssInvalidCharsetRule" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CssInvalidElement" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="CssInvalidElementInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CssInvalidFunction" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="CssInvalidHtmlTagReference" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CssInvalidHtmlTagReferenceInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CssInvalidImport" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CssInvalidImportInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CssInvalidMediaFeature" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="CssInvalidPropertyValue" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="CssInvalidPseudoSelector" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="CssInvalidShorthandPropertyValue" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="CssMissingSemicolon" enabled="false" level="WARNING" enabled_by_default="false" />
@@ -610,15 +643,21 @@
<inspection_tool class="DivideByZeroJS" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="DjangoBrokenLineCommentInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="DjangoCloseTagInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="DjangoIncompatibleInspection" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="DjangoOrmInspection" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="DjangoRelationInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="DjangoUnresolvedFilterInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="DjangoUnresolvedLoadInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="DjangoUnresolvedStaticReferenceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="DjangoUnresolvedTagInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="DjangoUnresolvedTemplateReferenceInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="DjangoUnresolvedUrlInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
+ <inspection_tool class="DjangoUrlArgumentsInspection" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="Django_close_tag" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="DocumentWriteJS" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="DollarSignInName" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="DontUsePairConstructor" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="DoubleBraceInitialization" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="DoubleCheckedLocking" enabled="false" level="WARNING" enabled_by_default="false">
<option name="ignoreOnVolatileVariables" value="false" />
</inspection_tool>
@@ -724,7 +763,9 @@
<inspection_tool class="EqualsHashCodeCalledOnUrl" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="EqualsUsesNonFinalVariable" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="EqualsWhichDoesntCheckParameterClass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="EqualsWithItself" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ErrorRethrown" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="Eslint" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="ExceptionCaughtLocallyJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ExceptionFromCatchWhichDoesntWrap" enabled="false" level="WARNING" enabled_by_default="false">
<option name="ignoreGetMessage" value="false" />
@@ -835,6 +876,7 @@
<inspection_tool class="GWTStyleCheck" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="Geronimo" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="GherkinBrokenTableInspection" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="GherkinMisplacedBackground" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="GjsLint" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GlassFish" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="Glassfish" enabled="true" level="ERROR" enabled_by_default="true" />
@@ -1290,8 +1332,11 @@
<inspection_tool class="JSValidateJSDoc" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JSValidateJSON" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="JSValidateTypes" enabled="true" level="INFO" enabled_by_default="true" />
+ <inspection_tool class="JSXLanguageLevel" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="JUnit3MethodNamingConvention" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JUnit3StyleTestMethodInJUnit4Class" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JUnit4AnnotatedMethodInJUnit3TestCase" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="JUnit4MethodNamingConvention" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JUnitAbstractTestClassNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
<option name="m_regex" value="[A-Z][A-Za-z\d]*TestCase" />
<option name="m_minLength" value="12" />
@@ -1362,8 +1407,10 @@
<inspection_tool class="JpaQlInspection" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="JpaQueryApiInspection" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="JpdlModelInspection" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="Jscs" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="JsfJamExtendsClassInconsistencyInspection" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="JsfManagedBeansInconsistencyInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="JsonStandardCompliance" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="JspAbsolutePathInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JspDirectiveInspection" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="JspPropertiesInspection" enabled="true" level="ERROR" enabled_by_default="true" />
@@ -1538,6 +1585,7 @@
<option name="checkDivision" value="false" />
</inspection_tool>
<inspection_tool class="NakedNotify" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="NativeMethodNamingConvention" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="NativeMethods" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="NegatedConditional" enabled="false" level="WARNING" enabled_by_default="false">
<option name="m_ignoreNegatedNullComparison" value="true" />
@@ -1732,6 +1780,7 @@
<option name="m_maxLength" value="32" />
</inspection_tool>
<inspection_tool class="ParameterOfConcreteClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ParameterTypePreventsOverriding" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ParameterizedParametersStaticCollection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ParametersPerConstructor" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ParametersPerFunctionJS" enabled="false" level="WARNING" enabled_by_default="false">
@@ -1797,10 +1846,12 @@
<inspection_tool class="PointlessBooleanExpressionJS" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PointlessIndexOfComparison" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PointlessNullCheck" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PostfixTemplateDescriptionNotFound" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PrimitiveArrayArgumentToVariableArgMethod" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PrivateMemberAccessBetweenOuterAndInnerClass" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ProblematicVarargsMethodOverride" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ProblematicWhitespace" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PropertyValueSetToItself" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ProtectedField" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ProtectedInnerClass" enabled="false" level="WARNING" enabled_by_default="false">
<option name="ignoreEnums" value="false" />
@@ -1913,13 +1964,7 @@
<inspection_tool class="PyUnboundLocalVariableInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PyUnnecessaryBackslashInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PyUnreachableCodeInspection" enabled="true" level="WARNING" enabled_by_default="true" />
- <inspection_tool class="PyUnresolvedReferencesInspection" enabled="false" level="WARNING" enabled_by_default="false">
- <option name="ignoredIdentifiers">
- <value>
- <list size="0" />
- </value>
- </option>
- </inspection_tool>
+ <inspection_tool class="PyUnresolvedReferencesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PyUnusedLocalInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreTupleUnpacking" value="true" />
<option name="ignoreLambdaParameters" value="true" />
@@ -2017,6 +2062,7 @@
<option name="ignorePrivateMethods" value="true" />
</inspection_tool>
<inspection_tool class="ReturnOfDateField" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ReturnOfInnerClass" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ReturnThis" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ReuseOfLocalVariable" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ReuseOfLocalVariableJS" enabled="false" level="WARNING" enabled_by_default="false" />
@@ -2069,6 +2115,7 @@
<option name="ignoreAnonymousInnerClasses" value="false" />
<option name="superClassString" value="java.awt.Component" />
</inspection_tool>
+ <inspection_tool class="SerializableStoresNonSerializable" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SerializableWithUnconstructableAncestor" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ServerEndpointInconsistencyInspection" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="ServletWithoutMappingInspection" enabled="true" level="ERROR" enabled_by_default="true" />
@@ -2112,8 +2159,10 @@
<inspection_tool class="SpringBeanInstantiationInspection" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="SpringBeanLookupMethodInspection" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="SpringBeanNameConventionInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SpringComponentScan" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="SpringContextConfigurationInspection" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="SpringElInspection" enabled="false" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SpringElStaticFieldInjectionInspection" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SpringFacetCodeInspection" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SpringFacetInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="checkTestFiles" value="false" />
@@ -2121,6 +2170,7 @@
<inspection_tool class="SpringFacetProgrammaticInspection" enabled="false" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="SpringFactoryMethodInspection" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="SpringHandlersSchemasHighlighting" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SpringInactiveProfileHighlightingInspection" enabled="false" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SpringIncorrectResourceTypeInspection" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="SpringInjectionValueConsistencyInspection" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="SpringInjectionValueStyleInspection" enabled="true" level="WARNING" enabled_by_default="true" />
@@ -2149,6 +2199,7 @@
<inspection_tool class="SpringTransactionalComponentInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="SpringWebServiceAnnotationsInconsistencyInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SpringWebServicesConfigurationsInspection" enabled="true" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="SpringWebSocketConfigurationInspection" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="SqlAddNotNullColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlAmbiguousColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlAutoIncrementDuplicateInspection" enabled="false" level="WARNING" enabled_by_default="false" />
@@ -2248,6 +2299,7 @@
<inspection_tool class="SuperClassHasFrequentlyUsedInheritors" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SuppressionAnnotation" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SuspiciousArrayCast" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SuspiciousGetterSetter" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SuspiciousIndentAfterControlStatement" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SuspiciousMethodCalls" enabled="true" level="WARNING" enabled_by_default="true">
<option name="REPORT_CONVERTIBLE_METHOD_CALLS" value="true" />
@@ -2311,6 +2363,7 @@
<option name="assertionMethods" value="org.junit.Assert,assert.*|fail.*,junit.framework.Assert,assert.*|fail.*,org.mockito.Mockito,verify.*" />
<option name="assertKeywordIsAssertion" value="false" />
</inspection_tool>
+ <inspection_tool class="TestNGMethodNamingConvention" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="TestOnlyProblems" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="TextLabelInSwitchStatement" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="TextLabelInSwitchStatementJS" enabled="false" level="WARNING" enabled_by_default="false" />
@@ -2343,6 +2396,8 @@
<option name="m_limit" value="3" />
</inspection_tool>
<inspection_tool class="ThrowsRuntimeException" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ThymeleafMessagesResolveInspection" enabled="false" level="ERROR" enabled_by_default="true" />
+ <inspection_tool class="ThymeleafVariablesResolveInspection" enabled="false" level="ERROR" enabled_by_default="true" />
<inspection_tool class="TimeToString" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ToArrayCallWithZeroLengthArrayArgument" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="TodoComment" enabled="false" level="WARNING" enabled_by_default="false" />
@@ -2526,6 +2581,7 @@
<inspection_tool class="UnusedProperty" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UnusedReturnValue" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UpperCaseFieldNameNotConstant" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UseCouple" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UseJBColor" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UseOfAWTPeerClass" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UseOfAnotherObjectsPrivateField" enabled="false" level="WARNING" enabled_by_default="false">
@@ -2534,6 +2590,7 @@
</inspection_tool>
<inspection_tool class="UseOfJDBCDriverClass" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UseOfObsoleteAssert" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UseOfObsoleteDateTimeApi" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UseOfProcessBuilder" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UseOfPropertiesAsHashtable" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UseOfSunClasses" enabled="false" level="WARNING" enabled_by_default="false" />
diff --git a/.project b/.project
index 8bf15cf..e19a7be 100644
--- a/.project
+++ b/.project
@@ -1,16 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
- <name>mkgmap</name>
- <comment />
- <projects />
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments />
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
+ <name>mkgmap</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.apache.ivyde.eclipse.ivynature</nature>
+ </natures>
</projectDescription>
-
diff --git a/.settings/org.apache.ivyde.eclipse.prefs b/.settings/org.apache.ivyde.eclipse.prefs
new file mode 100644
index 0000000..a95f744
--- /dev/null
+++ b/.settings/org.apache.ivyde.eclipse.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+org.apache.ivyde.eclipse.standaloneretrieve=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><setuplist/>
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..7078bf8
--- /dev/null
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,100 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
+org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
+org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
+org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
+org.eclipse.jdt.core.compiler.problem.nullReference=warning
+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
+org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.7
diff --git a/doc/options.txt b/doc/options.txt
index 7aeeb73..78086de 100644
--- a/doc/options.txt
+++ b/doc/options.txt
@@ -350,13 +350,22 @@ will ask you to try a value for this option.
;--route
: Create maps that support routing.
+;--drive-on=left|right|detect|detect,left|detect,right
+: Explicitly specify which side of the road vehicles are
+expected to drive on.
+If the first option is detect, the program tries
+to find out the proper flag. If that detection
+fails, the second value is used (or right if none is given).
+With OSM data as input, the detection tries to find out
+the country each road is in and compares the number
+of drive-on-left roads with the rest.
+Use the --bounds option to make sure that the detection
+finds the correct country.
+
;--drive-on-left
;--drive-on-right
-: Explicitly specify which side of the road vehicles are
-expected to drive on. If neither of these options are
-specified, it is assumed that vehicles drive on the right
-unless --check-roundabouts is specified and the first
-roundabout processed is clockwise.
+: Deprecated: Use drive-on instead.
+The options are translated to drive-on=left|right.
;--check-roundabouts
: Check that roundabouts have the expected direction (clockwise
diff --git a/doc/styles/rules-filters.txt b/doc/styles/rules-filters.txt
index c46e9e9..6bf7314 100644
--- a/doc/styles/rules-filters.txt
+++ b/doc/styles/rules-filters.txt
@@ -12,11 +12,22 @@ matters.
`${oneway\|def:no}`
-| conv | `factor` |
-Use for conversions between units. The only supported version is from meters to feet
-number. It is multiplied by the argument.
+| conv | `m=>ft` |
+Use for conversions between units.
+With the argument +m=>ft+ the value is converted into feet, with the
+value being assumed to be in meters, unless the value includes a unit
+already.
+If any of the units are not recognised then the value is unchanged.
-`${height\|conv:m=>ft}`
+`${height\|conv:"m=>ft"}`
+
+So if +height+ is 10, then the result is 33, and if +height+ is 10ft,
+then the result is 10, as it is already in feet.
+
+The possible units are:
+
+* Length: m, km, ft (feet), mi (miles).
+* Speed: mph; km/h (or kmh, kmph), knots
| subst | `from=>to` +
`from~>to`|
@@ -81,12 +92,21 @@ The second is the maximum length of references that do not contain numbers.
If there is just the one number then it is used in both cases.
| height | `m=>ft` |
-This is the same as the +conv+ filter, except that it prepends a special
+This is exactly the same as the +conv+ filter, except that it prepends a special
separation character before the value which is intended for elevations.
-As with +conv+ the only supported conversion currently is from meters to feet.
`${ele\|height:"m=>ft"}`
+| country-ISO | |
+Use to normalize country names to the 3 character ISO 1366 code.
+The filter has no arguments. It uses the list in LocatorConfig.xml.
+Possible arguments are country names, or ISO codes in 2 or 3 characters,
+for example "Deutschland", "Germany", "Bundesrepublik Deutschland", or "DE"
+will all return "DEU", also different cases like "GERMANY" or " germany "
+will work.
+
+If the value is not found in the list, then the value is unchanged.
+
| not-equal | `tag` |
Used to check for duplicate tags. If the value of this tag is equal to
the value of the tag named as the argument to +not-equal+, then value
diff --git a/doc/styles/rules.txt b/doc/styles/rules.txt
index 0795106..db7f725 100644
--- a/doc/styles/rules.txt
+++ b/doc/styles/rules.txt
@@ -535,18 +535,16 @@ by the filter name, then a colon ":" and an argument. If there is more than
one argument required then they are usually separated by colons too, but
that is not a rule.
-[source]
- ${tagname|filter:arg1:arg2}
++${tagname|filter:arg1:arg2}+
You can apply as many filter expressions to a substitution as you like.
-[source]
- ${tagname|filter1:arg|filter2:arg}
+
++${tagname|filter1:arg|filter2:arg}+
If the argument contains spaces or symbols it should be quoted.
-[source]
- ${tagname|filter1:"arg with spaces"}
++${tagname|filter1:"arg with spaces"}+
For backward compatibility, most cases where you have spaces or symbols
do not actually need to be quoted, however we would recommend that you
diff --git a/ivy.xml b/ivy.xml
index d6f9fc1..06dd7a4 100644
--- a/ivy.xml
+++ b/ivy.xml
@@ -64,6 +64,9 @@
<dependency org="javax.media.jai" name="com.springsource.javax.media.jai.core" rev="1.1.3"
conf="optional->default(*),compile(*),master(*)"/>
+ <dependency org="uk.org.mkgmap" name="splitter" rev="412"
+ conf="optional->*"/>
+
<dependency org="org.geotools" name="gt-api" rev="2.7.5" conf="optional->default,compile">
<!-- A broken version of this is in the main repo which causes problems. Since we already depend on it, just ignore it here -->
<exclude module="jai_core"/>
diff --git a/ivysettings.xml b/ivysettings.xml
index ee4c8ab..c20b124 100644
--- a/ivysettings.xml
+++ b/ivysettings.xml
@@ -20,7 +20,7 @@
</chain>
- <ibiblio name="geotools-resolver" m2compatible="true" root="http://repo.opengeo.org/" />
+ <ibiblio name="geotools-resolver" m2compatible="true" root="http://download.osgeo.org/webdav/geotools/" />
<url name="spring-resolver" >
<ivy pattern="http://repository.springsource.com/ivy/bundles/external/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
diff --git a/resources/LocatorConfig.xml b/resources/LocatorConfig.xml
index ffec3f9..d2e74ba 100644
--- a/resources/LocatorConfig.xml
+++ b/resources/LocatorConfig.xml
@@ -33,7 +33,7 @@
<variant>AO</variant>
<variant>AGO</variant>
</country>
- <country name="Anguilla" abr="AIA">
+ <country name="Anguilla" abr="AIA" driveOnLeft="true">
<variant>AI</variant>
<variant>AIA</variant>
</country>
@@ -41,7 +41,7 @@
<variant>AQ</variant>
<variant>ATA</variant>
</country>
- <country name="Antigua and Barbuda" abr="ATG">
+ <country name="Antigua and Barbuda" abr="ATG" driveOnLeft="true">
<variant>AG</variant>
<variant>ATG</variant>
</country>
@@ -57,7 +57,7 @@
<variant>AW</variant>
<variant>ABW</variant>
</country>
- <country name="Australia" abr="AUS">
+ <country name="Australia" abr="AUS" driveOnLeft="true">
<variant>AU</variant>
<variant>AUS</variant>
</country>
@@ -74,7 +74,7 @@
<variant>AZE</variant>
<variant>Azərbaycan</variant>
</country>
- <country name="Bahamas" abr="BHS">
+ <country name="Bahamas" abr="BHS" driveOnLeft="true">
<variant>BS</variant>
<variant>BHS</variant>
<variant>The Bahamas</variant>
@@ -84,12 +84,12 @@
<variant>BHR</variant>
<variant>الإسلامية</variant>
</country>
- <country name="Bangladesh" abr="BGD">
+ <country name="Bangladesh" abr="BGD" driveOnLeft="true">
<variant>BD</variant>
<variant>BGD</variant>
<variant>বাংলাদেশ</variant>
</country>
- <country name="Barbados" abr="BRB">
+ <country name="Barbados" abr="BRB" driveOnLeft="true">
<variant>BB</variant>
<variant>BRB</variant>
</country>
@@ -117,11 +117,11 @@
<variant>BJ</variant>
<variant>BEN</variant>
</country>
- <country name="Bermuda" abr="BMU">
+ <country name="Bermuda" abr="BMU" driveOnLeft="true">
<variant>BM</variant>
<variant>BMU</variant>
</country>
- <country name="Bhutan" abr="BTN">
+ <country name="Bhutan" abr="BTN" driveOnLeft="true">
<variant>BT</variant>
<variant>BTN</variant>
</country>
@@ -139,7 +139,7 @@
<variant>BIH</variant>
<variant>Bosnia and Herzegovina</variant>
</country>
- <country name="Botswana" abr="BWA">
+ <country name="Botswana" abr="BWA" driveOnLeft="true">
<variant>BW</variant>
<variant>BWA</variant>
</country>
@@ -155,7 +155,7 @@
<variant>IO</variant>
<variant>IOT</variant>
</country>
- <country name="Brunei Darussalam" abr="BRN">
+ <country name="Brunei Darussalam" abr="BRN" driveOnLeft="true">
<variant>BN</variant>
<variant>BRN</variant>
<variant>برني دارالسلام</variant>
@@ -193,7 +193,7 @@
<variant>CPV</variant>
<variant>Cabo Verde</variant>
</country>
- <country name="Cayman Islands" abr="CYM">
+ <country name="Cayman Islands" abr="CYM" driveOnLeft="true">
<variant>KY</variant>
<variant>CYM</variant>
</country>
@@ -216,11 +216,11 @@
<variant>CHN</variant>
<variant>People's Republic of China</variant>
</country>
- <country name="Christmas Island" abr="CXR">
+ <country name="Christmas Island" abr="CXR" driveOnLeft="true">
<variant>CX</variant>
<variant>CXR</variant>
</country>
- <country name="Cocos (Keeling) Islands" abr="CCK">
+ <country name="Cocos (Keeling) Islands" abr="CCK" driveOnLeft="true">
<variant>CC</variant>
<variant>CCK</variant>
</country>
@@ -244,7 +244,7 @@
<variant>COD</variant>
<variant>Congo-Kinshasa</variant>
</country>
- <country name="Cook Islands" abr="COK">
+ <country name="Cook Islands" abr="COK" driveOnLeft="true">
<variant>CK</variant>
<variant>COK</variant>
</country>
@@ -269,7 +269,7 @@
<variant>CW</variant>
<variant>CUW</variant>
</country>
- <country name="Cyprus" abr="CYP">
+ <country name="Cyprus" abr="CYP" driveOnLeft="true">
<variant>CY</variant>
<variant>CYP</variant>
<variant>Κυπριακή Δημοκρατία</variant>
@@ -289,7 +289,7 @@
<variant>DJ</variant>
<variant>DJI</variant>
</country>
- <country name="Dominica" abr="DMA">
+ <country name="Dominica" abr="DMA" driveOnLeft="true">
<variant>DM</variant>
<variant>DMA</variant>
</country>
@@ -330,7 +330,7 @@
<variant>ET</variant>
<variant>ETH</variant>
</country>
- <country name="Falkland Islands (Malvinas)" abr="FLK">
+ <country name="Falkland Islands (Malvinas)" abr="FLK" driveOnLeft="true">
<variant>FK</variant>
<variant>FLK</variant>
</country>
@@ -339,7 +339,7 @@
<variant>FRO</variant>
<variant>Føroyar</variant>
</country>
- <country name="Fiji" abr="FJI">
+ <country name="Fiji" abr="FJI" driveOnLeft="true">
<variant>FJ</variant>
<variant>FJI</variant>
<variant>VITI</variant>
@@ -406,7 +406,7 @@
<variant>GL</variant>
<variant>GRL</variant>
</country>
- <country name="Grenada" abr="GRD">
+ <country name="Grenada" abr="GRD" driveOnLeft="true">
<variant>GD</variant>
<variant>GRD</variant>
</country>
@@ -423,7 +423,7 @@
<variant>GT</variant>
<variant>GTM</variant>
</country>
- <country name="Guernsey" abr="GGY">
+ <country name="Guernsey" abr="GGY" driveOnLeft="true">
<variant>GG</variant>
<variant>GGY</variant>
</country>
@@ -436,7 +436,7 @@
<variant>GNB</variant>
<variant>Guiné-Bissau</variant>
</country>
- <country name="Guyana" abr="GUY">
+ <country name="Guyana" abr="GUY" driveOnLeft="true">
<variant>GY</variant>
<variant>GUY</variant>
</country>
@@ -460,7 +460,7 @@
<variant>HN</variant>
<variant>HND</variant>
</country>
- <country name="Hong Kong" abr="HKG">
+ <country name="Hong Kong" abr="HKG" driveOnLeft="true">
<variant>HK</variant>
<variant>HKG</variant>
</country>
@@ -476,11 +476,11 @@
<variant>ICE</variant>
<variant>ISL</variant>
</country>
- <country name="India" abr="IND">
+ <country name="India" abr="IND" driveOnLeft="true">
<variant>IN</variant>
<variant>IND</variant>
</country>
- <country name="Indonesia" abr="IDN" streetBeforeHousenumber="true">
+ <country name="Indonesia" abr="IDN" streetBeforeHousenumber="true" driveOnLeft="true">
<variant>ID</variant>
<variant>IDN</variant>
</country>
@@ -495,13 +495,13 @@
<variant>IRQ</variant>
<variant>جمهورية العراق</variant>
</country>
- <country name="Ireland" abr="IRL" regionOffset="3">
+ <country name="Ireland" abr="IRL" regionOffset="3" driveOnLeft="true">
<variant>Republic of Ireland</variant>
<variant>Éire</variant>
<variant>IE</variant>
<variant>IRL</variant>
</country>
- <country name="Isle of Man" abr="IMN">
+ <country name="Isle of Man" abr="IMN" driveOnLeft="true">
<variant>IM</variant>
<variant>IMN</variant>
</country>
@@ -515,16 +515,16 @@
<variant>IT</variant>
<variant>ITA</variant>
</country>
- <country name="Jamaica" abr="JAM">
+ <country name="Jamaica" abr="JAM" driveOnLeft="true">
<variant>JM</variant>
<variant>JAM</variant>
</country>
- <country name="Japan" abr="JPN">
+ <country name="Japan" abr="JPN" driveOnLeft="true">
<variant>JP</variant>
<variant>JPN</variant>
<variant>日本</variant>
</country>
- <country name="Jersey" abr="JEY">
+ <country name="Jersey" abr="JEY" driveOnLeft="true">
<variant>JE</variant>
<variant>JEY</variant>
</country>
@@ -537,11 +537,11 @@
<variant>KAZ</variant>
<variant>Казахстан</variant>
</country>
- <country name="Kenya" abr="KEN">
+ <country name="Kenya" abr="KEN" driveOnLeft="true">
<variant>KE</variant>
<variant>KEN</variant>
</country>
- <country name="Kiribati" abr="KIR">
+ <country name="Kiribati" abr="KIR" driveOnLeft="true">
<variant>KI</variant>
<variant>KIR</variant>
</country>
@@ -581,7 +581,7 @@
<variant>LBN</variant>
<variant>الجمهورية اللبنانية</variant>
</country>
- <country name="Lesotho" abr="LSO">
+ <country name="Lesotho" abr="LSO" driveOnLeft="true">
<variant>LS</variant>
<variant>LSO</variant>
<variant>Kingdom of Lesotho</variant>
@@ -612,7 +612,7 @@
<variant>Groussherzogtum Lëtzebuerg</variant>
<variant>Grand Duchy of Luxembourg</variant>
</country>
- <country name="Macao" abr="MAC">
+ <country name="Macao" abr="MAC" driveOnLeft="true">
<variant>MO</variant>
<variant>MAC</variant>
</country>
@@ -627,16 +627,16 @@
<variant>MDG</variant>
<variant>Madagasikara</variant>
</country>
- <country name="Malawi" abr="MWI">
+ <country name="Malawi" abr="MWI" driveOnLeft="true">
<variant>MW</variant>
<variant>MWI</variant>
<variant>Republic of Malawi</variant>
</country>
- <country name="Malaysia" abr="MYS">
+ <country name="Malaysia" abr="MYS" driveOnLeft="true">
<variant>MY</variant>
<variant>MYS</variant>
</country>
- <country name="Maldives" abr="MDV">
+ <country name="Maldives" abr="MDV" driveOnLeft="true">
<variant>MV</variant>
<variant>MDV</variant>
<variant>ދިވެހިރާއްޖޭގެ ޖުމުހޫރިއްޔާ</variant>
@@ -645,7 +645,7 @@
<variant>ML</variant>
<variant>MLI</variant>
</country>
- <country name="Malta" abr="MLT">
+ <country name="Malta" abr="MLT" driveOnLeft="true">
<variant>MT</variant>
<variant>MLT</variant>
</country>
@@ -662,7 +662,7 @@
<variant>MR</variant>
<variant>MRT</variant>
</country>
- <country name="Mauritius" abr="MUS">
+ <country name="Mauritius" abr="MUS" driveOnLeft="true">
<variant>MU</variant>
<variant>MUS</variant>
</country>
@@ -698,7 +698,7 @@
<variant>ME</variant>
<variant>MNE</variant>
</country>
- <country name="Montserrat" abr="MSR">
+ <country name="Montserrat" abr="MSR" driveOnLeft="true">
<variant>MS</variant>
<variant>MSR</variant>
</country>
@@ -706,7 +706,7 @@
<variant>MA</variant>
<variant>MAR</variant>
</country>
- <country name="Mozambique" abr="MOZ">
+ <country name="Mozambique" abr="MOZ" driveOnLeft="true">
<variant>MZ</variant>
<variant>MOZ</variant>
<variant>Moçambique</variant>
@@ -715,16 +715,16 @@
<variant>MM</variant>
<variant>MMR</variant>
</country>
- <country name="Namibia" abr="NAM">
+ <country name="Namibia" abr="NAM" driveOnLeft="true">
<variant>NA</variant>
<variant>NAM</variant>
</country>
- <country name="Nauru" abr="NRU">
+ <country name="Nauru" abr="NRU" driveOnLeft="true">
<variant>NR</variant>
<variant>NRU</variant>
<variant>NAOERO</variant>
</country>
- <country name="Nepal" abr="NPL">
+ <country name="Nepal" abr="NPL" driveOnLeft="true">
<variant>NP</variant>
<variant>NPL</variant>
<variant>नेपाल</variant>
@@ -739,7 +739,7 @@
<variant>NC</variant>
<variant>NCL</variant>
</country>
- <country name="New Zealand" abr="NZL">
+ <country name="New Zealand" abr="NZL" driveOnLeft="true">
<variant>NZ</variant>
<variant>NZL</variant>
<variant>AOTEAROA NEW ZEALAND</variant>
@@ -756,11 +756,11 @@
<variant>NG</variant>
<variant>NGA</variant>
</country>
- <country name="Niue" abr="NIU">
+ <country name="Niue" abr="NIU" driveOnLeft="true">
<variant>NU</variant>
<variant>NIU</variant>
</country>
- <country name="Norfolk Island" abr="NFK">
+ <country name="Norfolk Island" abr="NFK" driveOnLeft="true">
<variant>NF</variant>
<variant>NFK</variant>
</country>
@@ -780,7 +780,7 @@
<variant>OMN</variant>
<variant>سلطنة عمان</variant>
</country>
- <country name="Pakistan" abr="PAK">
+ <country name="Pakistan" abr="PAK" driveOnLeft="true">
<variant>PK</variant>
<variant>PAK</variant>
<variant>پاکستان</variant>
@@ -800,7 +800,7 @@
<variant>PAN</variant>
<variant>Panamá</variant>
</country>
- <country name="Papua New Guinea" abr="PNG">
+ <country name="Papua New Guinea" abr="PNG" driveOnLeft="true">
<variant>PG</variant>
<variant>PNG</variant>
<variant>PAPUA NIUGINI</variant>
@@ -817,7 +817,7 @@
<variant>PH</variant>
<variant>PHL</variant>
</country>
- <country name="Pitcairn" abr="PCN">
+ <country name="Pitcairn" abr="PCN" driveOnLeft="true">
<variant>PN</variant>
<variant>PCN</variant>
</country>
@@ -866,19 +866,19 @@
<variant>BLM</variant>
<variant>Saint-Barthélémy</variant>
</country>
- <country name="Saint Helena" abr="SHN">
+ <country name="Saint Helena" abr="SHN" driveOnLeft="true">
<variant>Ascension</variant>
<variant>Tristan da Cunha</variant>
<variant>SH</variant>
<variant>SHN</variant>
</country>
- <country name="Saint Kitts and Nevis" abr="KNA">
+ <country name="Saint Kitts and Nevis" abr="KNA" driveOnLeft="true">
<variant>Saint Kitts</variant>
<variant>Nevis</variant>
<variant>KN</variant>
<variant>KNA</variant>
</country>
- <country name="Saint Lucia" abr="LCA">
+ <country name="Saint Lucia" abr="LCA" driveOnLeft="true">
<variant>LC</variant>
<variant>LCA</variant>
</country>
@@ -892,13 +892,13 @@
<variant>PM</variant>
<variant>SPM</variant>
</country>
- <country name="Saint Vincent and the Grenadines" abr="VCT">
+ <country name="Saint Vincent and the Grenadines" abr="VCT" driveOnLeft="true">
<variant>Saint Vincent</variant>
<variant>Grenadines</variant>
<variant>VC</variant>
<variant>VCT</variant>
</country>
- <country name="Samoa" abr="WSM">
+ <country name="Samoa" abr="WSM" driveOnLeft="true">
<variant>WS</variant>
<variant>WSM</variant>
</country>
@@ -928,7 +928,7 @@
<variant>Serbia</variant>
<variant>Republic of Serbia</variant>
</country>
- <country name="Seychelles" abr="SYC">
+ <country name="Seychelles" abr="SYC" driveOnLeft="true">
<variant>SC</variant>
<variant>SYC</variant>
<variant>SESEL</variant>
@@ -937,7 +937,7 @@
<variant>SL</variant>
<variant>SLE</variant>
</country>
- <country name="Singapore" abr="SGP">
+ <country name="Singapore" abr="SGP" driveOnLeft="true">
<variant>SG</variant>
<variant>SGP</variant>
<variant>SINGAPURA</variant>
@@ -956,7 +956,7 @@
<variant>SVN</variant>
<variant>Slovenia</variant>
</country>
- <country name="Solomon Islands" abr="SLB">
+ <country name="Solomon Islands" abr="SLB" driveOnLeft="true">
<variant>SB</variant>
<variant>SLB</variant>
</country>
@@ -965,7 +965,7 @@
<variant>SOM</variant>
<variant>Soomaaliya</variant>
</country>
- <country name="South Africa" abr="ZAF">
+ <country name="South Africa" abr="ZAF" driveOnLeft="true">
<variant>ZA</variant>
<variant>ZAF</variant>
</country>
@@ -980,7 +980,7 @@
<variant>ES</variant>
<variant>ESP</variant>
</country>
- <country name="Sri Lanka" abr="LKA">
+ <country name="Sri Lanka" abr="LKA" driveOnLeft="true">
<variant>LK</variant>
<variant>LKA</variant>
<variant>ශ්රී ලංකා</variant>
@@ -995,7 +995,7 @@
<variant>SDN</variant>
<variant>جمهورية السودان</variant>
</country>
- <country name="Suriname" abr="SUR">
+ <country name="Suriname" abr="SUR" driveOnLeft="true">
<variant>SR</variant>
<variant>SUR</variant>
</country>
@@ -1005,7 +1005,7 @@
<variant>SJ</variant>
<variant>SJM</variant>
</country>
- <country name="Swaziland" abr="SWZ">
+ <country name="Swaziland" abr="SWZ" driveOnLeft="true">
<variant>SZ</variant>
<variant>SWZ</variant>
<variant>Swatini</variant>
@@ -1037,17 +1037,17 @@
<variant>TJK</variant>
<variant>Тоҷикистон</variant>
</country>
- <country name="Tanzania" abr="TZA">
+ <country name="Tanzania" abr="TZA" driveOnLeft="true">
<variant>United Republic of Tanzania</variant>
<variant>TZ</variant>
<variant>TZA</variant>
</country>
- <country name="Thailand" abr="THA">
+ <country name="Thailand" abr="THA" driveOnLeft="true">
<variant>TH</variant>
<variant>THA</variant>
<variant>ราชอาณาจักรไทย</variant>
</country>
- <country name="Timor-Leste" abr="TLS">
+ <country name="Timor-Leste" abr="TLS" driveOnLeft="true">
<variant>TL</variant>
<variant>TLS</variant>
<variant>Timór Loro Sa'e</variant>
@@ -1058,7 +1058,7 @@
<variant>TGO</variant>
<variant>République Togolaise</variant>
</country>
- <country name="Tokelau" abr="TKL">
+ <country name="Tokelau" abr="TKL" driveOnLeft="true">
<variant>TK</variant>
<variant>TKL</variant>
</country>
@@ -1066,7 +1066,7 @@
<variant>TO</variant>
<variant>TON</variant>
</country>
- <country name="Trinidad and Tobago" abr="TTO">
+ <country name="Trinidad and Tobago" abr="TTO" driveOnLeft="true">
<variant>Trinidad</variant>
<variant>Tobago</variant>
<variant>TT</variant>
@@ -1086,15 +1086,15 @@
<variant>TKM</variant>
<variant>Türkmenistan</variant>
</country>
- <country name="Turks and Caicos Islands" abr="TCA">
+ <country name="Turks and Caicos Islands" abr="TCA" driveOnLeft="true">
<variant>TC</variant>
<variant>TCA</variant>
</country>
- <country name="Tuvalu" abr="TUV">
+ <country name="Tuvalu" abr="TUV" driveOnLeft="true">
<variant>TV</variant>
<variant>TUV</variant>
</country>
- <country name="Uganda" abr="UGA">
+ <country name="Uganda" abr="UGA" driveOnLeft="true">
<variant>UG</variant>
<variant>UGA</variant>
</country>
@@ -1109,7 +1109,7 @@
<variant>ARE</variant>
<variant>الإمارات العربيّة المتّحدة</variant>
</country>
- <country name="United Kingdom" abr="GBR">
+ <country name="United Kingdom" abr="GBR" driveOnLeft="true">
<variant>England</variant>
<variant>Scotland</variant>
<variant>Wales</variant>
@@ -1153,12 +1153,12 @@
<variant>VNM</variant>
<variant>Việt Nam</variant>
</country>
- <country name="Virgin Islands, British" abr="VGB">
+ <country name="Virgin Islands, British" abr="VGB" driveOnLeft="true">
<variant>VG</variant>
<variant>VGB</variant>
<variant>British Virgin Islands</variant>
</country>
- <country name="Virgin Islands, U.S." abr="VIR">
+ <country name="Virgin Islands, U.S." abr="VIR" driveOnLeft="true">
<variant>VI</variant>
<variant>VIR</variant>
</country>
@@ -1177,11 +1177,11 @@
<variant>YEM</variant>
<variant>اليمن</variant>
</country>
- <country name="Zambia" abr="ZMB">
+ <country name="Zambia" abr="ZMB" driveOnLeft="true">
<variant>ZM</variant>
<variant>ZMB</variant>
</country>
- <country name="Zimbabwe" abr="ZWE">
+ <country name="Zimbabwe" abr="ZWE" driveOnLeft="true">
<variant>ZW</variant>
<variant>ZWE</variant>
</country>
diff --git a/resources/help/en/options b/resources/help/en/options
index 47dcf1d..e8ac20f 100644
--- a/resources/help/en/options
+++ b/resources/help/en/options
@@ -347,13 +347,22 @@ Miscellaneous options:
--route
Create maps that support routing.
+--drive-on=left|right|detect|detect,left|detect,right
+ Explicitly specify which side of the road vehicles are
+ expected to drive on.
+ If the first option is detect, the program tries
+ to find out the proper flag. If that detection
+ fails, the second value is used (or right if none is given).
+ With OSM data as input, the detection tries to find out
+ the country each road is in and compares the number
+ of drive-on-left roads with the rest.
+ Use the --bounds option to make sure that the detection
+ finds the correct country.
+
--drive-on-left
--drive-on-right
- Explicitly specify which side of the road vehicles are
- expected to drive on. If neither of these options are
- specified, it is assumed that vehicles drive on the right
- unless --check-roundabouts is specified and the first
- roundabout processed is clockwise.
+ Deprecated: Use drive-on instead.
+ The options are translated to drive-on=left|right.
--check-roundabouts
Check that roundabouts have the expected direction (clockwise
diff --git a/resources/mkgmap-version.properties b/resources/mkgmap-version.properties
index f1389b0..9f108d2 100644
--- a/resources/mkgmap-version.properties
+++ b/resources/mkgmap-version.properties
@@ -1,2 +1,2 @@
-svn.version: 3333
-build.timestamp: 2014-08-08T07:32:50+0100
+svn.version: 3366
+build.timestamp: 2014-12-08T07:00:53+0000
diff --git a/resources/styles/default/inc/address b/resources/styles/default/inc/address
index 7c2b3bc..f01b26e 100644
--- a/resources/styles/default/inc/address
+++ b/resources/styles/default/inc/address
@@ -5,8 +5,8 @@
# first set the country code
mkgmap:country!=* & mkgmap:admin_level2=* { set mkgmap:country='${mkgmap:admin_level2}' }
-mkgmap:country!=* & addr:country=* { set mkgmap:country='${addr:country}' }
-mkgmap:country!=* & is_in:country=* { set mkgmap:country='${is_in:country}' }
+mkgmap:country!=* & addr:country=* { set mkgmap:country='${addr:country|country-ISO:}' }
+mkgmap:country!=* & is_in:country=* { set mkgmap:country='${is_in:country|country-ISO:}' }
# country specific rules first
@@ -31,7 +31,7 @@ mkgmap:country=AUT & mkgmap:city!=* & mkgmap:admin_level10=* { set mkgmap:city='
mkgmap:country=AUT & mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8|subst:Gemeinde |subst:Stadt }' }
# Poland = POL
-mkgmap:country=POL & mkgmap:city!=* & mkgmap:admin_level10=* { set mkgmap:city='${mkgmap:admin_level10}' }
+#After recent changes in OSM-Poland we don't use level 10 - all cities and villages are in level 8
mkgmap:country=POL & mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8}' }
mkgmap:country=POL & mkgmap:region!=* & mkgmap:admin_level4=* { set mkgmap:region='${mkgmap:admin_level4|subst:województwo =>}' }
@@ -59,7 +59,21 @@ mkgmap:country=CHE & mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='$
# Canada
mkgmap:country=CAN & mkgmap:region!=* & mkgmap:admin_level4=* { set mkgmap:region='${mkgmap:admin_level4}' }
-mkgmap:country=CAN & mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8}' }
+mkgmap:country=CAN & mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8|subst:City of }' }
+
+# United States
+mkgmap:country=USA & mkgmap:region!=* & mkgmap:admin_level4=* { set mkgmap:region='${mkgmap:admin_level4}' }
+# New York City has different admin levels than the rest of the US.
+# https://wiki.openstreetmap.org/wiki/United_States_admin_level
+mkgmap:country=USA & mkgmap:city!=* & mkgmap:admin_level5='New York City' & mkgmap:admin_level6='New York County' { set mkgmap:city='New York' }
+mkgmap:country=USA & mkgmap:city!=* & mkgmap:admin_level5='New York City' & mkgmap:admin_level6='Bronx County' { set mkgmap:city='Bronx' }
+mkgmap:country=USA & mkgmap:city!=* & mkgmap:admin_level5='New York City' & mkgmap:admin_level6='Kings County' { set mkgmap:city='Brooklyn' }
+# Queens uses neighborhoods for city in postal addresses
+# http://en.wikipedia.org/wiki/List_of_Queens_neighborhoods
+mkgmap:country=USA & mkgmap:city!=* & mkgmap:admin_level5='New York City' & mkgmap:admin_level6='Queens County' & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8}' }
+mkgmap:country=USA & mkgmap:city!=* & mkgmap:admin_level5='New York City' & mkgmap:admin_level6='Queens County' { set mkgmap:city='Queens' }
+mkgmap:country=USA & mkgmap:city!=* & mkgmap:admin_level5='New York City' & mkgmap:admin_level6='Richmond County' { set mkgmap:city='Staten Island' }
+mkgmap:country=USA & mkgmap:city!=* & mkgmap:admin_level8=* { set mkgmap:city='${mkgmap:admin_level8|subst:City of }' }
# Ecuador = ECU
mkgmap:country=ECU & mkgmap:region!=* & mkgmap:admin_level4=* { set mkgmap:region='${mkgmap:admin_level4}' }
diff --git a/resources/styles/default/inc/water_lines b/resources/styles/default/inc/water_lines
index 908f028..e829a8a 100644
--- a/resources/styles/default/inc/water_lines
+++ b/resources/styles/default/inc/water_lines
@@ -1,5 +1,6 @@
natural=coastline [0x15 resolution 12]
+route=ferry & (motorcar=no | motor_vehicle=no) {add mkgmap:ferry=1} [0x1b road_class=0 road_speed=0 resolution 23]
route=ferry {add mkgmap:ferry=1} [0x1b road_class=3 road_speed=0 resolution 19]
waterway=canal [0x1f resolution 21]
diff --git a/resources/styles/default/points b/resources/styles/default/points
index eb88a5c..e571d63 100644
--- a/resources/styles/default/points
+++ b/resources/styles/default/points
@@ -42,21 +42,21 @@ barrier=kissing_gate | barrier=stile | barrier=block
internet_access=yes { name 'Internet ${name}' | 'Internet' } [0x2f12 resolution 24 continue]
internet_access=* & internet_access!=no & internet_access!=yes { name 'Internet(${internet_access}) ${name|def:}' } [0x2f12 resolution 24 continue]
-(highway=bus_stop | railway=tram_stop | railway=halt | railway=station)
+(public_transport=platform | highway=bus_stop | railway=tram_stop | railway=halt | railway=station)
& (ref=* | route_ref=*) {
set ref='${ref|def:}(${route_ref})';
}
-(highway=bus_stop | railway=tram_stop | railway=halt | railway=station)
+(public_transport=platform | highway=bus_stop | railway=tram_stop | railway=halt | railway=station)
& lit=yes & (shelter=yes | covered=yes)
{
set ref='${ref|def:}*';
}
-(highway=bus_stop | railway=tram_stop | railway=halt | railway=station)
+(public_transport=platform | highway=bus_stop | railway=tram_stop | railway=halt | railway=station)
& lit!=yes & (shelter=yes | covered=yes)
{
set ref='${ref|def:}+';
}
-(highway=bus_stop | railway=tram_stop | railway=halt | railway=station)
+(public_transport=platform | highway=bus_stop | railway=tram_stop | railway=halt | railway=station)
& (shelter=no | covered=no)
{
set ref='${ref|def:}-';
@@ -190,8 +190,6 @@ landuse=village_green & name=* [0x2c06 resolution 24]
healthcare=hospital | amenity=hospital [0x3002 resolution 22]
healthcare=* | amenity=dentist | amenity=doctors [0x3002 resolution 24]
-highway=bus_stop [0x2f17 resolution 24]
-
highway=motorway_junction [0x2100 resolution 24]
highway=services & mkgmap:area2poi!=true [0x210f resolution 24 default_name 'Services']
@@ -224,9 +222,9 @@ natural=peak {name '${name|def:}${ele|height:m=>ft|def:}' } [0x6616 resolution 2
natural=rock [0x6614 resolution 24]
natural=volcano [0x2c0c resolution 24]
-railway=halt [0x2f08 resolution 23]
railway=station [0x2f08 resolution 22]
-railway=tram_stop [0x2f17 resolution 24]
+( public_transport=platform & rail=yes ) | railway=halt [0x2f08 resolution 23]
+public_transport=platform | highway=bus_stop | railway=tram_stop [0x2f17 resolution 24]
shop=bakers [0x2e02 resolution 24]
shop=bakery [0x2e02 resolution 24]
diff --git a/src/uk/me/parabola/imgfmt/app/BufferedImgFileReader.java b/src/uk/me/parabola/imgfmt/app/BufferedImgFileReader.java
index 0a1776c..2a9b295 100644
--- a/src/uk/me/parabola/imgfmt/app/BufferedImgFileReader.java
+++ b/src/uk/me/parabola/imgfmt/app/BufferedImgFileReader.java
@@ -201,11 +201,7 @@ public class BufferedImgFileReader implements ImgFileReader {
int ch = firstChar & 0xff;
do {
- if (str11.length() == 0) {
- // Not found
- if (ch < 0x80)
- return "";
- }
+ assert !(str11.length() == 0 && (ch & 0x80) == 0);
if ((ch & 0x80) != 0)
--term;
@@ -215,9 +211,8 @@ public class BufferedImgFileReader implements ImgFileReader {
} while (term != 0);
// Remove any trailing delimiters
- int idx;
- if ((idx = str11.lastIndexOf("A")) >= 0)
- str11.setLength(idx);
+ while (str11.length() > 0 && str11.charAt(str11.length()-1) == 'A')
+ str11.setLength(str11.length()-1);
// Convert in-line delimiters to the char delimiter
int len = str11.length();
diff --git a/src/uk/me/parabola/imgfmt/app/Coord.java b/src/uk/me/parabola/imgfmt/app/Coord.java
index 5daa21a..c1486e7 100644
--- a/src/uk/me/parabola/imgfmt/app/Coord.java
+++ b/src/uk/me/parabola/imgfmt/app/Coord.java
@@ -458,7 +458,7 @@ public class Coord implements Comparable<Coord> {
public Coord makeBetweenPoint(Coord other, double fraction) {
int dLat30 = other.getHighPrecLat() - getHighPrecLat();
int dLon30 = other.getHighPrecLon() - getHighPrecLon();
- if ((Math.abs(dLat30) < 1000000 && Math.abs(dLon30) < 1000000 )){
+ if (dLon30 == 0 || Math.abs(dLat30) < 1000000 && Math.abs(dLon30) < 1000000 ){
// distances are rather small, we can use flat earth approximation
int lat30 = (int) (getHighPrecLat() + dLat30 * fraction);
int lon30 = (int) (getHighPrecLon() + dLon30 * fraction);
@@ -705,16 +705,21 @@ public class Coord implements Comparable<Coord> {
double lat2 = lat1 + deltaLat;
// check for some daft bugger going past the pole, normalise latitude if so
if (Math.abs(lat2) > Math.PI/2) lat2 = lat2>0 ? Math.PI-lat2 : -Math.PI-lat2;
-
- double deltaPhi = Math.log(Math.tan(lat2/2+Math.PI/4)/Math.tan(lat1/2+Math.PI/4));
- double q = Math.abs(deltaPhi) > 10e-12 ? deltaLat / deltaPhi : Math.cos(lat1); // E-W course becomes ill-conditioned with 0/0
-
- double deltaLon = distRad*Math.sin(brngRad)/q;
-
- double lon2 = lon1 + deltaLon;
-
- lon2 = (lon2 + 3*Math.PI) % (2*Math.PI) - Math.PI; // normalise to -180..+180º
-
+ double lon2;
+ // catch special case: normalised value would be -8388608
+ if (this.getLongitude() == 8388608 && brng == 0)
+ lon2 = lon1;
+ else {
+ double deltaPhi = Math.log(Math.tan(lat2/2+Math.PI/4)/Math.tan(lat1/2+Math.PI/4));
+ double q = Math.abs(deltaPhi) > 10e-12 ? deltaLat / deltaPhi : Math.cos(lat1); // E-W course becomes ill-conditioned with 0/0
+
+ double deltaLon = distRad*Math.sin(brngRad)/q;
+
+ lon2 = lon1 + deltaLon;
+
+ lon2 = (lon2 + 3*Math.PI) % (2*Math.PI) - Math.PI; // normalise to -180..+180º
+ }
+
return new Coord(Math.toDegrees(lat2), Math.toDegrees(lon2));
}
diff --git a/src/uk/me/parabola/imgfmt/app/lbl/LBLFileReader.java b/src/uk/me/parabola/imgfmt/app/lbl/LBLFileReader.java
index 0523291..fd58cd5 100644
--- a/src/uk/me/parabola/imgfmt/app/lbl/LBLFileReader.java
+++ b/src/uk/me/parabola/imgfmt/app/lbl/LBLFileReader.java
@@ -386,14 +386,13 @@ public class LBLFileReader extends ImgFile {
if (hasStreetNum) {
byte b = reader.get();
- String num = reader.getBase11str(b, '-');
- if (num.isEmpty()) {
+ if ((b & 0x80) == 0) {
int mpoffset = (b << 16) & 0xff0000;
mpoffset |= reader.getChar() & 0xffff;
- poi.setComplexPhoneNumber(fetchLabel(mpoffset));
+ poi.setComplexStreetNumber(fetchLabel(mpoffset));
} else {
- poi.setSimpleStreetNumber(num);
+ poi.setSimpleStreetNumber(reader.getBase11str(b, '-'));
}
}
@@ -425,16 +424,14 @@ public class LBLFileReader extends ImgFile {
if (hasPhone) {
byte b = reader.get();
- String num = reader.getBase11str(b, '-');
- if (num.isEmpty()) {
+ if ((b & 0x80) == 0) {
// Yes this is a bit strange it is a byte followed by a char
int mpoffset = (b << 16) & 0xff0000;
mpoffset |= reader.getChar() & 0xffff;
- Label label = fetchLabel(mpoffset);
- poi.setComplexPhoneNumber(label);
+ poi.setComplexPhoneNumber(fetchLabel(mpoffset));
} else {
- poi.setSimplePhoneNumber(num);
+ poi.setSimplePhoneNumber(reader.getBase11str(b, '-'));
}
}
diff --git a/src/uk/me/parabola/imgfmt/app/lbl/POIRecord.java b/src/uk/me/parabola/imgfmt/app/lbl/POIRecord.java
index a44e945..e87ca70 100644
--- a/src/uk/me/parabola/imgfmt/app/lbl/POIRecord.java
+++ b/src/uk/me/parabola/imgfmt/app/lbl/POIRecord.java
@@ -295,27 +295,6 @@ public class POIRecord {
}
/**
- * Address abbreviations.
- */
- //static class AddrAbbr {
- // private final char code;
- // private final String value;
- //
- // AddrAbbr(char code, String value) {
- // this.code = code;
- // this.value = value;
- // }
- //
- // public String toString() {
- // return value;
- // }
- //
- // public char getCode() {
- // return code;
- // }
- //}
-
- /**
* Street and Phone numbers can be stored in two different ways in the poi record
* Simple Number that only contain digits are coded in base 11 coding.
* This helper class tries to code the given number. If the number contains other
@@ -330,7 +309,7 @@ public class POIRecord {
* Encode a string as base 11.
* @param str The input string.
* @return If the string is not all numeric (or A) then false is returned
- * and the string will be encoded as a label instead.
+ * and this object is invalid.
*/
public boolean set(String str) {
@@ -393,10 +372,18 @@ public class POIRecord {
return encodedSize;
}
- private int decodeChar(char ch)
- {
- return (ch - '0');
+ /**
+ * Convert the characters '0' to '9' and '-' to a number 0-10 (base 11).
+ * @param ch The character to convert.
+ * @return A number between 0 and 10 or -1 if the character is not valid.
+ */
+ private int decodeChar(char ch) {
+ if (ch == '-')
+ return 10;
+ else if (ch >= '0' && ch <= '9')
+ return (ch - '0');
+ else
+ return -1;
}
-
}
}
diff --git a/src/uk/me/parabola/imgfmt/app/net/NODFile.java b/src/uk/me/parabola/imgfmt/app/net/NODFile.java
index a684dff..6649368 100644
--- a/src/uk/me/parabola/imgfmt/app/net/NODFile.java
+++ b/src/uk/me/parabola/imgfmt/app/net/NODFile.java
@@ -186,4 +186,8 @@ public class NODFile extends ImgFile {
this.roads = roads;
this.boundary = boundary;
}
+
+ public void setDriveOnLeft(boolean dol) {
+ nodHeader.setDriveOnLeft(dol);
+ }
}
diff --git a/src/uk/me/parabola/imgfmt/app/net/NODHeader.java b/src/uk/me/parabola/imgfmt/app/net/NODHeader.java
index 59744b1..65a57a8 100644
--- a/src/uk/me/parabola/imgfmt/app/net/NODHeader.java
+++ b/src/uk/me/parabola/imgfmt/app/net/NODHeader.java
@@ -47,16 +47,7 @@ public class NODHeader extends CommonHeader {
private int align;
private int mult1;
private int tableARecordLen;
-
- /**
- * The driveOnLeft flag is set via a static method. Using a ThreadLocal
- * ensures thread safety when using more than one thread.
- */
- private static final ThreadLocal<Boolean> driveOnLeft = new ThreadLocal<Boolean>() {
- protected Boolean initialValue() {
- return Boolean.FALSE;
- }
- };
+ private boolean driveOnLeft;
public NODHeader() {
super(HEADER_LEN, "GARMIN NOD");
@@ -115,7 +106,7 @@ public class NODHeader extends CommonHeader {
assert Integer.bitCount(DISTANCE_MULT) == 1;
assert DISTANCE_MULT_SHIFT < 8;
flags |= DISTANCE_MULT_SHIFT << 5;
- if(driveOnLeft.get())
+ if(driveOnLeft)
flags |= 0x0100;
writer.putInt(flags);
@@ -191,8 +182,8 @@ public class NODHeader extends CommonHeader {
return classBoundaries;
}
- public static void setDriveOnLeft(boolean dol) {
- driveOnLeft.set(dol);
+ public void setDriveOnLeft(boolean dol) {
+ driveOnLeft = dol;
}
public int getFlags() {
diff --git a/src/uk/me/parabola/imgfmt/app/net/RoadDef.java b/src/uk/me/parabola/imgfmt/app/net/RoadDef.java
index 3b55592..95e5a4f 100644
--- a/src/uk/me/parabola/imgfmt/app/net/RoadDef.java
+++ b/src/uk/me/parabola/imgfmt/app/net/RoadDef.java
@@ -53,7 +53,7 @@ import uk.me.parabola.log.Logger;
* @author Robert Vollmert
*/
-public class RoadDef implements Comparable<RoadDef> {
+public class RoadDef {
private static final Logger log = Logger.getLogger(RoadDef.class);
public static final int NET_FLAG_NODINFO = 0x40;
@@ -689,23 +689,6 @@ public class RoadDef implements Comparable<RoadDef> {
netFlags |= NET_FLAG_ADDRINFO;
}
- public int compareTo(RoadDef other) {
- // sort by city name - this is used to group together
- // roads that have been split into segments
- if(other == this)
- return 0;
-
- // TODO: look at what this is doing...
- if(city != null && other.city != null)
- return city.getName().compareTo(other.city.getName());
- if (hashCode() == other.hashCode())
- return 0;
- else if (hashCode() < other.hashCode())
- return -1;
- else
- return 0;
- }
-
public City getCity() {
return city;
}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/Subdivision.java b/src/uk/me/parabola/imgfmt/app/trergn/Subdivision.java
index d8ee51d..aaf455d 100644
--- a/src/uk/me/parabola/imgfmt/app/trergn/Subdivision.java
+++ b/src/uk/me/parabola/imgfmt/app/trergn/Subdivision.java
@@ -85,7 +85,7 @@ public class Subdivision {
// Set if this is the last one.
private boolean last;
- private final List<Subdivision> divisions = new ArrayList<Subdivision>();
+ private final List<Subdivision> divisions = new ArrayList<>();
private int extTypeAreasOffset;
private int extTypeLinesOffset;
@@ -299,9 +299,8 @@ public class Subdivision {
} else {
maxSetIdx = 2;
}
- } else {
- maxSetIdx = 3;
}
+
String[] refs = Arrays.copyOfRange(labels, 1, maxSetIdx+1);
if(refs.length == 1) {
// don't bother to add a single ref that looks the
@@ -545,7 +544,6 @@ public class Subdivision {
}
/**
* Set the sizes for the extended type data. See {@link #writeLastExtTypeOffsetsRecord(ImgFileWriter)}
- * @param reader
*/
public void readLastExtTypeOffsetsRecord(ImgFileReader reader) {
extTypeAreasSize = reader.getInt() - extTypeAreasOffset;
@@ -640,4 +638,20 @@ public class Subdivision {
public Coord getCenter(){
return new Coord(getLatitude(),getLongitude());
}
+
+ /**
+ * Get the unshifted width of the subdivision.
+ * @return The true (unshifted) width.
+ */
+ public int getWidth() {
+ return width << getShift();
+ }
+
+ /**
+ * Get the unshifted height of the subdivision.
+ * @return The true (unshifted) height.
+ */
+ public int getHeight() {
+ return height << getShift();
+ }
}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/TREFile.java b/src/uk/me/parabola/imgfmt/app/trergn/TREFile.java
index 589f018..8542279 100644
--- a/src/uk/me/parabola/imgfmt/app/trergn/TREFile.java
+++ b/src/uk/me/parabola/imgfmt/app/trergn/TREFile.java
@@ -361,4 +361,8 @@ public class TREFile extends ImgFile implements Configurable {
public void addPoiDisplayFlags(byte b) {
header.addPoiDisplayFlags(b);
}
+
+ public void setDriveOnLeft(boolean b) {
+ header.setDriveOnLeft(b);
+ }
}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/TREFileReader.java b/src/uk/me/parabola/imgfmt/app/trergn/TREFileReader.java
index e849f64..11eb272 100644
--- a/src/uk/me/parabola/imgfmt/app/trergn/TREFileReader.java
+++ b/src/uk/me/parabola/imgfmt/app/trergn/TREFileReader.java
@@ -112,7 +112,7 @@ public class TREFileReader extends ImgReader {
int endRgnOffset = reader.getu3();
SubdivData subdivData = new SubdivData(flags,
- lat, lon, width, height,
+ lat, lon, 2*width, 2*height,
lastRgnOffset, endRgnOffset);
Subdivision subdiv = Subdivision.readSubdivision(mapLevels[count], subdivData);
@@ -127,7 +127,7 @@ public class TREFileReader extends ImgReader {
}
/**
- * Read the extended type info for the sub divisions. Corresponds to {@link #TREFile.writeExtTypeOffsetsRecords()}.
+ * Read the extended type info for the sub divisions. Corresponds to {@link TREFile#writeExtTypeOffsetsRecords()}.
*/
private void readExtTypeOffsetsRecords() {
ImgFileReader reader = getReader();
@@ -230,4 +230,4 @@ public class TREFileReader extends ImgReader {
}
return msgs.toArray(new String[msgs.size()]);
}
-}
\ No newline at end of file
+}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java b/src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java
index e3d3fc1..ee71936 100644
--- a/src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java
+++ b/src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java
@@ -240,9 +240,6 @@ public class TREHeader extends CommonHeader {
if (props.containsKey("transparent"))
poiDisplayFlags |= POI_FLAG_TRANSPARENT;
-
- if (props.containsKey("drive-on-left"))
- poiDisplayFlags |= POI_FLAG_DRIVE_ON_LEFT;
}
/**
@@ -260,7 +257,12 @@ public class TREHeader extends CommonHeader {
public void setMapId(int id) {
mapId = id;
}
-
+
+ public void setDriveOnLeft(boolean dol) {
+ if (dol)
+ this.poiDisplayFlags |= POI_FLAG_DRIVE_ON_LEFT;
+ }
+
public void addPoiDisplayFlags(byte poiDisplayFlags) {
this.poiDisplayFlags |= poiDisplayFlags;
}
diff --git a/src/uk/me/parabola/mkgmap/CommandArgsReader.java b/src/uk/me/parabola/mkgmap/CommandArgsReader.java
index b4ba2e9..9d5fd60 100644
--- a/src/uk/me/parabola/mkgmap/CommandArgsReader.java
+++ b/src/uk/me/parabola/mkgmap/CommandArgsReader.java
@@ -119,7 +119,7 @@ public class CommandArgsReader {
// If there is more than one filename argument we inform of this fact
// via a fake option.
proc.processOption("number-of-files", String.valueOf(arglist.getFilenameCount()));
-
+
// Now process the arguments in order.
for (ArgType a : arglist) {
a.processArg();
@@ -145,6 +145,20 @@ public class CommandArgsReader {
*/
private void addOption(String optval) {
CommandOption opt = new CommandOption(new Option(optval));
+ boolean legacyOptionDetected = false;
+ // translate legacy options drive-on-left and drive-on-right
+ String option = opt.getOption();
+ if ("drive-on-left".equals(option)){
+ opt = new CommandOption(new Option("drive-on=left"));
+ legacyOptionDetected = true;
+ }
+ if ("drive-on-right".equals(option)){
+ opt = new CommandOption(new Option("drive-on=right"));
+ legacyOptionDetected = true;
+ }
+ if (legacyOptionDetected){
+ System.err.println("Option " + option + " is deprecated. Will use " + opt.getOption() + "=" + opt.getValue() + " as replacement for " + optval);
+ }
addOption(opt);
}
@@ -267,6 +281,7 @@ public class CommandArgsReader {
fmt.format("%8.8s", mapname);
}
args.setProperty("mapname", fmt.toString());
+ fmt.close();
} catch (NumberFormatException e) {
// If the name is not a number then we just leave it alone...
}
diff --git a/src/uk/me/parabola/mkgmap/build/LocatorConfig.java b/src/uk/me/parabola/mkgmap/build/LocatorConfig.java
index d29de30..c754f33 100644
--- a/src/uk/me/parabola/mkgmap/build/LocatorConfig.java
+++ b/src/uk/me/parabola/mkgmap/build/LocatorConfig.java
@@ -35,13 +35,15 @@ public class LocatorConfig {
private static final Logger log = Logger.getLogger(LocatorConfig.class);
/** maps country name (in all variants) to the 3 letter ISO code */
- private final Map<String,String> isoMap = new HashMap<String,String>();
+ private final Map<String,String> isoMap = new HashMap<>();
/** maps the ISO code to the offset of the region in the is_in tag */
- private final Map<String,Integer> regOffsetMap = new HashMap<String,Integer>();
+ private final Map<String,Integer> regOffsetMap = new HashMap<>();
/** maps the ISO code to the POI display flag */
- private final Map<String,Integer> poiDispFlagMap = new HashMap<String,Integer>();
+ private final Map<String,Integer> poiDispFlagMap = new HashMap<>();
+ /** maps the ISO code to the drive-on-left flag */
+ private final Map<String,Boolean> driveOnLeftFlagMap = new HashMap<>();
/** contains the names of all continents */
- private final Set<String> continents = new HashSet<String>();
+ private final Set<String> continents = new HashSet<>();
/** maps ISO => default country name */
private final Map<String, String> defaultCountryNames = new HashMap<String, String>();
@@ -153,6 +155,10 @@ public class LocatorConfig {
if (poiDispTag != 0x0 && iso != null) {
setPoiDispTag(iso, poiDispTag);
}
+ Node driveOnLeft = attr.getNamedItem("driveOnLeft");
+ if (driveOnLeft != null && "true".equals(driveOnLeft.getNodeValue())){
+ driveOnLeftFlagMap.put(iso, true);
+ }
}
if (iso != null) {
@@ -339,5 +345,14 @@ public class LocatorConfig {
String s = continent.toUpperCase().trim();
return continents.contains(s);
}
+
+ public synchronized boolean getDriveOnLeftFlag(String iso)
+ {
+ if (iso == null)
+ return false;
+ if (driveOnLeftFlagMap.containsKey(iso))
+ return true;
+ return false;
+ }
}
diff --git a/src/uk/me/parabola/mkgmap/build/MapArea.java b/src/uk/me/parabola/mkgmap/build/MapArea.java
index 650b4bd..df899f4 100644
--- a/src/uk/me/parabola/mkgmap/build/MapArea.java
+++ b/src/uk/me/parabola/mkgmap/build/MapArea.java
@@ -17,6 +17,7 @@
package uk.me.parabola.mkgmap.build;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import uk.me.parabola.imgfmt.app.Area;
@@ -52,7 +53,8 @@ public class MapArea implements MapDataSource {
private static final int INITIAL_CAPACITY = 100;
private static final int MAX_RESOLUTION = 24;
-
+ private static final int LARGE_OBJECT_DIM = 8192;
+
public static final int POINT_KIND = 0;
public static final int LINE_KIND = 1;
public static final int SHAPE_KIND = 2;
@@ -72,9 +74,9 @@ public class MapArea implements MapDataSource {
private int maxLon = Integer.MIN_VALUE;
// The contents of the area.
- private final List<MapPoint> points = new ArrayList<MapPoint>(INITIAL_CAPACITY);
- private final List<MapLine> lines = new ArrayList<MapLine>(INITIAL_CAPACITY);
- private final List<MapShape> shapes = new ArrayList<MapShape>(INITIAL_CAPACITY);
+ private final List<MapPoint> points = new ArrayList<>(INITIAL_CAPACITY);
+ private final List<MapLine> lines = new ArrayList<>(INITIAL_CAPACITY);
+ private final List<MapShape> shapes = new ArrayList<>(INITIAL_CAPACITY);
// amount of space required for the contents
private final int[] sizes = new int[NUM_KINDS];
@@ -98,8 +100,6 @@ public class MapArea implements MapDataSource {
public MapArea(MapDataSource src, int resolution) {
this.areaResolution = 0;
this.bounds = src.getBounds();
- addToBounds(bounds);
-
for (MapPoint p : src.getPoints()) {
if(bounds.contains(p.getLocation()))
addPoint(p);
@@ -119,9 +119,7 @@ public class MapArea implements MapDataSource {
MapFilterChain chain = new MapFilterChain() {
public void doFilter(MapElement element) {
MapShape shape = (MapShape) element;
- shapes.add(shape);
- addToBounds(shape.getBounds());
- addSize(element, shape.hasExtendedType()? XT_SHAPE_KIND : SHAPE_KIND);
+ addShape(shape);
}
};
@@ -148,9 +146,7 @@ public class MapArea implements MapDataSource {
MapFilterChain chain = new MapFilterChain() {
public void doFilter(MapElement element) {
MapLine line = (MapLine) element;
- lines.add(line);
- addToBounds(line.getBounds());
- addSize(element, line.hasExtendedType()? XT_LINE_KIND : LINE_KIND);
+ addLine(line);
}
};
@@ -173,7 +169,6 @@ public class MapArea implements MapDataSource {
private MapArea(Area area, int res) {
bounds = area;
areaResolution = res;
- addToBounds(area);
}
/**
@@ -193,6 +188,7 @@ public class MapArea implements MapDataSource {
log.info("Splitting area " + bounds + " into " + nx + "x" + ny + " pieces at resolution " + resolution);
boolean useNormalSplit = true;
while (true){
+ List<MapArea> largeObjectAreas = new ArrayList<>();
for (int i = 0; i < nx * ny; i++) {
mapAreas[i] = new MapArea(areas[i], resolution);
if (log.isDebugEnabled())
@@ -212,14 +208,28 @@ public class MapArea implements MapDataSource {
used[pos] = true;
}
-
+ int maxWidth = areas[0].getWidth();
+ int maxHeight = areas[0].getHeight();
+ if (nx*ny == 1 || maxWidth < LARGE_OBJECT_DIM|| maxHeight < LARGE_OBJECT_DIM){
+ // don't separate large objects
+ maxWidth = Integer.MAX_VALUE;
+ maxHeight = Integer.MAX_VALUE;
+ }
+
int areaIndex = 0;
for (MapLine l : this.lines) {
// Drop any zero sized lines.
if (l instanceof MapRoad == false && l.getRect().height <= 0 && l.getRect().width <= 0)
continue;
- if (useNormalSplit)
+ if (useNormalSplit){
areaIndex = pickArea(mapAreas, l, xbase30, ybase30, nx, ny, dx30, dy30);
+ if (l.getBounds().getHeight() > maxHeight || l.getBounds().getWidth() > maxWidth){
+ MapArea largeObjectArea = new MapArea(l.getBounds(), resolution);
+ largeObjectArea.addLine(l);
+ largeObjectAreas.add(largeObjectArea);
+ continue;
+ }
+ }
else
areaIndex = ++areaIndex % mapAreas.length;
mapAreas[areaIndex].addLine(l);
@@ -227,8 +237,15 @@ public class MapArea implements MapDataSource {
}
for (MapShape e : this.shapes) {
- if (useNormalSplit)
+ if (useNormalSplit){
areaIndex = pickArea(mapAreas, e, xbase30, ybase30, nx, ny, dx30, dy30);
+ if (e.getBounds().getHeight() > maxHeight || e.getBounds().getWidth() > maxWidth){
+ MapArea largeObjectArea = new MapArea(e.getBounds(), resolution);
+ largeObjectArea.addShape(e);
+ largeObjectAreas.add(largeObjectArea);
+ continue;
+ }
+ }
else
areaIndex = ++areaIndex % mapAreas.length;
mapAreas[areaIndex].addShape(e);
@@ -245,6 +262,14 @@ public class MapArea implements MapDataSource {
useNormalSplit = false;
continue;
}
+
+ if (largeObjectAreas.isEmpty() == false){
+ // combine list and array
+ int pos = mapAreas.length;
+ mapAreas = Arrays.copyOf(mapAreas, mapAreas.length + largeObjectAreas.size());
+ for (MapArea ma : largeObjectAreas)
+ mapAreas[pos++] = ma;
+ }
return mapAreas;
}
}
@@ -462,7 +487,7 @@ public class MapArea implements MapDataSource {
*/
private void addPoint(MapPoint p) {
points.add(p);
- addToBounds(p.getLocation());
+ addToBounds(p.getLocation());
addSize(p, p.hasExtendedType()? XT_POINT_KIND : POINT_KIND);
}
@@ -511,18 +536,26 @@ public class MapArea implements MapDataSource {
maxLon = l;
}
+ /**
+ * Add to bounds considering high precision values.
+ * @param co
+ */
private void addToBounds(Coord co) {
- int l = co.getLatitude();
- if (l < minLat)
- minLat = l;
- if (l > maxLat)
- maxLat = l;
-
- l = co.getLongitude();
- if (l < minLon)
- minLon = l;
- if (l > maxLon)
- maxLon = l;
+ int lat30 = co.getHighPrecLat();
+ int latLower = lat30 >> Coord.DELTA_SHIFT;
+ int latUpper = (latLower << Coord.DELTA_SHIFT) < lat30 ? latLower + 1 : latLower;
+ if (latLower < minLat)
+ minLat = latLower;
+ if (latUpper > maxLat)
+ maxLat = latUpper;
+
+ int lon30 = co.getHighPrecLon();
+ int lonLeft = lon30 >> Coord.DELTA_SHIFT;
+ int lonRight = (lonLeft << Coord.DELTA_SHIFT) < lon30 ? lonLeft + 1 : lonLeft;
+ if (lonLeft < minLon)
+ minLon = lonLeft;
+ if (lonRight > maxLon)
+ maxLon = lonRight;
}
@@ -575,4 +608,13 @@ public class MapArea implements MapDataSource {
}
return xcell * ny + ycell;
}
+
+ /**
+ * @return true if this area contains any data
+ */
+ public boolean hasData() {
+ if (points.isEmpty() && lines.isEmpty() && shapes.isEmpty())
+ return false;
+ return true;
+ }
}
diff --git a/src/uk/me/parabola/mkgmap/build/MapBuilder.java b/src/uk/me/parabola/mkgmap/build/MapBuilder.java
index 54ad0b5..49a9aaf 100644
--- a/src/uk/me/parabola/mkgmap/build/MapBuilder.java
+++ b/src/uk/me/parabola/mkgmap/build/MapBuilder.java
@@ -110,7 +110,7 @@ public class MapBuilder implements Configurable {
private List<String> copyrights = new ArrayList<String>();
private boolean doRoads;
-
+ private Boolean driveOnLeft;
private Locator locator;
private final java.util.Map<String, Highway> highways = new HashMap<String, Highway>();
@@ -180,6 +180,11 @@ public class MapBuilder implements Configurable {
locator = new Locator(props);
locator.setDefaultCountry(countryName, countryAbbr);
+ String driveOn = props.getProperty("drive-on",null);
+ if ("left".equals(driveOn))
+ driveOnLeft = true;
+ if ("right".equals(driveOn))
+ driveOnLeft = false;
}
/**
@@ -214,6 +219,16 @@ public class MapBuilder implements Configurable {
processOverviews(map, src);
processInfo(map, src);
makeMapAreas(map, src);
+
+ if (driveOnLeft == null){
+ // check if source gives info about driving side
+ if (src instanceof MapperBasedMapDataSource){
+ driveOnLeft = ((MapperBasedMapDataSource) src).getDriveOnLeft();
+ }
+ }
+ if (driveOnLeft == null)
+ driveOnLeft = false;
+ treFile.setDriveOnLeft(driveOnLeft);
treFile.setLastRgnPos(rgnFile.position() - RGNHeader.HEADER_LEN);
@@ -229,6 +244,7 @@ public class MapBuilder implements Configurable {
NODFile nodFile = map.getNodFile();
if (nodFile != null) {
nodFile.setNetwork(network.getCenters(), network.getRoadDefs(), network.getBoundary());
+ nodFile.setDriveOnLeft(driveOnLeft);
nodFile.write();
}
netFile.write(lblFile.numCities(), lblFile.numZips());
@@ -524,22 +540,16 @@ public class MapBuilder implements Configurable {
r.setStreetName(streetName);
}
- if(p.getHouseNumber() != null)
- {
- if(!r.setSimpleStreetNumber(p.getHouseNumber()))
- {
- Label streetNumber = lbl.newLabel(p.getHouseNumber());
- r.setComplexStreetNumber(streetNumber);
- }
+ String houseNumber = p.getHouseNumber();
+ if (houseNumber != null && !houseNumber.isEmpty()) {
+ if(!r.setSimpleStreetNumber(houseNumber))
+ r.setComplexStreetNumber(lbl.newLabel(houseNumber));
}
- if(p.getPhone() != null)
- {
- if(!r.setSimplePhoneNumber(p.getPhone()))
- {
- Label phoneNumber = lbl.newLabel(p.getPhone());
- r.setComplexPhoneNumber(phoneNumber);
- }
+ String phone = p.getPhone();
+ if (phone != null && !phone.isEmpty()) {
+ if(!r.setSimplePhoneNumber(phone))
+ r.setComplexPhoneNumber(lbl.newLabel(phone));
}
poimap.put(p, r);
diff --git a/src/uk/me/parabola/mkgmap/build/MapSplitter.java b/src/uk/me/parabola/mkgmap/build/MapSplitter.java
index e787319..b3884d5 100644
--- a/src/uk/me/parabola/mkgmap/build/MapSplitter.java
+++ b/src/uk/me/parabola/mkgmap/build/MapSplitter.java
@@ -59,8 +59,12 @@ public class MapSplitter {
public static final int MAX_XT_LINES_SIZE = 0xff00;
public static final int MAX_XT_SHAPES_SIZE = 0xff00;
- public static final int MIN_DIMENSION = 10; // just a reasonable value
+ public static final int MIN_DIMENSION = 10; // just a reasonable value
+ // The target number of estimated bytes for one area, smaller values
+ // result in more and typically smaller areas and larger *.img files
+ private static final int WANTED_MAX_AREA_SIZE = 0x3fff;
+
private final Zoom zoom;
/**
@@ -99,7 +103,7 @@ public class MapSplitter {
// Now step through each area and see if any have too many map features
// in them. For those that do, we further split them. This is done
// recursively until everything fits.
- List<MapArea> alist = new ArrayList<MapArea>();
+ List<MapArea> alist = new ArrayList<>();
addAreasToList(areas, alist, 0);
MapArea[] results = new MapArea[alist.size()];
@@ -120,6 +124,8 @@ public class MapSplitter {
for (MapArea area : areas) {
Area bounds = area.getBounds();
int[] sizes = area.getEstimatedSizes();
+ if (area.hasData() == false)
+ continue;
if(log.isInfoEnabled()) {
String padding = depth + " ";
log.info(padding.substring(0, (depth + 1) * 2) +
@@ -129,7 +135,8 @@ public class MapSplitter {
", lines = " + area.getNumLines() + "/" + sizes[MapArea.LINE_KIND] +
", shapes = " + area.getNumShapes() + "/" + sizes[MapArea.SHAPE_KIND]);
}
-
+ boolean doSplit = false;
+
if (area.getNumLines() > MAX_NUM_LINES ||
area.getNumPoints() > MAX_NUM_POINTS ||
(sizes[MapArea.POINT_KIND] +
@@ -137,7 +144,21 @@ public class MapSplitter {
sizes[MapArea.SHAPE_KIND]) > MAX_RGN_SIZE ||
sizes[MapArea.XT_POINT_KIND] > MAX_XT_POINTS_SIZE ||
sizes[MapArea.XT_LINE_KIND] > MAX_XT_LINES_SIZE ||
- sizes[MapArea.XT_SHAPE_KIND] > MAX_XT_SHAPES_SIZE) {
+ sizes[MapArea.XT_SHAPE_KIND] > MAX_XT_SHAPES_SIZE)
+ doSplit = true; // we must split
+ else if (bounds.getMaxDimension() > MIN_DIMENSION) {
+ int sumSize = 0;
+ for (int s : sizes)
+ sumSize += s;
+ if (sumSize > WANTED_MAX_AREA_SIZE) {
+ if (area.getLines().size() + area.getShapes().size() >= 2) {
+ // area has more bytes than wanted, and we can split
+ log.debug("splitting area because size is larger than wanted: " + sumSize);
+ doSplit = true;
+ }
+ }
+ }
+ if (doSplit){
if (bounds.getMaxDimension() > MIN_DIMENSION) {
if (log.isDebugEnabled())
log.debug("splitting area", area);
diff --git a/src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java b/src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java
index 645643f..f173a2c 100644
--- a/src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java
+++ b/src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java
@@ -536,19 +536,18 @@ public class GmapsuppBuilder implements Combiner {
totHeaderEntries += mdrSlots;
}
- // There are 2 entries for the header itself.
- totHeaderEntries += 2;
+ // Add for header itself, plus the first directory block.
+ totHeaderEntries += DIRECTORY_OFFSET_ENTRY + 1;
int totHeaderBlocks = totHeaderEntries * 512 / bs;
log.info("total blocks for", bs, "is", totHeaderBlocks, "based on slots=", totHeaderEntries);
- int reserveEntries = DIRECTORY_OFFSET_ENTRY + 1 + totHeaderEntries;
- if (totBlocks + reserveEntries < 0xfffe && totHeaderBlocks <= ENTRY_SIZE) {
- return new BlockInfo(bs, reserveEntries);
+ if (totBlocks + totHeaderEntries < 0xfffe && totHeaderBlocks <= ENTRY_SIZE) {
+ return new BlockInfo(bs, totHeaderEntries);
}
}
- throw new IllegalArgumentException("hmm");
+ throw new IllegalArgumentException("Could not select a suitable block size. Try to reduce the number of splits.");
}
public void setCreateIndex(boolean create) {
diff --git a/src/uk/me/parabola/mkgmap/main/StyleTester.java b/src/uk/me/parabola/mkgmap/main/StyleTester.java
index 41f2ee1..cf49a2f 100644
--- a/src/uk/me/parabola/mkgmap/main/StyleTester.java
+++ b/src/uk/me/parabola/mkgmap/main/StyleTester.java
@@ -294,6 +294,10 @@ public class StyleTester implements OsmConverter {
converter.end();
}
+ @Override
+ public Boolean getDriveOnLeft() {
+ return null; // unknown
+ }
private static void printResult(String[] results) {
for (String s : results) {
@@ -670,6 +674,11 @@ public class StyleTester implements OsmConverter {
rule.setFinalizeRule(finalizeRule);
}
}
+
+ @Override
+ public void printStats(String header) {
+ // TODO Auto-generated method stub
+ }
}
/**
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/ActionRule.java b/src/uk/me/parabola/mkgmap/osmstyle/ActionRule.java
index 4eaa7bb..8151c1a 100644
--- a/src/uk/me/parabola/mkgmap/osmstyle/ActionRule.java
+++ b/src/uk/me/parabola/mkgmap/osmstyle/ActionRule.java
@@ -18,6 +18,7 @@ package uk.me.parabola.mkgmap.osmstyle;
import java.util.List;
+import uk.me.parabola.log.Logger;
import uk.me.parabola.mkgmap.osmstyle.actions.Action;
import uk.me.parabola.mkgmap.osmstyle.eval.Op;
import uk.me.parabola.mkgmap.reader.osm.Element;
@@ -36,10 +37,13 @@ import uk.me.parabola.mkgmap.reader.osm.TypeResult;
* @author Steve Ratcliffe
*/
public class ActionRule implements Rule {
+ private static final Logger statsLog = Logger.getLogger(ActionRule.class.getPackage().getName()+".stats");
private Op expression;
private final List<Action> actions;
private final GType type;
private Rule finalizeRule;
+ private long numEval; // count how often the expression was evaluated
+ private long numTrue; // count how often the evaluation returned true
/** Finalize rules must not have an element type definition so the add method must never be called. */
private final static TypeResult finalizeTypeResult = new TypeResult() {
@@ -66,9 +70,10 @@ public class ActionRule implements Rule {
public int resolveType(int cacheId, Element el, TypeResult result) {
Element element = el;
if (expression != null) {
+ numEval++;
if (!expression.eval(cacheId, element))
return cacheId;
-
+ numTrue++;
// If this is a continue and we are not to propagate the effects
// of the action on the element to further rules, then make
// a copy of the element so that the original is unsullied.
@@ -108,8 +113,10 @@ public class ActionRule implements Rule {
public void resolveType(Element el, TypeResult result) {
Element element = el;
if (expression != null) {
+ numEval++;
if (!expression.eval(element))
return;
+ numTrue++;
// If this is a continue and we are not to propagate the effects
// of the action on the element to further rules, then make
// a copy of the element so that the original is unsullied.
@@ -168,4 +175,9 @@ public class ActionRule implements Rule {
this.expression = expression;
}
+ @Override
+ public void printStats(String header) {
+ if (statsLog.isInfoEnabled())
+ statsLog.info(header,"stats (rule/evals/true)", this.toString() + "/" + numEval + "/" + numTrue);
+ }
}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/ExpressionRule.java b/src/uk/me/parabola/mkgmap/osmstyle/ExpressionRule.java
index 8c934ad..7df93f7 100644
--- a/src/uk/me/parabola/mkgmap/osmstyle/ExpressionRule.java
+++ b/src/uk/me/parabola/mkgmap/osmstyle/ExpressionRule.java
@@ -16,6 +16,7 @@
*/
package uk.me.parabola.mkgmap.osmstyle;
+import uk.me.parabola.log.Logger;
import uk.me.parabola.mkgmap.osmstyle.eval.Op;
import uk.me.parabola.mkgmap.reader.osm.Element;
import uk.me.parabola.mkgmap.reader.osm.GType;
@@ -29,9 +30,13 @@ import uk.me.parabola.mkgmap.reader.osm.TypeResult;
* @author Steve Ratcliffe
*/
public class ExpressionRule implements Rule {
+ private static final Logger statsLog = Logger.getLogger(ExpressionRule.class.getPackage().getName()+".stats");
+
private Op expression;
private final GType gtype;
private Rule finalizeRule;
+ private long numEval; // count how often the expression was evaluated
+ private long numTrue; // count how often the evaluation returned true
/** Finalize rules must not have an element type definition so the add method must never be called. */
private final static TypeResult finalizeTypeResult = new TypeResult() {
@@ -47,7 +52,9 @@ public class ExpressionRule implements Rule {
public void resolveType(Element el, TypeResult result) {
+ numEval++;
if (expression.eval(el)) {
+ numTrue++;
// expression matches
if (finalizeRule != null) {
if (gtype.isContinueSearch()) {
@@ -63,7 +70,9 @@ public class ExpressionRule implements Rule {
}
public int resolveType(int cacheId, Element el, TypeResult result) {
+ numEval++;
if (expression.eval(cacheId, el)){
+ numTrue++;
if (finalizeRule != null) {
if (gtype.isContinueSearch()) {
el = el.copy();
@@ -93,5 +102,10 @@ public class ExpressionRule implements Rule {
public void setOp(Op expression){
this.expression = expression;
}
-
+
+ @Override
+ public void printStats(String header) {
+ if (statsLog.isInfoEnabled())
+ statsLog.info(header,"stats (rule/evals/true)", this.toString() + "/" + numEval + "/" + numTrue);
+ }
}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java b/src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java
index f9459a1..1d69c56 100644
--- a/src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java
+++ b/src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java
@@ -243,7 +243,7 @@ public class RuleFileReader {
* from the expression.
*/
private void saveRule(TokenScanner scanner, Op op, ActionList actions, GType gt) {
- log.info("EXP", op, ", type=", gt);
+ log.debug("EXP", op, ", type=", gt);
// check if the type definition is allowed
if (inFinalizeSection && gt != null)
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/RuleSet.java b/src/uk/me/parabola/mkgmap/osmstyle/RuleSet.java
index b54cb6c..77a1f1f 100644
--- a/src/uk/me/parabola/mkgmap/osmstyle/RuleSet.java
+++ b/src/uk/me/parabola/mkgmap/osmstyle/RuleSet.java
@@ -46,6 +46,7 @@ import uk.me.parabola.mkgmap.reader.osm.WatchableTypeResult;
public class RuleSet implements Rule, Iterable<Rule> {
private static final Logger log = Logger.getLogger(RuleSet.class);
private Rule[] rules;
+ private Rule finalizeRule;
// identifies cached values
int cacheId;
@@ -259,5 +260,18 @@ public class RuleSet implements Rule, Iterable<Rule> {
rule.setFinalizeRule(finalizeRule);
compiled = false;
+ this.finalizeRule = finalizeRule;
}
+
+ @Override
+ public void printStats(String header) {
+ if (rules == null)
+ return;
+ for (Rule rule : rules){
+ rule.printStats(header);
+ }
+ if (finalizeRule != null)
+ finalizeRule.printStats(header);
+ }
+
}
\ No newline at end of file
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java b/src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java
index f88691a..1cc2448 100644
--- a/src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java
+++ b/src/uk/me/parabola/mkgmap/osmstyle/StyleImpl.java
@@ -568,6 +568,14 @@ public class StyleImpl implements Style {
}
return style;
}
+
+ @Override
+ public void reportStats() {
+ relations.printStats("relations");
+ nodes.printStats("points");
+ lines.printStats("lines");
+ polygons.printStats("polygons");
+ }
public static void main(String[] args) throws FileNotFoundException {
String file = args[0];
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java b/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
index f51fa56..bbc6093 100644
--- a/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
+++ b/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
@@ -31,6 +31,7 @@ import java.util.List;
import java.util.Map;
import java.util.logging.Level;
+import uk.me.parabola.imgfmt.ExitException;
import uk.me.parabola.imgfmt.app.Area;
import uk.me.parabola.imgfmt.app.Coord;
import uk.me.parabola.imgfmt.app.CoordNode;
@@ -38,10 +39,10 @@ import uk.me.parabola.imgfmt.app.Exit;
import uk.me.parabola.imgfmt.app.Label;
import uk.me.parabola.imgfmt.app.net.AccessTagsAndBits;
import uk.me.parabola.imgfmt.app.net.GeneralRouteRestriction;
-import uk.me.parabola.imgfmt.app.net.NODHeader;
import uk.me.parabola.imgfmt.app.trergn.ExtTypeAttributes;
import uk.me.parabola.imgfmt.app.trergn.MapObject;
import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.build.LocatorConfig;
import uk.me.parabola.mkgmap.build.LocatorUtil;
import uk.me.parabola.mkgmap.filters.LineSizeSplitterFilter;
import uk.me.parabola.mkgmap.general.AreaClipper;
@@ -124,9 +125,15 @@ public class StyledConverter implements OsmConverter {
private final Rule nodeRules;
private final Rule lineRules;
private final Rule polygonRules;
-
- private boolean driveOnLeft;
- private boolean driveOnRight;
+ private Style style;
+
+ private String driveOn;
+ private Boolean driveOnLeft;
+ private int numDriveOnLeftRoads;
+ private int numDriveOnRightRoads;
+ private int numDriveOnSideUnknown;
+ private int numRoads;
+
private final boolean checkRoundabouts;
private int reportDeadEnds;
private final boolean linkPOIsToWays;
@@ -153,22 +160,44 @@ public class StyledConverter implements OsmConverter {
nameTagList.add(TagDict.getInstance().xlate(n));
} else
nameTagList = null;
-
+ this.style = style;
wayRules = style.getWayRules();
nodeRules = style.getNodeRules();
lineRules = style.getLineRules();
polygonRules = style.getPolygonRules();
housenumberGenerator = new HousenumberGenerator(props);
-
- driveOnLeft = props.getProperty("drive-on-left") != null;
- // check if the setDriveOnLeft flag should be ignored
- // (this is the case if precompiled sea is loaded)
- if (props.getProperty("ignore-drive-on-left") == null)
- // do not ignore the flag => initialize it
- NODHeader.setDriveOnLeft(driveOnLeft);
- driveOnRight = props.getProperty("drive-on-right") != null;
- checkRoundabouts = props.getProperty("check-roundabouts") != null;
+
+ driveOn = props.getProperty("drive-on", null);
+ if (driveOn == null){
+ // support legacy options --drive-on-left and --drive-on-right
+ boolean dol = props.getProperty("drive-on-left", false);
+ boolean dor = props.getProperty("drive-on-right", false);
+ if (dol && dor)
+ throw new ExitException("options drive-on-left and drive-on-right and mutually exclusive");
+ if (dol)
+ driveOn = "left";
+ if (dor)
+ driveOn = "right";
+ }
+ if (driveOn == null)
+ driveOn = "detect,right";
+ switch (driveOn) {
+ case "left":
+ driveOnLeft = true;
+ break;
+ case "right":
+ driveOnLeft = false;
+ break;
+ case "detect":
+ case "detect,left":
+ case "detect,right":
+ break;
+ default:
+ throw new ExitException("invalid parameters for option drive-on:"+driveOn);
+ }
+
+ checkRoundabouts = props.getProperty("check-roundabouts",false);
reportDeadEnds = props.getProperty("report-dead-ends", 1);
LineAdder overlayAdder = style.getOverlays(lineAdder);
@@ -332,8 +361,19 @@ public class StyledConverter implements OsmConverter {
cw.setReversed(wasReversed);
if (cw.isRoad()){
roads.add(cw);
- if (wasReversed && cw.isRoundabout())
- log.warn("Roundabout", way.getId(), "has reverse oneway tag (" + way.getPoints().get(0).toOSMURL() + ")");
+ numRoads++;
+ String country = way.getTag(countryTagKey);
+ if (country != null) {
+ if (LocatorConfig.get().getDriveOnLeftFlag(country))
+ numDriveOnLeftRoads++;
+ else
+ numDriveOnRightRoads++;
+ } else
+ numDriveOnSideUnknown++;
+ if (cw.isRoundabout()) {
+ if (wasReversed)
+ log.warn("Roundabout", way.getId(), "has reverse oneway tag (" + way.getPoints().get(0).toOSMURL() + ")");
+ }
lastRoadId = way.getId();
}
else
@@ -504,6 +544,9 @@ public class StyledConverter implements OsmConverter {
}
public void end() {
+ style.reportStats();
+ driveOnLeft = calcDrivingSide();
+
setHighwayCounts();
findUnconnectedRoads();
rotateClosedWaysToFirstNode();
@@ -533,7 +576,8 @@ public class StyledConverter implements OsmConverter {
}
for (Long wayId: deletedRoads){
if (wayRelMap.containsKey(wayId)){
- log.error("internal error: was that is used in valid restriction relation was removed, id:",wayId);
+ // may happen e.g. when very short way is leading to nowhere
+ log.warn("Way that is used in valid restriction relation was removed, id:",wayId);
}
}
deletedRoads = null;
@@ -558,7 +602,6 @@ public class StyledConverter implements OsmConverter {
if (cw.isValid())
addRoad(cw);
}
-
housenumberGenerator.generate(lineAdder);
createRouteRestrictionsFromPOI();
@@ -569,6 +612,12 @@ public class StyledConverter implements OsmConverter {
}
roads = null;
+ // at this point the check-roundabout option might have changed the driveOn value
+// if ("left".equals(driveOn) && !ignoreDriveOn){
+// NODHeader.setDriveOnLeft(true);
+// TREHeader.setDriveOnLeft(true);
+// }
+
for(Relation relation : throughRouteRelations) {
Node node = null;
Way w1 = null;
@@ -615,6 +664,49 @@ public class StyledConverter implements OsmConverter {
nodeIdMap = null;
throughRouteRelations.clear();
restrictions.clear();
+
+ }
+
+ /**
+ * Check the counters and verify the driveOn value to calculate
+ * the drive on left flag.
+ */
+ private Boolean calcDrivingSide() {
+ Boolean dol = null;
+ log.info("Found", numRoads, "roads",
+ numDriveOnLeftRoads, "in drive-on-left country,",
+ numDriveOnRightRoads, "in drive-on-right country, and",
+ numDriveOnSideUnknown, " with unknwon country");
+ if (numDriveOnLeftRoads> 0 && numDriveOnRightRoads > 0)
+ log.error("Attention: Tile contains both drive-on-left (" + numDriveOnLeftRoads +
+ ") and drive-on-right roads (" + numDriveOnRightRoads + ")");
+ if (driveOn.startsWith("detect")) {
+ if (numDriveOnSideUnknown > numRoads * 0.05){
+ // warn if more than 5% of the roads are in unknown area
+ log.warn("Found", numDriveOnSideUnknown, "roads with unknown country and driving side");
+ }
+ if (numDriveOnLeftRoads > numDriveOnRightRoads + numDriveOnSideUnknown) {
+ dol = true;
+ } else if (numDriveOnRightRoads > numDriveOnLeftRoads + numDriveOnSideUnknown) {
+ dol = false;
+ } else {
+ if (driveOn.endsWith("left"))
+ dol = true;
+ else
+ dol = false;
+ }
+ log.info("detected value for driving on left flag is:",dol);
+ } else {
+ driveOnLeft = ("left".equals(driveOn));
+ // warn if user given flag is obviously wrong
+ if ("left".equals(driveOn) && numDriveOnLeftRoads == 0 && numDriveOnRightRoads > 0)
+ log.warn("The drive-on-left flag is set but tile contains only drive-on-right roads");
+ if ("right".equals(driveOn) && numDriveOnRightRoads == 0 && numDriveOnLeftRoads > 0)
+ log.warn("The drive-on-left flag is NOT set used but tile contains only drive-on-left roads");
+ }
+ if (dol == null)
+ dol = false; // should not happen
+ return dol;
}
/**
@@ -704,32 +796,14 @@ public class StyledConverter implements OsmConverter {
boolean clockwise = dir > 0;
if (points.get(0) == points.get(points.size() - 1)) {
// roundabout is a loop
- if (!driveOnLeft && !driveOnRight) {
- if (clockwise) {
- log.info("Roundabout "
- + way.getId()
- + " is clockwise so assuming vehicles should drive on left side of road ("
- + centre.toOSMURL() + ")");
- driveOnLeft = true;
- NODHeader.setDriveOnLeft(true);
- } else {
- log.info("Roundabout "
- + way.getId()
- + " is anti-clockwise so assuming vehicles should drive on right side of road ("
- + centre.toOSMURL() + ")");
- driveOnRight = true;
- }
- }
- if (driveOnLeft && !clockwise || driveOnRight
- && clockwise) {
+ if (driveOnLeft == true && !clockwise || driveOnLeft == false && clockwise) {
log.warn("Roundabout "
+ way.getId()
+ " direction is wrong - reversing it (see "
+ centre.toOSMURL() + ")");
way.reverse();
}
- } else if (driveOnLeft && !clockwise || driveOnRight
- && clockwise) {
+ } else if (driveOnLeft == true && !clockwise || driveOnLeft == false && clockwise) {
// roundabout is a line
log.warn("Roundabout segment " + way.getId()
+ " direction looks wrong (see "
@@ -926,7 +1000,7 @@ public class StyledConverter implements OsmConverter {
}
else {
mp = new MapPoint();
- log.warn("Motorway exit", node.getName(), "(" + node.getLocation().toOSMURL() + ") has no motorway! (either make the exit share a node with the motorway or specify the motorway ref with a", Exit.TAG_ROAD_REF, "tag)");
+ log.warn("Motorway exit", node.getName(), "(" + node.toBrowseURL() + ") has no motorway! (either make the exit share a node with the motorway or specify the motorway ref with a", Exit.TAG_ROAD_REF, "tag)");
}
}
else {
@@ -1685,8 +1759,8 @@ public class StyledConverter implements OsmConverter {
}
}
}
-
}
+
/**
* Increment the highway counter for each coord of each road.
@@ -1932,5 +2006,9 @@ public class StyledConverter implements OsmConverter {
}
}
+ public Boolean getDriveOnLeft(){
+ assert roads == null : "getDriveOnLeft() should be called after end()";
+ return driveOnLeft;
+ }
}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/TypeReader.java b/src/uk/me/parabola/mkgmap/osmstyle/TypeReader.java
index 544b151..03afc2f 100644
--- a/src/uk/me/parabola/mkgmap/osmstyle/TypeReader.java
+++ b/src/uk/me/parabola/mkgmap/osmstyle/TypeReader.java
@@ -124,7 +124,7 @@ public class TypeReader {
}
if (kind == FeatureKind.POLYLINE && gt.getMinLevel() == 0 && gt.getMaxLevel() >= 0){
if (GType.isSpecialRoutableLineType(usedType)){
- if (gt.isRoad() == false){
+ if (gt.hasRoadAttribute() == false){
String msg = "Warning: routable type " + type + " is used for non-routable line with level 0. This may break routing. Style file "+ ts.getFileName() + ", line " + ts.getLinenumber();
if (fromOverlays)
msg += typeOverlaidMsg;
@@ -142,7 +142,7 @@ public class TypeReader {
foundRoutableType = true;
}
}
- if (gt.isRoad() && foundRoutableType == false && gt.getMinLevel() == 0 && gt.getMaxLevel() >= 0){
+ if (gt.hasRoadAttribute() && foundRoutableType == false && gt.getMinLevel() == 0 && gt.getMaxLevel() >= 0){
String msg = "Warning: non-routable type " + type + " is used in combination with road_class/road_speed. Line will not be routable. Style file "+ ts.getFileName() + ", line " + ts.getLinenumber();
if (fromOverlays)
msg += ". Type is overlaid, but not with a routable type";
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/WrongAngleFixer.java b/src/uk/me/parabola/mkgmap/osmstyle/WrongAngleFixer.java
index a4ce874..7e22452 100644
--- a/src/uk/me/parabola/mkgmap/osmstyle/WrongAngleFixer.java
+++ b/src/uk/me/parabola/mkgmap/osmstyle/WrongAngleFixer.java
@@ -1396,7 +1396,7 @@ public class WrongAngleFixer {
}
modifiedPoints.add(cm);
}
- if (modifiedPoints.get(0) != modifiedPoints.get(modifiedPoints.size()-1))
+ if (modifiedPoints.size() > 1 && modifiedPoints.get(0) != modifiedPoints.get(modifiedPoints.size()-1))
modifiedPoints.add(modifiedPoints.get(0));
return modifiedPoints;
}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/AddLabelAction.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/AddLabelAction.java
index 0a9b357..d7adc34 100644
--- a/src/uk/me/parabola/mkgmap/osmstyle/actions/AddLabelAction.java
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/AddLabelAction.java
@@ -65,7 +65,7 @@ public class AddLabelAction extends ValueBuildedAction {
sb.append(vb);
sb.append(" | ");
}
- sb.setLength(sb.length() - 1);
+ sb.setLength(sb.length() - 3);
return sb.toString();
}
}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/ConvertFilter.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/ConvertFilter.java
index 64ce549..b972859 100644
--- a/src/uk/me/parabola/mkgmap/osmstyle/actions/ConvertFilter.java
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/ConvertFilter.java
@@ -16,33 +16,55 @@
*/
package uk.me.parabola.mkgmap.osmstyle.actions;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
import uk.me.parabola.mkgmap.osmstyle.eval.UnitConversions;
import uk.me.parabola.mkgmap.reader.osm.Element;
/**
* Convert a numeric quantity from one set of units to another.
*
- * TODO: this will change a lot it is just here for backward compatibility
- * at present.
* @author Steve Ratcliffe
*/
public class ConvertFilter extends ValueFilter {
- private final double factor;
+ private static final Pattern UNIT_RE = Pattern.compile("\\s*([\\d.]+)\\s*([\\w/]*)\\s*");
+
+ private final UnitConversions units;
public ConvertFilter(String arg) {
- factor = UnitConversions.convertFactor(arg);
+ units = UnitConversions.createConversion(arg);
}
protected String doFilter(String value, Element el) {
- if (value == null) return null;
-
- try {
- double d = Double.parseDouble(value);
+ if (value == null || !units.isValid())
+ return value;
- double res = d * factor;
- res = Math.round(res);
- return String.valueOf((int) res);
+ String number = value;
+ Double factor = units.getDefaultFactor();
+
+ // If this is not a pure number, then extract the number part and the unit part
+ // and convert based on the found values. There are also various possible error
+ // cases.
+ if (!Character.isDigit(value.charAt(value.length() - 1))) {
+ // Extract number and unit string
+ Matcher matcher = UNIT_RE.matcher(value);
+ if (matcher.matches()) {
+ number = matcher.group(1);
+ String source = matcher.group(2);
+ factor = units.convertFactor(source);
+ if (factor == null)
+ return value;
+ } else {
+ return value;
+ }
+ }
+
+ try {
+ double d = Double.parseDouble(number);
+ return String.valueOf(Math.round(d * factor));
} catch (NumberFormatException e) {
+ // Turns out it wasn't a pure number, just return the value unchanged.
return value;
}
}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/CountryISOFilter.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/CountryISOFilter.java
new file mode 100644
index 0000000..7ba94f1
--- /dev/null
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/CountryISOFilter.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 or
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import uk.me.parabola.mkgmap.build.LocatorConfig;
+import uk.me.parabola.mkgmap.reader.osm.Element;
+
+/**
+ * Convert a string containing a country name or ISO string to the 3 character ISO string.
+ * Samples: Deutschland->DEU, UK->GBR
+ *
+ * @author GerdP
+ */
+public class CountryISOFilter extends ValueFilter {
+
+ public CountryISOFilter() {
+ }
+
+ protected String doFilter(String value, Element el) {
+ if (value == null)
+ return value;
+ String s = LocatorConfig.get().getCountryISOCode(value);
+ if (s != null)
+ return s;
+ else
+ return value;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/HeightFilter.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/HeightFilter.java
index 33b2180..597d3a6 100644
--- a/src/uk/me/parabola/mkgmap/osmstyle/actions/HeightFilter.java
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/HeightFilter.java
@@ -16,7 +16,7 @@ package uk.me.parabola.mkgmap.osmstyle.actions;
import uk.me.parabola.mkgmap.reader.osm.Element;
/**
- * A <code>HeightFilter</code> transforms values into Garmin-tagged elevations.
+ * A {@code HeightFilter} transforms values into Garmin-tagged elevations.
*
* @author Toby Speight
*
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/NameAction.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/NameAction.java
index f72c879..1707cb8 100644
--- a/src/uk/me/parabola/mkgmap/osmstyle/actions/NameAction.java
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/NameAction.java
@@ -59,7 +59,7 @@ public class NameAction extends ValueBuildedAction {
sb.append(vb);
sb.append(" | ");
}
- sb.setLength(sb.length() - 1);
+ sb.setLength(sb.length() - 3);
return sb.toString();
}
}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/SubstringFilter.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/SubstringFilter.java
index 3710a81..fd88bbc 100644
--- a/src/uk/me/parabola/mkgmap/osmstyle/actions/SubstringFilter.java
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/SubstringFilter.java
@@ -50,7 +50,7 @@ public class SubstringFilter extends ValueFilter {
args = 0;
}
} catch (NumberFormatException e) {
- throw new ExitException("Not valid numbers in style substring command: " + arg);
+ throw new ExitException(String.format("Numbers not valid in style substring command: '%s'", arg));
}
}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/actions/ValueBuilder.java b/src/uk/me/parabola/mkgmap/osmstyle/actions/ValueBuilder.java
index c0aad6d..b942153 100644
--- a/src/uk/me/parabola/mkgmap/osmstyle/actions/ValueBuilder.java
+++ b/src/uk/me/parabola/mkgmap/osmstyle/actions/ValueBuilder.java
@@ -24,6 +24,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
/**
* Build a value that can have tag values substituted in it.
@@ -37,7 +38,7 @@ public class ValueBuilder {
Pattern.compile("[ \t]*([^: \\t|]+:'[^']+')[ \t]*"),
// This must be last
- Pattern.compile("([ \t]*[^: \\t|]+:[^|]*)"),
+ Pattern.compile("[ \t]*([^: \\t|]+:[^|]*)"),
};
private final List<ValueItem> items = new ArrayList<>();
@@ -224,6 +225,11 @@ public class ValueBuilder {
case "part":
item.addFilter(new PartFilter(arg));
break;
+ case "country-ISO":
+ item.addFilter(new CountryISOFilter());
+ break;
+ default:
+ throw new SyntaxException(String.format("Unknown filter '%s'", cmd));
}
}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/eval/UnitConversions.java b/src/uk/me/parabola/mkgmap/osmstyle/eval/UnitConversions.java
index 51737d4..a1836af 100644
--- a/src/uk/me/parabola/mkgmap/osmstyle/eval/UnitConversions.java
+++ b/src/uk/me/parabola/mkgmap/osmstyle/eval/UnitConversions.java
@@ -18,38 +18,166 @@ package uk.me.parabola.mkgmap.osmstyle.eval;
import java.util.HashMap;
import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import uk.me.parabola.mkgmap.scan.SyntaxException;
/**
* Converting quantities from one unit to another.
*
- * TODO: this will probably change a lot.
- *
* @author Steve Ratcliffe
*/
public class UnitConversions {
- private static final Map<String, Double> conversions = new HashMap<String, Double>();
+ private static final Pattern CODE_RE = Pattern.compile("(.*)=>(.*)");
+
+ private static final Map<UnitType, Map<String, Double>> CONVERSIONS = new HashMap<>();
+
+ private static final Map<String, Double> LENGTH_FACTORS = new HashMap<>();
+ private static final Map<String, Double> SPEED_FACTORS = new HashMap<>();
- // Initially we are just supporting the existing case for contour
- // lines where we convert to feet.
static {
- Map<String, Double> m = conversions;
- m.put("m=>ft", 3.2808399);
+ Map<String, Double> m = LENGTH_FACTORS;
+ m.put("m", 1.0);
+ m.put("km", 1000.0);
+ m.put("ft", 0.3048);
+ m.put("mi", 1_609.344);
+ CONVERSIONS.put(UnitType.LENGTH, LENGTH_FACTORS);
+
+ m = SPEED_FACTORS;
+ m.put("kmh", 1.0);
+ m.put("km/h", 1.0);
+ m.put("kmph", 1.0);
+ m.put("mph", 1.60934);
+ m.put("knots", 1.852);
+ CONVERSIONS.put(UnitType.SPEED, SPEED_FACTORS);
+ }
+
+ /** The type of unit, speed, length etc. */
+ private final UnitType unitType;
+ /** The target unit */
+ private final String target;
+ /** The factor to convert from the default source unit to the target */
+ private final double defaultFactor;
+
+ /**
+ * Create a converter between the units given in the {@code code} argument.
+ *
+ * This will be something like m=>ft to convert from meters to feet. If the input is a plain
+ * value such as 10, then the input is in meters and it is converted to feet. If the
+ * input already has a unit, eg 10ft, then the conversion will be from that unit to
+ * the target unit. So in this case, since the input is already in feet, then result is 10.
+ *
+ * @param code A specifier from=>to.
+ */
+ public static UnitConversions createConversion(String code) {
+ Matcher matcher = CODE_RE.matcher(code);
+ if (!matcher.matches())
+ throw new SyntaxException(String.format("Unrecognised unit conversion: '%s'", code));
+
+ String source = matcher.group(1);
+ String target = matcher.group(2);
+
+ return new UnitConversions(source, target);
+ }
+
+ private UnitConversions(String source, String target) {
+ this.target = target;
+
+ UnitType type = getType(source);
+ if (type != null && type == getType(target)) {
+ unitType = type;
+ defaultFactor = getConversion(source);
+ } else {
+ unitType = null;
+ defaultFactor = 1;
+ }
+ }
+
+ /**
+ * The conversion factor; multiply by this value to convert to the target unit.
+ * @param source If this is not null, then use this as the source unit.
+ * @return The factor to multiply the value by to convert from the source to target units.
+ */
+ public Double convertFactor(String source) {
+ // The value has no unit, so use the default one. We already know the conversion factor for the
+ // default source unit, so just return it.
+ if (source == null)
+ return defaultFactor;
+
+ if (unitType == null)
+ return null;
+
+ return getConversion(source);
+ }
+
+ public double convertFrom(String source) {
+ assert source != null && unitType != null;
+
+ if (CONVERSIONS.get(unitType).containsKey(source))
+ return getConversion(source);
+ else
+ return 0;
+ }
+
+ public boolean isValid() {
+ return unitType != null;
}
- //
- //private double factor;
- //
- //public double convert(double in) {
- // return in * factor;
- //}
/**
- * Get the conversion factor for the given conversion.
- * @param code A string such as 'm=>ft' which would mean meters
- * to feet.
- * @return The factor required to convert the first to the second.
+ * Find the unit type that corresponds to the unit abbreviation.
+ *
+ * For example for km, this would be LENGTH.
+ * @param source A unit specifier.
+ * @return The type of unit.
*/
- public static double convertFactor(String code) {
- Double f = conversions.get(code);
- return (f == null)?1 :f;
+ private static UnitType getType(String source) {
+ for (UnitType t : UnitType.values()) {
+ Map<String, Double> map = CONVERSIONS.get(t);
+ for (String unit : map.keySet()) {
+ if (unit.equals(source))
+ return t;
+ }
+ }
+ return null;
+ }
+
+ private double getFactor(String unit) {
+ assert isValid();
+
+ Double d = CONVERSIONS.get(unitType).get(unit);
+ return d == null? 0: d;
+ }
+
+ private Double getConversion(String source) {
+ Double in = getInFactor(unitType, source);
+ if (in == null)
+ return null;
+ double out = getOutFactor(unitType, target);
+
+ return in * out;
+ }
+
+ private static Double getInFactor(UnitType type, String source) {
+ if (source.isEmpty())
+ return 1.0;
+
+ Map<String, Double> map = CONVERSIONS.get(type);
+ assert map != null;
+
+ return map.get(source);
+ }
+
+ private static double getOutFactor(UnitType type, String target) {
+ return 1.0 / getInFactor(type, target);
+ }
+
+ public double getDefaultFactor() {
+ return defaultFactor;
+ }
+
+ public static enum UnitType {
+ LENGTH,
+ SPEED,
}
}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/housenumber/HousenumberGenerator.java b/src/uk/me/parabola/mkgmap/osmstyle/housenumber/HousenumberGenerator.java
index 5ebb99f..13c7aa2 100644
--- a/src/uk/me/parabola/mkgmap/osmstyle/housenumber/HousenumberGenerator.java
+++ b/src/uk/me/parabola/mkgmap/osmstyle/housenumber/HousenumberGenerator.java
@@ -17,9 +17,9 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
+import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
-
import uk.me.parabola.imgfmt.app.Coord;
import uk.me.parabola.imgfmt.app.CoordNode;
import uk.me.parabola.imgfmt.app.net.NumberStyle;
@@ -28,6 +28,7 @@ import uk.me.parabola.log.Logger;
import uk.me.parabola.mkgmap.general.LineAdder;
import uk.me.parabola.mkgmap.general.MapRoad;
import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.FakeIdGenerator;
import uk.me.parabola.mkgmap.reader.osm.Node;
import uk.me.parabola.mkgmap.reader.osm.Relation;
import uk.me.parabola.mkgmap.reader.osm.Way;
@@ -86,6 +87,9 @@ public class HousenumberGenerator {
String streetname = getStreetname(n);
if (streetname != null) {
houseNumbers.add(streetname, n);
+ } else {
+ if (log.isDebugEnabled())
+ log.debug(n.toBrowseURL()," ignored, doesn't contain a street name.");
}
}
}
@@ -102,6 +106,13 @@ public class HousenumberGenerator {
String streetname = getStreetname(w);
if (streetname != null) {
houseNumbers.add(streetname, w);
+ } else {
+ if (log.isDebugEnabled()){
+ if (FakeIdGenerator.isFakeId(w.getId()))
+ log.debug("mp-created way ignored, doesn't contain a street name. Tags:",w.toTagString());
+ else
+ log.debug(w.toBrowseURL()," ignored, doesn't contain a street name.");
+ }
}
}
}
@@ -115,7 +126,6 @@ public class HousenumberGenerator {
public void addRoad(Way osmRoad, MapRoad road) {
roads.add(road);
if (numbersEnabled) {
- // first try to get the streetname from mkgmap:streetname
String name = getStreetname(osmRoad);
if (name != null) {
if (log.isDebugEnabled())
@@ -125,10 +135,125 @@ public class HousenumberGenerator {
}
}
+ /**
+ * Evaluate type=associatedStreet relations.
+ */
public void addRelation(Relation r) {
- // TODO
+ if (numbersEnabled == false)
+ return;
+ String relType = r.getTag("type");
+ // the wiki says that we should also evaluate type=street
+ if ("associatedStreet".equals(relType) || "street".equals(relType)){
+ List<Element> houses= new ArrayList<>();
+ List<Element> streets = new ArrayList<>();
+ for (Map.Entry<String, Element> member : r.getElements()) {
+ if (member.getValue() instanceof Node) {
+ Node node = (Node) member.getValue();
+ houses.add(node);
+ } else if (member.getValue() instanceof Way) {
+ Way w = (Way) member.getValue();
+ String role = member.getKey();
+ switch (role) {
+ case "house":
+ case "addr:houselink":
+ case "address":
+ houses.add(w);
+ break;
+ case "street":
+ streets.add(w);
+ break;
+ case "":
+ if (w.getTag("highway") != null){
+ streets.add(w);
+ continue;
+ }
+ String buildingTag = w.getTag("building");
+ if (buildingTag != null)
+ houses.add(w);
+ else
+ log.warn("Relation",r.toBrowseURL(),": role of member",w.toBrowseURL(),"unclear");
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ if (houses.isEmpty()){
+ if ("associatedStreet".equals(relType))
+ log.warn("Relation",r.toBrowseURL(),": ignored, found no houses");
+ return;
+ }
+ String streetName = r.getTag("name");
+ String streetNameFromRoads = null;
+ boolean nameFromStreetsIsUnclear = false;
+ if (streets.isEmpty() == false) {
+ for (Element street : streets) {
+ String roadName = street.getTag("name");
+ if (roadName == null)
+ continue;
+ if (streetNameFromRoads == null)
+ streetNameFromRoads = roadName;
+ else if (streetNameFromRoads.equals(roadName) == false)
+ nameFromStreetsIsUnclear = true;
+ }
+ }
+ if (streetName == null){
+ if (nameFromStreetsIsUnclear == false)
+ streetName = streetNameFromRoads;
+ else {
+ log.warn("Relation",r.toBrowseURL(),": ignored, street name is not clear.");
+ return;
+ }
+
+ } else {
+ if (streetNameFromRoads != null){
+ if (nameFromStreetsIsUnclear == false && streetName.equals(streetNameFromRoads) == false){
+ log.warn("Relation",r.toBrowseURL(),": street name is not clear, using the name from the way, not that of the relation.");
+ streetName = streetNameFromRoads;
+ }
+ else if (nameFromStreetsIsUnclear == true){
+ log.warn("Relation",r.toBrowseURL(),": street name is not clear, using the name from the relation.");
+ }
+ }
+ }
+ int countOK = 0;
+ if (streetName != null && streetName.isEmpty() == false){
+ for (Element house : houses) {
+ if (addStreetTagFromRel(r, house, streetName) )
+ countOK++;
+ }
+ }
+ if (countOK > 0)
+ log.info("Relation",r.toBrowseURL(),": added tag mkgmap:street=",streetName,"to",countOK,"of",houses.size(),"house members");
+ else
+ log.info("Relation",r.toBrowseURL(),": ignored, the house members all have a addr:street or mkgmap:street tag");
+ }
}
+ /**
+ * Add the tag mkgmap:street=streetName to the element of the
+ * relation if it does not already have a street name tag.
+ */
+ private boolean addStreetTagFromRel(Relation r, Element house, String streetName){
+ String addrStreet = getStreetname(house);
+ if (addrStreet == null){
+ house.addTag("mkgmap:street", streetName);
+ if (log.isDebugEnabled())
+ log.debug("Relation",r.toBrowseURL(),": adding tag mkgmap:street=" + streetName, "to house",house.toBrowseURL());
+ return true;
+ }
+ else if (addrStreet.equals(streetName) == false){
+ if (house.getTag("mkgmap:street") != null){
+ log.warn("Relation",r.toBrowseURL(),": street name from relation doesn't match existing mkgmap:street tag for house",house.toBrowseURL(),"the house seems to be member of another type=associatedStreet relation");
+ house.deleteTag("mkgmap:street");
+ }
+ else
+ log.warn("Relation",r.toBrowseURL(),": street name from relation doesn't match existing name for house",house.toBrowseURL());
+ }
+ return false;
+ }
+
+
public void generate(LineAdder adder) {
if (numbersEnabled) {
for (Entry<String, List<Element>> numbers : houseNumbers.entrySet()) {
@@ -195,9 +320,20 @@ public class HousenumberGenerator {
private static void match(String streetname, List<Element> elements, List<MapRoad> roads) {
List<HousenumberMatch> numbersList = new ArrayList<HousenumberMatch>(
elements.size());
- for (Element node : elements) {
+ for (Element element : elements) {
try {
- numbersList.add(new HousenumberMatch(node));
+ HousenumberMatch match = new HousenumberMatch(element);
+ if (match.getLocation() == null) {
+ // there has been a report that indicates match.getLocation() == null
+ // could not reproduce so far but catching it here with some additional
+ // information. (WanMil)
+ log.error("OSM element seems to have no point.");
+ log.error("Element: "+element.toBrowseURL()+" " +element);
+ log.error("Please report on the mkgmap mailing list.");
+ log.error("Continue creating the map. This should be possible without a problem.");
+ } else {
+ numbersList.add(match);
+ }
} catch (IllegalArgumentException exp) {
log.debug(exp);
}
diff --git a/src/uk/me/parabola/mkgmap/reader/MapperBasedMapDataSource.java b/src/uk/me/parabola/mkgmap/reader/MapperBasedMapDataSource.java
index 40d9946..2c4b061 100644
--- a/src/uk/me/parabola/mkgmap/reader/MapperBasedMapDataSource.java
+++ b/src/uk/me/parabola/mkgmap/reader/MapperBasedMapDataSource.java
@@ -42,6 +42,7 @@ import uk.me.parabola.util.EnhancedProperties;
public abstract class MapperBasedMapDataSource implements MapDataSource, Configurable {
protected final MapDetails mapper = new MapDetails();
private EnhancedProperties configProps;
+ private boolean driveOnLeft;
/**
* Get the area that this map covers. Delegates to the map collector.
@@ -138,4 +139,16 @@ public abstract class MapperBasedMapDataSource implements MapDataSource, Configu
boundary.setPoints(coords);
mapper.addLine(boundary);
}
+
+ /**
+ * @return true/false if source contains info about driving side, else null
+ */
+ public Boolean getDriveOnLeft(){
+ return driveOnLeft;
+ }
+
+ protected void setDriveOnLeft(boolean b) {
+ driveOnLeft = b;
+ }
+
}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/CoastlineFileLoader.java b/src/uk/me/parabola/mkgmap/reader/osm/CoastlineFileLoader.java
index 6892f4f..6b393f5 100644
--- a/src/uk/me/parabola/mkgmap/reader/osm/CoastlineFileLoader.java
+++ b/src/uk/me/parabola/mkgmap/reader/osm/CoastlineFileLoader.java
@@ -73,8 +73,6 @@ public final class CoastlineFileLoader {
private CoastlineFileLoader() {
this.coastlineFiles = new HashSet<String>();
this.coastConfig = new EnhancedProperties();
- // disable drive-on-left handling
- this.coastConfig.setProperty("ignore-drive-on-left", "true");
}
private static final CoastlineFileLoader loader = new CoastlineFileLoader();
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/Element.java b/src/uk/me/parabola/mkgmap/reader/osm/Element.java
index e6a77d0..d4c610a 100644
--- a/src/uk/me/parabola/mkgmap/reader/osm/Element.java
+++ b/src/uk/me/parabola/mkgmap/reader/osm/Element.java
@@ -251,7 +251,7 @@ public abstract class Element {
}
public String toBrowseURL() {
- return "http://www.openstreetmap.org/browse/" + kind() + "/" + id;
+ return "http://www.openstreetmap.org/" + kind() + "/" + id;
}
public Element copy() {
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/GType.java b/src/uk/me/parabola/mkgmap/reader/osm/GType.java
index 5e10ae4..d851a88 100644
--- a/src/uk/me/parabola/mkgmap/reader/osm/GType.java
+++ b/src/uk/me/parabola/mkgmap/reader/osm/GType.java
@@ -45,7 +45,8 @@ public class GType {
private int roadClass;
private int roadSpeed;
- private boolean road;
+ private boolean hasRoadAttribute;
+ private boolean levelsWereFixed = false;
/** If this is set, then we look for further types after this one is matched */
private boolean continueSearch;
@@ -133,6 +134,7 @@ public class GType {
if (info.getBits() <= maxResolution)
minLevel = info.getLevel();
}
+ levelsWereFixed = true;
}
public String toString() {
@@ -151,7 +153,7 @@ public class GType {
else
fmt.format(" level %d-%d", minLevel, maxLevel);
}
- if (road)
+ if (hasRoadAttribute)
fmt.format(" road_class=%d road_speed=%d", roadClass, roadSpeed);
if (continueSearch)
@@ -179,7 +181,7 @@ public class GType {
public void setRoadClass(int roadClass) {
// road class might also be set for nodes used by the link-pois-to-ways option
if (getFeatureKind() == FeatureKind.POLYLINE)
- road = true;
+ hasRoadAttribute = true;
this.roadClass = roadClass;
}
@@ -190,12 +192,21 @@ public class GType {
public void setRoadSpeed(int roadSpeed) {
// road speed might also be set for nodes used by the link-pois-to-ways option
if (getFeatureKind() == FeatureKind.POLYLINE)
- road = true;
+ hasRoadAttribute = true;
this.roadSpeed = roadSpeed;
}
+ public boolean hasRoadAttribute() {
+ return hasRoadAttribute;
+ }
+
+ /**
+ * @return true if the object has valid attributes to be used as a routable way
+ */
public boolean isRoad() {
- return road;
+ if (!levelsWereFixed)
+ log.error("internal: isRoad() called before fixLevels()");
+ return hasRoadAttribute && minLevel == 0;
}
public boolean isContinueSearch() {
@@ -217,7 +228,7 @@ public class GType {
/**
*
* @param type the type value
- * @return true if the type is can be used for routable lines
+ * @return true if the type can be used for routable lines
*/
public static boolean isRoutableLineType(int type){
return type >= 0x01 && type <= 0x3f;
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java b/src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java
index 44ced84..03365f6 100644
--- a/src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java
+++ b/src/uk/me/parabola/mkgmap/reader/osm/MultiPolygonRelation.java
@@ -725,6 +725,17 @@ public class MultiPolygonRelation extends Relation {
}
polygonStatusList.add(new PolygonStatus("outer".equals(role), polyIndex, polygon));
}
+ // sort by role and then by number of points, this improves performance
+ // in the routines which add the polygons to areas
+ if (polygonStatusList.size() > 2){
+ Collections.sort(polygonStatusList, new Comparator<PolygonStatus>() {
+ public int compare(PolygonStatus o1, PolygonStatus o2) {
+ if (o1.outer != o2.outer)
+ return (o1.outer) ? -1 : 1;
+ return o1.polygon.getPoints().size() - o2.polygon.getPoints().size();
+ }
+ });
+ }
return polygonStatusList;
}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/OsmConverter.java b/src/uk/me/parabola/mkgmap/reader/osm/OsmConverter.java
index 3354bbf..3d32ba6 100644
--- a/src/uk/me/parabola/mkgmap/reader/osm/OsmConverter.java
+++ b/src/uk/me/parabola/mkgmap/reader/osm/OsmConverter.java
@@ -72,4 +72,9 @@ public interface OsmConverter {
* Called when all conversion has been done.
*/
public void end();
+
+ /**
+ * @return true/false if source contains info about driving side, else null
+ */
+ public Boolean getDriveOnLeft();
}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java b/src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java
index c09a21f..ad83575 100644
--- a/src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java
+++ b/src/uk/me/parabola/mkgmap/reader/osm/OsmMapDataSource.java
@@ -150,13 +150,13 @@ public abstract class OsmMapDataSource extends MapperBasedMapDataSource
*/
protected void setupHandler(OsmHandler handler) {
createElementSaver();
+ createConverter();
+
osmReadingHooks = pluginChain(elementSaver, getConfig());
handler.setElementSaver(elementSaver);
handler.setHooks(osmReadingHooks);
- createConverter();
-
handler.setUsedTags(getUsedTags());
String deleteTagsFileName = getConfig().getProperty("delete-tags-file");
@@ -180,10 +180,12 @@ public abstract class OsmMapDataSource extends MapperBasedMapDataSource
protected OsmReadingHooks pluginChain(ElementSaver saver, EnhancedProperties props) {
List<OsmReadingHooks> plugins = new ArrayList<OsmReadingHooks>();
-
for (OsmReadingHooks p : getPossibleHooks()) {
- if (p.init(saver, props))
+ if (p.init(saver, props)){
plugins.add(p);
+ if (p instanceof RelationStyleHook)
+ ((RelationStyleHook) p).setStyle(style);
+ }
}
OsmReadingHooks hooks;
@@ -266,4 +268,9 @@ public abstract class OsmMapDataSource extends MapperBasedMapDataSource
public Set<String> getUsedTags() {
return usedTags;
}
+
+ @Override
+ public Boolean getDriveOnLeft(){
+ return converter.getDriveOnLeft();
+ }
}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/RelationStyleHook.java b/src/uk/me/parabola/mkgmap/reader/osm/RelationStyleHook.java
index 76138ae..7932dac 100644
--- a/src/uk/me/parabola/mkgmap/reader/osm/RelationStyleHook.java
+++ b/src/uk/me/parabola/mkgmap/reader/osm/RelationStyleHook.java
@@ -35,10 +35,13 @@ public class RelationStyleHook extends OsmReadingHooksAdaptor {
public boolean init(ElementSaver saver, EnhancedProperties props) {
this.saver = saver;
nameTagList = LocatorUtil.getNameTags(props);
- style = StyleImpl.readStyle(props);
return super.init(saver, props);
}
+ public void setStyle(Style style){
+ this.style = style;
+ }
+
public void end() {
Rule relationRules = style.getRelationRules();
for (Relation rel : saver.getRelations().values()) {
@@ -57,8 +60,6 @@ public class RelationStyleHook extends OsmReadingHooksAdaptor {
}
}
super.end();
-
- style = null;
}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/Rule.java b/src/uk/me/parabola/mkgmap/reader/osm/Rule.java
index 1488946..0a0dd62 100644
--- a/src/uk/me/parabola/mkgmap/reader/osm/Rule.java
+++ b/src/uk/me/parabola/mkgmap/reader/osm/Rule.java
@@ -53,5 +53,6 @@ public interface Rule {
*/
public void setFinalizeRule(Rule finalizeRule);
+ public void printStats(String header);
}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/SeaGenerator.java b/src/uk/me/parabola/mkgmap/reader/osm/SeaGenerator.java
index a8bd725..c27e221 100644
--- a/src/uk/me/parabola/mkgmap/reader/osm/SeaGenerator.java
+++ b/src/uk/me/parabola/mkgmap/reader/osm/SeaGenerator.java
@@ -511,9 +511,6 @@ public class SeaGenerator extends OsmReadingHooksAdaptor {
private Collection<Way> loadPrecompTile(InputStream is, String filename) {
OsmMapDataSource src = createTileReader(filename);
EnhancedProperties props = new EnhancedProperties();
- // set a flag that the StyledConverter which is created by the
- // OsmMapDataSource does not set the drive-on-left flag
- props.setProperty("ignore-drive-on-left", "true");
src.config(props);
log.info("Started loading coastlines from", filename);
try{
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/Style.java b/src/uk/me/parabola/mkgmap/reader/osm/Style.java
index a974e80..f5956d2 100644
--- a/src/uk/me/parabola/mkgmap/reader/osm/Style.java
+++ b/src/uk/me/parabola/mkgmap/reader/osm/Style.java
@@ -74,4 +74,9 @@ public interface Style {
* Get the tags that are used by this style.
*/
public Set<String> getUsedTags();
+
+ /**
+ * Report statistics for rule expressions.
+ */
+ public void reportStats();
}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/TagDict.java b/src/uk/me/parabola/mkgmap/reader/osm/TagDict.java
index 3a358a6..989b7a1 100644
--- a/src/uk/me/parabola/mkgmap/reader/osm/TagDict.java
+++ b/src/uk/me/parabola/mkgmap/reader/osm/TagDict.java
@@ -23,9 +23,9 @@ import uk.me.parabola.imgfmt.MapFailedException;
*
*/
public class TagDict{
- private static TagDict instance = null;
- private HashMap<String,Short> map;
- private ArrayList<String> list;
+ private final static TagDict INSTANCE = new TagDict();
+ private final HashMap<String,Short> map = new HashMap<>();
+ private final ArrayList<String> list = new ArrayList<>();
public static final short INVALID_TAG_VALUE = 0;
@@ -33,8 +33,6 @@ public class TagDict{
* create an empty dictionary
*/
private TagDict() {
- map = new HashMap<>();
- list = new ArrayList<>();
map.put("invalid tag", INVALID_TAG_VALUE);
list.add("invalid tag");
}
@@ -43,11 +41,8 @@ public class TagDict{
* give access to the singleton instance
* @return
*/
- public static synchronized TagDict getInstance() {
- if (instance == null) {
- instance = new TagDict();
- }
- return instance;
+ public static TagDict getInstance() {
+ return INSTANCE;
}
/**
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryConverter.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryConverter.java
index 0aad1d0..272ff0e 100644
--- a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryConverter.java
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryConverter.java
@@ -57,4 +57,9 @@ public class BoundaryConverter implements OsmConverter {
public void end() {
}
+ @Override
+ public Boolean getDriveOnLeft(){
+ return null; // unknown
+ }
+
}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryDiff.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryDiff.java
index 0459bf7..7a55fa2 100644
--- a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryDiff.java
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryDiff.java
@@ -56,16 +56,15 @@ public class BoundaryDiff {
* or a single *.bnd file
* @return
*/
- private List<String> getBoundsFiles(String dirName) {
+ private static List<String> getBoundsFiles(String dirName) {
File dir = new File(dirName);
System.out.println(dirName);
if (dir.isFile() && dir.getName().endsWith(".bnd")) {
- List<String> boundaryFiles = new ArrayList<String>();
+ List<String> boundaryFiles = new ArrayList<>();
boundaryFiles.add(dir.getName());
return boundaryFiles;
- } else {
- return BoundaryUtil.getBoundaryDirContent(dirName);
}
+ return BoundaryUtil.getBoundaryDirContent(dirName);
}
/**
@@ -85,8 +84,8 @@ public class BoundaryDiff {
Collections.sort(b1);
Collections.sort(b2);
- Queue<String> bounds1 = new LinkedList<String>(b1);
- Queue<String> bounds2 = new LinkedList<String>(b2);
+ Queue<String> bounds1 = new LinkedList<>(b1);
+ Queue<String> bounds2 = new LinkedList<>(b2);
b1 = null;
b2 = null;
@@ -153,7 +152,7 @@ public class BoundaryDiff {
* @param value the tag value
* @return a new Area (which might be empty)
*/
- private Area loadArea(String dirName, String fileName, String tag, String value) {
+ private static Area loadArea(String dirName, String fileName, String tag, String value) {
String dir = dirName;
String bndFileName = fileName;
if (dir.endsWith(".bnd")){
@@ -190,7 +189,7 @@ public class BoundaryDiff {
* @param tagKey used to build the gpx file name
* @param tagValue used to build the gpx file name
*/
- private void saveArea(Area a, String subDirName, String tagKey, String tagValue) {
+ private static void saveArea(Area a, String subDirName, String tagKey, String tagValue) {
String gpxBasename = "gpx/diff/" + subDirName + "/"
+ tagKey + "=" + tagValue + "/";
@@ -240,17 +239,17 @@ public class BoundaryDiff {
printUsage();
}
- List<Entry<String,String>> tags = new ArrayList<Entry<String,String>>();
+ List<Entry<String,String>> tags = new ArrayList<>();
if (args.length > 2) {
for (int i = 2; i < args.length; i++) {
final String[] parts = args[i].split(Pattern.quote("="));
- tags.add(new AbstractMap.SimpleImmutableEntry<String, String>(
+ tags.add(new AbstractMap.SimpleImmutableEntry<>(
parts[0], parts[1]));
}
} else {
for (int adminlevel = 2; adminlevel <= 11; adminlevel++) {
- tags.add(new AbstractMap.SimpleImmutableEntry<String, String>(
+ tags.add(new AbstractMap.SimpleImmutableEntry<>(
"admin_level", String.valueOf(adminlevel)));
}
}
@@ -258,8 +257,7 @@ public class BoundaryDiff {
int processors = Runtime.getRuntime().availableProcessors();
ExecutorService excSvc = Executors.newFixedThreadPool(processors);
- ExecutorCompletionService<String> executor = new ExecutorCompletionService<String>(
- excSvc);
+ ExecutorCompletionService<String> executor = new ExecutorCompletionService<>(excSvc);
for (final Entry<String, String> tag : tags) {
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryPreprocessor.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryPreprocessor.java
index 66aa84d..2012066 100644
--- a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryPreprocessor.java
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryPreprocessor.java
@@ -43,7 +43,7 @@ public class BoundaryPreprocessor implements Runnable {
// must be last as it is the default
"uk.me.parabola.mkgmap.reader.osm.boundary.Osm5BoundaryDataSource", };
- loaders = new ArrayList<Class<? extends LoadableBoundaryDataSource>>();
+ loaders = new ArrayList<>();
for (String source : sources) {
try {
@@ -93,7 +93,7 @@ public class BoundaryPreprocessor implements Runnable {
private String boundaryFilename;
private String outDir;
private ExecutorService threadPool;
- private final BlockingQueue<Future<Object>> remainingTasks = new LinkedBlockingQueue<Future<Object>>();
+ private final BlockingQueue<Future<Object>> remainingTasks = new LinkedBlockingQueue<>();
/**
* constructor for stand-alone usage (workout only)
@@ -215,14 +215,13 @@ public class BoundaryPreprocessor implements Runnable {
if (threadPool == null) {
// only one thread available for the preparer
// so execute the task directly
- FutureTask<V> future = new FutureTask<V>(worker);
+ FutureTask<V> future = new FutureTask<>(worker);
future.run();
return future;
- } else {
- Future<Object> task = threadPool.submit((Callable<Object>) worker);
- remainingTasks.add(task);
- return (Future<V>) task;
}
+ Future<Object> task = threadPool.submit((Callable<Object>) worker);
+ remainingTasks.add(task);
+ return (Future<V>) task;
}
/**
@@ -275,8 +274,7 @@ public class BoundaryPreprocessor implements Runnable {
long dt = System.currentTimeMillis() - t1;
log.info("splitting", boundsFilename, "took", dt, "ms");
if (bqt != null){
- File outDir = new File(boundsDir);
- BoundarySaver saver = new BoundarySaver(outDir, BoundarySaver.QUADTREE_DATA_FORMAT);
+ BoundarySaver saver = new BoundarySaver(new File(boundsDir), BoundarySaver.QUADTREE_DATA_FORMAT);
saver.setCreateEmptyFiles(false);
saver.saveQuadTree(bqt, boundsFilename);
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryQuadTree.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryQuadTree.java
index 61b0662..5c6cbbb 100644
--- a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryQuadTree.java
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryQuadTree.java
@@ -13,8 +13,10 @@
package uk.me.parabola.mkgmap.reader.osm.boundary;
import java.awt.Rectangle;
+import java.awt.Shape;
import java.awt.geom.Area;
import java.awt.geom.Path2D;
+import java.awt.geom.PathIterator;
import java.awt.geom.Rectangle2D;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
@@ -40,6 +42,7 @@ import uk.me.parabola.mkgmap.reader.osm.Way;
import uk.me.parabola.util.EnhancedProperties;
import uk.me.parabola.util.GpxCreator;
import uk.me.parabola.util.Java2DConverter;
+import uk.me.parabola.util.ShapeSplitter;
/**
* A quadtree implementation to handle areas formed by boundaries.
@@ -54,10 +57,13 @@ public class BoundaryQuadTree {
// debugging aid
private static final String DEBUG_TREEPATH = "?";
private static final boolean DO_ALL_TESTS = false;
-
+
+ private static final boolean DO_CLIP = true;
+ private static final boolean DO_NOT_CLIP = false;
+
// maps the "normal" tags of the boundaries that are saved in this tree to
// the boundaryId
- private final HashMap<String, Tags> boundaryTags = new LinkedHashMap<String,Tags>();
+ private final HashMap<String, Tags> boundaryTags = new LinkedHashMap<>();
// maps the location relevant info to the boundaryId
private final HashMap<String, BoundaryLocationInfo> preparedLocationInfo;
// property controlled preparer
@@ -67,7 +73,7 @@ public class BoundaryQuadTree {
// the bounding box of the quadtree
private final Rectangle bbox;
private final String bbox_key;
-
+
// tags that can be returned in the get method
public final static String[] mkgmapTagsArray = {
"mkgmap:admin_level1",
@@ -97,7 +103,7 @@ public class BoundaryQuadTree {
uk.me.parabola.imgfmt.app.Area fileBbox,
uk.me.parabola.imgfmt.app.Area searchBbox, EnhancedProperties props)
throws IOException {
- preparedLocationInfo = new LinkedHashMap<String, BoundaryLocationInfo> ();
+ preparedLocationInfo = new LinkedHashMap<> ();
preparer = new BoundaryLocationPreparer(props);
assert fileBbox != null: "parameter fileBbox must not be null";
this.bbox = new Rectangle(fileBbox.getMinLong(), fileBbox.getMinLat(),
@@ -133,7 +139,7 @@ public class BoundaryQuadTree {
return;
- HashMap<String,Boundary> bMap = new HashMap<String,Boundary>();
+ HashMap<String,Boundary> bMap = new HashMap<>();
for (Boundary b: boundaries){
bMap.put(b.getId(), b);
boundaryTags.put(b.getId(), b.getTags());
@@ -141,7 +147,7 @@ public class BoundaryQuadTree {
sortBoundaryTagsMap();
// add the boundaries in a specific order
for (String id: boundaryTags.keySet()){
- root.add (bMap.get(id).getArea(), id, null);
+ root.add (bMap.get(id).getArea(), id, null, DO_NOT_CLIP);
}
bMap = null;
root.split("_");
@@ -180,7 +186,7 @@ public class BoundaryQuadTree {
* AdminLevelCollator and then reversed.
*/
public Map<String, Tags> getTagsMap() {
- return new LinkedHashMap<String, Tags>(boundaryTags);
+ return new LinkedHashMap<>(boundaryTags);
}
/**
@@ -192,7 +198,7 @@ public class BoundaryQuadTree {
* @return A HashMap mapping BoundaryIds to a List with all area parts
*/
public Map<String, List<Area>> getAreas(){
- Map<String, List<Area>> areas = new HashMap<String, List<Area>>();
+ Map<String, List<Area>> areas = new HashMap<>();
root.getAreas(areas, "_", null);
return areas;
}
@@ -261,10 +267,10 @@ public class BoundaryQuadTree {
*/
private void sortBoundaryTagsMap(){
// make sure that the merged LinkedHashMap is sorted as mergeBoundaries() needs it
- ArrayList<String> ids = new ArrayList<String>(boundaryTags.keySet());
+ ArrayList<String> ids = new ArrayList<>(boundaryTags.keySet());
Collections.sort(ids, new AdminLevelCollator());
Collections.reverse(ids);
- HashMap<String,Tags> tmp = new LinkedHashMap<String,Tags>(boundaryTags);
+ HashMap<String,Tags> tmp = new LinkedHashMap<>(boundaryTags);
boundaryTags.clear();
for (String id: ids){
boundaryTags.put(id,tmp.get(id));
@@ -282,7 +288,7 @@ public class BoundaryQuadTree {
* @param id the boundaryId
* @throws IOException
*/
- private void writeBoundaryTags(OutputStream stream, Tags tags, String id) throws IOException{
+ private static void writeBoundaryTags(OutputStream stream, Tags tags, String id) throws IOException{
DataOutputStream dOutStream = new DataOutputStream(stream);
dOutStream.writeUTF("TAGS");
dOutStream.writeUTF(id);
@@ -308,12 +314,12 @@ public class BoundaryQuadTree {
/**
* Read a stream in QUADTREE_DATA_FORMAT
* @param inpStream the already opened DataInputStream
- * @param bbox a bounding box. Areas not intersecting the bbox are
+ * @param searchBBox a bounding box. Areas not intersecting the bbox are
* ignored.
* @throws IOException
*/
private void readStreamQuadTreeFormat(DataInputStream inpStream,
- uk.me.parabola.imgfmt.app.Area bbox) throws IOException{
+ uk.me.parabola.imgfmt.app.Area searchBBox) throws IOException{
boolean isFirstArea = true;
try {
while (true) {
@@ -338,13 +344,15 @@ public class BoundaryQuadTree {
int minLong = inpStream.readInt();
int maxLat = inpStream.readInt();
int maxLong = inpStream.readInt();
- log.debug("Next boundary. Lat min:",minLat,"max:",maxLat,"Long min:",minLong,"max:",maxLong);
+ if (log.isDebugEnabled()){
+ log.debug("Next boundary. Lat min:",minLat,"max:",maxLat,"Long min:",minLong,"max:",maxLong);
+ }
uk.me.parabola.imgfmt.app.Area rBbox = new uk.me.parabola.imgfmt.app.Area(
minLat, minLong, maxLat, maxLong);
int bSize = inpStream.readInt();
log.debug("Size:",bSize);
- if ( bbox == null || bbox.intersects(rBbox)) {
+ if ( searchBBox == null || searchBBox.intersects(rBbox)) {
log.debug("Bbox intersects. Load the boundary");
String treePath = inpStream.readUTF();
String id = inpStream.readUTF();
@@ -464,7 +472,7 @@ public class BoundaryQuadTree {
int lat = co.getLatitude();
for (NodeElem nodeElem: nodes){
if (nodeElem.tagMask > 0){
- if (nodeElem.area.contains(lon,lat)){
+ if (nodeElem.getArea().contains(lon,lat)){
String res = new String (nodeElem.boundaryId);
if (nodeElem.locationDataSrc != null)
res += ";" + nodeElem.locationDataSrc;
@@ -499,7 +507,7 @@ public class BoundaryQuadTree {
int lat = co.getLatitude();
for (NodeElem nodeElem: nodes){
if (nodeElem.tagMask > 0){
- if (nodeElem.area.contains(lon,lat)){
+ if (nodeElem.getArea().contains(lon,lat)){
return nodeElem.locTags;
}
}
@@ -549,8 +557,8 @@ public class BoundaryQuadTree {
boolean ok = true;
for (int i=0; i< nodes.size()-1; i++){
for (int j=i+1; j < nodes.size(); j++){
- Area a = new Area (nodes.get(i).area);
- a.intersect(nodes.get(j).area);
+ Area a = new Area (nodes.get(i).getArea());
+ a.intersect(nodes.get(j).getArea());
if (a.isEmpty())
continue;
@@ -592,7 +600,7 @@ public class BoundaryQuadTree {
Node node = this;
String path = treePath;
while(path.isEmpty() == false){
- int idx = Integer.valueOf(path.substring(0, 1));
+ int idx = Integer.parseInt(path.substring(0, 1));
path = path.substring(1);
if (node.childs == null)
node.allocChilds();
@@ -600,7 +608,7 @@ public class BoundaryQuadTree {
}
if (node.nodes == null){
- node.nodes = new ArrayList<NodeElem>();
+ node.nodes = new ArrayList<>();
}
NodeElem nodeElem = new NodeElem(boundaryId, area, refs);
assert (area.getBounds2D().getWidth() == 0 || area.getBounds2D().getHeight() == 0 || this.bbox.intersects(area.getBounds2D())) : "boundary bbox doesn't fit into quadtree "+ bbox + " " + area.getBounds2D();
@@ -608,40 +616,29 @@ public class BoundaryQuadTree {
}
/**
- * Add an area and the related tags to the tree.
- * @param area the part of the boundary area that should be added to the tree.
- * @param locTags the location relevant tags from the boundary
+ * Add a shape and the related tags to the tree.
+ * @param shape the part of the boundary area that should be added to the tree.
* @param boundaryId id of the originating boundary
+ * @param refs A string containing boundaryIds and admin-level info
+ * of all boundaries with lower admin levels that share the same area.
+ * @param clipOption true: clip the shape with the bounding box of the nodeElem,
+ * false: use shape without clipping
*/
- private void add(Area area, String boundaryId, String refs){
- if (!isLeaf){
- // should not happen
- for (int i = 0; i < 4; i++){
- childs[i].add(area, boundaryId, refs);
- }
- return;
- }
- // only add areas that intersect with this part of the tree
- if (area.intersects(this.bbox) == false)
- return;
- Area a;
- if (area.contains(bbox))
- a = new Area(this.bbox); // quadtree bbox lies entirely in area
- else {
- a = new Area(area);
- Area bboxArea = new Area(this.bbox);
- // check if area lies entirely in quadtree bbox
- if (bboxArea.contains(area.getBounds2D()) == false){
- // worst case: area and bbox partly intersect
- a.intersect(bboxArea);
- }
- }
- if (a.isEmpty() == false){
- if (nodes == null)
- nodes = new ArrayList<NodeElem>();
- NodeElem nodeElem = new NodeElem(boundaryId, a, refs);
- nodes.add(nodeElem);
+ private void add(Shape shape, String boundaryId, String refs, boolean clipOption){
+ assert isLeaf;
+ Path2D.Double path;
+ if (clipOption){
+ path = ShapeSplitter.clipShape (shape, bbox);
+ // only add areas that intersect with this part of the tree
+ if (path == null)
+ return;
}
+ else
+ path = new Path2D.Double(shape);
+ if (nodes == null)
+ nodes = new ArrayList<>();
+ NodeElem nodeElem = new NodeElem(boundaryId, path, refs);
+ nodes.add(nodeElem);
}
/**
@@ -658,7 +655,7 @@ public class BoundaryQuadTree {
else{
// (sub) tree is different, rebuild it as combination of
// both trees.
- HashMap<String,List<Area>> areas = new HashMap<String, List<Area>>();
+ HashMap<String,List<Area>> areas = new HashMap<>();
this.getAreas(areas, treePath,null);
other.getAreas(areas, treePath,null);
isLeaf = true;
@@ -673,7 +670,7 @@ public class BoundaryQuadTree {
for (Area area : aList){
path.append(area, false);
}
- add(new Area(path), id, null);
+ add(new Area(path), id, null, DO_NOT_CLIP);
}
split(treePath);
}
@@ -686,16 +683,19 @@ public class BoundaryQuadTree {
* @return a new Area instance (might be empty)
*/
private Area getCoveredArea(Integer admLevel, String treePath){
- HashMap<String,List<Area>> areas = new HashMap<String, List<Area>>();
+ HashMap<String,List<Area>> areas = new HashMap<>();
this.getAreas(areas, treePath, admLevel);
- Path2D.Double path = new Path2D.Double();
- for (Entry <String, List<Area>> entry : areas.entrySet()){
- for (Area area: entry.getValue()){
- path.append(area, false);
+ if (areas.isEmpty() == false){
+ Path2D.Double path = new Path2D.Double(PathIterator.WIND_NON_ZERO, 1024 * 1024);
+ for (Entry <String, List<Area>> entry : areas.entrySet()){
+ for (Area area: entry.getValue()){
+ path.append(area, false);
+ }
}
+ Area combinedArea = new Area(path);
+ return combinedArea;
}
- Area combinedArea = new Area(path);
- return combinedArea;
+ return new Area();
}
/**
@@ -722,9 +722,9 @@ public class BoundaryQuadTree {
if (testMask != null && (nodeElem.tagMask & testMask) == 0)
continue;
List<Area> aList = areas.get(id);
- Area a = new Area(nodeElem.area);
+ Area a = new Area(nodeElem.getArea());
if (aList == null){
- aList = new ArrayList<Area>(4);
+ aList = new ArrayList<>(4);
areas.put(id, aList);
}
aList.add(a);
@@ -742,9 +742,9 @@ public class BoundaryQuadTree {
}
id = relParts[1];
aList = areas.get(id);
- a = new Area(nodeElem.area);
+ a = new Area(nodeElem.getArea());
if (aList == null){
- aList = new ArrayList<Area>(4);
+ aList = new ArrayList<>(4);
areas.put(id, aList);
}
aList.add(a);
@@ -768,13 +768,20 @@ public class BoundaryQuadTree {
printNodes("start", treePath);
}
long t1 = System.currentTimeMillis();
+ if (DEBUG){
+ if (treePath.equals(DEBUG_TREEPATH) || DEBUG_TREEPATH.equals("all")){
+ for (NodeElem nodeElem: nodes){
+ nodeElem.saveGPX("start",treePath);
+ }
+ }
+ }
mergeEqualIds();
mergeLastRectangles();
if (DEBUG)
printNodes("prep", treePath);
- List<NodeElem> reworked = new ArrayList<NodeElem>();
+ List<NodeElem> reworked = new ArrayList<>();
// detect intersection of areas, merge tag info
for (int i=0; i < nodes.size(); i++){
@@ -790,32 +797,32 @@ public class BoundaryQuadTree {
if (toAdd.isValid() == false)
break;
NodeElem currElem = reworked.get(j);
- if (currElem.srcPos == i || currElem.area.isEmpty())
+ if (currElem.srcPos == i || currElem.getArea().isEmpty())
continue;
- Rectangle2D rCurr = currElem.area.getBounds2D();
+ Rectangle2D rCurr = currElem.getArea().getBounds2D();
- Rectangle2D rAdd = rCurr.createIntersection(toAdd.area.getBounds2D());
+ Rectangle2D rAdd = rCurr.createIntersection(toAdd.getArea().getBounds2D());
if (rAdd.isEmpty()){
continue;
}
// the bounding boxes intersect, so we have to find out if the areas also intersect
- Area toAddxCurr = new Area(currElem.area);
- toAddxCurr.intersect(toAdd.area);
+ Area toAddxCurr = new Area(currElem.getArea());
+ toAddxCurr.intersect(toAdd.getArea());
if (!isWritable(toAddxCurr)){
continue; // empty or only too small fragments
}
- Area toAddMinusCurr = new Area(toAdd.area);
- toAddMinusCurr.subtract(currElem.area);
+ Area toAddMinusCurr = new Area(toAdd.getArea());
+ toAddMinusCurr.subtract(currElem.getArea());
if (toAddMinusCurr.isEmpty()){
// toadd is fully covered by curr
if (toAdd.tagMask == POSTCODE_ONLY){
// if we get here, toAdd has only zip code that is already known
// in larger or equal area of currElem
- toAdd.area.reset(); // ignore this
+ toAdd.getArea().reset(); // ignore this
break;
}
}
@@ -833,11 +840,11 @@ public class BoundaryQuadTree {
log.warn(chkMsg);
}
- Area currMinusToAdd = new Area(currElem.area);
- currMinusToAdd.subtract(toAdd.area);
+ Area currMinusToAdd = new Area(currElem.getArea());
+ currMinusToAdd.subtract(toAdd.getArea());
// remove intersection part from toAdd
- toAdd.area = toAddMinusCurr;
+ toAdd.setArea(toAddMinusCurr);
if (!isWritable(currMinusToAdd)){
// curr is fully covered by toAdd
if (toAdd.tagMask != POSTCODE_ONLY){
@@ -854,7 +861,7 @@ public class BoundaryQuadTree {
}
// remove intersection part also from curr
- currElem.area = currMinusToAdd;
+ currElem.setArea(currMinusToAdd);
if (toAdd.tagMask != POSTCODE_ONLY){
// combine tag info in intersection
@@ -871,8 +878,9 @@ public class BoundaryQuadTree {
removeEmptyAreas(treePath);
long dt = System.currentTimeMillis()-t1;
- if (dt > 1000)
- log.info(bbox_key, ": merge required long time:", dt, "ms");
+ if (dt > 1000){
+ log.info(bbox_key, " : makeDistinct required long time:", dt, "ms");
+ }
if (DEBUG)
printNodes("end", treePath);
@@ -891,7 +899,7 @@ public class BoundaryQuadTree {
int start = nodes.size()-1;
for (int i = start; i > 0; i--){
if (nodes.get(i).boundaryId.equals(nodes.get(i-1).boundaryId)){
- nodes.get(i-1).area.add(nodes.get(i).area);
+ nodes.get(i-1).getArea().add(nodes.get(i).getArea());
nodes.remove(i);
}
}
@@ -912,10 +920,10 @@ public class BoundaryQuadTree {
NodeElem lastNode = nodes.get(nodes.size()-1);
NodeElem prevNode = nodes.get(nodes.size()-2);
// don't merge admin_level tags into zip-code only boundary
- if (prevNode.tagMask != POSTCODE_ONLY && lastNode.area.isRectangular() && prevNode.area.isRectangular()){
+ if (prevNode.tagMask != POSTCODE_ONLY && lastNode.getArea().isRectangular() && prevNode.getArea().isRectangular()){
// two areas are rectangles, it is likely that they are equal to the bounding box
// In this case we add the tags to the existing area instead of creating a new one
- if (prevNode.area.equals(lastNode.area)){
+ if (prevNode.getArea().equals(lastNode.getArea())){
prevNode.addLocInfo(lastNode);
nodes.remove(nodes.size()-1);
done = false;
@@ -936,12 +944,12 @@ public class BoundaryQuadTree {
NodeElem chkRemove = nodes.get(j);
if (chkRemove.isValid() == false)
removeThis = true;
- else if (this.bbox.intersects(chkRemove.area.getBounds2D()) == false){
+ else if (this.bbox.intersects(chkRemove.getArea().getBounds2D()) == false){
// we might get here because of errors in java.awt.geom.Area
// sometimes, Area.subtract() seems to produce an area which
// lies outside of original areas
removeThis = true;
- }else if (!isWritable(chkRemove.area)){
+ }else if (!isWritable(chkRemove.getArea())){
removeThis = true;
}
if (removeThis){
@@ -949,7 +957,7 @@ public class BoundaryQuadTree {
}
}
}
-
+
/**
* allocate 4 childs with bounding boxes that have 1/4 of the
* size of the parent.
@@ -991,11 +999,13 @@ public class BoundaryQuadTree {
return ;
}
- mergeLastRectangles();
+// mergeLastRectangles();
allocChilds();
- for (int i = 0; i < 4; i++){
- for (NodeElem nodeElem: nodes){
- childs[i].add(nodeElem.area, nodeElem.boundaryId, nodeElem.locationDataSrc);
+ for (NodeElem nodeElem: nodes){
+ Rectangle shapeBBox = nodeElem.shape.getBounds();
+ for (int i = 0; i < 4; i++){
+ if (childs[i].bbox.intersects(shapeBBox))
+ childs[i].add(nodeElem.shape, nodeElem.boundaryId, nodeElem.locationDataSrc, DO_CLIP);
}
}
// return memory to GC
@@ -1011,6 +1021,8 @@ public class BoundaryQuadTree {
private class NodeElem{
// the intersections of the boundaries with the bounding box of this node
private Area area;
+
+ private Shape shape; // for temp. use when splitting
// location relevant tags of boundaries that intersect with the bounding box of this node
private Tags locTags;
@@ -1023,10 +1035,10 @@ public class BoundaryQuadTree {
private int srcPos;
/**
- * Create a node elem.
+ * Create a node element.
* @param boundaryId The boundary Id
* @param area the (part of the) boundary area stored in this node
- * @param refs A string containing boundaryIds and admin-level infos
+ * @param refs A string containing boundaryIds and admin level info
* of all boundaries with lower admin levels that share the same area.
*/
NodeElem (String boundaryId, Area area, String refs){
@@ -1038,7 +1050,22 @@ public class BoundaryQuadTree {
}
/**
- * Create a new node elem as a partly copy of an existing
+ * Create a node element.
+ * @param boundaryId The boundary Id
+ * @param shape the (part of the) boundary area stored in this node
+ * @param refs A string containing boundaryIds and admin level info
+ * of all boundaries with lower admin levels that share the same area.
+ */
+ NodeElem (String boundaryId, Shape shape, String refs){
+ srcPos = -1;
+ this.boundaryId = boundaryId;
+ this.shape = shape;
+ this.locationDataSrc = refs;
+ calcLocTags();
+ }
+
+ /**
+ * Create a new node element as a partly copy of an existing
* NodeElem and a new area.
* @param other the existing NodeElem instance
* @param area the new area
@@ -1060,8 +1087,11 @@ public class BoundaryQuadTree {
* the tags should be ignored.
*/
private boolean isValid(){
- if (tagMask == 0 || area == null || area.isEmpty()
- || area.getBounds2D().getWidth() <= BoundaryUtil.MIN_DIMENSION && area.getBounds2D().getHeight() <= BoundaryUtil.MIN_DIMENSION)
+ if (tagMask == 0)
+ return false;
+ Area checkArea = getArea();
+ if (checkArea == null || checkArea.isEmpty()
+ || checkArea.getBounds2D().getWidth() <= BoundaryUtil.MIN_DIMENSION && checkArea.getBounds2D().getHeight() <= BoundaryUtil.MIN_DIMENSION)
return false;
return true;
}
@@ -1159,28 +1189,27 @@ public class BoundaryQuadTree {
*/
private void save(OutputStream stream, String treePath) throws IOException{
ByteArrayOutputStream oneItemStream = new ByteArrayOutputStream();
- DataOutputStream dos = new DataOutputStream(oneItemStream);
- String id = this.boundaryId;
- dos.writeUTF(treePath.substring(1));
- dos.writeUTF(id);
- if (this.locationDataSrc == null)
- dos.writeUTF("");
- else
- dos.writeUTF(this.locationDataSrc);
- BoundarySaver.writeArea(dos, this.area);
- dos.close();
-
+ try(DataOutputStream dos = new DataOutputStream(oneItemStream)){
+ String id = this.boundaryId;
+ dos.writeUTF(treePath.substring(1));
+ dos.writeUTF(id);
+ if (this.locationDataSrc == null)
+ dos.writeUTF("");
+ else
+ dos.writeUTF(this.locationDataSrc);
+ BoundarySaver.writeArea(dos, this.getArea());
+ }
// now start to write into the real stream
// first write the bounding box so that is possible to skip the
// complete entry
- uk.me.parabola.imgfmt.app.Area bbox = Java2DConverter.createBbox(this.area);
+ uk.me.parabola.imgfmt.app.Area outBBox = Java2DConverter.createBbox(this.getArea());
DataOutputStream dOutStream = new DataOutputStream(stream);
dOutStream.writeUTF("AREA");
- dOutStream.writeInt(bbox.getMinLat());
- dOutStream.writeInt(bbox.getMinLong());
- dOutStream.writeInt(bbox.getMaxLat());
- dOutStream.writeInt(bbox.getMaxLong());
+ dOutStream.writeInt(outBBox.getMinLat());
+ dOutStream.writeInt(outBBox.getMinLong());
+ dOutStream.writeInt(outBBox.getMaxLat());
+ dOutStream.writeInt(outBBox.getMaxLong());
// write the size of the boundary block so that it is possible to
// skip it
@@ -1192,7 +1221,22 @@ public class BoundaryQuadTree {
dOutStream.write(data);
dOutStream.flush();
}
-
+
+
+ private Area getArea(){
+ if (shape != null){
+ area = new Area(shape);
+ shape = null;
+ }
+ return area;
+ }
+
+ private void setArea(Area area) {
+ this.area = area;
+ this.shape = null;
+ }
+
+
/**
* calculate a handy short value that represents the available location tags
* @return a bit mask, a bit with value 1 means the corresponding entry in {@link locationTagNames }
@@ -1288,6 +1332,7 @@ public class BoundaryQuadTree {
}
}
+
/***
* Used to sort BoundaryLocationInfo. Input are boundaryIds.
* @author gerd
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundarySaver.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundarySaver.java
index 6c30d6e..e2d4a14 100644
--- a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundarySaver.java
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundarySaver.java
@@ -12,10 +12,11 @@
*/
package uk.me.parabola.mkgmap.reader.osm.boundary;
-import java.awt.Rectangle;
-import java.awt.geom.Area;
+import it.unimi.dsi.fastutil.ints.IntArrayList;
+import it.unimi.dsi.fastutil.ints.IntStack;
+
+import java.awt.Shape;
import java.awt.geom.PathIterator;
-import java.awt.geom.Rectangle2D;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
@@ -37,6 +38,7 @@ import java.util.regex.Pattern;
import uk.me.parabola.log.Logger;
import uk.me.parabola.mkgmap.Version;
+import uk.me.parabola.mkgmap.reader.osm.Tags;
import uk.me.parabola.util.Java2DConverter;
public class BoundarySaver {
@@ -86,7 +88,7 @@ public class BoundarySaver {
}
private int lastAccessNo = 0;
- private final List<StreamInfo> openStreams = new ArrayList<StreamInfo>();
+ private final List<StreamInfo> openStreams = new ArrayList<>();
/** keeps the open streams */
private final Map<String, StreamInfo> streams;
private boolean createEmptyFiles = false;
@@ -98,8 +100,8 @@ public class BoundarySaver {
System.exit(-1);
}
this.dataFormat = mode;
- this.streams = new HashMap<String, StreamInfo>();
- this.writtenFileNames = new HashSet<String>();
+ this.streams = new HashMap<>();
+ this.writtenFileNames = new HashSet<>();
}
/**
@@ -129,14 +131,14 @@ public class BoundarySaver {
}
public void addBoundary(Boundary boundary) {
- Map<String, Area> splitBounds = splitArea(boundary.getArea());
- for (Entry<String, Area> split : splitBounds.entrySet()) {
- saveToFile(split.getKey(),
- new Boundary(split.getValue(), boundary.getTags(), boundary
- .getId()));
+ Map<String, Shape> splitBounds = BoundaryUtil.rasterArea(boundary.getArea());
+ for (Entry<String, Shape> split : splitBounds.entrySet()) {
+ saveToFile(split.getKey(), split.getValue(), boundary.getTags(),
+ boundary.getId());
}
}
+
public HashSet<String> end() {
if (isCreateEmptyFiles() && getBbox() != null) {
// a bounding box is set => fill the gaps with empty files
@@ -197,69 +199,6 @@ public class BoundarySaver {
log.debug("Remaining", openStreams.size(), "open streams.");
}
- private Map<String, Area> splitArea(Area areaToSplit) {
- return splitArea(areaToSplit, new HashMap<String, Area>(), null);
- }
-
- /**
- * Split a given area into the raster tiles.
- * @param areaToSplit the area
- * @param splits a map the splitted tiles are added to
- * @return the map with the splitted tiles
- */
- private Map<String, Area> splitArea(Area areaToSplit, Map<String, Area> splits, Rectangle knownBbox) {
- if (areaToSplit.isEmpty())
- return splits;
- Rectangle2D areaBounds;
-
- if (knownBbox != null){
- // within recursion: use the calculated rectangle, not the area,
- // as the latter might contain a spike that "looks" out of the bbox
- // and can cause a stack overflow
- areaBounds = knownBbox.getBounds2D();
- }
- else
- areaBounds = areaToSplit.getBounds2D();
-
- // use high precision bounds with later rounding to avoid some little rounding
- // errors (49999.99999999 instead of 50000.0)
- int sMinLong = BoundaryUtil.getSplitBegin((int)Math.round(areaBounds.getMinX()));
- int sMinLat = BoundaryUtil.getSplitBegin((int)Math.round(areaBounds.getMinY()));
- int sMaxLong = BoundaryUtil.getSplitEnd((int)Math.round(areaBounds.getMaxX()));
- int sMaxLat = BoundaryUtil.getSplitEnd((int)Math.round(areaBounds.getMaxY()));
-
- int dLon = sMaxLong- sMinLong;
- int dLat = sMaxLat - sMinLat;
- if (dLon > BoundaryUtil.RASTER || dLat > BoundaryUtil.RASTER){
- // split into two halves
- Rectangle r1,r2;
- int middle;
- if (dLon > dLat) {
- middle = BoundaryUtil.getSplitEnd(sMinLong+dLon/2);
- r1 = new Rectangle(sMinLong, sMinLat, middle-sMinLong, dLat);
- r2 = new Rectangle(middle, sMinLat, sMaxLong-middle, dLat);
- } else {
- middle = BoundaryUtil.getSplitEnd(sMinLat+dLat/2);
- r1 = new Rectangle(sMinLong, sMinLat, dLon, middle-sMinLat);
- r2 = new Rectangle(sMinLong, middle, dLon, sMaxLat-middle);
- }
- Area a = new Area(r1);
- // intersect with the both halves
- // and split both halves recursively
- a.intersect(areaToSplit);
- splitArea(a, splits, r1);
-
- a = new Area(r2);
- a.intersect(areaToSplit);
- splitArea(a, splits, r2);
- } else {
- // the area fully fits into one raster tile
- splits.put(BoundaryUtil.getKey(sMinLat, sMinLong), areaToSplit);
- }
- return splits;
-
- }
-
private void openStream(StreamInfo streamInfo, boolean newFile) {
if (streamInfo.file.getParentFile().exists() == false
&& streamInfo.file.getParentFile() != null)
@@ -274,8 +213,8 @@ public class BoundarySaver {
String[] keyParts = streamInfo.boundsKey.split(Pattern
.quote("_"));
- int lat = Integer.valueOf(keyParts[0]);
- int lon = Integer.valueOf(keyParts[1]);
+ int lat = Integer.parseInt(keyParts[0]);
+ int lon = Integer.parseInt(keyParts[1]);
if (lat < minLat) {
minLat = lat;
log.debug("New min Lat:", minLat);
@@ -339,11 +278,11 @@ public class BoundarySaver {
// write the header part 2
// write it first to a byte array to be able to calculate the length of the header
ByteArrayOutputStream headerStream = new ByteArrayOutputStream();
- DataOutputStream headerDataStream = new DataOutputStream(headerStream);
- headerDataStream.writeUTF(dataFormat);
- headerDataStream.writeInt(CURRENT_RECORD_ID);
- headerDataStream.writeUTF(Version.VERSION);
- headerDataStream.close();
+ try(DataOutputStream headerDataStream = new DataOutputStream(headerStream)){
+ headerDataStream.writeUTF(dataFormat);
+ headerDataStream.writeInt(CURRENT_RECORD_ID);
+ headerDataStream.writeUTF(Version.VERSION);
+ }
byte[] header2 = headerStream.toByteArray();
// write the length of the header part 2 so that it is possible to add
@@ -353,25 +292,38 @@ public class BoundarySaver {
dos.flush();
}
- private void saveToFile(String filekey, Boundary boundary) {
+ /**
+ * Save the elements that build a boundary with a given key
+ * that identifies the lower left corner of the raster.
+ * @param filekey the string that identifies the lower left corner
+ * @param shape the shape that describes the area of the boundary
+ * @param tags the tags of the boundary
+ * @param id the boundary id
+ */
+ private void saveToFile(String filekey, Shape shape, Tags tags, String id) {
try {
StreamInfo streamInfo = getStream(filekey);
if (streamInfo != null && streamInfo.isOpen()) {
- writeRawFormat(streamInfo.stream, boundary);
+ writeRawFormat(streamInfo.stream, shape, tags, id);
}
} catch (Exception exp) {
log.error("Cannot write boundary: " + exp, exp);
}
tidyStreams();
+
}
+
/**
- * Write a boundary to a given stream.
+ * Save the elements of a boundary to a stream.
* @param stream the already opened OutputStream
- * @param boundary the boundary
+ * @param shape the shape that describes the area of the boundary
+ * @param tags the tags of the boundary
+ * @param id the boundary id
*/
- private void writeRawFormat(OutputStream stream, Boundary boundary) {
+ private void writeRawFormat(OutputStream stream, Shape shape, Tags tags,
+ String id) {
ByteArrayOutputStream oneItemStream = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(oneItemStream);
if (dataFormat == QUADTREE_DATA_FORMAT) {
@@ -379,14 +331,13 @@ public class BoundarySaver {
System.exit(1);
}
try {
- dos.writeUTF(boundary.getId());
+ dos.writeUTF(id);
// write the tags
- int noOfTags = boundary.getTags().size();
+ int noOfTags = tags.size();
dos.writeInt(noOfTags);
- Iterator<Entry<String, String>> tagIter = boundary.getTags()
- .entryIterator();
+ Iterator<Entry<String, String>> tagIter = tags.entryIterator();
while (tagIter.hasNext()) {
Entry<String, String> tag = tagIter.next();
dos.writeUTF(tag.getKey());
@@ -394,23 +345,24 @@ public class BoundarySaver {
noOfTags--;
}
assert noOfTags == 0 : "Remaining tags: " + noOfTags + " size: "
- + boundary.getTags().size() + " "
- + boundary.getTags().toString();
+ + tags.size() + " "
+ + tags.toString();
- writeArea(dos,boundary.getArea());
+ //writeArea(dos,boundary.getArea());
+ writeArea(dos, shape);
dos.close();
// now start to write into the real stream
// first write the bounding box so that is possible to skip the
// complete entry
- uk.me.parabola.imgfmt.app.Area bbox = Java2DConverter
- .createBbox(boundary.getArea());
+ uk.me.parabola.imgfmt.app.Area outBBox = Java2DConverter
+ .createBbox(shape);
DataOutputStream dOutStream = new DataOutputStream(stream);
- dOutStream.writeInt(bbox.getMinLat());
- dOutStream.writeInt(bbox.getMinLong());
- dOutStream.writeInt(bbox.getMaxLat());
- dOutStream.writeInt(bbox.getMaxLong());
+ dOutStream.writeInt(outBBox.getMinLat());
+ dOutStream.writeInt(outBBox.getMinLong());
+ dOutStream.writeInt(outBBox.getMaxLat());
+ dOutStream.writeInt(outBBox.getMaxLong());
// write the size of the boundary block so that it is possible to
// skip it
@@ -426,8 +378,9 @@ public class BoundarySaver {
log.error(exp.toString());
}
+
}
-
+
/**
* Write area to stream with Double precision. The coordinates
* are saved as varying length doubles with delta coding.
@@ -435,10 +388,11 @@ public class BoundarySaver {
* @param area the area (can be non-singular)
* @throws IOException
*/
- public static void writeArea(DataOutputStream dos, Area area) throws IOException{
+ public static void writeArea(DataOutputStream dos, Shape area) throws IOException{
double[] res = new double[6];
double[] lastRes = new double[2];
- List<Integer> pairs = new LinkedList<Integer>();
+
+ IntArrayList pairs = new IntArrayList();
// step 1: count parts
PathIterator pit = area.getPathIterator(null);
int prevType = -1;
@@ -458,7 +412,7 @@ public class BoundarySaver {
// 2nd pass: write the data
pit = area.getPathIterator(null);
prevType = -1;
-
+ int pairsPos = 0;
dos.writeInt(pit.getWindingRule());
while (!pit.isDone()) {
int type = pit.currentSegment(res);
@@ -467,7 +421,7 @@ public class BoundarySaver {
switch (type) {
case PathIterator.SEG_LINETO:
if (prevType != type){
- len = pairs.remove(0);
+ len = pairs.getInt(pairsPos++);
dos.writeInt(len);
}
// no break
@@ -570,6 +524,6 @@ public class BoundarySaver {
buffer[numBytes-1] &= 0x7f;
dos.write(buffer, 0, numBytes);
- }
+ }
}
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryUtil.java b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryUtil.java
index d4f1609..43da6ed 100644
--- a/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryUtil.java
+++ b/src/uk/me/parabola/mkgmap/reader/osm/boundary/BoundaryUtil.java
@@ -12,9 +12,12 @@
*/
package uk.me.parabola.mkgmap.reader.osm.boundary;
+import java.awt.Rectangle;
+import java.awt.Shape;
import java.awt.geom.Area;
import java.awt.geom.Path2D;
import java.awt.geom.PathIterator;
+import java.awt.geom.Rectangle2D;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
@@ -24,6 +27,7 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
@@ -44,6 +48,7 @@ import uk.me.parabola.mkgmap.reader.osm.Way;
import uk.me.parabola.util.EnhancedProperties;
import uk.me.parabola.util.Java2DConverter;
import uk.me.parabola.util.MultiHashMap;
+import uk.me.parabola.util.ShapeSplitter;
public class BoundaryUtil {
private static final Logger log = Logger.getLogger(BoundaryUtil.class);
@@ -75,7 +80,7 @@ public class BoundaryUtil {
return Collections.emptyList();
}
- List<BoundaryElement> bElements = new ArrayList<BoundaryElement>();
+ List<BoundaryElement> bElements = new ArrayList<>();
for (List<Coord> singleElement : areaElements) {
if (singleElement.size() <= 3) {
// need at least 4 items to describe a polygon
@@ -140,53 +145,49 @@ public class BoundaryUtil {
public static Map<String,BoundaryQuadTree> loadQuadTrees (String boundaryDirName,
List<String> boundaryFileNames,
uk.me.parabola.imgfmt.app.Area searchBbox, EnhancedProperties props){
- Map<String,BoundaryQuadTree> trees = new HashMap<String,BoundaryQuadTree>();
+ Map<String,BoundaryQuadTree> trees = new HashMap<>();
File boundaryDir = new File(boundaryDirName);
BoundaryQuadTree bqt;
- if (boundaryDir.isDirectory()){
- for (String boundaryFileName: boundaryFileNames){
- log.info("loading boundary file:", boundaryFileName);
- // no support for nested directories
- File boundaryFile = new File(boundaryDir, boundaryFileName);
- try {
- if (boundaryFile.exists()){
- InputStream stream = new FileInputStream(boundaryFile);
- bqt = BoundaryUtil.loadQuadTreeFromStream(stream, boundaryFileName, searchBbox, props);
- if (bqt != null)
- trees.put(boundaryFileName,bqt);
- }
+ if (boundaryDir.isDirectory()){
+ for (String boundaryFileName: boundaryFileNames){
+ log.info("loading boundary file:", boundaryFileName);
+ // no support for nested directories
+ File boundaryFile = new File(boundaryDir, boundaryFileName);
+ if (boundaryFile.exists()){
+ try(InputStream stream = new FileInputStream(boundaryFile)){
+ bqt = BoundaryUtil.loadQuadTreeFromStream(stream, boundaryFileName, searchBbox, props);
+ if (bqt != null)
+ trees.put(boundaryFileName,bqt);
} catch (IOException exp) {
log.error("Cannot load boundary file " + boundaryFileName + "." + exp);
}
-
- }
- } else if (boundaryDirName.endsWith(".zip")) {
- String currentFileName = "";
- try{
- ZipFile zipFile = new ZipFile(boundaryDir);
-
- for (String boundaryFileName : boundaryFileNames){
- log.info("loading boundary file:", boundaryFileName);
- currentFileName = boundaryFileName;
- // direct access
- ZipEntry entry = zipFile.getEntry(boundaryFileName);
- if (entry != null){
- bqt = BoundaryUtil.loadQuadTreeFromStream(zipFile.getInputStream(entry),
- boundaryFileName, searchBbox, props);
+ }
+ }
+ } else if (boundaryDirName.endsWith(".zip")) {
+ String currentFileName = "";
+ try(ZipFile zipFile = new ZipFile(boundaryDir)){
+ for (String boundaryFileName : boundaryFileNames){
+ log.info("loading boundary file:", boundaryFileName);
+ currentFileName = boundaryFileName;
+ // direct access
+ ZipEntry entry = zipFile.getEntry(boundaryFileName);
+ if (entry != null){
+ try(InputStream stream = zipFile.getInputStream(entry)){
+ bqt = BoundaryUtil.loadQuadTreeFromStream(stream, boundaryFileName, searchBbox, props);
if (bqt != null)
trees.put(boundaryFileName,bqt);
}
}
- zipFile.close();
- } catch (IOException exp) {
- log.error("Cannot load boundary file " + currentFileName + "." + exp);
}
- } else{
- log.error("Cannot read " + boundaryDirName);
+ } catch (IOException exp) {
+ log.error("Cannot load boundary file " + currentFileName + "." + exp);
}
+ } else{
+ log.error("Cannot read " + boundaryDirName);
+ }
return trees;
}
-
+
/**
* read path iterator info from stream and create Area.
@@ -197,7 +198,7 @@ public class BoundaryUtil {
*/
public static Area readAreaAsPath(DataInputStream inpStream) throws IOException{
double[] res = new double[2];
- Path2D.Double path = new Path2D.Double();
+ Path2D.Double path = new Path2D.Double(PathIterator.WIND_NON_ZERO, 1024);
int windingRule = inpStream.readInt();
path.setWindingRule(windingRule);
int type = inpStream.readInt();
@@ -282,7 +283,7 @@ public class BoundaryUtil {
private static List<Boundary> readStreamRawFormat(
DataInputStream inpStream, String fname,
uk.me.parabola.imgfmt.app.Area bbox) throws IOException {
- List<Boundary> boundaryList = new ArrayList<Boundary>();
+ List<Boundary> boundaryList = new ArrayList<>();
try {
while (true) {
@@ -290,7 +291,8 @@ public class BoundaryUtil {
int minLong = inpStream.readInt();
int maxLat = inpStream.readInt();
int maxLong = inpStream.readInt();
- log.debug("Next boundary. Lat min:",minLat,"max:",maxLat,"Long min:",minLong,"max:",maxLong);
+ if (log.isDebugEnabled())
+ log.debug("Next boundary. Lat min:",minLat,"max:",maxLat,"Long min:",minLong,"max:",maxLong);
uk.me.parabola.imgfmt.app.Area rBbox = new uk.me.parabola.imgfmt.app.Area(
minLat, minLong, maxLat, maxLong);
int bSize = inpStream.readInt();
@@ -332,11 +334,11 @@ public class BoundaryUtil {
* @return a List with the names
*/
public static List<String> getRequiredBoundaryFileNames(uk.me.parabola.imgfmt.app.Area bbox) {
- List<String> names = new ArrayList<String>();
- for (int latSplit = BoundaryUtil.getSplitBegin(bbox.getMinLat()); latSplit <= BoundaryUtil
- .getSplitBegin(bbox.getMaxLat()); latSplit += BoundaryUtil.RASTER) {
- for (int lonSplit = BoundaryUtil.getSplitBegin(bbox.getMinLong()); lonSplit <= BoundaryUtil
- .getSplitBegin(bbox.getMaxLong()); lonSplit += BoundaryUtil.RASTER) {
+ List<String> names = new ArrayList<>();
+ for (int latSplit = getSplitBegin(bbox.getMinLat()); latSplit <= BoundaryUtil
+ .getSplitBegin(bbox.getMaxLat()); latSplit += RASTER) {
+ for (int lonSplit = getSplitBegin(bbox.getMinLong()); lonSplit <= BoundaryUtil
+ .getSplitBegin(bbox.getMaxLong()); lonSplit += RASTER) {
names.add("bounds_"+ getKey(latSplit, lonSplit) + ".bnd");
}
}
@@ -350,7 +352,7 @@ public class BoundaryUtil {
* @return the available *.bnd files in dirName.
*/
public static List<String> getBoundaryDirContent(String dirName) {
- List<String> names = new ArrayList<String>();
+ List<String> names = new ArrayList<>();
File boundaryDir = new File(dirName);
if (!boundaryDir.exists())
log.error("boundary directory/zip does not exist: " + dirName);
@@ -364,8 +366,7 @@ public class BoundaryUtil {
}
}
else if (boundaryDir.getName().endsWith(".zip")){
- try {
- ZipFile zipFile = new ZipFile(boundaryDir);
+ try (ZipFile zipFile = new ZipFile(boundaryDir)){
Enumeration<? extends ZipEntry> entries = zipFile.entries();
boolean isFlat = true;
while(entries.hasMoreElements()) {
@@ -376,7 +377,6 @@ public class BoundaryUtil {
if (entry.getName().endsWith(".bnd"))
names.add(entry.getName());
}
- zipFile.close();
if (!isFlat){
log.error("boundary zip file contains directories. Files in directories will be ignored." + dirName);
}
@@ -428,8 +428,8 @@ public class BoundaryUtil {
filename = filename.substring(0,filename.length()-4);
String[] fParts = filename.split(Pattern.quote("_"));
- int lat = Integer.valueOf(fParts[1]);
- int lon = Integer.valueOf(fParts[2]);
+ int lat = Integer.parseInt(fParts[1]);
+ int lon = Integer.parseInt(fParts[2]);
return new uk.me.parabola.imgfmt.app.Area(lat, lon, lat+RASTER, lon+RASTER);
}
@@ -450,11 +450,8 @@ public class BoundaryUtil {
uk.me.parabola.imgfmt.app.Area searchBbox,
EnhancedProperties props)throws IOException{
BoundaryQuadTree bqt = null;
- uk.me.parabola.imgfmt.app.Area qtBbox = BoundaryUtil.getBbox(fname);
- try {
- DataInputStream inpStream = new DataInputStream(
- new BufferedInputStream(stream, 1024 * 1024));
-
+ uk.me.parabola.imgfmt.app.Area qtBbox = getBbox(fname);
+ try (DataInputStream inpStream = new DataInputStream(new BufferedInputStream(stream, 1024 * 1024))){
try {
// 1st read the mkgmap release the boundary file is created by
String mkgmapRel = "?";
@@ -472,9 +469,8 @@ public class BoundaryUtil {
int nBytes = inpStream.read(header, bytesRead, headerLength-bytesRead);
if (nBytes<0) {
throw new IOException("Cannot read header with size "+headerLength);
- } else {
- bytesRead += nBytes;
}
+ bytesRead += nBytes;
}
ByteArrayInputStream rawHeaderStream = new ByteArrayInputStream(header);
@@ -513,11 +509,7 @@ public class BoundaryUtil {
catch (FormatException exp) {
log.error("Failed to read boundary file " + fname + " " + exp.getMessage());
}
- inpStream.close();
- } finally {
- if (stream != null)
- stream.close();
- }
+ }
return bqt;
}
@@ -527,9 +519,9 @@ public class BoundaryUtil {
* @return the boundary list with postal code areas merged
*/
private static List<Boundary> mergePostalCodes(List<Boundary> boundaries) {
- List<Boundary> mergedList = new ArrayList<Boundary>(boundaries.size());
+ List<Boundary> mergedList = new ArrayList<>(boundaries.size());
- MultiHashMap<String, Boundary> equalPostalCodes = new MultiHashMap<String, Boundary>();
+ MultiHashMap<String, Boundary> equalPostalCodes = new MultiHashMap<>();
for (Boundary boundary : boundaries) {
String postalCode = getPostalCode(boundary.getTags());
if (postalCode == null) {
@@ -595,26 +587,21 @@ public class BoundaryUtil {
if ("boundary".equals(type) || "multipolygon".equals(type)) {
String boundaryVal = b.getTags().get("boundary");
- if ("administrative".equals(boundaryVal)) {
- // for boundary=administrative the admin_level must be set
- if (b.getTags().get("admin_level") == null) {
- return false;
- }
- // and a name must be set (check only for a tag containing name
- Iterator<Entry<String,String>> tagIterator = b.getTags().entryIterator();
- while (tagIterator.hasNext()) {
- Entry<String,String> tag = tagIterator.next();
- if (tag.getKey().contains("name")) {
- return true;
- }
- }
- // does not contain a name tag => do not use it
- return false;
- } else {
+ if ("administrative".equals(boundaryVal) == false)
+ return false;
+ // for boundary=administrative the admin_level must be set
+ if (b.getTags().get("admin_level") == null) {
return false;
}
- } else {
- return false;
+ // and a name must be set (check only for a tag containing name
+ Iterator<Entry<String,String>> tagIterator = b.getTags().entryIterator();
+ while (tagIterator.hasNext()) {
+ Entry<String,String> tag = tagIterator.next();
+ if (tag.getKey().contains("name")) {
+ return true;
+ }
+ }
+ // does not contain a name tag => do not use it
}
} else if (b.getId().startsWith("w")) {
// the boundary tag must be "administrative" or "postal_code"
@@ -633,13 +620,9 @@ public class BoundaryUtil {
}
}
// does not contain a name tag => do not use it
- return false;
- } else {
- return false;
}
- } else {
- return false;
- }
+ }
+ return false;
}
@@ -719,4 +702,99 @@ public class BoundaryUtil {
return Double.longBitsToDouble(res);
}
+ /**
+ * Raster a given area. This is the non-recursive public method.
+ * @param areaToSplit the area
+ * @return a map with the divided shapes
+ */
+ public static Map<String, Shape> rasterArea(Area areaToSplit) {
+ return rasterShape(areaToSplit, new HashMap<String, Shape>());
+ }
+
+ /**
+ * Raster a given shape. This method calls itself recursively.
+ * @param shapeToSplit the shape
+ * @param splits a map that will contain the resulting shapes
+ * @return a reference to the map
+ */
+ private static Map<String, Shape> rasterShape(Shape shapeToSplit, Map<String, Shape> splits) {
+ double minX = Double.POSITIVE_INFINITY,minY = Double.POSITIVE_INFINITY,
+ maxX = Double.NEGATIVE_INFINITY,maxY = Double.NEGATIVE_INFINITY;
+ PathIterator pit = shapeToSplit.getPathIterator(null);
+ double[] points = new double[512];
+ double[] res = new double[6];
+ int num = 0;
+ while (!pit.isDone()) {
+ int type = pit.currentSegment(res);
+ double x = res[0];
+ double y = res[1];
+ if (x < minX) minX = x;
+ if (x > maxX) maxX = x;
+ if (y < minY) minY = y;
+ if (y > maxY) maxY = y;
+ switch (type) {
+ case PathIterator.SEG_LINETO:
+ case PathIterator.SEG_MOVETO:
+ if (num + 2 >= points.length) {
+ points = Arrays.copyOf(points, points.length * 2);
+ }
+ points[num++] = x;
+ points[num++] = y;
+ break;
+ case PathIterator.SEG_CLOSE:
+ int sMinLong = getSplitBegin((int)Math.round(minX));
+ int sMinLat = getSplitBegin((int)Math.round(minY));
+ int sMaxLong = getSplitEnd((int)Math.round(maxX));
+ int sMaxLat = getSplitEnd((int)Math.round(maxY));
+
+ int dLon = sMaxLong- sMinLong;
+ int dLat = sMaxLat - sMinLat;
+ Rectangle2D.Double bbox = new Rectangle2D.Double(minX,minY,maxX-minX,maxY-minY);
+ if (dLon > RASTER || dLat > RASTER) {
+ // split into two halves
+ Rectangle clip1,clip2;
+ if (dLon > dLat) {
+ int midLon = getSplitEnd(sMinLong+dLon/2);
+ clip1 = new Rectangle(sMinLong, sMinLat, midLon-sMinLong, dLat);
+ clip2 = new Rectangle(midLon, sMinLat, sMaxLong-midLon, dLat);
+ } else {
+ int midLat = getSplitEnd(sMinLat+dLat/2);
+ clip1 = new Rectangle(sMinLong, sMinLat, dLon, midLat-sMinLat);
+ clip2 = new Rectangle(sMinLong, midLat, dLon, sMaxLat-midLat);
+ }
+
+ // intersect with the both halves
+ // and split both halves recursively
+ Path2D.Double clippedPath = ShapeSplitter.clipSinglePathWithSutherlandHodgman (points, num, clip1, bbox);
+ if (clippedPath != null)
+ rasterShape(clippedPath, splits);
+ clippedPath = ShapeSplitter.clipSinglePathWithSutherlandHodgman (points, num, clip2, bbox);
+ if (clippedPath != null)
+ rasterShape(clippedPath, splits);
+ }
+ else {
+ String key = getKey(sMinLat, sMinLong);
+ // no need to split, path fits into one tile
+ Path2D.Double segment = ShapeSplitter.pointsToPath2D(points, num);
+ if (segment != null){
+ Path2D.Double path = (Path2D.Double) splits.get(key);
+ if (path == null)
+ splits.put(key, segment);
+ else
+ path.append(segment, false);
+ }
+ }
+ num = 0;
+ minX = minY = Double.POSITIVE_INFINITY;
+ maxX = maxY = Double.NEGATIVE_INFINITY;
+ break;
+ default:
+ log.error("Unsupported path iterator type " + type
+ + ". This is an mkgmap error.");
+ }
+
+ pit.next();
}
+ return splits;
+ }
+}
diff --git a/src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java b/src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java
index 4c3b803..a001070 100644
--- a/src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java
+++ b/src/uk/me/parabola/mkgmap/reader/polish/PolishMapDataSource.java
@@ -96,6 +96,7 @@ public class PolishMapDataSource extends MapperBasedMapDataSource implements Loa
private int lineNo;
private boolean havePolygon4B;
+ private Boolean driveOnLeft;
// Use to decode labels if they are not in cp1252
private CharsetDecoder dec;
@@ -667,6 +668,12 @@ public class PolishMapDataSource extends MapperBasedMapDataSource implements Loa
} else if (name.equals("CodePage")) {
dec = Charset.forName("cp" + value).newDecoder();
dec.onUnmappableCharacter(CodingErrorAction.REPLACE);
+ } else if (name.endsWith("LeftSideTraffic")){
+ if ("Y".equals(value)){
+ setDriveOnLeft(true);
+ } else if ("N".equals(value)){
+ setDriveOnLeft(false);
+ }
}
}
diff --git a/src/uk/me/parabola/util/Java2DConverter.java b/src/uk/me/parabola/util/Java2DConverter.java
index 5879ff3..4c3a857 100644
--- a/src/uk/me/parabola/util/Java2DConverter.java
+++ b/src/uk/me/parabola/util/Java2DConverter.java
@@ -14,6 +14,7 @@ package uk.me.parabola.util;
import java.awt.Polygon;
import java.awt.Rectangle;
+import java.awt.Shape;
import java.awt.geom.Area;
import java.awt.geom.Path2D;
import java.awt.geom.PathIterator;
@@ -47,16 +48,17 @@ public class Java2DConverter {
}
/**
- * Converts the bounding box of a Java2D {@link Area} object to an mkgmap
+ * Converts the bounding box of a Java2D {@link Shape} object to an mkgmap
* {@link uk.me.parabola.imgfmt.app.Area} object.
*
- * @param area a Java2D area
+ * @param shape a Java2D Shape (Area, Path2D, ...)
* @return the bounding box
*/
- public static uk.me.parabola.imgfmt.app.Area createBbox(Area area) {
- Rectangle areaBounds = area.getBounds();
+ public static uk.me.parabola.imgfmt.app.Area createBbox(Shape shape) {
+ Rectangle areaBounds = shape.getBounds();
return new uk.me.parabola.imgfmt.app.Area(areaBounds.y,areaBounds.x,(int) areaBounds.getMaxY(),(int) areaBounds.getMaxX());
}
+
/**
* Creates a Java2D {@link Area} object from a polygon given as a list of
@@ -66,10 +68,22 @@ public class Java2DConverter {
* @return the converted Java2D area
*/
public static Area createArea(List<Coord> polygonPoints) {
- if (polygonPoints.size()<3)
- return new Area();
- Path2D path = new Path2D.Double();
+ return new Area(createPath2D(polygonPoints));
+ }
+
+ /**
+ * Creates a Java2D {@link Path2D} object from a polygon given as a list of
+ * {@link Coord} objects. This list should describe a closed polygon.
+ *
+ * @param polygonPoints a list of points that describe a closed polygon
+ * @return the converted Java2D path
+ */
+ public static Path2D createPath2D (List<Coord> polygonPoints) {
int n = polygonPoints.size();
+ if (n < 3)
+ return new Path2D.Double();
+
+ Path2D path = new Path2D.Double(PathIterator.WIND_NON_ZERO, n);
if (polygonPoints.get(0).highPrecEquals(polygonPoints.get(n-1))){
// if first and last point are high-prec-equal, ignore last point
// because we use closePath() to signal that
@@ -92,8 +106,7 @@ public class Java2DConverter {
lastLat = lat30;
}
path.closePath();
- return new Area(path);
-
+ return path;
}
public static Polygon createHighPrecPolygon(List<Coord> points) {
@@ -120,7 +133,7 @@ public class Java2DConverter {
} else if (area.isSingular()) {
return Collections.singletonList(area);
} else {
- List<Area> singularAreas = new ArrayList<Area>();
+ List<Area> singularAreas = new ArrayList<>();
// all ways in the area MUST define outer areas
// it is not possible that one of the areas define an inner segment
@@ -193,7 +206,7 @@ public class Java2DConverter {
case PathIterator.SEG_MOVETO:
if (points != null)
log.error("area not singular");
- points = new ArrayList<Coord>();
+ points = new ArrayList<>();
points.add(Coord.makeHighPrecCoord(lat30, lon30));
break;
case PathIterator.SEG_LINETO:
@@ -244,7 +257,7 @@ public class Java2DConverter {
* @return a list of closed polygons
*/
public static List<List<Coord>> areaToShapes(java.awt.geom.Area area) {
- List<List<Coord>> outputs = new ArrayList<List<Coord>>(4);
+ List<List<Coord>> outputs = new ArrayList<>(4);
double[] res = new double[6];
PathIterator pit = area.getPathIterator(null);
@@ -284,7 +297,7 @@ public class Java2DConverter {
}
}
if (type == PathIterator.SEG_MOVETO){
- coords = new ArrayList<Coord>();
+ coords = new ArrayList<>();
coords.add(Coord.makeHighPrecCoord(lat30, lon30));
prevLat30 = lat30;
prevLong30 = lon30;
diff --git a/src/uk/me/parabola/util/ShapeSplitter.java b/src/uk/me/parabola/util/ShapeSplitter.java
new file mode 100644
index 0000000..1f2bc6e
--- /dev/null
+++ b/src/uk/me/parabola/util/ShapeSplitter.java
@@ -0,0 +1,260 @@
+package uk.me.parabola.util;
+
+import java.awt.Shape;
+import java.awt.geom.Path2D;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Rectangle2D;
+import java.util.Arrays;
+
+import uk.me.parabola.log.Logger;
+
+public class ShapeSplitter {
+ private static final Logger log = Logger.getLogger(ShapeSplitter.class);
+ private static final int LEFT = 0;
+ private static final int TOP = 1;
+ private static final int RIGHT = 2;
+ private static final int BOTTOM= 3;
+
+
+ /**
+ * Clip a given shape with a given rectangle.
+ * @param shape the subject shape to clip
+ * @param clippingRect the clipping rectangle
+ * @return the intersection of the shape and the rectangle
+ * or null if they don't intersect.
+ * The intersection may contain dangling edges.
+ */
+ public static Path2D.Double clipShape (Shape shape, Rectangle2D clippingRect) {
+ double minX = Double.POSITIVE_INFINITY,minY = Double.POSITIVE_INFINITY,
+ maxX = Double.NEGATIVE_INFINITY,maxY = Double.NEGATIVE_INFINITY;
+ PathIterator pit = shape.getPathIterator(null);
+ double[] points = new double[512];
+ int num = 0;
+ Path2D.Double result = null;
+ double[] res = new double[6];
+ while (!pit.isDone()) {
+ int type = pit.currentSegment(res);
+ double x = res[0];
+ double y = res[1];
+ if (x < minX) minX = x;
+ if (x > maxX) maxX = x;
+ if (y < minY) minY = y;
+ if (y > maxY) maxY = y;
+ switch (type) {
+ case PathIterator.SEG_LINETO:
+ case PathIterator.SEG_MOVETO:
+ if (num + 2 >= points.length) {
+ points = Arrays.copyOf(points, points.length * 2);
+ }
+ points[num++] = x;
+ points[num++] = y;
+ break;
+ case PathIterator.SEG_CLOSE:
+ Path2D.Double segment = null;
+ if (clippingRect.contains(minX, minY) == false || clippingRect.contains(maxX,maxY) == false){
+ Rectangle2D.Double bbox = new Rectangle2D.Double(minX,minY,maxX-minX,maxY-minY);
+ segment = clipSinglePathWithSutherlandHodgman (points, num, clippingRect, bbox);
+ } else
+ segment = pointsToPath2D(points, num);
+ if (segment != null){
+ if (result == null)
+ result = segment;
+ else
+ result.append(segment, false);
+ }
+ num = 0;
+ minX = minY = Double.POSITIVE_INFINITY;
+ maxX = maxY = Double.NEGATIVE_INFINITY;
+ break;
+ default:
+ log.error("Unsupported path iterator type " + type
+ + ". This is an mkgmap error.");
+ }
+
+ pit.next();
+ }
+ return result;
+ }
+
+ /**
+ * Convert a list of longitude+latitude values to a Path2D.Double
+ * @param points the pairs
+ * @return the path or null if the path describes a point or line.
+ */
+ public static Path2D.Double pointsToPath2D(double[] points, int num) {
+ if (num < 2)
+ return null;
+ if (points[0] == points[num-2] && points[1] == points[num-1])
+ num -= 2;
+ if (num < 6)
+ return null;
+ Path2D.Double path = new Path2D.Double(Path2D.WIND_NON_ZERO, num / 2 + 2);
+ double lastX = points[0], lastY = points[1];
+ path.moveTo(lastX, lastY);
+ int numOut = 1;
+ for (int i = 2; i < num; ){
+ double x = points[i++], y = points[i++];
+ if (x != lastX || y != lastY){
+ path.lineTo(x,y);
+ lastX = x; lastY = y;
+ ++numOut;
+ }
+ }
+ if (numOut < 3)
+ return null;
+ path.closePath();
+ return path;
+ }
+
+ // The Sutherland�Hodgman algorithm Pseudo-Code:
+ // List outputList = subjectPolygon;
+ // for (Edge clipEdge in clipPolygon) do
+ // List inputList = outputList;
+ // outputList.clear();
+ // Point S = inputList.last;
+ // for (Point E in inputList) do
+ // if (E inside clipEdge) then
+ // if (S not inside clipEdge) then
+ // outputList.add(ComputeIntersection(S,E,clipEdge));
+ // end if
+ // outputList.add(E);
+ // else if (S inside clipEdge) then
+ // outputList.add(ComputeIntersection(S,E,clipEdge));
+ // end if
+ // S = E;
+ // done
+ // done
+
+ /**
+ * Clip a single path with a given rectangle using the Sutherland-Hodgman algorithm. This is much faster compared to
+ * the area.intersect method, but may create dangling edges.
+ * @param points a list of longitude+latitude pairs
+ * @param num the nnumber of valid values in points
+ * @param clippingRect the clipping rectangle
+ * @param bbox the bounding box of the path
+ * @return the clipped path as a Path2D.Double or null if the result is empty
+ */
+ public static Path2D.Double clipSinglePathWithSutherlandHodgman (double[] points, int num, Rectangle2D clippingRect, Rectangle2D.Double bbox) {
+ if (num <= 2 || bbox.intersects(clippingRect) == false){
+ return null;
+ }
+
+ int countVals = num;
+ if (points[0] == points[num-2] && points[1] == points[num-1]){
+ countVals -= 2;
+ }
+ double[] outputList = points;
+ double[] input;
+
+ double leftX = clippingRect.getMinX();
+ double rightX = clippingRect.getMaxX();
+ double lowerY = clippingRect.getMinY();
+ double upperY = clippingRect.getMaxY();
+ boolean eIsIn = false, sIsIn = false;
+ for (int side = LEFT; side <= BOTTOM; side ++){
+ if (countVals < 6)
+ return null; // ignore point or line
+
+ boolean skipTestForThisSide;
+ switch(side){
+ case LEFT: skipTestForThisSide = (bbox.getMinX() >= leftX); break;
+ case TOP: skipTestForThisSide = (bbox.getMaxY() < upperY); break;
+ case RIGHT: skipTestForThisSide = (bbox.getMaxX() < rightX); break;
+ default: skipTestForThisSide = (bbox.getMinY() >= lowerY);
+ }
+ if (skipTestForThisSide)
+ continue;
+
+ input = outputList;
+ outputList = new double[countVals + 16];
+ double sLon = 0,sLat = 0;
+ double pLon = 0,pLat = 0; // intersection
+ int posIn = countVals - 2;
+ int posOut = 0;
+ for (int i = 0; i < countVals+2; i+=2){
+ if (posIn >= countVals)
+ posIn = 0;
+ double eLon = input[posIn++];
+ double eLat = input[posIn++];
+ switch (side){
+ case LEFT: eIsIn = (eLon >= leftX); break;
+ case TOP: eIsIn = (eLat < upperY); break;
+ case RIGHT: eIsIn = (eLon < rightX); break;
+ default: eIsIn = (eLat >= lowerY);
+ }
+ if (i > 0){
+ if (eIsIn != sIsIn){
+ // compute intersection
+ double slope;
+ if (eLon != sLon)
+ slope = (eLat - sLat) / (eLon-sLon);
+ else slope = 1;
+
+ switch (side){
+ case LEFT:
+ pLon = leftX;
+ pLat = slope *(leftX-sLon) + sLat;
+ break;
+ case RIGHT:
+ pLon = rightX;
+ pLat = slope *(rightX-sLon) + sLat;
+ break;
+
+ case TOP:
+ if (eLon != sLon)
+ pLon = sLon + (upperY - sLat) / slope;
+ else
+ pLon = sLon;
+ pLat = upperY;
+ break;
+ default: // BOTTOM
+ if (eLon != sLon)
+ pLon = sLon + (lowerY - sLat) / slope;
+ else
+ pLon = sLon;
+ pLat = lowerY;
+ break;
+
+ }
+ }
+ int toAdd = 0;
+ if (eIsIn){
+ if (!sIsIn){
+ toAdd += 2;
+ }
+ toAdd += 2;
+ }
+ else {
+ if (sIsIn){
+ toAdd += 2;
+ }
+ }
+ if (posOut + toAdd >= outputList.length) {
+ // unlikely
+ outputList = Arrays.copyOf(outputList, outputList.length * 2);
+ }
+ if (eIsIn){
+ if (!sIsIn){
+ outputList[posOut++] = pLon;
+ outputList[posOut++] = pLat;
+ }
+ outputList[posOut++] = eLon;
+ outputList[posOut++] = eLat;
+ }
+ else {
+ if (sIsIn){
+ outputList[posOut++] = pLon;
+ outputList[posOut++] = pLat;
+ }
+ }
+ }
+ // S = E
+ sLon = eLon; sLat = eLat;
+ sIsIn = eIsIn;
+ }
+ countVals = posOut;
+ }
+ return pointsToPath2D(outputList, countVals);
+ }
+
+}
diff --git a/test/func/route/SimpleRouteTest.java b/test/func/route/SimpleRouteTest.java
index 8fae3b4..c9df2ba 100644
--- a/test/func/route/SimpleRouteTest.java
+++ b/test/func/route/SimpleRouteTest.java
@@ -63,7 +63,7 @@ public class SimpleRouteTest extends Base {
count++;
System.out.println("TRE size " + size);
// Size varies depending on svn modified status
- assertThat("TRE size", size, new RangeMatcher(1554, 2));
+ assertThat("TRE size", size, new RangeMatcher(1454, 2));
break;
case "LBL":
count++;
diff --git a/test/uk/me/parabola/imgfmt/app/CoordTest.java b/test/uk/me/parabola/imgfmt/app/CoordTest.java
index 6b5d1f3..52e6a10 100644
--- a/test/uk/me/parabola/imgfmt/app/CoordTest.java
+++ b/test/uk/me/parabola/imgfmt/app/CoordTest.java
@@ -30,6 +30,8 @@ public class CoordTest {
Coord p1_11 = new Coord (1.0, 11.0);
Coord p60_10 = new Coord (60.0, 10.0);
Coord p61_11 = new Coord (61.0, 11.0);
+ Coord russia1 = new Coord(3069580,8388608);
+ Coord russia2 = new Coord(3105677,8388608);
/**
*/
@@ -71,4 +73,17 @@ public class CoordTest {
assertEquals(124100, p60_10.distanceHaversine(p61_11), 100);
}
+ @Test
+ public void testMakeBetweenAt180(){
+ Coord russia3 = russia1.makeBetweenPoint(russia2, 0.5);
+ assertEquals(russia3.getLongitude(), russia1.getLongitude());
+ }
+
+ @Test
+ public void destOnRhumLineAt180(){
+ Coord russia3 = russia1.destOnRhumLine(1, 0.0);
+ assertEquals(russia3.getLongitude(), russia1.getLongitude());
+ Coord russia4 = russia1.destOnRhumLine(10000, 0.0);
+ assertEquals(russia4.getLongitude(), russia1.getLongitude());
+ }
}
diff --git a/test/uk/me/parabola/mkgmap/osmstyle/actions/ConvertFilterTest.java b/test/uk/me/parabola/mkgmap/osmstyle/actions/ConvertFilterTest.java
new file mode 100644
index 0000000..ce2d077
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/osmstyle/actions/ConvertFilterTest.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2014.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 or
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import java.util.Arrays;
+import java.util.List;
+
+import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class ConvertFilterTest {
+ private final List<Data> simpleTests = Arrays.asList(
+ new Data("kmh=>mph", "100", "62"),
+ new Data("km/h=>mph", "100", "62"),
+ new Data("mph=>km/h", "60", "97"),
+ new Data("m=>ft", "10", "33"),
+ new Data("km=>ft", "10", "32808"),
+ new Data("ft=>m", "100", "30"),
+ new Data("mi=>km", "100", "161"),
+ new Data("knots=>mph", "20", "23")
+ );
+
+ /** This is not used by this filter, so no need to create a new one for each test */
+ private final Element el = new Way(1);
+
+ /**
+ * Just test a whole bunch of different conversions.
+ */
+ @Test
+ public void testConversions() {
+ for (Data data : simpleTests) {
+ ConvertFilter f = new ConvertFilter(data.conv);
+ String result = f.doFilter(data.input, el);
+ assertEquals("Simple test for conversion " + data.conv, data.output, result);
+ }
+ }
+
+ /**
+ * If there is a unit on the input value, and that is the same as the default, then the conversion
+ * should be between the units as stated.
+ *
+ * Separate test, since there is likely to be a different code path involved.
+ */
+ @Test
+ public void testConvertWithUnitSameAsDefault() {
+ ConvertFilter f = new ConvertFilter("m=>ft");
+ assertEquals("328", f.doFilter("100m", el));
+ }
+
+ /**
+ * If the value has a unit which is the same as the target unit, then the result will be the
+ * input value (without the unit).
+ */
+ @Test
+ public void testConvertWIthUnitSameAsTarget() {
+ ConvertFilter f = new ConvertFilter("m=>ft");
+ assertEquals("100", f.doFilter("100ft", el));
+ }
+
+ /**
+ * Test the case where the input string has a unit specified that is neither the source nor the
+ * target string in the conversion specifier.
+ */
+ @Test
+ public void testConvertWithDifferentUnit() {
+ ConvertFilter f = new ConvertFilter("km=>ft");
+ assertEquals("33", f.doFilter("10m", el));
+ }
+
+ @Test
+ public void testConvertNumberWithSpaces() {
+ ConvertFilter f = new ConvertFilter("m=>ft");
+ String s = f.doFilter(" 10 ", el);
+ assertEquals("33", s);
+ }
+
+ @Test
+ public void testConvertWithSpaces() {
+ ConvertFilter f = new ConvertFilter("km/h=>mph");
+ String s = f.doFilter(" 10 km/h ", el);
+ assertEquals("6", s);
+ }
+
+ @Test(expected = SyntaxException.class)
+ public void testUnrecognisable() {
+ ConvertFilter f = new ConvertFilter("fjdkfjdk");
+ }
+
+ @Test
+ public void testBadConversion() {
+ ConvertFilter f = new ConvertFilter("kk=>ft");
+
+ String in = "10m";
+ assertEquals(in, f.doFilter(in, el));
+ }
+
+ @Test
+ public void testValueNotNumber() {
+ ConvertFilter f = new ConvertFilter("km=>m");
+
+ String in = "x10m";
+ assertEquals(in, f.doFilter(in, el));
+ }
+
+ @Test
+ public void testUnknownUnit() {
+ ConvertFilter f = new ConvertFilter("m=>ft");
+ String in = "10abc";
+ String s = f.doFilter(in, el);
+ assertEquals(in, s);
+ }
+
+ /**
+ * Converting between a distance and a speed for example.
+ */
+ @Test
+ public void testIncompatibleConversion() {
+ ConvertFilter f = new ConvertFilter("m=>mph");
+ String in = "10m";
+ String s = f.doFilter(in, el);
+ assertEquals(in, s);
+ }
+
+ class Data {
+ private final String conv;
+ private final String input;
+ private final String output;
+
+ Data(String conv, String input, String output) {
+ this.conv = conv;
+ this.input = input;
+ this.output = output;
+ }
+ }
+}
diff --git a/test/uk/me/parabola/mkgmap/osmstyle/actions/CountryISOFilterTest.java b/test/uk/me/parabola/mkgmap/osmstyle/actions/CountryISOFilterTest.java
new file mode 100644
index 0000000..2db6159
--- /dev/null
+++ b/test/uk/me/parabola/mkgmap/osmstyle/actions/CountryISOFilterTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2014
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 or
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+/* Create date: 28-Nov-2014 */
+package uk.me.parabola.mkgmap.osmstyle.actions;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author GerdP
+ *
+ */
+public class CountryISOFilterTest {
+ /**
+ * Test different inputs for the country-ISO filter
+ */
+ @Test
+ public void testDoFilter() {
+ CountryISOFilter filter = new CountryISOFilter();
+ String s;
+ s = filter.doFilter("Germany", null);
+ assertEquals("Germany", "DEU", s);
+ s = filter.doFilter("Deutschland", null);
+ assertEquals("Deutschland", "DEU", s);
+ s = filter.doFilter("United Kingdom", null);
+ assertEquals("United Kingdom", "GBR", s);
+ s = filter.doFilter("UNITED KINGDOM", null);
+ assertEquals("UNITED KINGDOM", "GBR", s);
+ s = filter.doFilter("united kingdom", null);
+ assertEquals("united kingdom", "GBR", s);
+ s = filter.doFilter("UK", null);
+ assertEquals("UK", "GBR", s);
+ s = filter.doFilter("xyz", null);
+ assertEquals("xyz", "xyz", s);
+ s = filter.doFilter("Ελλάδα", null);
+ assertEquals("Ελλάδα", "GRC", s);
+ s = filter.doFilter(" germany ", null);
+ assertEquals(" germany ", "DEU", s);
+
+
+ }
+
+}
diff --git a/test/uk/me/parabola/mkgmap/osmstyle/actions/ValueBuilderTest.java b/test/uk/me/parabola/mkgmap/osmstyle/actions/ValueBuilderTest.java
index 52de042..8a30ca6 100644
--- a/test/uk/me/parabola/mkgmap/osmstyle/actions/ValueBuilderTest.java
+++ b/test/uk/me/parabola/mkgmap/osmstyle/actions/ValueBuilderTest.java
@@ -130,6 +130,20 @@ public class ValueBuilderTest {
assertEquals("substitutions in name", "x|y w|w", s);
}
+ /**
+ * Test that you can use a space before the pipe with the old unquoted syntax.
+ */
+ @Test
+ public void testSpacedArgsOldSyntax() {
+ ValueBuilder vb = new ValueBuilder("{ name '${rcnname | substring:1:14}' }");
+ Element el = new Way(1);
+
+ el.addTag("rcnname", "1234567890123456789");
+
+ String s = vb.build(el, null);
+ assertEquals("value is trimmed", "{ name '2345678901234' }", s);
+ }
+
@Test
public void testQuotedSplitLines() {
String value =
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/mkgmap.git
More information about the Pkg-grass-devel
mailing list