Compare commits
24 Commits
2dd955ee70
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 325cdb6c67 | |||
| fb7a210501 | |||
| b8cfa7301a | |||
| bdeaf2d777 | |||
| a03711e0ad | |||
| 3026a1e5f0 | |||
| 3e40017904 | |||
| 8455b93b5b | |||
| 94ec22b5ac | |||
| 1052cde48a | |||
| fdf9110c45 | |||
| 31f424e3e9 | |||
| 16546a247f | |||
| e011b74f03 | |||
| e3cfd57d6e | |||
| e0d5a043b6 | |||
| 6931334fc6 | |||
| 1f4c5b52f2 | |||
| f4d2d60286 | |||
| 119658de07 | |||
| 7d9580965f | |||
| 3e54ae8f23 | |||
| e7956db333 | |||
| 65a8601ea1 |
91
.gitignore
vendored
91
.gitignore
vendored
@@ -1,9 +1,98 @@
|
||||
# Covers JetBrains IDEs: IntelliJ, GoLand, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# AWS User-specific
|
||||
.idea/**/aws.xml
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
# .idea/compiler.xml
|
||||
# .idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
target/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# SonarLint plugin
|
||||
.idea/sonarlint/
|
||||
.idea/sonarlint.xml # see https://community.sonarsource.com/t/is-the-file-idea-idea-idea-sonarlint-xml-intended-to-be-under-source-control/121119
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based HTTP Client
|
||||
.idea/httpRequests
|
||||
http-client.private.env.json
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
# Apifox Helper cache
|
||||
.idea/.cache/.Apifox_Helper
|
||||
.idea/ApifoxUploaderProjectSetting.xml
|
||||
|
||||
# Github Copilot persisted session migrations, see: https://github.com/microsoft/copilot-intellij-feedback/issues/712#issuecomment-3322062215
|
||||
.idea/**/copilot.data.migration.*.xml
|
||||
|
||||
# ---> Java
|
||||
# Compiled class file
|
||||
*.class
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
logfile*.txt
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
@@ -24,3 +113,5 @@
|
||||
hs_err_pid*
|
||||
replay_pid*
|
||||
|
||||
# Pliki binarne, generowane.
|
||||
*.bin
|
||||
|
||||
10
.idea/.gitignore
generated
vendored
Normal file
10
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Ignored default folder with query files
|
||||
/queries/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
13
.idea/compiler.xml
generated
Normal file
13
.idea/compiler.xml
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<annotationProcessing>
|
||||
<profile name="Maven default annotation processors profile" enabled="true">
|
||||
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||
<outputRelativeToContentRoot value="true" />
|
||||
<module name="terrain-utilities" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
</component>
|
||||
</project>
|
||||
7
.idea/encodings.xml
generated
Normal file
7
.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="file://$PROJECT_DIR$" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
||||
25
.idea/jarRepositories.xml
generated
Normal file
25
.idea/jarRepositories.xml
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="nexus-homelab" />
|
||||
<option name="name" value="nexus-homelab" />
|
||||
<option name="url" value="https://nexus.rulka.pl/repository/maven-public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Central Repository" />
|
||||
<option name="url" value="https://nexus.rulka.pl/repository/maven-public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
||||
14
.idea/misc.xml
generated
Normal file
14
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="MavenProjectsManager">
|
||||
<option name="originalFiles">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/pom.xml" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_25" default="true" project-jdk-name="jdk-25.0.2-sim" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
9
.idea/terrain-utilities.iml
generated
Normal file
9
.idea/terrain-utilities.iml
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
55
log4j.properties
Normal file
55
log4j.properties
Normal file
@@ -0,0 +1,55 @@
|
||||
#Glowny logger, pierwsza wartosc to poziom logowania
|
||||
#Logowane sa zdarzenia o poziomie wiekszym lub rownym danemu
|
||||
#Hierarchia poziomow to: DEBUG<INFO<WARN<ERROR<FATAL
|
||||
#Po przecinku, rozdzielane przecinakmi appendery, moze byc ich wiecej niz jeden, wtedy logi zapisuje sie w kilka miejsc
|
||||
#Nie ma problemu, aby zapisywac np. do trzech roznych plikow i na konsole
|
||||
#Appendery rozrozniane sa po nazwach, nazwy nadajemy sami, potem wykorzystujemy je w definicji appenderow
|
||||
#
|
||||
#Ustawilem dla calosci logowanie od DEBUG w gore.
|
||||
log4j.rootLogger=DEBUG, Konsola
|
||||
#Appendery tworza hierarchie, na gorze jest rootLogger, potem loggery maja hierarchie mniej wiecej jak pakiety w javie
|
||||
#np. logger: pl
|
||||
# ^
|
||||
# / \
|
||||
# |
|
||||
# |
|
||||
# pl.edu
|
||||
# Jezeli w pliku konfiguracyjnym znajduje sie definicja np. log4j.logger.pl.wat.wcy=WARN, Konsola to zostanie ona uzyta
|
||||
# , ale jezeli jest tez definicja log4j.logger.pl.wat.wcy.au2=INFO - to wybrana bedzie ta, czyli taka, co najbardziej pasuje
|
||||
# w definicji loggera mozna podac, jaki poziom logowac, mozna tez podawac appendery, tylko tu uwaga,
|
||||
# zadzialaja wszystkie appendery w hierarchii, czyli dla konfiguracji
|
||||
# log4j.logger.pl.wat.wcy.au2=INFO, Konsola
|
||||
# log4j.logger.pl.wat.wcy=INFO, Konsola
|
||||
# zdarzenie logowania dla zdefiniowanego wczesniej logowania o poziomie, np. warn, wypisane bedzie na konsoli dwa razy
|
||||
#
|
||||
#Ustawilem dla mojego pakietu logowanie wszystkiego.
|
||||
log4j.logger.pl.wat.wcy.mip=WARN
|
||||
log4j.logger.pl.wat.wcy.db=DEBUG
|
||||
log4j.logger.pl.wat.wcy.au2krok=DEBUG
|
||||
log4j.logger.pl.wat.wcy.au2krok.JednostkaSym=TRACE
|
||||
log4j.logger.pl.wat.wcy.au2krok.JednostkaZaop=DEBUG
|
||||
log4j.logger.pl.wat.wcy.warstwy=DEBUG
|
||||
log4j.logger.pl.wat.wcy.au2=DEBUG
|
||||
#log4j.logger.pl.wat.wcy.au2.gui=DEBUG
|
||||
|
||||
#Appender zrzucajacy logi do pliku-----------------------------------------
|
||||
log4j.appender.Plik=org.apache.log4j.FileAppender
|
||||
#Od jakiego poziomu ten appender bedzie dzialac, czyli tu do pliku zapisywane beda dane o poziomie ERROR i FATAL
|
||||
log4j.appender.Plik.threshold=TRACE
|
||||
#Nazwa pliku dziennika
|
||||
#log4j.appender.XXXX.parametr=wartosc - gdzie XXXX to nazwa naszego appendera, my ja wymyslamy, obowiazuje w ramach konfiguracji w tym pliku
|
||||
log4j.appender.Plik.File=log.txt
|
||||
log4j.appender.Plik.layout=org.apache.log4j.PatternLayout
|
||||
#Format zrzucanych informacji (odsylam do manuala w kwestii definicji mozliwych do zastosowania znacznikow)
|
||||
#Uzycie niektorych znacznikow potrafi drastycznie zmniejszyc wydajnosc zapisu do dziennikow.
|
||||
log4j.appender.Plik.layout.ConversionPattern=[%-5p] %d - %m%n
|
||||
|
||||
#Appender zapisujacy dane logowania na konsole-----------------------------
|
||||
log4j.appender.Konsola=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.Konsola.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.Konsola.layout.ConversionPattern=[%-5p] %d - %m%n
|
||||
#W pliku moze byc zdefiniowana dowolna liczba appenderow, moga byc niewykorzystywane
|
||||
log4j.appender.Konsola2=org.apache.log4j.ConsoleAppender
|
||||
#log4j.appender.Konsola2.threshold=DEBUG
|
||||
log4j.appender.Konsola2.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.Konsola2.layout.ConversionPattern=[%-5p] %l - %m%n
|
||||
27
logback.xml
Normal file
27
logback.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<configuration>
|
||||
<timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<!-- <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>-->
|
||||
<pattern>%-20(%d{HH:mm:ss.SSS} [%thread]) %-5level %logger{1} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
|
||||
<file>logfile-${bySecond}.txt</file>
|
||||
<!-- <file>terrain.log</file>-->
|
||||
<append>true</append>
|
||||
<encoder>
|
||||
<!-- <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>-->
|
||||
<!-- <pattern>%-30(%d{HH:mm:ss.SSS} [%thread]) %-5level %logger{0} - %msg%n</pattern>-->
|
||||
<pattern>%-20(%d{HH:mm:ss.SSS} [%thread]) %-5level :: %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="pl.wat.ms4ds.terrain" level="debug">
|
||||
<appender-ref ref="FILE"/>
|
||||
</logger>
|
||||
|
||||
<root level="debug">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
</configuration>
|
||||
199
pom.xml
Normal file
199
pom.xml
Normal file
@@ -0,0 +1,199 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>ms4ds</groupId>
|
||||
<artifactId>teren-utils</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>nexus-homelab</id>
|
||||
<name>nexus-homelab</name>
|
||||
<url>https://nexus.rulka.pl/repository/maven-public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<javafx.version>25.0.1</javafx.version>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>${basedir}</directory>
|
||||
<includes>
|
||||
<include>*.properties</include>
|
||||
<include>logback.xml</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.14.1</version>
|
||||
<configuration>
|
||||
<source>25</source>
|
||||
<target>25</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.4.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.12.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!--/JR Generowanie aplikacji-->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>3.9.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-dependencies</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/teren/lib</outputDirectory>
|
||||
<overWriteReleases>false</overWriteReleases>
|
||||
<overWriteSnapshots>false</overWriteSnapshots>
|
||||
<overWriteIfNewer>true</overWriteIfNewer>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/teren/lib</outputDirectory>
|
||||
<archive>
|
||||
<manifest>
|
||||
<addClasspath>true</addClasspath>
|
||||
<mainClass>pl.wat.ms4ds.terrain.nmt.NmtDataProvider</mainClass>
|
||||
</manifest>
|
||||
<manifestEntries>
|
||||
<Class-Path>teren-funkcje-1.0.2-SNAPSHOT.jar</Class-Path>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.4.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-resources-runbat</id>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/teren/lib</outputDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>${basedir}</directory>
|
||||
<filtering>true</filtering>
|
||||
<includes>
|
||||
<include>*.properties</include>
|
||||
<include>*.bat</include>
|
||||
<include>*.xml</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!--/JR Generowanie aplikacji-->
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<distributionManagement>
|
||||
<snapshotRepository>
|
||||
<id>nexus-snapshots</id>
|
||||
<url>https://nexus.rulka.pl/repository/maven-snapshots/</url>
|
||||
</snapshotRepository>
|
||||
<repository>
|
||||
<id>nexus-releases</id>
|
||||
<url>https://nexus.rulka.pl/repository/maven-releases/</url>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>ms4ds</groupId>
|
||||
<artifactId>common-types</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
<version>1.5.25</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.5.25</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>2.0.17</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.nocrala</groupId>
|
||||
<artifactId>shapefilereader</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-controls</artifactId>
|
||||
<version>${javafx.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-fxml</artifactId>
|
||||
<version>${javafx.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-graphics</artifactId>
|
||||
<version>${javafx.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-swing</artifactId>
|
||||
<version>${javafx.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
336
src/main/java/pl/wat/ms4ds/terrain/AStar.java
Normal file
336
src/main/java/pl/wat/ms4ds/terrain/AStar.java
Normal file
@@ -0,0 +1,336 @@
|
||||
package pl.wat.ms4ds.terrain;
|
||||
|
||||
import pl.wat.ms4ds.common.EGeoDirection;
|
||||
import pl.wat.ms4ds.common.ERodzajDzialania;
|
||||
import pl.wat.ms4ds.common.ERodzajPodwozia;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public final class AStar {
|
||||
|
||||
private static class Node {
|
||||
|
||||
int x;
|
||||
int y;
|
||||
boolean koncowy;
|
||||
boolean zamkniety;
|
||||
double kosztOdStartu;
|
||||
double kosztZHeurystyka;
|
||||
Node poprzednik;
|
||||
EGeoDirection zKierunku;
|
||||
|
||||
private static Hashtable<Node, Node> allNodes = new Hashtable<>();
|
||||
private static Node roboczy = new Node(0, 0);
|
||||
|
||||
static Node dajAStarNode(int x, int y) {
|
||||
if (x < 0 || y < 0) {
|
||||
return null;
|
||||
}
|
||||
roboczy.x = x;
|
||||
roboczy.y = y;
|
||||
Node node = allNodes.get(roboczy);
|
||||
if (node == null) {
|
||||
node = new Node(x, y);
|
||||
allNodes.put(node, node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
ArrayList<Node> dajNiezamknietychSasiadow() {
|
||||
ArrayList<Node> wynik = new ArrayList<>();
|
||||
Node sasiad;
|
||||
sasiad = Node.dajAStarNode(this.x - 1, this.y - 1);
|
||||
if (null != sasiad && !sasiad.zamkniety)
|
||||
wynik.add(sasiad);
|
||||
sasiad = Node.dajAStarNode(this.x - 1, this.y);
|
||||
if (null != sasiad && !sasiad.zamkniety)
|
||||
wynik.add(sasiad);
|
||||
sasiad = Node.dajAStarNode(this.x - 1, this.y + 1);
|
||||
if (null != sasiad && !sasiad.zamkniety)
|
||||
wynik.add(sasiad);
|
||||
sasiad = Node.dajAStarNode(this.x, this.y - 1);
|
||||
if (null != sasiad && !sasiad.zamkniety)
|
||||
wynik.add(sasiad);
|
||||
sasiad = Node.dajAStarNode(this.x, this.y + 1);
|
||||
if (null != sasiad && !sasiad.zamkniety)
|
||||
wynik.add(sasiad);
|
||||
sasiad = Node.dajAStarNode(this.x + 1, this.y - 1);
|
||||
if (null != sasiad && !sasiad.zamkniety)
|
||||
wynik.add(sasiad);
|
||||
sasiad = Node.dajAStarNode(this.x + 1, this.y);
|
||||
if (null != sasiad && !sasiad.zamkniety)
|
||||
wynik.add(sasiad);
|
||||
sasiad = Node.dajAStarNode(this.x + 1, this.y + 1);
|
||||
if (null != sasiad && !sasiad.zamkniety)
|
||||
wynik.add(sasiad);
|
||||
return wynik;
|
||||
}
|
||||
|
||||
static void reset() {
|
||||
allNodes.clear();
|
||||
}
|
||||
|
||||
Node(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
koncowy = false;
|
||||
zamkniety = false;
|
||||
kosztOdStartu = 0.0;
|
||||
kosztZHeurystyka = Double.MAX_VALUE;
|
||||
poprzednik = null;
|
||||
zKierunku = EGeoDirection.UNDEFINED;
|
||||
}
|
||||
|
||||
Node(Coord.Grid id) {
|
||||
this(id.x, id.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AStar.Node{" +
|
||||
"x=" + x +
|
||||
", y=" + y +
|
||||
", koncowy=" + koncowy +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = prime + x;
|
||||
result = prime * result + y;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (obj instanceof Node other) {
|
||||
if (x != other.x) {
|
||||
return false;
|
||||
}
|
||||
return y == other.y;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Funkcja wyznacza drogę po sąsiednich kwadratach przechodzącą przez punkty profilujące punktyProfilujace
|
||||
*
|
||||
* @param punktyProfilujace punkty profilujące drogę (droga musi je zawierać)
|
||||
* @param staryKierunek kierunek z którego osiągnięto punkt startowy (1. punkt profilujący)
|
||||
* @param podwozie rodzaj podwozia
|
||||
* @param rodzajDzialania rodzaj działania, w ramach którego określana jest droga
|
||||
* @return uporządkowana kolekcja współrzędnych kolejnych kwadratów drogi zawierająca kwadrat startowy i docelowy lub kolekcja pusta, gdy nie istnieje droga
|
||||
*/
|
||||
public static ArrayList<Coord.Grid> wyznaczDroge(Coord.Grid[] punktyProfilujace, EGeoDirection staryKierunek,
|
||||
ERodzajPodwozia podwozie, ERodzajDzialania rodzajDzialania) {
|
||||
if (null == punktyProfilujace || 0 == punktyProfilujace.length) {
|
||||
return null;
|
||||
}
|
||||
Node.reset();
|
||||
ArrayList<Coord.Grid> wynik = new ArrayList<>();
|
||||
Coord.Grid start;
|
||||
Coord.Grid stop = punktyProfilujace[0];
|
||||
ArrayList<Coord.Grid> odcinek;
|
||||
for (int i = 1; i < punktyProfilujace.length; i++) {
|
||||
start = stop;
|
||||
stop = punktyProfilujace[i];
|
||||
EGeoDirection staryKier;
|
||||
if (wynik.size() > 1) {
|
||||
staryKier = GeomUtils.kierunekDlaSasiada(wynik.get(wynik.size() - 2), wynik.get(wynik.size() - 1));
|
||||
} else {
|
||||
staryKier = staryKierunek;
|
||||
}
|
||||
if (i == 1) {
|
||||
odcinek = wyznaczDroge(start, stop, staryKier, true, podwozie, rodzajDzialania);
|
||||
} else {
|
||||
odcinek = wyznaczDroge(start, stop, staryKier, false, podwozie, rodzajDzialania);
|
||||
}
|
||||
if (odcinek.isEmpty()) {
|
||||
// gdy nie istnieje droga między danymi punktami profilującymi, to zwracam kolekcję pustą
|
||||
return odcinek;
|
||||
}
|
||||
wynik.addAll(odcinek);
|
||||
Node.reset();
|
||||
}
|
||||
return wynik;
|
||||
}
|
||||
|
||||
/**
|
||||
* Funkcja wyznacza drogę po sąsiednich kwadratach od kwadratu startowego start do docelowego stop
|
||||
*
|
||||
* @param start współrzędne kwadratu startowego
|
||||
* @param stop współrzędne kwadratu docelowego
|
||||
* @param staryKierunek kierunek z którego osiągnięto punkt startowy (1. punkt profilujący)
|
||||
* @param podwozie rodzaj podwozia
|
||||
* @param rodzajDzialania rodzaj działania, w ramach którego określana jest droga
|
||||
* @param zawieraStartowy parametr wskazujący, czy wyznaczona droga ma zawierać kwadrat startowy
|
||||
* @return uporządkowana kolekcja współrzędnych kolejnych kwadratów drogi zawierająca kwadrat startowy (jeśli zawieraStartowy==true) i docelowy lub kolekcja pusta, gdy nie istnieje droga
|
||||
*/
|
||||
public static ArrayList<Coord.Grid> wyznaczDroge(Coord.Grid start, Coord.Grid stop, EGeoDirection staryKierunek,
|
||||
boolean zawieraStartowy, ERodzajPodwozia podwozie, ERodzajDzialania rodzajDzialania) {
|
||||
|
||||
PriorityQueue<Node> listaOtwarta = new PriorityQueue<>(100, (o1, o2) -> Double.compare(o1.kosztZHeurystyka, o2.kosztZHeurystyka));
|
||||
boolean naPrzelaj = false;
|
||||
switch (rodzajDzialania) {
|
||||
case DZIALANIE_ATAK:
|
||||
case DZIALANIE_MAGIC_MOVEMENT:
|
||||
case DZIALANIE_OBRONA:
|
||||
case DZIALANIE_OPL:
|
||||
case DZIALANIE_WRIA:
|
||||
case DZIALANIE_ROZMIESZCZENIE:
|
||||
case DZIALANIE_ZESRODKOWANIE:
|
||||
case DZIALANIE_MINOWANIE:
|
||||
naPrzelaj = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
Node aktualny = Node.dajAStarNode(stop.x, stop.y);
|
||||
aktualny.koncowy = true;
|
||||
ArrayList<Node> sasiedzi;
|
||||
aktualny = Node.dajAStarNode(start.x, start.y);
|
||||
aktualny.zKierunku = staryKierunek;
|
||||
listaOtwarta.add(aktualny);
|
||||
ArrayList<Coord.Grid> wynik = new ArrayList<Coord.Grid>();
|
||||
int licznik_zabezpieczajacy = 200000;
|
||||
while (listaOtwarta.size() > 0 && licznik_zabezpieczajacy-- > 0) {
|
||||
aktualny = listaOtwarta.remove();
|
||||
if (aktualny.koncowy) {
|
||||
while (null != aktualny) {
|
||||
wynik.add(new Coord.Grid(aktualny.x, aktualny.y));
|
||||
aktualny = aktualny.poprzednik;
|
||||
}
|
||||
if (!zawieraStartowy) {
|
||||
//Usuwam poczatek drogi
|
||||
wynik.remove(wynik.size() - 1);
|
||||
}
|
||||
Collections.reverse(wynik);
|
||||
return wynik;
|
||||
}
|
||||
sasiedzi = aktualny.dajNiezamknietychSasiadow();
|
||||
for (Node sasiad : sasiedzi) {
|
||||
// double stopienPrzejezdnosci = Teren.getStopienPrzejezdnosci(aktualny.x, aktualny.y, sasiad.x, sasiad.y,
|
||||
// aktualny.zKierunku, podwozie);
|
||||
double stopienPrzejezdnosci = 1;
|
||||
if (stopienPrzejezdnosci < 0.005f) {
|
||||
continue;
|
||||
}
|
||||
if (naPrzelaj) {
|
||||
stopienPrzejezdnosci = Math.max(Teren.minStopienPrzejezdNaPrzelaj, stopienPrzejezdnosci);
|
||||
}
|
||||
double nowyKosztOdStartu = aktualny.kosztOdStartu + Coord.Grid.distance(aktualny.x, aktualny.y, sasiad.x, sasiad.y) / stopienPrzejezdnosci;
|
||||
double nowyKosztZHeurystyka = nowyKosztOdStartu + Coord.Grid.distance(sasiad.x, sasiad.y, stop.x, stop.y);
|
||||
if (sasiad.kosztZHeurystyka > nowyKosztZHeurystyka) {
|
||||
//UPDATE kosztow i zmiany w kolejce
|
||||
sasiad.kosztOdStartu = nowyKosztOdStartu;
|
||||
sasiad.kosztZHeurystyka = nowyKosztZHeurystyka;
|
||||
sasiad.poprzednik = aktualny;
|
||||
sasiad.zKierunku = GeomUtils.kierunekDlaSasiada(aktualny.x, aktualny.y, sasiad.x, sasiad.y);
|
||||
listaOtwarta.remove(sasiad);
|
||||
listaOtwarta.add(sasiad);
|
||||
}
|
||||
}
|
||||
aktualny.zamkniety = true;
|
||||
}
|
||||
return wynik;
|
||||
}
|
||||
|
||||
/**
|
||||
* Funkcja wyznacza drogę po sąsiednich kwadratach od kwadratu startowego start do docelowego stop
|
||||
*
|
||||
* @param start współrzędne kwadratu startowego
|
||||
* @param stop współrzędne kwadratu docelowego
|
||||
* @param staryKierunek kierunek z którego osiągnięto punkt startowy (1. punkt profilujący)
|
||||
* @param podwozie rodzaj podwozia
|
||||
* @param rodzajDzialania rodzaj działania, w ramach którego określana jest droga
|
||||
* @param zawieraStartowy parametr wskazujący, czy wyznaczona droga ma zawierać kwadrat startowy
|
||||
* @return uporządkowana kolekcja współrzędnych kolejnych kwadratów drogi zawierająca kwadrat startowy (jeśli zawieraStartowy==true) i docelowy lub kolekcja pusta, gdy nie istnieje droga
|
||||
*/
|
||||
public static ArrayList<Coord.Grid> wyznaczDrogeNew(Coord.Grid start, Coord.Grid stop, EGeoDirection staryKierunek,
|
||||
boolean zawieraStartowy, ERodzajPodwozia podwozie,
|
||||
ERodzajDzialania rodzajDzialania,
|
||||
double szerokoscPokonywRowow,
|
||||
double glebokoscBrodzenia,
|
||||
double predkoscPlywania) {
|
||||
PriorityQueue<Node> listaOtwarta = new PriorityQueue<>(100, new Comparator<Node>() {
|
||||
public int compare(Node o1, Node o2) {
|
||||
return Double.compare(o1.kosztZHeurystyka, o2.kosztZHeurystyka);
|
||||
}
|
||||
});
|
||||
// PriorityQueue<AStarNode> listaOtwarta = new PriorityQueue<>(100, (AStarNode o1, AStarNode o2) -> Double.compare(o1.kosztZHeurystyka, o2.kosztZHeurystyka));
|
||||
boolean naPrzelaj = false;
|
||||
switch (rodzajDzialania) {
|
||||
case DZIALANIE_ATAK:
|
||||
case DZIALANIE_MAGIC_MOVEMENT:
|
||||
case DZIALANIE_OBRONA:
|
||||
case DZIALANIE_OPL:
|
||||
case DZIALANIE_WRIA:
|
||||
case DZIALANIE_ROZMIESZCZENIE:
|
||||
case DZIALANIE_ZESRODKOWANIE:
|
||||
case DZIALANIE_MINOWANIE:
|
||||
naPrzelaj = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
Node aktualny = Node.dajAStarNode(stop.x, stop.y);
|
||||
aktualny.koncowy = true;
|
||||
ArrayList<Node> sasiedzi;
|
||||
aktualny = Node.dajAStarNode(start.x, start.y);
|
||||
aktualny.zKierunku = staryKierunek;
|
||||
listaOtwarta.add(aktualny);
|
||||
ArrayList<Coord.Grid> wynik = new ArrayList<Coord.Grid>();
|
||||
int licznik_zabezpieczajacy = 200000;
|
||||
while (listaOtwarta.size() > 0 && licznik_zabezpieczajacy-- > 0) {
|
||||
aktualny = listaOtwarta.remove();
|
||||
if (aktualny.koncowy) {
|
||||
while (null != aktualny) {
|
||||
wynik.add(new Coord.Grid(aktualny.x, aktualny.y));
|
||||
aktualny = aktualny.poprzednik;
|
||||
}
|
||||
if (!zawieraStartowy) {
|
||||
//Usuwam poczatek drogi
|
||||
wynik.remove(wynik.size() - 1);
|
||||
}
|
||||
Collections.reverse(wynik);
|
||||
return wynik;
|
||||
}
|
||||
sasiedzi = aktualny.dajNiezamknietychSasiadow();
|
||||
for (Node sasiad : sasiedzi) {
|
||||
// double stopienPrzejezdnosci = Teren.getStopienPrzejezdnosciNew(aktualny.x, aktualny.y, sasiad.x, sasiad.y,
|
||||
// aktualny.zKierunku, podwozie, szerokoscPokonywRowow, glebokoscBrodzenia, predkoscPlywania);
|
||||
double stopienPrzejezdnosci = 1;
|
||||
if (stopienPrzejezdnosci < 0.005f) {
|
||||
continue;
|
||||
}
|
||||
if (naPrzelaj) {
|
||||
stopienPrzejezdnosci = Math.max(Teren.minStopienPrzejezdNaPrzelaj, stopienPrzejezdnosci);
|
||||
}
|
||||
double nowyKosztOdStartu = aktualny.kosztOdStartu + Coord.Grid.distance(aktualny.x, aktualny.y, sasiad.x, sasiad.y) / stopienPrzejezdnosci;
|
||||
double nowyKosztZHeurystyka = nowyKosztOdStartu + Coord.Grid.distance(sasiad.x, sasiad.y, stop.x, stop.y);
|
||||
if (sasiad.kosztZHeurystyka > nowyKosztZHeurystyka) {
|
||||
//UPDATE kosztow i zmiany w kolejce
|
||||
sasiad.kosztOdStartu = nowyKosztOdStartu;
|
||||
sasiad.kosztZHeurystyka = nowyKosztZHeurystyka;
|
||||
sasiad.poprzednik = aktualny;
|
||||
sasiad.zKierunku = GeomUtils.kierunekDlaSasiada(aktualny.x, aktualny.y, sasiad.x, sasiad.y);
|
||||
listaOtwarta.remove(sasiad);
|
||||
listaOtwarta.add(sasiad);
|
||||
}
|
||||
}
|
||||
aktualny.zamkniety = true;
|
||||
}
|
||||
return wynik;
|
||||
}
|
||||
|
||||
}
|
||||
198
src/main/java/pl/wat/ms4ds/terrain/AltitudeColorMapper.java
Normal file
198
src/main/java/pl/wat/ms4ds/terrain/AltitudeColorMapper.java
Normal file
@@ -0,0 +1,198 @@
|
||||
package pl.wat.ms4ds.terrain;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class AltitudeColorMapper {
|
||||
|
||||
// Define the color stops and corresponding normalized values (0.0 to 1.0)
|
||||
private static final float[] STOPS = {0.0f, 0.1f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f};
|
||||
private static final Color[] COLORS2 = {
|
||||
new Color(0, 0, 64), // Dark Navy Blue
|
||||
new Color(0, 64, 204), // Medium Blue
|
||||
new Color(51, 204, 51), // Bright Green
|
||||
new Color(255, 255, 128),// Yellow
|
||||
new Color(228, 96, 0), // Orange
|
||||
new Color(96, 0, 0), // Red
|
||||
new Color(158, 110, 110),
|
||||
new Color(220, 220, 220), // Red
|
||||
Color.WHITE // White
|
||||
};
|
||||
private static final Color[] COLORS = {
|
||||
new Color(40, 0, 40),
|
||||
|
||||
// new Color(20, 0, 60),
|
||||
|
||||
new Color(0, 0, 80), // DARK BLUE
|
||||
|
||||
// new Color(0, 0, 160),
|
||||
// new Color(0, 0, 200),
|
||||
|
||||
new Color(0, 0, 255), // BLUE
|
||||
|
||||
// new Color(0, 80, 255),
|
||||
// new Color(0, 160, 255),
|
||||
// new Color(0, 200, 255),
|
||||
|
||||
new Color(0, 255, 255),
|
||||
|
||||
// new Color(0, 255, 200),
|
||||
//
|
||||
// new Color(0, 255, 160),
|
||||
|
||||
new Color(0, 255, 0), // GREEN
|
||||
|
||||
// new Color(80, 255, 0),
|
||||
|
||||
// new Color(80, 160, 20),
|
||||
|
||||
// new Color(120, 255, 0),
|
||||
|
||||
// new Color(200, 255, 0),
|
||||
|
||||
new Color(255, 255, 0), // YELLOW
|
||||
|
||||
// new Color(255, 200, 0),
|
||||
// new Color(255, 120, 0),
|
||||
// new Color(255, 60, 0),
|
||||
|
||||
new Color(255, 0, 0), // RED
|
||||
|
||||
// new Color(120, 0, 0),
|
||||
|
||||
new Color(40, 0, 0), // DARK RED
|
||||
|
||||
// new Color(80, 40, 40),
|
||||
// new Color(120, 60, 60),
|
||||
// new Color(160, 100, 100),
|
||||
// new Color(200, 140, 140),
|
||||
|
||||
// new Color(220, 180, 180),
|
||||
new Color(255, 215, 215),
|
||||
|
||||
Color.WHITE // White
|
||||
};
|
||||
|
||||
/**
|
||||
* RGB value representing the color in the default sRGB ColorModel.
|
||||
* Bits 24-31 are alpha, 16-23 are red, 8-15 are green, 0-7 are blue.
|
||||
* value = ((a & 0xFF) << 24) |
|
||||
* ((r & 0xFF) << 16) |
|
||||
* ((g & 0xFF) << 8) |
|
||||
* ((b & 0xFF) << 0);
|
||||
*/
|
||||
private static final int[] COLORS_RGB = new int[7];
|
||||
|
||||
// static {
|
||||
// Color c = new Color(0x37004E);
|
||||
// int v = 0x37004E;
|
||||
// int a = 0;
|
||||
// int r = 0;
|
||||
// int g = 0;
|
||||
// int b = 50;
|
||||
// int value = ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | ((b & 0xFF) << 0);
|
||||
// COLORS_RGB[0] = value;
|
||||
// a = 0;
|
||||
// r = 0;
|
||||
// g = 0;
|
||||
// b = 0;
|
||||
// value = ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | ((b & 0xFF) << 0);
|
||||
// COLORS_RGB[0] = value;
|
||||
// }
|
||||
|
||||
private static final Color[] gamaKolorow;
|
||||
|
||||
static {
|
||||
Color[] gamaKolorowTemp = new Color[2000];
|
||||
int i = 0;
|
||||
int r = 40;
|
||||
int g = 0;
|
||||
int b = 40;
|
||||
gamaKolorowTemp[i++] = new Color(r, g, b, 255);
|
||||
for (int j = 0; j < 40; j++) {
|
||||
// r: 40->0, g:0, b: 40->80
|
||||
r--;
|
||||
b++;
|
||||
gamaKolorowTemp[i++] = new Color(r, g, b, 255);
|
||||
}
|
||||
for (int j = 0; j < 175; j++) {
|
||||
// r: 0, g:0, b: 80->255
|
||||
b++;
|
||||
gamaKolorowTemp[i++] = new Color(r, g, b, 255);
|
||||
}
|
||||
for (int j = 0; j < 255; j++) {
|
||||
// r: 0, g:1->255, b: 255
|
||||
g++;
|
||||
gamaKolorowTemp[i++] = new Color(r, g, b, 255);
|
||||
}
|
||||
for (int j = 0; j < 255; j++) {
|
||||
// r: 0, g:255, b: 254->0
|
||||
b--;
|
||||
gamaKolorowTemp[i++] = new Color(r, g, b, 255);
|
||||
}
|
||||
for (int j = 0; j < 255; j++) {
|
||||
// r: 1->255, g:255, b: 0
|
||||
r++;
|
||||
gamaKolorowTemp[i++] = new Color(r, g, b, 255);
|
||||
}
|
||||
for (int j = 0; j < 255; j++) {
|
||||
// r: 255, g:254->0, b: 0
|
||||
g--;
|
||||
gamaKolorowTemp[i++] = new Color(r, g, b, 255);
|
||||
}
|
||||
for (int j = 0; j < 215; j++) {
|
||||
// r: 254->40, g: 0, b: 0
|
||||
r--;
|
||||
gamaKolorowTemp[i++] = new Color(r, g, b, 255);
|
||||
}
|
||||
for (int j = 0; j < 215; j++) {
|
||||
// r: 41->255, g: 0->215, b: 0->215
|
||||
r++;
|
||||
g++;
|
||||
b++;
|
||||
gamaKolorowTemp[i++] = new Color(r, g, b, 255);
|
||||
}
|
||||
gamaKolorow = Arrays.copyOf(gamaKolorowTemp, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the color corresponding to a given altitude value within a specified range.
|
||||
*
|
||||
* @param value The altitude value.
|
||||
* @param minValue The minimum possible altitude.
|
||||
* @param maxValue The maximum possible altitude.
|
||||
* @return The interpolated color.
|
||||
*/
|
||||
public static Color getColorForAltitude(double value, double minValue, double maxValue) {
|
||||
// Normalize the value to a 0.0 to 1.0 range
|
||||
double normalizedValue = (value - minValue) / (maxValue - minValue);
|
||||
|
||||
if (normalizedValue <= 0.0) return COLORS[0];
|
||||
if (normalizedValue >= 1.0) return COLORS[COLORS.length - 1];
|
||||
|
||||
// Find the correct interval in the color stops array
|
||||
int stopIndex = 0;
|
||||
while (stopIndex < STOPS.length - 1 && normalizedValue > STOPS[stopIndex + 1]) {
|
||||
stopIndex++;
|
||||
}
|
||||
|
||||
// Interpolate between the two nearest colors
|
||||
float start = STOPS[stopIndex];
|
||||
float end = STOPS[stopIndex + 1];
|
||||
float range = end - start;
|
||||
float fraction = (float) ((normalizedValue - start) / range);
|
||||
|
||||
Color c1 = COLORS[stopIndex];
|
||||
Color c2 = COLORS[stopIndex + 1];
|
||||
|
||||
int r = (int) (c1.getRed() + (c2.getRed() - c1.getRed()) * fraction);
|
||||
int g = (int) (c1.getGreen() + (c2.getGreen() - c1.getGreen()) * fraction);
|
||||
int b = (int) (c1.getBlue() + (c2.getBlue() - c1.getBlue()) * fraction);
|
||||
|
||||
return new Color(r, g, b);
|
||||
}
|
||||
|
||||
static void main() {
|
||||
Color c = gamaKolorow[0];
|
||||
}
|
||||
}
|
||||
18
src/main/java/pl/wat/ms4ds/terrain/BigSquare.java
Normal file
18
src/main/java/pl/wat/ms4ds/terrain/BigSquare.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package pl.wat.ms4ds.terrain;
|
||||
|
||||
|
||||
import javafx.scene.image.ImageView;
|
||||
|
||||
abstract class BigSquare {
|
||||
abstract Square getSquare(int x, int y);
|
||||
|
||||
protected transient String fileName;
|
||||
public int idX = 0;
|
||||
public int idY = 0;
|
||||
public transient int liczbaZmian = 0;
|
||||
// TODO zamienic na 100
|
||||
static final int LICZBA_ZMIAN_DO_ZAPISU = 100000;
|
||||
public ImageView imageView = null;
|
||||
|
||||
|
||||
}
|
||||
529
src/main/java/pl/wat/ms4ds/terrain/Coord.java
Normal file
529
src/main/java/pl/wat/ms4ds/terrain/Coord.java
Normal file
@@ -0,0 +1,529 @@
|
||||
package pl.wat.ms4ds.terrain;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class Coord {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(Coord.class);
|
||||
|
||||
public static class Geo {
|
||||
public double lat;
|
||||
public double lon;
|
||||
|
||||
public Geo() {
|
||||
}
|
||||
|
||||
public Geo(double lat, double lon) {
|
||||
this.lat = lat;
|
||||
this.lon = lon;
|
||||
}
|
||||
|
||||
public Geo(Geo other) {
|
||||
lat = other.lat;
|
||||
lon = other.lon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Geo{" + "lat=" + lat + ", lon=" + lon + '}';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Współrzędne punktu odwzorowania kartograficznego PUWG 1992.
|
||||
* <p>
|
||||
* Wartości współrzędnych [metry].
|
||||
*
|
||||
*/
|
||||
public static class Puwg {
|
||||
/**
|
||||
* Współrzędna X (oś odcietych) odwzorowania kartograficznego [metry].
|
||||
*/
|
||||
public double easting;
|
||||
/**
|
||||
* Współrzędna Y (oś rzędnych) odwzorowania kartograficznego [metry].
|
||||
*/
|
||||
public double northing;
|
||||
|
||||
public Puwg() {
|
||||
this.easting = 0;
|
||||
this.northing = 0;
|
||||
}
|
||||
|
||||
public Puwg(double easting, double northing) {
|
||||
this.easting = easting;
|
||||
this.northing = northing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Puwg{" + "easting=" + easting + ", northing=" + northing + '}';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Klasa reprezentująca współrzędne/położenie w siatce kwadratów terenu.
|
||||
*
|
||||
*/
|
||||
public static class Grid {
|
||||
|
||||
/**
|
||||
* Współrzędna pozioma (oś OX) w siatce kwadratów. Indeks kolumny.
|
||||
*/
|
||||
public int x;
|
||||
/**
|
||||
* Współrzędna pionowa (oś OY) w siatce kwadratów. Indeks wiersza.
|
||||
*/
|
||||
public int y;
|
||||
|
||||
/**
|
||||
* Konstruktor klasy na bazie współrzędnych geograficznych.
|
||||
*
|
||||
* @param lon długość geograficzna
|
||||
* @param lat szerokość geograficzna
|
||||
*/
|
||||
public Grid(double lon, double lat) {
|
||||
double xms_f = (lon + 180) * MapConsts.DEG_MS;
|
||||
long xms = (long) xms_f;
|
||||
x = zamienWspXmsNaIdKwadratuX(xms);
|
||||
|
||||
double yms_f = (lat + 90) * MapConsts.DEG_MS;
|
||||
long yms = (long) yms_f;
|
||||
y = zamienWspYmsNaIdKwadratuY(yms);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Grid{" + "x=" + x + ", y=" + y + '}';
|
||||
}
|
||||
|
||||
private static final double ODWROT_SS_DX_MS = 1.0 / MapConsts.SS_DELTA_LON_MS;
|
||||
private static final double ODWROT_SS_DY_MS = 1.0 / MapConsts.SS_DELTA_LAT_MS;
|
||||
|
||||
public static double distance(Grid a, Grid b) {
|
||||
int dx = a.x - b.x;
|
||||
int dy = a.y - b.y;
|
||||
return Math.sqrt(dx * dx + dy * dy) * MapConsts.SS_SIZE;
|
||||
}
|
||||
|
||||
public static double distance(int x1, int y1, int x2, int y2) {
|
||||
int dx = x2 - x1;
|
||||
int dy = y2 - y1;
|
||||
return Math.sqrt(dx * dx + dy * dy) * MapConsts.SS_SIZE;
|
||||
}
|
||||
|
||||
private static final float DL_MK2 = MapConsts.SS_SIZE * 0.0009765625f;
|
||||
|
||||
/**
|
||||
* Funkcja zwraca aproksymowaną odległość między środkami małych kwadratów [m].
|
||||
*
|
||||
* @param x1 Wsp X id malego kwadratu pocz.
|
||||
* @param y1 Wsp Y id malego kwadratu pocz.
|
||||
* @param x2 Wsp X id malego kwadratu konc.
|
||||
* @param y2 Wsp Y id malego kwadratu konc.
|
||||
* @return Odległość miedzy srodkami malych kwadratow [m].
|
||||
*/
|
||||
public static float distanceApprox(int x1, int y1, int x2, int y2) {
|
||||
int dx = x2 - x1;
|
||||
int dy = y2 - y1;
|
||||
int min, max, approx;
|
||||
if (dx < 0) dx = -dx;
|
||||
if (dy < 0) dy = -dy;
|
||||
if (dx < dy) {
|
||||
min = dx;
|
||||
max = dy;
|
||||
} else {
|
||||
min = dy;
|
||||
max = dx;
|
||||
}
|
||||
approx = (max * 1007) + (min * 441);
|
||||
if (max < (min << 4)) {
|
||||
approx -= (max * 40);
|
||||
}
|
||||
float odl = approx * DL_MK2;
|
||||
return odl;
|
||||
}
|
||||
|
||||
public Grid() {
|
||||
x = -1;
|
||||
y = -1;
|
||||
}
|
||||
|
||||
public Grid(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public Grid(Grid orig) {
|
||||
this.x = orig.x;
|
||||
this.y = orig.y;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(int y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public void set(Grid orig) {
|
||||
x = orig.x;
|
||||
y = orig.y;
|
||||
}
|
||||
|
||||
public void set(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object o) {
|
||||
if (!(o instanceof Grid grid)) return false;
|
||||
|
||||
return x == grid.x && y == grid.y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
int result = x;
|
||||
result = 31 * result + y;
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Zamienia współrzęną GridCoord.x na długość geograficzną środka małego kwadratu
|
||||
*
|
||||
* @param idX współrzęna x GridCoord
|
||||
* @return długość geograficzna
|
||||
*/
|
||||
public static float convertGridXToLon(int idX) {
|
||||
long xms = zamienIdKwadratuXNaWspXms(idX);
|
||||
double lon = (double) xms / (double) MapConsts.DEG_MS - 180;
|
||||
return (float) lon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zamienia współrzęną GridCoord.y na szerokość geograficzną środka małego kwadratu
|
||||
*
|
||||
* @param idY współrzęna y GridCoord
|
||||
* @return szerokość geograficzna
|
||||
*/
|
||||
public static float covertGridYToLat(int idY) {
|
||||
long yms = zamienIdKwadratuYNaWspYms(idY);
|
||||
double lat = (double) yms / (double) MapConsts.DEG_MS - 90;
|
||||
return (float) lat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Funkcja zamienia wsp. X GridCoord na wsp. geo xms w milisekundach.
|
||||
* Zwracana wspolrzedna lezy w srodku kwadratu.
|
||||
*/
|
||||
public static long zamienIdKwadratuXNaWspXms(int idKwX) {
|
||||
// indeksowanie kwadratow pola walki zaczyna sie od (0, 0)
|
||||
// przesuniecie wspolrzednych do srodka kwadratu
|
||||
long xms = MapConsts.X_REF_MS + (long) ((idKwX + 0.5) * MapConsts.SS_DELTA_LON_MS);
|
||||
xms %= MapConsts.ANGLE_360_MS;
|
||||
return xms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Funkcja zamienia wsp. Y GridCoord na wsp. geo yms w milisekundach.
|
||||
* Zwracana wspolrzedna lezy w srodku kwadratu.
|
||||
*/
|
||||
public static long zamienIdKwadratuYNaWspYms(int idKwY) {
|
||||
// indeksowanie kwadratow pola walki zaczyna sie od (0, 0)
|
||||
// przesuniecie wspolrzednych do srodka kwadratu
|
||||
long yms = MapConsts.Y_REF_MS + (long) ((idKwY + 0.5) * MapConsts.SS_DELTA_LAT_MS);
|
||||
return yms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zamienia długość geograficzną na współrzędna x Coord.Grid.
|
||||
*
|
||||
* @param lon długość geograficzna
|
||||
* @return współrzędna x klasy GridCoord
|
||||
*/
|
||||
public static int convertLonToGridX(double lon) {
|
||||
double xms_f = (lon + 180) * MapConsts.DEG_MS;
|
||||
return zamienWspXmsNaIdKwadratuX((long) xms_f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zamienia szerokość geograficzną na współrzędna y Coord.Grid.
|
||||
*
|
||||
* @param lat szerokość geograficzna
|
||||
* @return współrzędna y klasy GridCoord
|
||||
*/
|
||||
public static int convertLatToGridY(double lat) {
|
||||
double yms_f = (lat + 90) * MapConsts.DEG_MS;
|
||||
return zamienWspYmsNaIdKwadratuY((long) yms_f);
|
||||
}
|
||||
|
||||
public static final double INVERT_SS_DELTA_LON = 1 / MapConsts.SS_DELTA_LON;
|
||||
public static final double INVERT_SS_DELTA_LAT = 1 / MapConsts.SS_DELTA_LAT;
|
||||
|
||||
private static final double REF_LON_OFFSET = 180 - MapConsts.REF_LON;
|
||||
private static final double REF_LAT_OFFSET = 90 - MapConsts.REF_LAT;
|
||||
|
||||
/**
|
||||
* Zamienia długość geograficzną w systemie WGS-84 na współrzędna x klasy {@link Grid}.
|
||||
*
|
||||
* @param lon długość geograficzna
|
||||
* @return współrzędna x klasy GridCoord
|
||||
*/
|
||||
public static int convertLonToGridX2(double lon) {
|
||||
double xx = (lon + REF_LON_OFFSET) * INVERT_SS_DELTA_LON;
|
||||
return (int) xx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zamienia szerokość geograficzną w systemie WGS-84 na współrzędna y klasy {@link Grid}.
|
||||
*
|
||||
* @param lat szerokość geograficzna
|
||||
* @return współrzędna y klasy GridCoord
|
||||
*/
|
||||
public static int convertLatToGridY2(double lat) {
|
||||
double yy = (lat + REF_LAT_OFFSET) * INVERT_SS_DELTA_LAT;
|
||||
return (int) yy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Funkcja zamienia dlugosc geog. xms w milisekundach na IdKwadrat.x.
|
||||
*
|
||||
* @param xms długość geograficzna (lon) w milisekundach
|
||||
* @return współrzędna GridCoord.x
|
||||
*/
|
||||
public static int zamienWspXmsNaIdKwadratuX(long xms) {
|
||||
// wspolrzedne geograficzne w milisekundach zawieraja sie w zakresie:
|
||||
// 0 <= x < 360 dlugosc geograficzna
|
||||
// 0 <= y <= 180 szerokosc geograficzna
|
||||
if (xms >= MapConsts.ANGLE_360_MS) {
|
||||
// poza zakresem
|
||||
return -1;
|
||||
}
|
||||
long x = xms;
|
||||
if (x < MapConsts.X_REF_MS) {
|
||||
// // poza zakresem
|
||||
long dx = x + MapConsts.ANGLE_360_MS - MapConsts.X_REF_MS;
|
||||
if (dx > MapConsts.DX_REF_MS) {
|
||||
return -1;
|
||||
}
|
||||
x += MapConsts.ANGLE_360_MS;
|
||||
}
|
||||
// if (x > MapConsts.X_REF_MS + MapConsts.DX_REF_MS) {
|
||||
// // poza zakresem
|
||||
// return -1;
|
||||
// }
|
||||
// indeksowanie kwadratow pola walki zaczyna sie od (0, 0)
|
||||
double xx = (x - MapConsts.X_REF_MS) * INVERT_SS_DELTA_LON_MS;
|
||||
// x = (x - MapConsts.X_REF_MS) / MapConsts.SS_DX_MS;
|
||||
return (int) xx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Funkcja zamienia szerokosc geog. yms w milisekundach na IdKwadrat.y.
|
||||
*
|
||||
* @param yms szerokosc geograficzna (lat) w milisekundach
|
||||
* @return współrzędna GridCoord.y
|
||||
*/
|
||||
public static int zamienWspYmsNaIdKwadratuY(long yms) {
|
||||
// wspolrzedne geograficzne w milisekundach zawieraja sie w zakresie:
|
||||
// 0 <= x < 360 dlugosc geograficzna
|
||||
// 0 <= y <= 180 szerokosc geograficzna
|
||||
if (yms < MapConsts.Y_REF_MS) {
|
||||
// poza zakresem
|
||||
return -1;
|
||||
}
|
||||
// indeksowanie kwadratow pola walki zaczyna sie od (0, 0)
|
||||
double yy = (yms - MapConsts.Y_REF_MS) * INVERT_SS_DELTA_LAT_MS;
|
||||
// long y = (yms - MapConsts.Y_REF_MS) / MapConsts.SS_DY_MS;
|
||||
return (int) yy;
|
||||
}
|
||||
|
||||
private static final double INVERT_SS_DELTA_LON_MS = 1.0 / MapConsts.SS_DELTA_LON_MS;
|
||||
private static final double INVERT_SS_DELTA_LAT_MS = 1.0 / MapConsts.SS_DELTA_LAT_MS;
|
||||
|
||||
/**
|
||||
* Funkcja służy do konwersji współrzednych elipsoidalnych WGS84 (lat/lon) na płaskie X-northing, Y-easting
|
||||
* odwzorowania kartograficznego 1992.
|
||||
*
|
||||
* @param puwgCoord współrzędne PUWG1992 (easting, northing) [metry]
|
||||
* @param lat szerokość geograficzna WSG-84 [stopnie dziesiętnie]
|
||||
* @param lon długość geograficzna WSG-84 [stopnie dziesiętnie]
|
||||
*/
|
||||
public static void convertWGS84ToPUWG1992(double lat, double lon, Coord.Puwg puwgCoord) {
|
||||
if (lon < 13.5 || lon > 25.5) {
|
||||
//Błędna wartość długości geograficznej (zwracana wartość 999999999999999)
|
||||
puwgCoord.easting = 999999999999999.0;
|
||||
puwgCoord.northing = 999999999999999.0;
|
||||
return;
|
||||
}
|
||||
double latRad = Math.toRadians(lat);
|
||||
double dlam = Math.toRadians(lon - 19.0);
|
||||
double dlam_pow_2 = dlam * dlam;
|
||||
double dlam_pow_3 = dlam_pow_2 * dlam;
|
||||
double dlam_pow_4 = dlam_pow_3 * dlam;
|
||||
double s = Math.sin(latRad);
|
||||
double c = Math.cos(latRad);
|
||||
double c_pow_2 = c * c;
|
||||
double c_pow_3 = c_pow_2 * c;
|
||||
double c_pow_4 = c_pow_3 * c;
|
||||
double t = s / c;
|
||||
double t_pow_2 = t * t;
|
||||
double t_pow_3 = t_pow_2 * t;
|
||||
double t_pow_4 = t_pow_3 * t;
|
||||
double t_pow_5 = t_pow_4 * t;
|
||||
double eta = E2_SQUARED * c_pow_2;
|
||||
double eta_pow_2 = eta * eta;
|
||||
double eta_pow_3 = eta_pow_2 * eta;
|
||||
double eta_pow_4 = eta_pow_3 * eta;
|
||||
double sn = sphsn(latRad);
|
||||
double tmd = sphtmd(latRad);
|
||||
double t1, t2, t3, t4, t5;
|
||||
t1 = tmd * OK;
|
||||
double sns = sn * s;
|
||||
t2 = sns * c * OK / 2.0;
|
||||
t3 = sns * c_pow_3 * OK * (5.0 - t_pow_2 + 9.0 * eta + 4.0 * eta_pow_2) / 24.0;
|
||||
t4 = sns * c_pow_4 * c * OK * (61.0 - 58.0 * t_pow_2 + t_pow_4 + 270.0 * eta - 330.0 * t_pow_2 * eta + 445.0 * eta_pow_2 + 324.0 * eta_pow_3 - 680.0 * t_pow_2 * eta_pow_2 + 88.0 * eta_pow_4 - 600.0 * t_pow_2 * eta_pow_3 - 192.0 * t_pow_2 * eta_pow_4) / 720.0;
|
||||
t5 = sns * c_pow_4 * c_pow_3 * OK * (1385.0 - 3111.0 * t_pow_2 + 543.0 * t_pow_4 - t_pow_5 * t) / 40320.0;
|
||||
puwgCoord.northing = -5300000.0 + t1 + dlam_pow_2 * t2 + dlam_pow_4 * t3 + dlam_pow_4 * dlam_pow_2 * t4 + dlam_pow_4 * dlam_pow_4 * t5;
|
||||
t1 = sn * c * OK;
|
||||
t2 = sn * c_pow_3 * OK * (1.0 - t_pow_2 + eta) / 6.0;
|
||||
t3 = sn * c_pow_4 * c * OK * (5.0 - 18.0 * t_pow_2 + t_pow_4 + 14.0 * eta - 58.0 * t_pow_2 * eta + 13.0 * eta_pow_2 + 4.0 * eta_pow_3 - 64.0 * t_pow_2 * eta_pow_2 - 24.0 * t_pow_2 * eta_pow_3) / 120.0;
|
||||
t4 = sn * c_pow_4 * c_pow_3 * OK * (61.0 - 479.0 * t_pow_2 + 179.0 * t_pow_4 - t_pow_5 * t) / 5040.0;
|
||||
puwgCoord.easting = 500000.0 + dlam * t1 + dlam_pow_3 * t2 + dlam_pow_4 * dlam * t3 + dlam_pow_4 * dlam_pow_3 * t4;// + 0.5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Funkcja do konwersji współrzędnych płaskich X/Y odwzorowania kartograficznego 1992 na elipsoidalne lat/lon elipsoide WGS84.
|
||||
* <p>
|
||||
* PUWGCoord.proj: odwzorowanie kartograficzne (proj = 1 odpowiada odwzorowaniu 1992, natomiast każda inna odwzorowaniu 2000)
|
||||
*
|
||||
* @param northing współrzędne na osi OY odwzorowania kartograficznego PUWG-1992 do konwersji [metry]
|
||||
* @param easting współrzędne na osi OX odwzorowania kartograficznego PUWG-1992 do konwersji [metry]
|
||||
* @param geoCoord współrzędne geograficzne odwzorowania WGS-84 po konwersji [stopnie]
|
||||
*/
|
||||
public static void convertPUWG1992ToWGS84(double northing, double easting, Coord.Geo geoCoord) {
|
||||
double tmd = (northing + 5300000.0) / OK;
|
||||
double sr = sphsr(0.0);
|
||||
double ftphi = tmd / sr;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
ftphi += (tmd - sphtmd(ftphi)) / sphsr(ftphi);
|
||||
}
|
||||
sr = sphsr(ftphi);
|
||||
double sn = sphsn(ftphi);
|
||||
double sn_pow_2 = sn * sn;
|
||||
double sn_pow_3 = sn_pow_2 * sn;
|
||||
double sn_pow_4 = sn_pow_3 * sn;
|
||||
double sn_pow_5 = sn_pow_4 * sn;
|
||||
double sn_pow_7 = sn_pow_5 * sn_pow_2;
|
||||
double s = Math.sin(ftphi);
|
||||
double c = Math.cos(ftphi);
|
||||
double t = s / c;
|
||||
double t_pow_2 = t * t;
|
||||
double t_pow_4 = t_pow_2 * t_pow_2;
|
||||
double t_pow_6 = t_pow_4 * t_pow_2;
|
||||
double eta = E2_SQUARED * (c * c);
|
||||
double eta_pow_2 = eta * eta;
|
||||
double eta_pow_3 = eta_pow_2 * eta;
|
||||
double eta_pow_4 = eta_pow_2 * eta_pow_2;
|
||||
double de = easting - 500000.0;
|
||||
double de_pow_2 = de * de;
|
||||
double de_pow_3 = de_pow_2 * de;
|
||||
double de_pow_4 = de_pow_3 * de;
|
||||
double t0, t1, t2, t3;
|
||||
t0 = t / (2.0 * sr * sn * OK_POW_2);
|
||||
t1 = t * (5.0 + 3.0 * t_pow_2 + eta - 4.0 * eta_pow_2 - 9.0 * t_pow_2 * eta) / (24.0 * sr * sn_pow_3 * OK_POW_4);
|
||||
t2 = t * (61.0 + 90.0 * t_pow_2 + 46.0 * eta + 45.0 * t_pow_4 - 252.0 * t_pow_2 * eta - 3.0 * eta_pow_2 + 100.0 * eta_pow_3 - 66.0 * t_pow_2 * eta_pow_2 - 90.0 * t_pow_4 * eta + 88.0 * eta_pow_4 + 225.0 * t_pow_4 * eta_pow_2 + 84.0 * t_pow_2 * eta_pow_3 - 192.0 * t_pow_2 * eta_pow_4) / (720.0 * sr * sn_pow_5 * OK_POW_6);
|
||||
t3 = t * (1385.0 + 3633.0 * t_pow_2 + 4095.0 * t_pow_4 + 1575.0 * t_pow_6) / (40320.0 * sr * sn_pow_7 * (OK_POW_8));
|
||||
double latrad = ftphi - de_pow_2 * t0 + de_pow_4 * t1 - de_pow_3 * de_pow_3 * t2 + de_pow_4 * de_pow_3 * t3;
|
||||
t0 = 1.0 / (sn * c * OK);
|
||||
t1 = (1.0 + 2.0 * t_pow_2 + eta) / (6.0 * sn_pow_3 * c * (OK_POW_3));
|
||||
t2 = (5.0 + 6.0 * eta + 28.0 * t_pow_2 - 3.0 * eta_pow_2 + 8.0 * t_pow_2 * eta + 24.0 * t_pow_4 - 4.0 * eta_pow_3 + 4.0 * t_pow_2 * eta_pow_2 + 24.0 * t_pow_2 * eta_pow_3) / (120.0 * sn_pow_5 * c * (OK_POW_5));
|
||||
t3 = (61.0 + 662.0 * t_pow_2 + 1320.0 * t_pow_4 + 720.0 * t_pow_6) / (5040.0 * sn_pow_7 * c * OK_POW_7);
|
||||
double dlam = de * t0 - de_pow_3 * t1 + de_pow_3 * de_pow_2 * t2 - de_pow_3 * de_pow_4 * t3;
|
||||
// 19.0 * DEG_2_RAD == 0.33161255787892263;
|
||||
// geoCoord.lon = 0.33161255787892263 + dlam;
|
||||
// geoCoord.lon *= RAD_2_DEG;
|
||||
geoCoord.lon = Math.toDegrees(dlam) + 19.0;
|
||||
geoCoord.lat = Math.toDegrees(latrad);
|
||||
}
|
||||
|
||||
/// //////////////////////////////////////////////////////////////////////////////
|
||||
// Funkcje pomocnicze i stałe
|
||||
static double calculateESquared(double a, double b) {
|
||||
a *= a;
|
||||
b *= b;
|
||||
return (a - b) / a;
|
||||
}
|
||||
|
||||
static double calculateE2Squared(double a, double b) {
|
||||
a *= a;
|
||||
b *= b;
|
||||
return (a - b) / b;
|
||||
}
|
||||
|
||||
static double denom(double sphi) {
|
||||
double sinSphi = Math.sin(sphi);
|
||||
return Math.sqrt(1.0 - E_SQUARED * (sinSphi * sinSphi));
|
||||
}
|
||||
|
||||
static double sphsr(double sphi) {
|
||||
double dn = denom(sphi);
|
||||
return A * (1.0 - E_SQUARED) / (dn * dn * dn);
|
||||
}
|
||||
|
||||
static double sphsn(double sphi) {
|
||||
double sinSphi = Math.sin(sphi);
|
||||
return A / Math.sqrt(1.0 - E_SQUARED * (sinSphi * sinSphi));
|
||||
}
|
||||
|
||||
static double sphtmd(double sphi) {
|
||||
return (AP * sphi) - (BP * Math.sin(2.0 * sphi)) + (CP * Math.sin(4.0 * sphi)) - (DP * Math.sin(6.0 * sphi)) + (EP * Math.sin(8.0 * sphi));
|
||||
}
|
||||
|
||||
/**
|
||||
* Dlługość dużej półsi, w metrach dla elipsoidy WGS-84.
|
||||
*/
|
||||
private static final double A = 6378137.0;
|
||||
|
||||
/**
|
||||
* double f: spłaszczenie elipsoidalne dla elipsoidy WGS-84, 1 / 298.257223563
|
||||
*/
|
||||
// private static final double F = 1.0 / 298.257223563;
|
||||
private static final double B = A * (1.0 - 1.0 / 298.257223563);
|
||||
private static final double E_SQUARED = calculateESquared(A, B);
|
||||
private static final double E2_SQUARED = calculateE2Squared(A, B);
|
||||
private static final double TN = (A - B) / (A + B);
|
||||
private static final double AP = A * (1.0 - TN + 5.0 * (TN * TN - TN * TN * TN) / 4.0 + 81.0 * TN * TN * TN * TN - TN * TN * TN * TN * TN / 64.0);
|
||||
private static final double BP = 3.0 * A * (TN - TN * TN + 7.0 * (TN * TN * TN - TN * TN * TN * TN) / 8.0 + 55.0 * TN * TN * TN * TN * TN / 64.0) / 2.0;
|
||||
private static final double CP = 15.0 * A * (TN * TN - TN * TN * TN + 3.0 * (TN * TN * TN * TN - TN * TN * TN * TN * TN) / 4.0) / 16.0;
|
||||
private static final double DP = 35.0 * A * (TN * TN * TN - TN * TN * TN * TN + 11.0 * TN * TN * TN * TN * TN / 16.0) / 48.0;
|
||||
private static final double EP = 315.0 * A * (TN * TN * TN * TN - TN * TN * TN * TN * TN) / 512.0;
|
||||
|
||||
/**
|
||||
* Współczynnik zniekształcenia skali mapy w południku osiowym dla odwzorowania kartograficznego PUWG-1992.
|
||||
*/
|
||||
private static final double OK = 0.9993;
|
||||
private static final double OK_POW_2 = OK * OK;
|
||||
private static final double OK_POW_3 = OK_POW_2 * OK;
|
||||
private static final double OK_POW_4 = OK_POW_3 * OK;
|
||||
private static final double OK_POW_5 = OK_POW_4 * OK;
|
||||
private static final double OK_POW_6 = OK_POW_5 * OK;
|
||||
private static final double OK_POW_7 = OK_POW_6 * OK;
|
||||
private static final double OK_POW_8 = OK_POW_7 * OK;
|
||||
|
||||
|
||||
}
|
||||
13
src/main/java/pl/wat/ms4ds/terrain/EmptyBigSquare.java
Normal file
13
src/main/java/pl/wat/ms4ds/terrain/EmptyBigSquare.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package pl.wat.ms4ds.terrain;
|
||||
|
||||
class EmptyBigSquare extends BigSquare {
|
||||
|
||||
public static final EmptyBigSquare EMPTY_BIG_SQUARE = new EmptyBigSquare();
|
||||
|
||||
private EmptyBigSquare() {
|
||||
}
|
||||
|
||||
Square getSquare(int ssX, int ssY) {
|
||||
return Square.EMPTY;
|
||||
}
|
||||
}
|
||||
1254
src/main/java/pl/wat/ms4ds/terrain/GeomUtils.java
Normal file
1254
src/main/java/pl/wat/ms4ds/terrain/GeomUtils.java
Normal file
File diff suppressed because it is too large
Load Diff
250
src/main/java/pl/wat/ms4ds/terrain/MapConsts.java
Normal file
250
src/main/java/pl/wat/ms4ds/terrain/MapConsts.java
Normal file
@@ -0,0 +1,250 @@
|
||||
package pl.wat.ms4ds.terrain;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
public final class MapConsts {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(MapConsts.class);
|
||||
|
||||
/**
|
||||
* Długość geograficzna referencyjna początku umownego układu współrzędnych w postaci siatki kwadratów. <p>
|
||||
* Wartości długości geograficznej mapowane są: [-180, 180) -> [0, 360).
|
||||
*/
|
||||
public static final int REF_LON;
|
||||
/**
|
||||
* Szerokość geograficzna referencyjna początku umownego układu współrzędnych w postaci siatki kwadratów. <p>
|
||||
* Wartości szerokości geograficznej mapowane są: [-90, 90] -> [0, 180].
|
||||
*/
|
||||
public static final int REF_LAT;
|
||||
|
||||
public static final int DELTA_LON_REF;
|
||||
public static final int DELTA_LAT_REF;
|
||||
|
||||
public static final String DATA_DIR;
|
||||
|
||||
/**
|
||||
* Nazwa pliku z konfiguracja mechanizmu odpowiedzialnego za transfer. Plik
|
||||
* musi znajdowac sie w katalogu glownym aplikacji, ewentualnie musi tu byc
|
||||
* podana sciezka bezwzgledna do niego.
|
||||
*/
|
||||
private static final String PROPERTIES_FILE = "teren.properties";
|
||||
|
||||
/**
|
||||
* Dlugosc boku duzego kwadratu na osi OX w liczbie malych kwadratow.
|
||||
*/
|
||||
public static final int SS_PER_BS_X;
|
||||
/**
|
||||
* Dlugosc boku duzego kwadratu na osi OY w liczbie malych kwadratow.
|
||||
*/
|
||||
public static final int SS_PER_BS_Y;
|
||||
/**
|
||||
* Dlugosc boku malego kwadratu w metrach.
|
||||
*/
|
||||
public static final int SS_SIZE;
|
||||
/**
|
||||
* Powierzchnia malego kwadratu w metrach.
|
||||
*/
|
||||
public static final int SS_AREA;
|
||||
/**
|
||||
* Szerokość małego kwadratu w stopniach.
|
||||
*/
|
||||
public static final double SS_DELTA_LON;
|
||||
/**
|
||||
* Wysokość małego kwadratu w stopniach.
|
||||
*/
|
||||
public static final double SS_DELTA_LAT;
|
||||
/**
|
||||
* Liczba duzych kwadratow na stopien geograficzny po osi OX (dlugosc geograficzna).
|
||||
*/
|
||||
public static final int BS_PER_DEG_X = 4;
|
||||
/**
|
||||
* Liczba duzych kwadratow na stopien geograficzny po osi OY (szerokosc geograficzna).
|
||||
*/
|
||||
public static final int BS_PER_DEG_Y = 6;
|
||||
/**
|
||||
* Szerokość duzych kwadratow w stopniach geograficznych po osi OX (dlugosc geograficzna).
|
||||
*/
|
||||
public static final double BS_DELTA_LON;
|
||||
/**
|
||||
* Wysokość duzych kwadratow w stopniach geograficznych po osi OY (szerokosc geograficzna).
|
||||
*/
|
||||
public static final double BS_DELTA_LAT;
|
||||
/**
|
||||
* Szerokości geograficzne środków kwadratów.
|
||||
*/
|
||||
static final double[] SS_LATS;
|
||||
/**
|
||||
* Długości geograficzne środków kwadratów.
|
||||
*/
|
||||
static final double[] SS_LONS;
|
||||
|
||||
static Properties properties;
|
||||
|
||||
static {
|
||||
String propertiesFileName = System.getProperty("user.dir") + "\\" + PROPERTIES_FILE;
|
||||
|
||||
properties = new Properties();
|
||||
try {
|
||||
LOGGER.debug("Odczyt ustawien z pliku: {}.", propertiesFileName);
|
||||
properties.load(new FileInputStream(propertiesFileName));
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Brak pliku z ustawieniami.");
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
// przesuniecie o 180 stop.
|
||||
// poludnik zerowy ma wartosc 180, zatem wspolrzedne zachodnie (ujemne) zawierają sie w <0, 180)
|
||||
// wspolrzedne wschodnie (nieujemne) zawieraja sie w przedziale <180, 360)
|
||||
REF_LON = Integer.parseInt(properties.getProperty("x_ref")) + 180;
|
||||
// przesuniecie o 90 stop.
|
||||
// rownik ma wartosc 90, zatem wspolrzedne poludniowe (ujemne) zawierają sie w <0, 90)
|
||||
// wspolrzedne polnocne (nieujemne) zawieraja sie w przedziale <90, 180>
|
||||
REF_LAT = Integer.parseInt(properties.getProperty("y_ref")) + 90;
|
||||
DELTA_LON_REF = Integer.parseInt(properties.getProperty("dx_ref"));
|
||||
DELTA_LAT_REF = Integer.parseInt(properties.getProperty("dy_ref"));
|
||||
double BS_X_NUM = DELTA_LON_REF / BS_PER_DEG_X;
|
||||
double BS_Y_NUM = DELTA_LAT_REF / BS_PER_DEG_Y;
|
||||
String val = properties.getProperty("dl_mk");
|
||||
switch (val) {
|
||||
case "20":
|
||||
SS_SIZE = 20;
|
||||
break;
|
||||
case "25":
|
||||
SS_SIZE = 25;
|
||||
break;
|
||||
case "50":
|
||||
SS_SIZE = 50;
|
||||
break;
|
||||
case "100":
|
||||
SS_SIZE = 100;
|
||||
break;
|
||||
default:
|
||||
SS_SIZE = 200;
|
||||
break;
|
||||
}
|
||||
SS_AREA = SS_SIZE * SS_SIZE;
|
||||
if (SS_SIZE == 20) {
|
||||
SS_PER_BS_X = 83 * 10;
|
||||
SS_PER_BS_Y = 93 * 10;
|
||||
SS_DELTA_LON = 1.0 / (double) (BS_PER_DEG_X * SS_PER_BS_X);
|
||||
SS_DELTA_LAT = 1.0 / (double) (BS_PER_DEG_Y * SS_PER_BS_Y);
|
||||
DATA_DIR = properties.getProperty("kwadraty_dir") + "20m/";
|
||||
} else if (SS_SIZE == 25) {
|
||||
SS_PER_BS_X = 83 * 8;
|
||||
SS_PER_BS_Y = 93 * 8;
|
||||
SS_DELTA_LON = 1.0 / (double) (BS_PER_DEG_X * SS_PER_BS_X);
|
||||
SS_DELTA_LAT = 1.0 / (double) (BS_PER_DEG_Y * SS_PER_BS_Y);
|
||||
DATA_DIR = properties.getProperty("kwadraty_dir") + "25m/";
|
||||
} else if (SS_SIZE == 50) {
|
||||
SS_PER_BS_X = 83 * 4;
|
||||
SS_PER_BS_Y = 93 * 4;
|
||||
SS_DELTA_LON = 1.0 / (double) (BS_PER_DEG_X * SS_PER_BS_X);
|
||||
SS_DELTA_LAT = 1.0 / (double) (BS_PER_DEG_Y * SS_PER_BS_Y);
|
||||
DATA_DIR = properties.getProperty("kwadraty_dir") + "50m/";
|
||||
} else if (SS_SIZE == 100) {
|
||||
SS_PER_BS_X = 83 * 2;
|
||||
SS_PER_BS_Y = 93 * 2;
|
||||
SS_DELTA_LON = 1.0 / (double) (BS_PER_DEG_X * SS_PER_BS_X);
|
||||
SS_DELTA_LAT = 1.0 / (double) (BS_PER_DEG_Y * SS_PER_BS_Y);
|
||||
DATA_DIR = properties.getProperty("kwadraty_dir") + "100m/";
|
||||
} else {
|
||||
// domyslnie dlugosc kwadratu 200m
|
||||
SS_PER_BS_X = 83;
|
||||
SS_PER_BS_Y = 93;
|
||||
SS_DELTA_LON = 1.0 / (double) (BS_PER_DEG_X * SS_PER_BS_X);
|
||||
SS_DELTA_LAT = 1.0 / (double) (BS_PER_DEG_Y * SS_PER_BS_Y);
|
||||
DATA_DIR = properties.getProperty("kwadraty_dir") + "200m/";
|
||||
}
|
||||
BS_DELTA_LON = 1.0 / (double) BS_PER_DEG_X;
|
||||
BS_DELTA_LAT = 1.0 / (double) BS_PER_DEG_Y;
|
||||
SS_LONS = new double[DELTA_LON_REF * BS_PER_DEG_X * SS_PER_BS_X];
|
||||
for (int i = 0; i < SS_LONS.length; i++) {
|
||||
SS_LONS[i] = REF_LON + SS_DELTA_LON * (i + 0.5);
|
||||
}
|
||||
SS_LATS = new double[DELTA_LAT_REF * BS_PER_DEG_Y * SS_PER_BS_Y];
|
||||
for (int i = 0; i < SS_LATS.length; i++) {
|
||||
SS_LATS[i] = REF_LAT + SS_DELTA_LAT * (i + 0.5);
|
||||
}
|
||||
LOGGER.debug("Wczytane ustawienia:\n \tLON_REF={}, LAT_REF={}, DX_REF={}, DY_REF{}, SQUARE_SIZE={}, GRID_SIZE={}x{}, DATA_DIR={}", REF_LON, REF_LAT, DELTA_LON_REF, DELTA_LAT_REF, SS_SIZE, SS_LONS.length, SS_LATS.length, DATA_DIR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Liczba milisekund na stopien.
|
||||
*/
|
||||
public static final int DEG_MS = 3600000;
|
||||
/**
|
||||
* Liczba milisekund na 360 stopni.
|
||||
*/
|
||||
public static final long ANGLE_360_MS = DEG_MS * 360;
|
||||
/**
|
||||
* Wielkosc cache'u pola walki (liczba duzych kwadratow trzymanych w RAM).
|
||||
*/
|
||||
public static final int MAX_BIG_SQUARES_IN_MEMORY = 500;
|
||||
|
||||
/**
|
||||
* Wspolrzedna referencyjna X (dlugosc geograficzna) lewego dolnego rogu mapy w stopniach geograficznych.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static int getX_REF() {
|
||||
return REF_LON;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wspolrzedna referencyjna Y (szerokosc geograficzna) lewego dolnego rogu mapy w stopniach geograficznych.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static int getY_REF() {
|
||||
return REF_LAT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Szerokosc referencyjna prostokata pola walki w stopniach na osi OX (dlugosc geograficzna).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static int getDX_REF() {
|
||||
return DELTA_LON_REF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wysokosc referencyjna prostokata pola walki w stopniach na osi OY (szerokosc geograficzna).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static int getDY_REF() {
|
||||
return DELTA_LAT_REF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dlugosci bokow malego kwadratu w milisekundach geograficznych po osi OX (dlugosc geograficzna).
|
||||
*/
|
||||
public static final double SS_DELTA_LON_MS = SS_DELTA_LON * DEG_MS;
|
||||
/**
|
||||
* Dlugosci bokow malego kwadratu w milisekundach geograficznych po osi OY (szerokosc geograficzna).
|
||||
*/
|
||||
public static final double SS_DELTA_LAT_MS = SS_DELTA_LAT * DEG_MS;
|
||||
// wspolrzedne dolnego lewego rogu mapy w ms
|
||||
// wspolrzedne geograficzne w milisekundach zawieraja sie w zakresie:
|
||||
// 0 <= x < 360 dlugosc geograficzna
|
||||
// 0 <= y <= 180 szerokosc geograficzna
|
||||
public static final int X_REF_MS = REF_LON * DEG_MS;
|
||||
public static final int Y_REF_MS = REF_LAT * DEG_MS;
|
||||
public static final int DX_REF_MS = DEG_MS * DELTA_LON_REF; // szerokosc pola walki w stopniach
|
||||
public static final int DY_REF_MS = DEG_MS * DELTA_LAT_REF; // wysokosc polwa walki w stopniach
|
||||
|
||||
public static final int BS_DX_MS = (int) (BS_DELTA_LON * DEG_MS);
|
||||
public static final int BS_DY_MS = (int) (BS_DELTA_LAT * DEG_MS);
|
||||
|
||||
/**
|
||||
* Liczba malych kwadratow przypadajaca na bok arkusza mapy drogowej.
|
||||
*/
|
||||
public static final int SS_PER_SHEET = 20;
|
||||
|
||||
|
||||
}
|
||||
323
src/main/java/pl/wat/ms4ds/terrain/RightBigSquare.java
Normal file
323
src/main/java/pl/wat/ms4ds/terrain/RightBigSquare.java
Normal file
@@ -0,0 +1,323 @@
|
||||
package pl.wat.ms4ds.terrain;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import pl.wat.ms4ds.terrain.nmt.NmtDataGenerator;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class RightBigSquare extends BigSquare {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(RightBigSquare.class);
|
||||
|
||||
private Square[][] squares;
|
||||
|
||||
Square getSquare(int ssX, int ssY) {
|
||||
return squares[ssX][ssY];
|
||||
}
|
||||
|
||||
public RightBigSquare() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Funkcja zapisująca do pliku duży kwadrat.<p>
|
||||
*
|
||||
* @param newDir opcjonalna nowa lokalizacja pliku
|
||||
* @throws IOException generowany wyjątek
|
||||
*/
|
||||
void writeToFile(String newDir) throws IOException {
|
||||
String fn;
|
||||
if (newDir != null) {
|
||||
fn = newDir + fileName + ".bin";
|
||||
} else {
|
||||
fn = MapConsts.DATA_DIR + fileName + ".bin";
|
||||
}
|
||||
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(fn));
|
||||
byte[] buf = new byte[10 * 256];
|
||||
int offset = 0;
|
||||
for (int x = 0; x < squares.length; x++) {
|
||||
for (int y = 0; y < squares[0].length; y++) {
|
||||
Square square = squares[x][y];
|
||||
offset = square.writeToBuffer(buf, offset);
|
||||
if (offset >= buf.length) {
|
||||
out.write(buf);
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (offset > 0) {
|
||||
out.write(buf, 0, offset);
|
||||
}
|
||||
out.close();
|
||||
logger.debug("Zapisano plik mapy: {}", fn);
|
||||
}
|
||||
|
||||
void readFromFile(String dir) throws IOException {
|
||||
if (fileName == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
String fullPath = dir + fileName + ".bin";
|
||||
BufferedInputStream in = new BufferedInputStream(new FileInputStream(fullPath), 2 * 8192);
|
||||
byte[] buffer = new byte[10 * 512];
|
||||
int offset = 0;
|
||||
int count = in.read(buffer);
|
||||
squares = new Square[MapConsts.SS_PER_BS_X][MapConsts.SS_PER_BS_Y];
|
||||
for (int x = 0; x < MapConsts.SS_PER_BS_X; x++) {
|
||||
for (int y = 0; y < MapConsts.SS_PER_BS_Y; y++) {
|
||||
Square kw = new Square(x, y);
|
||||
if (offset >= count) {
|
||||
count = in.read(buffer);
|
||||
offset = 0;
|
||||
}
|
||||
offset = kw.readFromBuffer(buffer, offset);
|
||||
squares[x][y] = kw;
|
||||
}
|
||||
}
|
||||
in.close();
|
||||
logger.debug("Doczytano plik mapy: {}", fullPath);
|
||||
} catch (IOException e) {
|
||||
squares = null;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generuje nowe, wyzerowane kwadraty w danej skali w nowym formacie.
|
||||
*
|
||||
* @param dir
|
||||
* @param dlmk
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeToFile_ElevationOnly(String dir, int dlmk) throws IOException {
|
||||
if (MapConsts.SS_SIZE != 100) {
|
||||
// operacja tylko dla danych terenowych o kwadratach 200m
|
||||
return;
|
||||
}
|
||||
final int m;
|
||||
String s = "";
|
||||
if (dlmk == 100) {
|
||||
m = 1;
|
||||
s = "100m/";
|
||||
} else if (dlmk == 50) {
|
||||
m = 2;
|
||||
s = "50m/";
|
||||
} else if (dlmk == 25) {
|
||||
m = 4;
|
||||
s = "25m/";
|
||||
} else if (dlmk == 20) {
|
||||
m = 5;
|
||||
s = "20m/";
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(100);
|
||||
sb.append(dir);
|
||||
sb.append(s);
|
||||
// Utworzenie katalogów, gdyby nie istniały.
|
||||
File directory = new File(sb.toString());
|
||||
directory.mkdirs();
|
||||
sb.append(fileName + ".bin");
|
||||
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(sb.toString()));
|
||||
byte[] buf = new byte[10 * 256];
|
||||
int offset = 0;
|
||||
for (int x = 0; x < squares.length; x++) {
|
||||
for (int i = 0; i < m; i++) {
|
||||
for (int y = 0; y < squares[0].length; y++) {
|
||||
Square square = squares[x][y];
|
||||
if (square.elevation > NmtDataGenerator.H_MAX) {
|
||||
logger.warn("Elevation: {}, fn= {}", square.elevation, fileName);
|
||||
}
|
||||
for (int j = 0; j < m; j++) {
|
||||
offset = square.writeToBuffer_ElevationOnly(buf, offset);
|
||||
if (offset >= buf.length) {
|
||||
out.write(buf);
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (offset > 0) {
|
||||
out.write(buf, 0, offset);
|
||||
}
|
||||
out.close();
|
||||
logger.debug("Zapisano plik mapy: {}", fileName);
|
||||
}
|
||||
|
||||
public void writeToFile_OldFormat(String dir) throws IOException {
|
||||
StringBuilder sb = new StringBuilder(100);
|
||||
sb.append(dir);
|
||||
// Utworzenie katalogów, gdyby nie istniały.
|
||||
File directory = new File(sb.toString());
|
||||
directory.mkdirs();
|
||||
sb.append(fileName);
|
||||
if (fileName.indexOf('.') < 0) {
|
||||
sb.append(".bin");
|
||||
}
|
||||
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(sb.toString()));
|
||||
for (int x = 0; x < squares.length; x++) {
|
||||
for (int y = 0; y < squares[0].length; y++) {
|
||||
Square square = squares[x][y];
|
||||
int hex_s = 0;
|
||||
int hex_w = 0;
|
||||
int hex_b = 0;
|
||||
int hex_f = 0;
|
||||
switch (square.terrainType) {
|
||||
// case 0, 1, 4:
|
||||
// hex = 0;
|
||||
// break;
|
||||
case SWAMP:
|
||||
hex_s = 100;
|
||||
break;
|
||||
case WATER:
|
||||
hex_w = 100;
|
||||
break;
|
||||
case BUILDINGS:
|
||||
hex_b = 100;
|
||||
break;
|
||||
case FOREST:
|
||||
hex_f = 100;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
out.writeByte(hex_f);
|
||||
out.writeByte(hex_w);
|
||||
out.writeByte(hex_b);
|
||||
out.writeByte(hex_s);
|
||||
int elevation = (int) square.elevation;
|
||||
out.writeInt(elevation);
|
||||
// Różnica wzniesień.
|
||||
out.writeInt(0);
|
||||
int bit_1;
|
||||
int hex = 0;
|
||||
bit_1 = 1;
|
||||
byte[] roads = square.roads;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
// jest odcinek drogi na tym kierunku
|
||||
if (roads[i] > 0) {
|
||||
hex |= bit_1;
|
||||
}
|
||||
bit_1 <<= 1;
|
||||
}
|
||||
out.writeByte(hex);
|
||||
hex = 0;
|
||||
bit_1 = 1;
|
||||
byte[] watercourses = square.watercourses;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
// jest odcinek przeszkody wodnej na tym kierunku
|
||||
if (watercourses[i] > 1) {
|
||||
hex |= bit_1;
|
||||
}
|
||||
bit_1 <<= 1;
|
||||
}
|
||||
out.writeByte(hex);
|
||||
hex = 0;
|
||||
bit_1 = 1;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
// jest odcinek rowu na tym kierunku
|
||||
if (watercourses[i] == 1) {
|
||||
hex |= bit_1;
|
||||
}
|
||||
bit_1 <<= 1;
|
||||
}
|
||||
out.writeByte(hex);
|
||||
}
|
||||
}
|
||||
out.close();
|
||||
logger.debug("Zapisano nowy plik mapy: {}", sb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Konstruktor ladujacy duzy kwadrat z pliku binarnego w starym formacie.
|
||||
*
|
||||
* @param dir opcjonalny katalog z danymi
|
||||
*
|
||||
*/
|
||||
void readFromFile_OldFormat(String dir) throws IOException {
|
||||
if (fileName == null) {
|
||||
return;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(100);
|
||||
if (dir == null) {
|
||||
sb.append(MapConsts.DATA_DIR);
|
||||
} else {
|
||||
sb.append(dir);
|
||||
}
|
||||
sb.append(fileName).append(".bin");
|
||||
try {
|
||||
ObjectInputStream in = new ObjectInputStream(new FileInputStream(sb.toString()));
|
||||
squares = new Square[MapConsts.SS_PER_BS_X][MapConsts.SS_PER_BS_Y];
|
||||
for (int x = 0; x < MapConsts.SS_PER_BS_X; x++) {
|
||||
for (int y = 0; y < MapConsts.SS_PER_BS_Y; y++) {
|
||||
Square kw = new Square(x, y);
|
||||
squares[x][y] = kw;
|
||||
kw.terrainType = TerrainType.NONE;
|
||||
int hex = in.readByte();
|
||||
if (hex > 30) {
|
||||
kw.terrainType = TerrainType.FOREST;
|
||||
}
|
||||
hex = in.readByte();
|
||||
if (hex > 30) {
|
||||
kw.terrainType = TerrainType.WATER;
|
||||
}
|
||||
hex = in.readByte();
|
||||
if (hex > 30) {
|
||||
kw.terrainType = TerrainType.BUILDINGS;
|
||||
}
|
||||
hex = in.readByte();
|
||||
if (hex > 30) {
|
||||
kw.terrainType = TerrainType.SWAMP;
|
||||
}
|
||||
kw.elevation = in.readInt();
|
||||
if (kw.elevation < NmtDataGenerator.H_MIN) {
|
||||
logger.warn("Elevation: {}, fn= {}", kw.elevation, fileName);
|
||||
}
|
||||
if (kw.elevation > NmtDataGenerator.H_MAX) {
|
||||
logger.warn("Elevation: {}, fn= {}", kw.elevation, fileName);
|
||||
}
|
||||
// Pomijam dane o różnicy wzniesień.
|
||||
in.readInt();
|
||||
int bit_1 = 1;
|
||||
hex = in.readByte();
|
||||
for (int i = 0; i < 8; i++) {
|
||||
// jest odcinek rowu na tym kierunku
|
||||
if ((hex & bit_1) != 0) {
|
||||
kw.roads[i] = 2;
|
||||
}
|
||||
bit_1 <<= 1;
|
||||
}
|
||||
bit_1 = 1;
|
||||
hex = in.readByte();
|
||||
for (int i = 0; i < 8; i++) {
|
||||
// jest odcinek rzeki na tym kierunku
|
||||
if ((hex & bit_1) != 0) {
|
||||
kw.watercourses[i] = 3;
|
||||
}
|
||||
bit_1 <<= 1;
|
||||
}
|
||||
bit_1 = 1;
|
||||
hex = in.readByte();
|
||||
for (int i = 0; i < 8; i++) {
|
||||
// jest odcinek rowu na tym kierunku
|
||||
if ((hex & bit_1) != 0) {
|
||||
kw.watercourses[i] = 1;
|
||||
}
|
||||
bit_1 <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
in.close();
|
||||
logger.debug("Doczytano plik mapy: {}", sb);
|
||||
} catch (IOException e) {
|
||||
squares = null;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RightBigSquare{" + fileName + '}';
|
||||
}
|
||||
}
|
||||
260
src/main/java/pl/wat/ms4ds/terrain/Square.java
Normal file
260
src/main/java/pl/wat/ms4ds/terrain/Square.java
Normal file
@@ -0,0 +1,260 @@
|
||||
package pl.wat.ms4ds.terrain;
|
||||
|
||||
/**
|
||||
*
|
||||
* A class representing the characteristics of a square of terrain within a regular grid.
|
||||
*
|
||||
*/
|
||||
public class Square {
|
||||
|
||||
/**
|
||||
* Horizontal grid coordinate.
|
||||
*/
|
||||
public final int x;
|
||||
/**
|
||||
* Vertical grid coordinate.
|
||||
*/
|
||||
public final int y;
|
||||
|
||||
/**
|
||||
* The height above the level of the sea. Unit of measure meter [m].
|
||||
*/
|
||||
public float elevation;
|
||||
|
||||
/**
|
||||
* Terrain type. <p></p>Possible values:
|
||||
* 0 - BARE_GROUND
|
||||
* 1 - GRASS
|
||||
* 2 - SWAMP
|
||||
* 3 - WATER
|
||||
* 4 - SCRUB, BUSHES
|
||||
* 5 - BUILDINGS
|
||||
* 6 - FOREST
|
||||
*/
|
||||
public TerrainType terrainType;
|
||||
|
||||
/**
|
||||
* Type of watercourse (water obstacle) in a given direction. Each index corresponds to a given direction.
|
||||
* <p></p>Possible values: 0 - no watercourse, 1 - drain, ditch, 2 - canal, stream, 3 - river
|
||||
*/
|
||||
public final byte[] watercourses;
|
||||
|
||||
/**
|
||||
* Type of road in a given direction. Each index corresponds to a given direction.
|
||||
* <p></p>Possible values: 0 - no road, 1 - small roads, 2 - minor roads, 3 - major roads
|
||||
*/
|
||||
public final byte[] roads;
|
||||
|
||||
/**
|
||||
* A type of crossing that allows overcoming terrain obstacles, e.g. rivers.
|
||||
* <p></p>Possible values: 0 - none, 1 - bridge, 2 - tunnel
|
||||
*/
|
||||
public CrossingType crossingType;
|
||||
|
||||
/**
|
||||
* Size of the square.
|
||||
*/
|
||||
public static final int SIZE = 50;
|
||||
|
||||
public enum CrossingType {
|
||||
NONE(0),
|
||||
BRIDGE(1),
|
||||
TUNNEL(2);
|
||||
|
||||
static final CrossingType[] values = values();
|
||||
|
||||
public static CrossingType valueById(int id) {
|
||||
return (0 <= id && id <= 2) ? values[id] : NONE;
|
||||
}
|
||||
|
||||
public final int id;
|
||||
|
||||
CrossingType(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obiekt reprezentujący tzw. pusty kwadrat (spoza obszaru).
|
||||
*/
|
||||
public static final Square EMPTY = new Square(-1, -1);
|
||||
|
||||
public Square() {
|
||||
this(-2, -2);
|
||||
}
|
||||
|
||||
public Square(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
roads = new byte[8];
|
||||
watercourses = new byte[8];
|
||||
}
|
||||
|
||||
public int writeToBuffer_ElevationOnly(byte[] buffer, int offset) {
|
||||
// Konwersja [m] -> [0.25m].
|
||||
int elev = (short) (elevation * 4);
|
||||
byte b1 = (byte) (elev & 0xFF);
|
||||
elev >>= 8;
|
||||
byte b0 = (byte) (elev & 0xFF);
|
||||
buffer[offset] = b0;
|
||||
buffer[offset + 1] = b1;
|
||||
buffer[offset + 2] = 0;
|
||||
buffer[offset + 3] = 0;
|
||||
buffer[offset + 4] = 0;
|
||||
buffer[offset + 5] = 0;
|
||||
buffer[offset + 6] = 0;
|
||||
buffer[offset + 7] = 0;
|
||||
buffer[offset + 8] = 0;
|
||||
buffer[offset + 9] = 0;
|
||||
return offset + 10;
|
||||
}
|
||||
|
||||
public int writeToBuffer(byte[] buffer, int offset) {
|
||||
// Konwersja [m] -> [0.25m].
|
||||
int elev = (short) (elevation * 4);
|
||||
byte bit = 1;
|
||||
byte drains = 0;
|
||||
byte streams = 0;
|
||||
byte rivers = 0;
|
||||
byte smallRoads = 0;
|
||||
byte minorRoads = 0;
|
||||
byte majorRoads = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
switch (watercourses[i]) {
|
||||
case 1:
|
||||
drains |= bit;
|
||||
break;
|
||||
case 2:
|
||||
streams |= bit;
|
||||
break;
|
||||
case 3:
|
||||
rivers |= bit;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (roads[i]) {
|
||||
case 1:
|
||||
smallRoads |= bit;
|
||||
break;
|
||||
case 2:
|
||||
minorRoads |= bit;
|
||||
break;
|
||||
case 3:
|
||||
majorRoads |= bit;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
bit <<= 1;
|
||||
}
|
||||
// Konwersja short -> 2 bytes
|
||||
byte b1 = (byte) (elev & 0xFF);
|
||||
elev >>= 8;
|
||||
byte b0 = (byte) (elev & 0xFF);
|
||||
buffer[offset + 1] = b1;
|
||||
buffer[offset] = b0;
|
||||
buffer[offset + 2] = (byte) terrainType.id;
|
||||
buffer[offset + 3] = smallRoads;
|
||||
buffer[offset + 4] = minorRoads;
|
||||
buffer[offset + 5] = majorRoads;
|
||||
buffer[offset + 6] = drains;
|
||||
buffer[offset + 7] = streams;
|
||||
buffer[offset + 8] = rivers;
|
||||
// 0 - brak, 1 - most, 2 - tunel
|
||||
buffer[offset + 9] = (byte) crossingType.id;
|
||||
return offset + 10;
|
||||
}
|
||||
|
||||
public int readFromBuffer(byte[] buffer, int offset) {
|
||||
// Odczyt wartości typu short
|
||||
//
|
||||
int elev = buffer[offset] & 0xFF;
|
||||
// elev = (elev << 8) + (buffer[offset + 1] & 0xFF);
|
||||
elev = (elev << 8) | (buffer[offset + 1] & 0xFF);
|
||||
// Rzutowanie "elev" na short zachowuje znak liczby.
|
||||
short v = (short) elev;
|
||||
// Konwersja jednostek [0.25m]->[m]
|
||||
elevation = (float) (v) / 4;
|
||||
terrainType = TerrainType.valueFromId(buffer[offset + 2]);
|
||||
byte smallRoads = buffer[offset + 3];
|
||||
byte minorRoads = buffer[offset + 4];
|
||||
byte majorRoads = buffer[offset + 5];
|
||||
byte drains = buffer[offset + 6];
|
||||
byte streams = buffer[offset + 7];
|
||||
byte rivers = buffer[offset + 8];
|
||||
byte b = buffer[offset + 9];
|
||||
crossingType = CrossingType.valueById(b);
|
||||
int bit = 1;
|
||||
// 8 kierunków geograficznych (0 - NORTH, 1 - NORTH_EAST, ...)
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int b1 = ((majorRoads & bit) != 0) ? 3 : 0;
|
||||
int b2 = ((minorRoads & bit) != 0) ? 2 : 0;
|
||||
int b3 = ((smallRoads & bit) != 0) ? 1 : 0;
|
||||
roads[i] = (byte) (b1 + b2 + b3);
|
||||
b1 = ((rivers & bit) != 0) ? 3 : 0;
|
||||
b2 = ((streams & bit) != 0) ? 2 : 0;
|
||||
b3 = ((drains & bit) != 0) ? 1 : 0;
|
||||
watercourses[i] = (byte) (b1 + b2 + b3);
|
||||
bit <<= 1;
|
||||
}
|
||||
return offset + 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object o) {
|
||||
if (!(o instanceof Square square)) return false;
|
||||
|
||||
return x == square.x && y == square.y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 7;
|
||||
result = 31 * result + x;
|
||||
result = 31 * result + y;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder linia = new StringBuilder(100);
|
||||
linia.append("[");
|
||||
char c = switch (terrainType) {
|
||||
case NONE -> 'G';
|
||||
case GRASS -> 'g';
|
||||
case SWAMP -> 'S';
|
||||
case WATER -> 'W';
|
||||
case SCRUB_BUSHES -> 'R';
|
||||
case BUILDINGS -> 'B';
|
||||
case FOREST -> 'F';
|
||||
};
|
||||
linia.append(c);
|
||||
linia.append(' ');
|
||||
String s = String.format("%7.2f", elevation);
|
||||
linia.append(s);
|
||||
linia.append(' ');
|
||||
for (byte road : roads) {
|
||||
c = switch (road) {
|
||||
case 1 -> '1';
|
||||
case 2 -> '2';
|
||||
case 3 -> '3';
|
||||
default -> '0';
|
||||
};
|
||||
linia.append(c);
|
||||
}
|
||||
linia.append(' ');
|
||||
for (byte watercours : watercourses) {
|
||||
c = switch (watercours) {
|
||||
case 1 -> '1';
|
||||
case 2 -> '2';
|
||||
case 3 -> '3';
|
||||
default -> '0';
|
||||
};
|
||||
linia.append(c);
|
||||
}
|
||||
linia.append(']');
|
||||
return linia.toString();
|
||||
}
|
||||
|
||||
}
|
||||
471
src/main/java/pl/wat/ms4ds/terrain/Teren.java
Normal file
471
src/main/java/pl/wat/ms4ds/terrain/Teren.java
Normal file
@@ -0,0 +1,471 @@
|
||||
package pl.wat.ms4ds.terrain;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import pl.wat.ms4ds.common.ERodzajPodwozia;
|
||||
import pl.wat.ms4ds.common.ERodzajTerenuPokrycie;
|
||||
import pl.wat.ms4ds.terrain.nmt.NmtDataProvider;
|
||||
|
||||
import static pl.wat.ms4ds.terrain.Square.EMPTY;
|
||||
|
||||
public class Teren {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Teren.class);
|
||||
|
||||
private static final int BIG_X_MAX = MapConsts.DELTA_LON_REF * MapConsts.BS_PER_DEG_X;
|
||||
private static final int BIG_Y_MAX = MapConsts.DELTA_LAT_REF * MapConsts.BS_PER_DEG_Y;
|
||||
|
||||
private static final BigSquare[][] bigSquares = new BigSquare[BIG_X_MAX][BIG_Y_MAX];
|
||||
|
||||
// tablica obiektów synchronizujących dostęp do dużych kwadratów przy odczycie z pliku
|
||||
private static Object bsSynch = new Object();
|
||||
|
||||
private static final float[][] STOPIEN_PRZEJEZDNOSCI;
|
||||
|
||||
private static final String LITERALS = "ABCDEF";
|
||||
|
||||
private static boolean przejezdnoscZawsze;
|
||||
static double minStopienPrzejezd;
|
||||
static double minStopienPrzejezdNaPrzelaj;
|
||||
|
||||
private static double minStopienPrzejezdNaDrodzeNachylenie;
|
||||
private static double minStopienPrzejezdNaPrzelajNachylenie;
|
||||
|
||||
private static double minKatNachylTerenuNaDrodze;
|
||||
private static double maxKatNachylTerenuNaDrodze;
|
||||
private static double minKatNachylTerenuNaPrzelaj;
|
||||
private static double maxKatNachylTerenuNaPrzelaj;
|
||||
|
||||
/**
|
||||
* Jawne wywolanie zapisu do pliku bufora zmian terenu. Zapisane zostaną aktywne/załadowane duże kwadraty.
|
||||
*/
|
||||
public static void saveToFiles(String dir) {
|
||||
for (int i = 0; i < BIG_X_MAX; i++) {
|
||||
for (int j = 0; j < BIG_Y_MAX; j++) {
|
||||
BigSquare bs = bigSquares[i][j];
|
||||
if (bs instanceof RightBigSquare rbs) {
|
||||
try {
|
||||
rbs.writeToFile(dir);
|
||||
} catch (IOException e) {
|
||||
LOGGER.warn("Błąd zapisu pliku mapy: " + rbs.fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
||||
public static void reset() {
|
||||
for (int i = 0; i < BIG_X_MAX; i++) {
|
||||
for (int j = 0; j < BIG_Y_MAX; j++) {
|
||||
bigSquares[i][j] = null;
|
||||
}
|
||||
}
|
||||
cache.clear();
|
||||
System.gc();
|
||||
}
|
||||
|
||||
/**
|
||||
* Zwraca nazwę pliku na podstawie współrzędnych geograficznych.
|
||||
*
|
||||
* @param lat szerokość geograficzna
|
||||
* @param lon długość geograficzna
|
||||
* @return Nazwa zwracanego pliku z danymi (null - gdy niepoprawne współrzędne).
|
||||
*/
|
||||
public static String getFileName(double lat, double lon) {
|
||||
int idX = Coord.convertLonToGridX(lon);
|
||||
int idY = Coord.convertLatToGridY(lat);
|
||||
int bigX = idX / MapConsts.SS_PER_BS_X;
|
||||
int bigY = idY / MapConsts.SS_PER_BS_Y;
|
||||
return getFileName(bigX, bigY);
|
||||
}
|
||||
|
||||
private static String getFileName(int bsX, int bsY) {
|
||||
int x_stop = MapConsts.REF_LON + bsX / MapConsts.BS_PER_DEG_X - 180;
|
||||
char cLon = (x_stop < 0) ? 'W' : 'E';
|
||||
if (x_stop < 0) {
|
||||
x_stop = -x_stop;
|
||||
}
|
||||
int dx = bsX % MapConsts.BS_PER_DEG_X;
|
||||
char cx = LITERALS.charAt(dx);
|
||||
int y_stop = MapConsts.REF_LAT + bsY / MapConsts.BS_PER_DEG_Y - 90;
|
||||
char cLat = (y_stop < 0) ? 'S' : 'N';
|
||||
if (y_stop < 0) {
|
||||
y_stop = -y_stop;
|
||||
}
|
||||
int dy = bsY % MapConsts.BS_PER_DEG_Y;
|
||||
char cy = LITERALS.charAt(dy);
|
||||
// przykładowa nazwa pliku: E024B_N50F
|
||||
//
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(cLon);
|
||||
if (x_stop < 10) {
|
||||
sb.append("00");
|
||||
} else if (x_stop < 100) {
|
||||
sb.append('0');
|
||||
}
|
||||
sb.append(x_stop);
|
||||
sb.append(cx);
|
||||
sb.append('_');
|
||||
sb.append(cLat);
|
||||
if (y_stop < 10) {
|
||||
sb.append('0');
|
||||
}
|
||||
sb.append(y_stop);
|
||||
sb.append(cy);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static BigSquare loadArea_OldFormat(int bsX, int bsY) {
|
||||
String fName = getFileName(bsX, bsY);
|
||||
try {
|
||||
RightBigSquare bs = new RightBigSquare();
|
||||
bs.fileName = fName;
|
||||
bs.readFromFile_OldFormat(MapConsts.DATA_DIR);
|
||||
return bs;
|
||||
} catch (IOException e) {
|
||||
LOGGER.warn("Brak pliku mapy: {}{}{}", MapConsts.DATA_DIR, fName, ".bin");
|
||||
return EmptyBigSquare.EMPTY_BIG_SQUARE;
|
||||
}
|
||||
}
|
||||
|
||||
private static BigSquare loadArea(int bsX, int bsY) {
|
||||
String fName = getFileName(bsX, bsY);
|
||||
try {
|
||||
RightBigSquare bs = new RightBigSquare();
|
||||
bs.fileName = fName;
|
||||
bs.readFromFile(MapConsts.DATA_DIR);
|
||||
return bs;
|
||||
} catch (IOException e) {
|
||||
LOGGER.warn("Brak pliku mapy: {}{}{}", MapConsts.DATA_DIR, fName, ".bin");
|
||||
return EmptyBigSquare.EMPTY_BIG_SQUARE;
|
||||
}
|
||||
}
|
||||
|
||||
private static ReentrantLock synchr;
|
||||
|
||||
public static Square getKwadratPUWG(double northing, double easting) {
|
||||
Coord.Geo geoCoord = new Coord.Geo();
|
||||
Coord.convertPUWG1992ToWGS84(northing, easting, geoCoord);
|
||||
return getSquare(geoCoord.lat, geoCoord.lon);
|
||||
}
|
||||
|
||||
public static Square getSquare(double lat, double lon) {
|
||||
int idX = Coord.convertLonToGridX(lon);
|
||||
int idY = Coord.convertLatToGridY(lat);
|
||||
return getSquare(idX, idY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zwraca kwadrat o podanych współrzędnych siatki (grida).
|
||||
*
|
||||
* @param x współrzędna pozioma (indeks kolumny)
|
||||
* @param y współrzędna pionowa (indeks wiersza)
|
||||
* @return obiekt reprezentujący charakterystyki fragmentu terenu
|
||||
*/
|
||||
public static Square getSquare(int x, int y) {
|
||||
if (x < 0 || y < 0) {
|
||||
return EMPTY;
|
||||
}
|
||||
// wspolrzędna x dużego kwadratu
|
||||
int bsX = x / MapConsts.SS_PER_BS_X;
|
||||
// wspolrzędna y dużego kwadratu
|
||||
int bsY = y / MapConsts.SS_PER_BS_Y;
|
||||
if (bsX >= BIG_X_MAX || bsY >= BIG_Y_MAX) {
|
||||
return EMPTY;
|
||||
}
|
||||
// wspolrzędna x małego kwadratu w ramach dużego kwadratu
|
||||
int ssX = x % MapConsts.SS_PER_BS_X;
|
||||
// wspolrzędna y małego kwadratu w ramach dużego kwadratu
|
||||
int ssY = y % MapConsts.SS_PER_BS_Y;
|
||||
synchronized (bsSynch) {
|
||||
if (bigSquares[bsX][bsY] == null) {
|
||||
makeRoom(bsX, bsY);
|
||||
bigSquares[bsX][bsY] = loadArea(bsX, bsY);
|
||||
}
|
||||
}
|
||||
return bigSquares[bsX][bsY].getSquare(ssX, ssY);
|
||||
}
|
||||
|
||||
private static Coord.Grid[] history = new Coord.Grid[MapConsts.MAX_BIG_SQUARES_IN_MEMORY];
|
||||
private static final ArrayList<Coord.Grid> cache = new ArrayList<>(MapConsts.MAX_BIG_SQUARES_IN_MEMORY);
|
||||
|
||||
private static void makeRoom(int bigX, int bigY) {
|
||||
if (cache.size() >= MapConsts.MAX_BIG_SQUARES_IN_MEMORY) {
|
||||
// Brak miejsca, zatem zwalniam/usuwam najstarszy element;
|
||||
Coord.Grid removing = cache.removeFirst();
|
||||
RightBigSquare rbs = (RightBigSquare) bigSquares[removing.x][removing.y];
|
||||
try {
|
||||
rbs.writeToFile(null);
|
||||
} catch (IOException _) {
|
||||
}
|
||||
bigSquares[removing.x][removing.y] = null;
|
||||
LOGGER.debug("Big square X= {}, Y= {}, fn= {} removed from cache", bigX, bigY, rbs.fileName);
|
||||
}
|
||||
cache.add(new Coord.Grid(bigX, bigY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tablica danych o braku rowów w kwadracie dla funkcji przejezdnosci, gdy nie uwzględniamy rowów.
|
||||
*/
|
||||
private static final boolean[] ROWY_DLA_PRZEJEZDNOSCI = new boolean[8];
|
||||
|
||||
private static final double TANG_ALFA_MAX_NA_DRODZE;
|
||||
private static final double TANG_ALFA_MIN_NA_DRODZE;
|
||||
|
||||
private static final double a1;
|
||||
private static final double b1;
|
||||
|
||||
/**
|
||||
* Funkcja opisujaca zmianę stopnia przejezdności podczas ruchu na drodze dla kątów w przedziale <22.5, 45>
|
||||
*
|
||||
* @param tangKataNachyl tangens kąta nachylenia zbocza
|
||||
* @return stopień przejezdności z punktu widzenia nachylenia terenu przy ruchu na drodze
|
||||
*/
|
||||
private static double stopienPrzejezdNaDrodzeNachylenie(double tangKataNachyl) {
|
||||
if (tangKataNachyl <= TANG_ALFA_MIN_NA_DRODZE) {
|
||||
return 1.0;
|
||||
}
|
||||
double st = tangKataNachyl * a1 + b1;
|
||||
return (st < minStopienPrzejezdNaDrodzeNachylenie) ? minStopienPrzejezdNaDrodzeNachylenie : st;
|
||||
}
|
||||
|
||||
private static final double TANG_ALFA_MAX_NA_PRZELAJ;
|
||||
private static final double TANG_ALFA_MIN_NA_PRZELAJ;
|
||||
|
||||
private static final double a2;
|
||||
private static final double b2;
|
||||
|
||||
/**
|
||||
* Funkcja opisujaca zmianę stopnia przejezdności podczas ruchu na przełaj dla kątów w przedziale <22.5, 45>
|
||||
*
|
||||
* @param tangKataNachyl tangens kąta nachylenia zbocza
|
||||
* @return stopień przejezdności z punktu widzenia nachylenia terenu przy ruchu na przełaj
|
||||
*/
|
||||
private static double stopienPrzejezdNaPrzelajNachylenie(double tangKataNachyl) {
|
||||
if (tangKataNachyl <= TANG_ALFA_MIN_NA_PRZELAJ) {
|
||||
return 1.0;
|
||||
}
|
||||
if (tangKataNachyl >= TANG_ALFA_MAX_NA_PRZELAJ || tangKataNachyl <= -TANG_ALFA_MAX_NA_PRZELAJ) {
|
||||
// brak przejezdnosci z powodu nachylenia
|
||||
return 0.0;
|
||||
}
|
||||
double st = tangKataNachyl * a2 + b2;
|
||||
return (st < minStopienPrzejezdNaPrzelajNachylenie) ? minStopienPrzejezdNaPrzelajNachylenie : st;
|
||||
}
|
||||
|
||||
private Teren() {
|
||||
}
|
||||
|
||||
static {
|
||||
for (int i = 0; i < history.length; i++) {
|
||||
history[i] = new Coord.Grid();
|
||||
}
|
||||
przejezdnoscZawsze = MapConsts.properties.getProperty("przejezdnosc_zawsze").equals("on");
|
||||
minStopienPrzejezd = Double.parseDouble(MapConsts.properties.getProperty("minimalny_stopien_przejezdnosci"));
|
||||
|
||||
minStopienPrzejezdNaPrzelaj = Double.parseDouble(MapConsts.properties.getProperty("stopien_przejezdnosci.minimalny_na_przelaj"));
|
||||
minStopienPrzejezdNaDrodzeNachylenie = Double.parseDouble(MapConsts.properties.getProperty("stopien_przejezdnosci.minimalny.na_drodze.nachylenie_terenu"));
|
||||
minStopienPrzejezdNaPrzelajNachylenie = Double.parseDouble(MapConsts.properties.getProperty("stopien_przejezdnosci.minimalny.na_przelaj.nachylenie_terenu"));
|
||||
|
||||
minKatNachylTerenuNaDrodze = Double.parseDouble(MapConsts.properties.getProperty("stopien_przejezdnosci.na_drodze.nachylenie_terenu.kat_minimalny"));
|
||||
minKatNachylTerenuNaDrodze = Math.max(0, minKatNachylTerenuNaDrodze);
|
||||
minKatNachylTerenuNaDrodze = Math.min(60, minKatNachylTerenuNaDrodze);
|
||||
minKatNachylTerenuNaDrodze *= Math.PI / 180;
|
||||
|
||||
maxKatNachylTerenuNaDrodze = Double.parseDouble(MapConsts.properties.getProperty("stopien_przejezdnosci.na_drodze.nachylenie_terenu.kat_maksymalny"));
|
||||
maxKatNachylTerenuNaDrodze = Math.max(0, maxKatNachylTerenuNaDrodze);
|
||||
maxKatNachylTerenuNaDrodze = Math.min(60, maxKatNachylTerenuNaDrodze);
|
||||
maxKatNachylTerenuNaDrodze *= Math.PI / 180;
|
||||
if (maxKatNachylTerenuNaDrodze < minKatNachylTerenuNaDrodze) {
|
||||
double temp = maxKatNachylTerenuNaDrodze;
|
||||
maxKatNachylTerenuNaDrodze = minKatNachylTerenuNaDrodze;
|
||||
minKatNachylTerenuNaDrodze = temp;
|
||||
}
|
||||
|
||||
minKatNachylTerenuNaPrzelaj = Double.parseDouble(MapConsts.properties.getProperty("stopien_przejezdnosci.na_przelaj.nachylenie_terenu.kat_minimalny"));
|
||||
minKatNachylTerenuNaPrzelaj = Math.max(0, minKatNachylTerenuNaPrzelaj);
|
||||
minKatNachylTerenuNaPrzelaj = Math.min(60, minKatNachylTerenuNaPrzelaj);
|
||||
minKatNachylTerenuNaPrzelaj *= Math.PI / 180;
|
||||
|
||||
maxKatNachylTerenuNaPrzelaj = Double.parseDouble(MapConsts.properties.getProperty("stopien_przejezdnosci.na_przelaj.nachylenie_terenu.kat_maksymalny"));
|
||||
maxKatNachylTerenuNaPrzelaj = Math.max(0, maxKatNachylTerenuNaPrzelaj);
|
||||
maxKatNachylTerenuNaPrzelaj = Math.min(60, maxKatNachylTerenuNaPrzelaj);
|
||||
maxKatNachylTerenuNaPrzelaj *= Math.PI / 180;
|
||||
if (maxKatNachylTerenuNaPrzelaj < minKatNachylTerenuNaPrzelaj) {
|
||||
double temp = maxKatNachylTerenuNaPrzelaj;
|
||||
maxKatNachylTerenuNaPrzelaj = minKatNachylTerenuNaPrzelaj;
|
||||
minKatNachylTerenuNaPrzelaj = temp;
|
||||
}
|
||||
|
||||
TANG_ALFA_MAX_NA_DRODZE = Math.tan(maxKatNachylTerenuNaDrodze);
|
||||
TANG_ALFA_MIN_NA_DRODZE = Math.tan(minKatNachylTerenuNaDrodze);
|
||||
a1 = (minStopienPrzejezdNaDrodzeNachylenie - 1) / (TANG_ALFA_MAX_NA_DRODZE - TANG_ALFA_MIN_NA_DRODZE);
|
||||
b1 = 1 - a1 * TANG_ALFA_MIN_NA_DRODZE;
|
||||
|
||||
TANG_ALFA_MAX_NA_PRZELAJ = Math.tan(maxKatNachylTerenuNaPrzelaj);
|
||||
TANG_ALFA_MIN_NA_PRZELAJ = Math.tan(minKatNachylTerenuNaPrzelaj);
|
||||
a2 = (minStopienPrzejezdNaPrzelajNachylenie - 1) / (TANG_ALFA_MAX_NA_PRZELAJ - TANG_ALFA_MIN_NA_PRZELAJ);
|
||||
b2 = 1 - a2 * TANG_ALFA_MIN_NA_PRZELAJ;
|
||||
|
||||
STOPIEN_PRZEJEZDNOSCI = new float[ERodzajPodwozia.numberOfValues()][ERodzajTerenuPokrycie.numberOfValues()];
|
||||
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.GASIENICE.id][ERodzajTerenuPokrycie.TEREN_ZABUDOWANY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_gasienicowe.teren_zabudowany"));
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.GASIENICE.id][ERodzajTerenuPokrycie.TEREN_ZALESIONY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_gasienicowe.teren_zalesiony"));
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.GASIENICE.id][ERodzajTerenuPokrycie.TEREN_ZABAGNIONY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_gasienicowe.teren_zabagniony"));
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.GASIENICE.id][ERodzajTerenuPokrycie.TEREN_ZAWODNIONY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_gasienicowe.teren_zawodniony"));
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.GASIENICE.id][ERodzajTerenuPokrycie.TEREN_CZYSTY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_gasienicowe.teren_czysty"));
|
||||
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.KOLA_GASIENICE.id][ERodzajTerenuPokrycie.TEREN_ZABUDOWANY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_kolowo_gasienicowe.teren_zabudowany"));
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.KOLA_GASIENICE.id][ERodzajTerenuPokrycie.TEREN_ZALESIONY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_kolowo_gasienicowe.teren_zalesiony"));
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.KOLA_GASIENICE.id][ERodzajTerenuPokrycie.TEREN_ZABAGNIONY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_kolowo_gasienicowe.teren_zabagniony"));
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.KOLA_GASIENICE.id][ERodzajTerenuPokrycie.TEREN_ZAWODNIONY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_kolowo_gasienicowe.teren_zawodniony"));
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.KOLA_GASIENICE.id][ERodzajTerenuPokrycie.TEREN_CZYSTY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_kolowo_gasienicowe.teren_czysty"));
|
||||
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.KOLA.id][ERodzajTerenuPokrycie.TEREN_ZABUDOWANY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_kolowe.teren_zabudowany"));
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.KOLA.id][ERodzajTerenuPokrycie.TEREN_ZALESIONY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_kolowe.teren_zalesiony"));
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.KOLA.id][ERodzajTerenuPokrycie.TEREN_ZABAGNIONY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_kolowe.teren_zabagniony"));
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.KOLA.id][ERodzajTerenuPokrycie.TEREN_ZAWODNIONY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_kolowe.teren_zawodniony"));
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.KOLA.id][ERodzajTerenuPokrycie.TEREN_CZYSTY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_kolowe.teren_czysty"));
|
||||
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.PODUSZKA_POW.id][ERodzajTerenuPokrycie.TEREN_ZABUDOWANY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_poduszka.teren_zabudowany"));
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.PODUSZKA_POW.id][ERodzajTerenuPokrycie.TEREN_ZALESIONY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_poduszka.teren_zalesiony"));
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.PODUSZKA_POW.id][ERodzajTerenuPokrycie.TEREN_ZABAGNIONY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_poduszka.teren_zabagniony"));
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.PODUSZKA_POW.id][ERodzajTerenuPokrycie.TEREN_ZAWODNIONY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_poduszka.teren_zawodniony"));
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.PODUSZKA_POW.id][ERodzajTerenuPokrycie.TEREN_CZYSTY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_poduszka.teren_czysty"));
|
||||
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.PLOZY.id][ERodzajTerenuPokrycie.TEREN_ZABUDOWANY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_plozy.teren_zabudowany"));
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.PLOZY.id][ERodzajTerenuPokrycie.TEREN_ZALESIONY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_plozy.teren_zalesiony"));
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.PLOZY.id][ERodzajTerenuPokrycie.TEREN_ZABAGNIONY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_plozy.teren_zabagniony"));
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.PLOZY.id][ERodzajTerenuPokrycie.TEREN_ZAWODNIONY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_plozy.teren_zawodniony"));
|
||||
STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.PLOZY.id][ERodzajTerenuPokrycie.TEREN_CZYSTY.id] =
|
||||
Float.parseFloat(MapConsts.properties.getProperty("stopien_przejezdnosci.podwozie_plozy.teren_czysty"));
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// boolean[] przeszk = new boolean[8];
|
||||
// boolean[] row = new boolean[8];
|
||||
// przeszk[2] = true;
|
||||
// przeszk[6] = true;
|
||||
|
||||
// Teren.poprawDaneWysokosciowe();
|
||||
|
||||
LOGGER.debug("start");
|
||||
// Teren.normalizujDanePokrycia();
|
||||
|
||||
String newDir = "D:/work/kwadraty_nmt/temp/100m/";
|
||||
String dir1 = "D:/work/terrain/";
|
||||
String inDir = "D:/work/kwadraty_nmt/withElevation/25m/";
|
||||
String dir2 = "C:/Workspace/_data/swdt/ms4ds/teren/kwadraty/100m/";
|
||||
|
||||
Set<String> fileNames = NmtDataProvider.listFiles(inDir);
|
||||
generateDataFromOldFormat(fileNames, newDir, 100);
|
||||
// Set<String> fileNames2 = new HashSet<>();
|
||||
// fileNames2.add(dir2 + "E014C_N53D.bin");
|
||||
// generateData(fileNames, inDir, newDir);
|
||||
|
||||
// Square kw = getKwadrat(1500, 2100);
|
||||
// System.out.println(kw);
|
||||
// kw = getKwadrat(2100, 1500);
|
||||
// System.out.println(kw);
|
||||
// String fn = "E017B_N54E";
|
||||
// RightBigSquare rbs = new RightBigSquare(dir2 + fn + ".bin", null);
|
||||
// rbs.writeToFileOldToNewFormatWithElevetion(dir1, 25);
|
||||
|
||||
// RightBigSquare rbs = new RightBigSquare();
|
||||
// rbs.fileName = "E017B_N54E";
|
||||
// rbs.readFromFile(dir1);
|
||||
// Teren.generateData(fileNames, dir1, newDir);
|
||||
|
||||
// Teren.generateDataOldToNewFormat(fileNames, dir2, dir1, 25);
|
||||
// Teren.wygenerujCzysteDane(dir, 25, false, false, false, false, true, false, false, false, false);
|
||||
// Teren.wyzerujDane();
|
||||
// Teren.zapisBuforaMapyDoPliku();
|
||||
// String dir1 = "D:/work/kwadraty_nmt/withElevation/25m/";
|
||||
// Set<String> fileNames = NMTDataProvider.listFiles(dir1);
|
||||
// for (String fileName : fileNames) {
|
||||
// File file = new File(fileName);
|
||||
// String fn = file.getName().substring(0, file.getName().lastIndexOf('.'));
|
||||
// RightBigSquare rbs = new RightBigSquare();
|
||||
// rbs.fileName = fn;
|
||||
// rbs.readFromFile(dir1);
|
||||
// }
|
||||
|
||||
// rbs.writeToFile(newDir);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generuje pliki z danymi w nowym formacie na podstawie danych w satrym formacie.
|
||||
*
|
||||
* @param outDir katalog z danymi terenowymi np. "d:/Workspace2/kwadraty/czyste-wysokosc/"
|
||||
* @param dlmk docelowy rozmiar generowanych kwadratów terenu
|
||||
*/
|
||||
public static void generateDataFromOldFormat(Set<String> fileNames, String outDir, int dlmk) throws IOException {
|
||||
for (String fileName : fileNames) {
|
||||
File file = new File(fileName);
|
||||
String fn = file.getName();
|
||||
RightBigSquare rbs = new RightBigSquare();
|
||||
rbs.fileName = fn.substring(0, fn.length() - 4);
|
||||
rbs.readFromFile_OldFormat(null);
|
||||
rbs.writeToFile_ElevationOnly(outDir, dlmk);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generuje pliki z danymi w starym formacie na podstawie danych w nowym formacie.
|
||||
*
|
||||
* @param outDir katalog z danymi terenowymi np. "d:/Workspace2/kwadraty/czyste-wysokosc/"
|
||||
*/
|
||||
public static void generateDataToOldFormat(Set<String> fileNames, String inDir, String outDir) throws IOException {
|
||||
for (String fileName : fileNames) {
|
||||
File file = new File(fileName);
|
||||
String fn = file.getName().substring(0, file.getName().lastIndexOf('.'));
|
||||
RightBigSquare rbs = new RightBigSquare();
|
||||
rbs.fileName = fn;
|
||||
rbs.readFromFile(inDir);
|
||||
rbs.writeToFile_OldFormat(outDir);
|
||||
}
|
||||
}
|
||||
|
||||
public static void generateData(Set<String> fileNames, String inDir, String outDir) throws IOException {
|
||||
for (String fileName : fileNames) {
|
||||
File file = new File(fileName);
|
||||
String fn = file.getName().substring(0, file.getName().lastIndexOf('.'));
|
||||
RightBigSquare rbs = new RightBigSquare();
|
||||
rbs.fileName = fn;
|
||||
rbs.readFromFile(inDir);
|
||||
rbs.writeToFile(outDir);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
24
src/main/java/pl/wat/ms4ds/terrain/TerrainType.java
Normal file
24
src/main/java/pl/wat/ms4ds/terrain/TerrainType.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package pl.wat.ms4ds.terrain;
|
||||
|
||||
public enum TerrainType {
|
||||
NONE(0),
|
||||
GRASS(1),
|
||||
SWAMP(2),
|
||||
WATER(3),
|
||||
SCRUB_BUSHES(4),
|
||||
BUILDINGS(5),
|
||||
FOREST(6);
|
||||
|
||||
static final TerrainType[] values = values();
|
||||
|
||||
public static TerrainType valueFromId(int id) {
|
||||
return values[id];
|
||||
}
|
||||
|
||||
public final int id;
|
||||
|
||||
TerrainType(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
}
|
||||
87
src/main/java/pl/wat/ms4ds/terrain/TerrainUtils.java
Normal file
87
src/main/java/pl/wat/ms4ds/terrain/TerrainUtils.java
Normal file
@@ -0,0 +1,87 @@
|
||||
package pl.wat.ms4ds.terrain;
|
||||
|
||||
|
||||
public class TerrainUtils {
|
||||
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* Wyznacza widoczność optyczną w linii prostej między zadanymi kwadratami. Widoczność jest cechą symetryczną
|
||||
* względem badanych kwadratów.
|
||||
* <p> Wersja metody z wykorzystaniem
|
||||
*
|
||||
* @param ho
|
||||
* @param ht
|
||||
* @param x1
|
||||
* @param y1
|
||||
* @param x2
|
||||
* @param y2
|
||||
* @return
|
||||
*/
|
||||
public static int lineOfSight(float ho, float ht, int x1, int y1, int x2, int y2) {
|
||||
if ((x1 == x2) && (y1 == y2)) {
|
||||
return 1;
|
||||
}
|
||||
Square start = Teren.getSquare(x1, y1);
|
||||
Square stop = Teren.getSquare(x2, y2);
|
||||
if (start == Square.EMPTY || stop == Square.EMPTY) {
|
||||
return 0;
|
||||
}
|
||||
// roznica wysokosci miedzy skrajnymi kwadratami
|
||||
float heightDiff;
|
||||
float observerTotalHeight = start.elevation + ho;
|
||||
float targetTotalHeight = stop.elevation + ht;
|
||||
if (observerTotalHeight > targetTotalHeight) {
|
||||
// zamiana ról
|
||||
int swap = x1;
|
||||
x1 = x2;
|
||||
x2 = swap;
|
||||
swap = y1;
|
||||
y1 = y2;
|
||||
y2 = swap;
|
||||
heightDiff = observerTotalHeight - targetTotalHeight;
|
||||
observerTotalHeight = targetTotalHeight;
|
||||
} else {
|
||||
heightDiff = targetTotalHeight - observerTotalHeight;
|
||||
}
|
||||
int[] seq = GeomUtils.generateSquaresOfSegment2(x1, y1, x2, y2);
|
||||
double dist = Coord.Grid.distance(x1, y1, x2, y2);
|
||||
double tangAlfa0 = heightDiff / dist;
|
||||
|
||||
float dh_max = 0;
|
||||
// Tablica współrzędnych: x0, y0, x1, y1, x2, y2, x3, y3...
|
||||
// Testowane kwadraty pośrednie między startowym a końcowym.
|
||||
for (int i = 2; i < seq.length - 2; ) {
|
||||
// badanie wewnetrznych kwadratow nalezacych do odcinka,
|
||||
// czy nie sa powyzej linii widocznosci dla kwadratow skrajnych
|
||||
int x = seq[i++];
|
||||
int y = seq[i++];
|
||||
Square curr = Teren.getSquare(x, y);
|
||||
float obstacleHeight = switch (curr.terrainType) {
|
||||
case TerrainType.SCRUB_BUSHES -> 1;
|
||||
case TerrainType.BUILDINGS -> 10;
|
||||
case TerrainType.FOREST -> 10;
|
||||
default -> 0;
|
||||
};
|
||||
// wyznaczenie roznicy wysokosci kwadratu badanego i docelowego
|
||||
// uwzgledniajac wysokosc obserwatora oraz wysokosc przeszkody
|
||||
float dh = curr.elevation + obstacleHeight - observerTotalHeight;
|
||||
if (dh_max >= dh) {
|
||||
continue;
|
||||
}
|
||||
dist = Coord.Grid.distance(x, y, x1, y1);
|
||||
// float tangAlfa = roznWysAkt / odleg;
|
||||
// if (tangAlfa0 < tangAlfa) {
|
||||
if (tangAlfa0 * dist < dh) {
|
||||
// wysokosc aktualnie badanego kwadratu jest powyzej
|
||||
// linii poprowadzonej z kwadratu startowego do docelowego (z uwzglednieniem wysokosci obserwatora i celu)
|
||||
// odpowiednio dla katow dodatnich
|
||||
|
||||
return 0;
|
||||
}
|
||||
dh_max = dh;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
71
src/main/java/pl/wat/ms4ds/terrain/nmt/NmtData.java
Normal file
71
src/main/java/pl/wat/ms4ds/terrain/nmt/NmtData.java
Normal file
@@ -0,0 +1,71 @@
|
||||
package pl.wat.ms4ds.terrain.nmt;
|
||||
|
||||
/**
|
||||
* Klasa pomocnicza do generowania danych terenowych NMT.
|
||||
* <p>
|
||||
* Cachuje i agreguje dane dotyczące wysokości odczytane z siatki punktów
|
||||
* w ramach wyznaczonych granic kwadratu terenu (współrzędne PUWG1992).
|
||||
*/
|
||||
public class NmtData {
|
||||
|
||||
/**
|
||||
* Współrzędna X kwadratu w ramach siatki terenu.
|
||||
*/
|
||||
public int x;
|
||||
/**
|
||||
* Współrzędna X kwadratu w ramach siatki terenu.
|
||||
*/
|
||||
public int y;
|
||||
|
||||
/**
|
||||
* Suma wysokości z punktów "wpadających" do tego kwadratu.
|
||||
*/
|
||||
public double sum;
|
||||
|
||||
/**
|
||||
* Licznik punktów "wpadających" do tego kwadratu.
|
||||
*/
|
||||
public int count;
|
||||
|
||||
//
|
||||
// Granice kwadratu wyrażone za pomocą współrzędnych PUWG1992 używanych w danych NMT.
|
||||
//
|
||||
/**
|
||||
* Wpółrzędne PUWG1992 easting lewego dolnego wierzchołka.
|
||||
*/
|
||||
public double ell;
|
||||
/**
|
||||
* Wpółrzędne PUWG1992 northing lewego dolnego wierzchołka.
|
||||
*/
|
||||
public double nll;
|
||||
/**
|
||||
* Wpółrzędne PUWG1992 easting prawego górnego wierzchołka.
|
||||
*/
|
||||
public double eur;
|
||||
/**
|
||||
* Wpółrzędne PUWG1992 northing prawego górnego wierzchołka.
|
||||
*/
|
||||
public double nur;
|
||||
|
||||
|
||||
public NmtData(int x, int y, double sum, int count) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.sum = sum;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NMTData{" +
|
||||
"x=" + x +
|
||||
", y=" + y +
|
||||
", sum=" + sum +
|
||||
", count=" + count +
|
||||
", ell=" + ell +
|
||||
", nll=" + nll +
|
||||
", eur=" + eur +
|
||||
", nur=" + nur +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
500
src/main/java/pl/wat/ms4ds/terrain/nmt/NmtDataGenerator.java
Normal file
500
src/main/java/pl/wat/ms4ds/terrain/nmt/NmtDataGenerator.java
Normal file
@@ -0,0 +1,500 @@
|
||||
package pl.wat.ms4ds.terrain.nmt;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import pl.wat.ms4ds.terrain.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
/**
|
||||
* Klasa odpowiedzialna za generowanie danych wysokościowych w przyjętym formacie (sieci kwadratów) na podstawie
|
||||
* pobranych danych NMT (spakowane w plikach o nazwach skorowidzów).
|
||||
*/
|
||||
public class NmtDataGenerator {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(NmtDataGenerator.class);
|
||||
|
||||
static void main(String[] args) {
|
||||
|
||||
/*
|
||||
* Generowanie danych terenowych odbywa się na podstawie plików z danymi NMT w dwóch formatach:
|
||||
* ASC (siatka/tabela wysokość) TXT (współrzędne geo, wysokość). Pliki są spakowane.
|
||||
* Pliki znajdują się w lokalizacji określonej przez "inDir" w katalogach (odpowiadających skorowidzom).
|
||||
* W katalogu "idDir" znajdują się pliki textowe z listą nazw plików w podkatalogach skorowidzowych.
|
||||
* Dane wysokościowe z plików NMT przetwarzane są współbieżnie przez executora.
|
||||
* W ramach tego etapu/wątku:
|
||||
* 1. pliki są rozpakowywane do katalogu roboczego "workDir",
|
||||
* 2. po czym następuje ich odczyt i zapamiętanie danych szczegółowych w obiektach
|
||||
* NMTData (suma wysokości, licznik, granice kwadratu terenu we współrzędnych PUWG1992),
|
||||
* 3. obiekty NMTData (odpowiadające kwadratom terenu) są cachowane w hashmapie
|
||||
* indywidualnie w ramach wątku executora.
|
||||
* 4. po zakończeniu odczytu plik jest usuwany,
|
||||
* 5. następnie dane zagregowane (średnie wysokości) są zapisywane do kwadratów terenu
|
||||
* (zapis w kwadratach jest synchronizowany).
|
||||
*
|
||||
* Wątki są synchronizowane po tym etapie w celu zrzucenia zaktualizowanych danych na dysk.
|
||||
*
|
||||
*/
|
||||
|
||||
String inDir = "D:/work/nmt/";
|
||||
String workDir = "D:/work/temp/";
|
||||
String outDir = "D:/work/kwadraty_nmt/temp/100m/";
|
||||
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
list.add("m-33");
|
||||
list.add("m-34");
|
||||
list.add("m-35");
|
||||
list.add("n-33");
|
||||
list.add("n-34");
|
||||
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
|
||||
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
String fn_list = inDir + list.get(i) + "_files.txt";
|
||||
generateNMTData(executor, fn_list, 0, 24000, inDir + list.get(i) + "/", workDir, outDir);
|
||||
}
|
||||
|
||||
System.out.println("End.");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generuje dane na podstawie listy spakowanych (zip) plików z podanego katalogu.
|
||||
*
|
||||
* @param fn_list
|
||||
* @param startPos
|
||||
* @param endPos
|
||||
* @param inDir
|
||||
* @param workDir
|
||||
* @param outDir
|
||||
*/
|
||||
static void generateNMTData(ExecutorService executor, String fn_list, int startPos, int endPos, String inDir, String workDir, String outDir) {
|
||||
final int TN = 8;
|
||||
File file = new File(fn_list);
|
||||
ArrayList<String> fileNames = new ArrayList<>();
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)))) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
fileNames.add(line);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
return;
|
||||
}
|
||||
int count = 0;
|
||||
int i = startPos;
|
||||
ArrayList<Future> futures = new ArrayList<>();
|
||||
while (i < endPos) {
|
||||
if (i >= fileNames.size()) {
|
||||
break;
|
||||
}
|
||||
int j;
|
||||
for (j = 0; j < TN; j++) {
|
||||
if (i >= fileNames.size()) {
|
||||
break;
|
||||
}
|
||||
// asynchroniczne wywołanie zadania
|
||||
int ii = i;
|
||||
i++;
|
||||
Future future = executor.submit(() -> {
|
||||
long start = System.currentTimeMillis();
|
||||
String fn = fileNames.get(ii);
|
||||
File f = null;
|
||||
String[] unzippedFileNames = null;
|
||||
try {
|
||||
unzippedFileNames = unzipFile(inDir + fn, workDir);
|
||||
} catch (IOException e) {
|
||||
logger.warn("IO error while processing zip file: {}", inDir + fn);
|
||||
} catch (Exception e) {
|
||||
logger.warn(e.getMessage());
|
||||
}
|
||||
HashMap<Coord.Grid, NmtData> nmtDataHashMap = new HashMap<>();
|
||||
for (String ufn : unzippedFileNames) {
|
||||
String fpath = workDir + ufn;
|
||||
try {
|
||||
f = new File(fpath);
|
||||
if (f.length() < 10) {
|
||||
logger.warn("File: {} is empty.", ufn);
|
||||
continue;
|
||||
}
|
||||
readFromFile(fpath, nmtDataHashMap);
|
||||
} catch (Exception e) {
|
||||
logger.warn("Error while reading from file: {}.", ufn);
|
||||
} finally {
|
||||
if (f != null) {
|
||||
f.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Coord.Grid gridCoord : nmtDataHashMap.keySet()) {
|
||||
NmtData nmtData = nmtDataHashMap.get(gridCoord);
|
||||
if (nmtData.count > 0) {
|
||||
Square square = Teren.getSquare(gridCoord.x, gridCoord.y);
|
||||
if (square == Square.EMPTY) {
|
||||
continue;
|
||||
}
|
||||
synchronized (square) {
|
||||
square.elevation = (float) (nmtData.sum / nmtData.count);
|
||||
// Zaokrąglenie do ćwiartki metra (0.0, 0.25, 0.5, 0.75)
|
||||
//
|
||||
square.elevation *= 4;
|
||||
square.elevation = (int) square.elevation;
|
||||
square.elevation /= 4;
|
||||
if (H_MIN >= square.elevation || H_MAX <= square.elevation) {
|
||||
logger.trace("!!!Dane poza zakresem: h= {}", square.elevation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nmtDataHashMap.clear();
|
||||
logger.debug("File processed: {}, duration= {}[ms], status: {}/{}", fn, System.currentTimeMillis() - start, ii, endPos - 1);
|
||||
});
|
||||
futures.add(future);
|
||||
}
|
||||
count += j;
|
||||
// Punkt synchronizacyjny.
|
||||
for (Future future : futures) {
|
||||
try {
|
||||
future.get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
logger.warn("Error in thread: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
futures.clear();
|
||||
if (count % 2000 == 0) {
|
||||
Teren.saveToFiles(outDir);
|
||||
}
|
||||
}
|
||||
Teren.saveToFiles(outDir);
|
||||
logger.info("Finished processing file list: {}", fn_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generuje dane na podstawie rozpakowanych danych z podanego katalogu.
|
||||
*
|
||||
* @param inDir
|
||||
* @param workDir
|
||||
* @param outDir
|
||||
*/
|
||||
static void generateNMTData(String inDir, String workDir, String outDir) {
|
||||
Set<String> files = NmtDataProvider.listFiles(inDir);
|
||||
HashMap<Coord.Grid, NmtData> nmtDataHashMap = new HashMap<>();
|
||||
for (String fn : files) {
|
||||
String fpath = workDir + fn;
|
||||
try {
|
||||
readFromFile(fpath, nmtDataHashMap);
|
||||
File f = new File(fpath);
|
||||
f.delete();
|
||||
} catch (Exception e) {
|
||||
logger.warn("Error while reading from file: {}", fpath);
|
||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter("D:/Work/nmt/status.txt", true))) {
|
||||
writer.write("Error while processing file: " + fn);
|
||||
} catch (IOException e1) {
|
||||
logger.error(e1.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Coord.Grid gridCoord : nmtDataHashMap.keySet()) {
|
||||
NmtData nmtData = nmtDataHashMap.get(gridCoord);
|
||||
Square square = Teren.getSquare(gridCoord.x, gridCoord.y);
|
||||
if (square == Square.EMPTY) {
|
||||
continue;
|
||||
}
|
||||
if (nmtData.count > 0) {
|
||||
square.elevation = (float) (nmtData.sum / nmtData.count);
|
||||
// Konwersja na jednostkę 0.25m i zaokrąglenie do (0.0, 0.25, 0.5, 0.75)
|
||||
square.elevation *= 4;
|
||||
square.elevation = (int) square.elevation;
|
||||
square.elevation /= 4;
|
||||
if (H_MIN >= square.elevation || H_MAX <= square.elevation) {
|
||||
logger.trace("!!!Dane poza zakresem: h= {}", square.elevation);
|
||||
}
|
||||
}
|
||||
}
|
||||
nmtDataHashMap.clear();
|
||||
Teren.saveToFiles(outDir);
|
||||
}
|
||||
|
||||
private static void saveFileList(String fn, String[] fileList) throws IOException {
|
||||
BufferedWriter writer = new BufferedWriter(new FileWriter(fn));
|
||||
for (String val : fileList) {
|
||||
writer.write(val);
|
||||
writer.newLine();
|
||||
}
|
||||
writer.close();
|
||||
}
|
||||
|
||||
// usuwanie z nazwy nadmiarowych rozszerz przed rozszerzeniem
|
||||
static void renameFiles(String inDir, String outDir) {
|
||||
Set<String> fileNames = NmtDataProvider.listFiles(inDir);
|
||||
for (String fn : fileNames) {
|
||||
String nfn = fn.substring(0, fn.indexOf('.'));
|
||||
File fileToMove = new File(inDir + fn);
|
||||
boolean isMoved = fileToMove.renameTo(new File(outDir + nfn + ".zip"));
|
||||
if (!isMoved) {
|
||||
logger.warn("Failed to rename {} to {}", inDir + fn, outDir + nfn + ".zip");
|
||||
}
|
||||
System.out.println(nfn);
|
||||
}
|
||||
}
|
||||
|
||||
// dodanie 0 do liczb dla wyrównania długości
|
||||
static void renameFiles2(String inDir, String outDir) {
|
||||
Set<String> fileNames = NmtDataProvider.listFiles(inDir);
|
||||
for (String fn : fileNames) {
|
||||
if (fn.length() >= 20) {
|
||||
continue;
|
||||
}
|
||||
// M-33-70-A-d-4-3.zip
|
||||
// M-33-7-A-d-4-3.zip
|
||||
int pos1 = fn.indexOf('-', 3);
|
||||
int pos2 = fn.indexOf('-', pos1 + 1);
|
||||
String f1 = fn.substring(0, pos1 + 1);
|
||||
String f2 = fn.substring(pos2);
|
||||
String val = fn.substring(pos1 + 1, pos2);
|
||||
int v = Integer.parseInt(val);
|
||||
String val_0;
|
||||
if (v < 10) {
|
||||
val_0 = "00" + val;
|
||||
} else if (v < 100) {
|
||||
val_0 = "0" + val;
|
||||
} else {
|
||||
val_0 = val;
|
||||
}
|
||||
String nfn = f1 + val_0 + f2;
|
||||
File fileToMove = new File(inDir + fn);
|
||||
boolean isMoved = fileToMove.renameTo(new File(outDir + nfn));
|
||||
if (!isMoved) {
|
||||
logger.warn("Failed to rename {} to {}", inDir + fn, outDir + nfn);
|
||||
}
|
||||
System.out.println(nfn);
|
||||
}
|
||||
}
|
||||
|
||||
private static void readFromFile(String fn, HashMap<Coord.Grid, NmtData> nmtDataHashMap) throws IOException {
|
||||
File file = new File(fn);
|
||||
InputStream inputStream = new FileInputStream(file);
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStream))) {
|
||||
String line = br.readLine();
|
||||
// Dzieli na podstringi biorąc jako znak podziału spację i jej wielokrotność
|
||||
// nawias kwadratowy zawiera znaki podziału
|
||||
String[] split = line.split("[ ]+");
|
||||
// Identyfikacja formatu na podstawie liczby danych w pierwszej linii.
|
||||
if (split.length == 2) {
|
||||
// ASC GRID format
|
||||
readASC(br, line, nmtDataHashMap);
|
||||
} else {
|
||||
// split.length ==3
|
||||
// XYZ format
|
||||
readXYZ(br, line, nmtDataHashMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final int H_MIN = -70;
|
||||
public static final int H_MAX = 2660;
|
||||
|
||||
private static void readASC(BufferedReader br, String firstLine, HashMap<Coord.Grid, NmtData> nmtDataHashMap) throws IOException {
|
||||
String line = firstLine;
|
||||
// Dzieli na podstringi biorąc jako znak podziału spację i jej wielokrotność
|
||||
// nawias kwadratowy zawiera znaki podziału
|
||||
String[] split = line.split("[ ]+");
|
||||
int ncols = Integer.parseInt(split[1]);
|
||||
line = br.readLine();
|
||||
split = line.split("[ ]+");
|
||||
int nrows = Integer.parseInt(split[1]);
|
||||
line = br.readLine();
|
||||
split = line.split("[ ]+");
|
||||
double xll_puwg = Double.parseDouble(split[1]);
|
||||
line = br.readLine();
|
||||
split = line.split("[ ]+");
|
||||
double yll_puwg = Double.parseDouble(split[1]);
|
||||
line = br.readLine();
|
||||
split = line.split("[ ]+");
|
||||
double cellsize = Double.parseDouble(split[1]);
|
||||
line = br.readLine();
|
||||
split = line.split("[ ]+");
|
||||
double nodata = Double.parseDouble(split[1]);
|
||||
double[][] data = new double[nrows][ncols];
|
||||
String s;
|
||||
for (int i = nrows - 1; i >= 0; i--) {
|
||||
line = br.readLine();
|
||||
// start od 0 (brak spacji na początku) lub 1 (wiersz zaczyna się od spacji)
|
||||
int start = (line.charAt(0) == ' ') ? 1 : 0;
|
||||
int end;
|
||||
for (int j = 0; j < ncols - 1; j++) {
|
||||
end = line.indexOf(' ', start);
|
||||
while (end - start == 0 && start < line.length() - 1) {
|
||||
start = end + 1;
|
||||
end = line.indexOf(' ', start);
|
||||
}
|
||||
s = line.substring(start, end);
|
||||
start = end + 1;
|
||||
data[i][j] = Double.parseDouble(s);
|
||||
}
|
||||
end = line.indexOf(' ', start);
|
||||
while (end - start == 0 && start < line.length() - 1) {
|
||||
start = end + 1;
|
||||
end = line.indexOf(' ', start);
|
||||
}
|
||||
s = line.substring(start);
|
||||
data[i][ncols - 1] = Double.parseDouble(s);
|
||||
}
|
||||
NmtData nmtData = new NmtData(-1, -1, 0, 0);
|
||||
Coord.Geo geoCoord = new Coord.Geo();
|
||||
Coord.Puwg puwgCoord = new Coord.Puwg();
|
||||
double h;
|
||||
int x;
|
||||
int y;
|
||||
double y_puwg = yll_puwg;
|
||||
for (int i = 0; i < nrows; i++) {
|
||||
double x_puwg = xll_puwg;
|
||||
for (int j = 0; j < ncols; j++) {
|
||||
h = data[i][j];
|
||||
if (h == nodata) {
|
||||
// Przejdź do następnej kolumny danych.
|
||||
x_puwg += cellsize;
|
||||
continue;
|
||||
}
|
||||
if (nmtData.ell > x_puwg || nmtData.eur < x_puwg || nmtData.nll > y_puwg || nmtData.nur < y_puwg) {
|
||||
// Punkt poza granicą bieżącego kwadratu.
|
||||
Coord.convertPUWG1992ToWGS84(y_puwg, x_puwg, geoCoord);
|
||||
x = Coord.convertLonToGridX(geoCoord.lon);
|
||||
y = Coord.convertLatToGridY(geoCoord.lat);
|
||||
final int x1 = x;
|
||||
final int y1 = y;
|
||||
nmtData = nmtDataHashMap.computeIfAbsent(new Coord.Grid(x, y), k -> new NmtData(x1, y1, 0, 0));
|
||||
if (nmtData.nur == 0) {
|
||||
// Kwadrat jeszcze nie był odczytany (czysty).
|
||||
// Współrzędne geo środka kwadratu.
|
||||
geoCoord.lon = Coord.convertGridXToLon(x);
|
||||
geoCoord.lat = Coord.covertGridYToLat(y);
|
||||
// Wyznacz współrzędne PUWG lewego dolnego rogu kwadratu.
|
||||
Coord.convertWGS84ToPUWG1992(geoCoord.lat - MapConsts.SS_DELTA_LAT / 2, geoCoord.lon - MapConsts.SS_DELTA_LON / 2, puwgCoord);
|
||||
nmtData.ell = (int) puwgCoord.easting;
|
||||
nmtData.nll = (int) puwgCoord.northing;
|
||||
// Wyznacz współrzędne PUWG prawego górnego rogu kwadratu.
|
||||
Coord.convertWGS84ToPUWG1992(geoCoord.lat + MapConsts.SS_DELTA_LAT / 2, geoCoord.lon + MapConsts.SS_DELTA_LON / 2, puwgCoord);
|
||||
nmtData.eur = (int) puwgCoord.easting;
|
||||
nmtData.nur = (int) puwgCoord.northing;
|
||||
}
|
||||
}
|
||||
nmtData.sum += h;
|
||||
nmtData.count++;
|
||||
// Przejdź do następnej kolumny.
|
||||
x_puwg += cellsize;
|
||||
}
|
||||
// Przejdź do następnego wiersza.
|
||||
y_puwg += cellsize;
|
||||
}
|
||||
}
|
||||
|
||||
private static void readXYZ(BufferedReader br, String firstLine, HashMap<Coord.Grid, NmtData> nmtDataHashMap) throws IOException {
|
||||
Coord.Puwg puwgCoord = new Coord.Puwg();
|
||||
Coord.Geo geo = new Coord.Geo();
|
||||
String line = firstLine;
|
||||
if (line.charAt(0) == 'S' || line.charAt(0) == 'E') {
|
||||
line = br.readLine();
|
||||
}
|
||||
char c = ' ';
|
||||
if (line.indexOf('\t', 1) != -1) {
|
||||
c = '\t';
|
||||
}
|
||||
double x_puwg;
|
||||
double y_puwg;
|
||||
double h;
|
||||
int x;
|
||||
int y;
|
||||
NmtData nmtData = new NmtData(-1, -1, 0, 0);
|
||||
int start;
|
||||
int end;
|
||||
int row = 0;
|
||||
while (line != null) {
|
||||
if (line.length() < 5 || line.charAt(0) == 'S' || line.charAt(0) == 'E') {
|
||||
line = br.readLine();
|
||||
row++;
|
||||
continue;
|
||||
}
|
||||
// start od 0, gdyż nie ma spacji na początku
|
||||
start = 0;
|
||||
end = line.indexOf(c, start);
|
||||
while (end - start == 0 && start < line.length() - 1) {
|
||||
start = end + 1;
|
||||
end = line.indexOf(c, start);
|
||||
}
|
||||
String s = line.substring(start, end);
|
||||
x_puwg = Double.parseDouble(s);
|
||||
start = end + 1;
|
||||
end = line.indexOf(c, start);
|
||||
while (end - start == 0 && start < line.length() - 1) {
|
||||
start = end + 1;
|
||||
end = line.indexOf(c, start);
|
||||
}
|
||||
s = line.substring(start, end);
|
||||
y_puwg = Double.parseDouble(s);
|
||||
start = end + 1;
|
||||
s = line.substring(start);
|
||||
h = Double.parseDouble(s);
|
||||
if (nmtData.ell > x_puwg || nmtData.eur < x_puwg || nmtData.nll > y_puwg || nmtData.nur < y_puwg) {
|
||||
// Punkt poza granicą bieżącego kwadratu.
|
||||
Coord.convertPUWG1992ToWGS84(y_puwg, x_puwg, geo);
|
||||
x = Coord.convertLonToGridX(geo.lon);
|
||||
y = Coord.convertLatToGridY(geo.lat);
|
||||
final int x1 = x;
|
||||
final int y1 = y;
|
||||
nmtData = nmtDataHashMap.computeIfAbsent(new Coord.Grid(x1, y1), k -> new NmtData(x1, y1, 0, 0));
|
||||
if (nmtData.nur == 0) {
|
||||
// Kwadrat jeszcze nie był odczytany (czysty).
|
||||
// Współrzędne geo środka kwadratu.
|
||||
geo.lon = Coord.convertGridXToLon(x);
|
||||
geo.lat = Coord.covertGridYToLat(y);
|
||||
// Wyznacz współrzędne PUWG lewego dolnego rogu kwadratu.
|
||||
Coord.convertWGS84ToPUWG1992(geo.lat - MapConsts.SS_DELTA_LAT / 2, geo.lon - MapConsts.SS_DELTA_LON / 2, puwgCoord);
|
||||
nmtData.ell = (int) puwgCoord.easting;
|
||||
nmtData.nll = (int) puwgCoord.northing;
|
||||
// Wyznacz współrzędne PUWG prawego górnego rogu kwadratu.
|
||||
Coord.convertWGS84ToPUWG1992(geo.lat + MapConsts.SS_DELTA_LAT / 2, geo.lon + MapConsts.SS_DELTA_LON / 2, puwgCoord);
|
||||
nmtData.eur = (int) puwgCoord.easting;
|
||||
nmtData.nur = (int) puwgCoord.northing;
|
||||
}
|
||||
}
|
||||
nmtData.sum += h;
|
||||
nmtData.count++;
|
||||
line = br.readLine();
|
||||
row++;
|
||||
}
|
||||
}
|
||||
|
||||
public static String[] unzipFile(String zipFileName, String destDir) throws IOException {
|
||||
byte[] buffer = new byte[1024];
|
||||
String[] unzipFileNames = new String[10];
|
||||
int i = 0;
|
||||
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFileName))) {
|
||||
ZipEntry zipEntry = zis.getNextEntry();
|
||||
while (zipEntry != null) {
|
||||
unzipFileNames[i] = zipEntry.getName();
|
||||
File newFile = new File(destDir + unzipFileNames[i]);
|
||||
// File newFile = new File(destDir + File.separator + unzipFileName);
|
||||
int len;
|
||||
// write file content
|
||||
FileOutputStream fos = new FileOutputStream(newFile);
|
||||
while ((len = zis.read(buffer)) > 0) {
|
||||
fos.write(buffer, 0, len);
|
||||
}
|
||||
fos.close();
|
||||
zipEntry = zis.getNextEntry();
|
||||
i++;
|
||||
}
|
||||
zis.closeEntry();
|
||||
}
|
||||
if (i > 0) {
|
||||
unzipFileNames = Arrays.copyOf(unzipFileNames, i);
|
||||
} else {
|
||||
unzipFileNames = new String[0];
|
||||
}
|
||||
return unzipFileNames;
|
||||
}
|
||||
}
|
||||
207
src/main/java/pl/wat/ms4ds/terrain/nmt/NmtDataProvider.java
Normal file
207
src/main/java/pl/wat/ms4ds/terrain/nmt/NmtDataProvider.java
Normal file
@@ -0,0 +1,207 @@
|
||||
package pl.wat.ms4ds.terrain.nmt;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.xml.stream.XMLInputFactory;
|
||||
import javax.xml.stream.XMLStreamConstants;
|
||||
import javax.xml.stream.XMLStreamReader;
|
||||
import java.io.*;
|
||||
import java.net.URI;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/**
|
||||
* Klasa odpowiedzialna za pozyskanie danych wysokościowych (NMT) ze stron geoportal.
|
||||
*/
|
||||
public class NmtDataProvider {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(NmtDataProvider.class);
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
String dir = "C:/Workspace/nmt/gugik_1m/unzip/";
|
||||
Set<String> files = listFiles(dir);
|
||||
for (String file : files) {
|
||||
String fn = file.substring(0, file.indexOf('.'));
|
||||
zipFile(dir + fn);
|
||||
File f = new File(dir + file);
|
||||
f.delete();
|
||||
}
|
||||
// File dir = new File(System.getProperty("user.home") + "/nmt/gugik_SkorowidzNMT2018.gml");
|
||||
// HashMap<String, String> map = new HashMap<>();
|
||||
// String fn0 = "D:/nmt/gugik_SkorowidzNMT20";
|
||||
// for (int i = 18; i < 26; i++) {
|
||||
// readFileLinksFromGugikXml(fn0 + i + ".gml", map);
|
||||
// }
|
||||
// saveLinks("D:/nmt/gugik_links.txt", map);
|
||||
|
||||
// start = 580-730, start=1091-1230
|
||||
//
|
||||
// String dir = "C:/Workspace/nmt/gugik_1m/";
|
||||
// String links_fn = "C:/Workspace/nmt/gugik_links.txt";
|
||||
// String dir = args[0];
|
||||
// String links_fn = args[1];
|
||||
// int start = Integer.parseInt(args[2]);
|
||||
// int end = Integer.parseInt(args[3]);
|
||||
|
||||
// Set<String> files = listFiles("C:/Workspace/nmt/gugik_1m/");
|
||||
|
||||
|
||||
// downloadFileSet(links_fn, start, end, dir);
|
||||
|
||||
LOGGER.info("Koniec");
|
||||
}
|
||||
|
||||
private static void saveLinks(String fn, HashMap<String, String> map) throws IOException {
|
||||
BufferedWriter writer = new BufferedWriter(new FileWriter(fn));
|
||||
for (String val : map.values()) {
|
||||
writer.write(val);
|
||||
writer.newLine();
|
||||
}
|
||||
writer.close();
|
||||
}
|
||||
|
||||
private static void downloadFile2(String urlStr, String dirName) throws IOException {
|
||||
String fn = urlStr.substring(urlStr.lastIndexOf('_') + 1);
|
||||
String path = dirName + fn;
|
||||
// URI uri = URI.create("https://opendata.geoportal.gov.pl/NumDaneWys/NMT/81441/81441_1643337_N-34-125-D-d-3-1.asc");
|
||||
URI uri = URI.create(urlStr);
|
||||
InputStream inputStream = uri.toURL().openStream();
|
||||
ReadableByteChannel readableByteChannel = Channels.newChannel(inputStream);
|
||||
FileOutputStream fos = new FileOutputStream(path);
|
||||
FileChannel fc = fos.getChannel();
|
||||
fc.transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
|
||||
fc.close();
|
||||
fos.close();
|
||||
}
|
||||
|
||||
public static Set<String> listFiles(String dir) {
|
||||
return Stream.of(new File(dir).listFiles())
|
||||
.filter(file -> !file.isDirectory())
|
||||
.map(File::getName)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private static void downloadFile(String urlStr, String dirName) throws IOException {
|
||||
String fn = urlStr.substring(urlStr.lastIndexOf('_') + 1);
|
||||
String path = dirName + fn;
|
||||
URI uri = URI.create(urlStr);
|
||||
try (InputStream inputStream = uri.toURL().openStream();) {
|
||||
BufferedInputStream bis = new BufferedInputStream(inputStream);
|
||||
FileOutputStream fos;
|
||||
String fext = fn.substring(fn.lastIndexOf('.') + 1);
|
||||
byte[] buffer = new byte[1024];
|
||||
int count;
|
||||
if (!fext.equals("zip")) {
|
||||
fos = new FileOutputStream(path + ".zip");
|
||||
ZipOutputStream zipOut = new ZipOutputStream(fos);
|
||||
File fileToZip = new File(path);
|
||||
ZipEntry zipEntry = new ZipEntry(fileToZip.getName());
|
||||
zipOut.putNextEntry(zipEntry);
|
||||
while ((count = bis.read(buffer)) != -1) {
|
||||
zipOut.write(buffer, 0, count);
|
||||
}
|
||||
zipOut.close();
|
||||
bis.close();
|
||||
return;
|
||||
}
|
||||
fos = new FileOutputStream(path);
|
||||
while ((count = bis.read(buffer, 0, 1024)) != -1) {
|
||||
fos.write(buffer, 0, count);
|
||||
}
|
||||
fos.close();
|
||||
bis.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static void zipFile(String sourceFile) throws IOException {
|
||||
FileOutputStream fos = new FileOutputStream(sourceFile + ".zip");
|
||||
ZipOutputStream zipOut = new ZipOutputStream(fos);
|
||||
|
||||
File fileToZip = new File(sourceFile + ".asc");
|
||||
FileInputStream fis = new FileInputStream(fileToZip);
|
||||
ZipEntry zipEntry = new ZipEntry(fileToZip.getName());
|
||||
zipOut.putNextEntry(zipEntry);
|
||||
byte[] bytes = new byte[1024];
|
||||
int length;
|
||||
while ((length = fis.read(bytes)) >= 0) {
|
||||
zipOut.write(bytes, 0, length);
|
||||
}
|
||||
zipOut.close();
|
||||
fis.close();
|
||||
fos.close();
|
||||
}
|
||||
|
||||
private static void downloadFileSet(String fn, int start, int end, String dirName) throws IOException {
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(fn)))) {
|
||||
File dir = new File(dirName);
|
||||
dir.mkdirs();
|
||||
String line;
|
||||
int i = 0;
|
||||
while ((line = br.readLine()) != null) {
|
||||
if (i >= start) {
|
||||
if (i >= end) {
|
||||
break;
|
||||
}
|
||||
// LOGGER.debug("Start i={}, addr={}", i, line);
|
||||
try {
|
||||
downloadFile(line, dirName);
|
||||
} catch (IOException e) {
|
||||
LOGGER.debug("Downloading error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Funkcja wykorzystana jednokrotnie w celu integracji w jednym pliku wszystkich linków
|
||||
// do zasobów rozproszonych w wielu plikach.
|
||||
private static void readFileLinksFromGugikXml(String fn, HashMap<String, String> map) throws Exception {
|
||||
XMLInputFactory factory = XMLInputFactory.newInstance();
|
||||
FileInputStream is = new FileInputStream(fn);
|
||||
BufferedInputStream bis = new BufferedInputStream(is);
|
||||
// XMLStreamReader reader = factory.createXMLStreamReader(ClassLoader.getSystemResourceAsStream(fn));
|
||||
XMLStreamReader reader = factory.createXMLStreamReader(bis);
|
||||
String tagContent;
|
||||
boolean foundLink = false;
|
||||
LOGGER.debug("Poczatek odczytu z pliku: " + fn);
|
||||
while (reader.hasNext()) {
|
||||
int eventType = reader.next();
|
||||
switch (eventType) {
|
||||
case XMLStreamConstants.START_ELEMENT:
|
||||
String str = reader.getLocalName();
|
||||
if ("url_do_pobrania".equals(str)) {
|
||||
foundLink = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case XMLStreamConstants.CHARACTERS:
|
||||
if (foundLink) {
|
||||
tagContent = reader.getText().trim();
|
||||
String godlo = tagContent.substring(tagContent.lastIndexOf('_') + 1);
|
||||
godlo = godlo.substring(0, godlo.indexOf('.'));
|
||||
String old = map.remove(godlo);
|
||||
map.put(godlo, tagContent);
|
||||
foundLink = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case XMLStreamConstants.END_ELEMENT:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
reader.close();
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
164
src/main/java/pl/wat/ms4ds/terrain/osm/CoordTest.java
Normal file
164
src/main/java/pl/wat/ms4ds/terrain/osm/CoordTest.java
Normal file
@@ -0,0 +1,164 @@
|
||||
package pl.wat.ms4ds.terrain.osm;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import pl.wat.ms4ds.terrain.Coord;
|
||||
|
||||
public class CoordTest {
|
||||
static Logger logger = LoggerFactory.getLogger(CoordTest.class);
|
||||
|
||||
static void main() {
|
||||
|
||||
byte[] INT_BYTE_ARRAY = new byte[]{
|
||||
(byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE
|
||||
};
|
||||
int intValue = 0xCAFEBABE;
|
||||
int v1 = 32000;
|
||||
short value = 32033;
|
||||
byte[] bytes1 = new byte[Short.BYTES];
|
||||
int length = bytes1.length;
|
||||
for (int i = 0; i < length; i++) {
|
||||
bytes1[length - i - 1] = (byte) (value & 0xFF);
|
||||
value >>= 8;
|
||||
}
|
||||
value = 0;
|
||||
for (byte b : bytes1) {
|
||||
value = (short) ((value << 8) + (b & 0xFF));
|
||||
}
|
||||
v1 = bytes1[0] & 0xFF;
|
||||
v1 = (v1 << 8) + (bytes1[1] & 0xFF);
|
||||
value = (short) v1;
|
||||
|
||||
// try {
|
||||
// BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("./CoordTest.bin"));
|
||||
short[] val1 = {-4, -100, 32035, 32036, 32037};
|
||||
byte[] val2 = {24, 25, 26, 27, 28};
|
||||
byte[] val3 = {7, 8, 9, 10, 11};
|
||||
int pos = 0;
|
||||
byte[] buf = new byte[4 * 5];
|
||||
for (int i = 0; i < 5; i++) {
|
||||
// 4 * i - pozycja startowa i-tego recordu
|
||||
pos = 4 * i;
|
||||
short val = val1[i];
|
||||
buf[pos + 1] = (byte) (val & 0xFF);
|
||||
val >>= 8;
|
||||
buf[pos] = (byte) (val & 0xFF);
|
||||
buf[pos + 2] = val2[i];
|
||||
buf[pos + 3] = val3[i];
|
||||
}
|
||||
// out.write(buf);
|
||||
// out.flush();
|
||||
// out.close();
|
||||
|
||||
// BufferedInputStream in = new BufferedInputStream(new FileInputStream("./CoordTest.bin"), 8);
|
||||
// byte[] buf = new byte[4 * 5];
|
||||
// in.read(buf2);
|
||||
for (int i = 0; i < 5; i++) {
|
||||
// 4 * i - pozycja startowa i-tego recordu
|
||||
pos = 4 * i;
|
||||
v1 = buf[pos] & 0xFF;
|
||||
v1 = (v1 << 8) | (buf[pos + 1] & 0xFF);
|
||||
val1[i] = (short) v1;
|
||||
val2[i] = buf[pos + 2];
|
||||
val3[i] = buf[pos + 3];
|
||||
}
|
||||
// in.close();
|
||||
|
||||
// } catch (IOException e) {
|
||||
// System.out.println(e.getMessage());
|
||||
// }
|
||||
|
||||
|
||||
short e1 = 110;
|
||||
float elevation = (float) (e1) / 4;
|
||||
e1 = 111;
|
||||
elevation = (float) (e1) / 4;
|
||||
float f1 = 101.237f;
|
||||
f1 *= 4;
|
||||
f1 = (int) f1;
|
||||
f1 /= 4;
|
||||
f1 = 101.257f;
|
||||
f1 *= 4;
|
||||
f1 = (int) f1;
|
||||
f1 /= 4;
|
||||
f1 = 101.25f;
|
||||
f1 *= 4;
|
||||
f1 = (int) f1;
|
||||
f1 /= 4;
|
||||
f1 = 101.75f;
|
||||
f1 *= 4;
|
||||
f1 = (int) f1;
|
||||
f1 /= 4;
|
||||
f1 = 101.0237f;
|
||||
f1 *= 4;
|
||||
f1 = (int) f1;
|
||||
f1 /= 4;
|
||||
f1 = 101.82f;
|
||||
f1 *= 4;
|
||||
f1 = (int) f1;
|
||||
f1 /= 4;
|
||||
String s = String.format("e = %9.4f", Math.E);
|
||||
|
||||
logger.debug(" ");
|
||||
|
||||
Coord.Puwg puwgCoord = new Coord.Puwg();
|
||||
Coord.Geo geoCoord = new Coord.Geo();
|
||||
geoCoord.lon = 19;
|
||||
geoCoord.lat = 50;
|
||||
Coord.convertWGS84ToPUWG1992(geoCoord.lat, geoCoord.lon, puwgCoord);
|
||||
logger.debug("Lat={}, Lon={} => PUWG (e,n)=({}, {})", geoCoord.lat, geoCoord.lon, puwgCoord.easting, puwgCoord.northing);
|
||||
double e = puwgCoord.easting;
|
||||
double n = puwgCoord.northing;
|
||||
geoCoord.lon = 20;
|
||||
geoCoord.lat = 51;
|
||||
Coord.convertWGS84ToPUWG1992(geoCoord.lat, geoCoord.lon, puwgCoord);
|
||||
|
||||
double dx = puwgCoord.easting - e;
|
||||
double dy = puwgCoord.northing - n;
|
||||
|
||||
|
||||
logger.debug("Lat={}, Lon={} => PUWG (e,n)=({}, {})", geoCoord.lat, geoCoord.lon, puwgCoord.easting, puwgCoord.northing);
|
||||
Coord.convertPUWG1992ToWGS84(puwgCoord.northing, puwgCoord.easting, geoCoord);
|
||||
logger.debug("PUWG (e,n)=({}, {}) => Lat={}, Lon={}", puwgCoord.easting, puwgCoord.northing, geoCoord.lat, geoCoord.lon);
|
||||
|
||||
// coord.proj = 1;
|
||||
// CoordUtils.convertWGS84ToPUWG(coord, geoCoord.lat, geoCoord.lon);
|
||||
// logger.debug("Lat={}, Lon={}, PUWG (proj={}, e={}, n={})", geoCoord.lat, geoCoord.lon, coord.proj, coord.easting, coord.northing);
|
||||
// CoordUtils.convertPuwg1992ToWgs84(coord, geoCoord);
|
||||
// logger.debug("Lat={}, Lon={}, PUWG (proj={}, e={}, n={})", geoCoord.lat, geoCoord.lon, coord.proj, coord.easting, coord.northing);
|
||||
//
|
||||
// coord.proj = 2;
|
||||
// CoordUtils.convertWGS84ToPUWG(coord, geoCoord.lat, geoCoord.lon);
|
||||
// logger.debug("Lat={}, Lon={}, PUWG (proj={}, e={}, n={})", geoCoord.lat, geoCoord.lon, coord.proj, coord.easting, coord.northing);
|
||||
// CoordUtils.convertPuwg2000ToWgs84(coord, geoCoord);
|
||||
// logger.debug("Lat={}, Lon={}, PUWG (proj={}, e={}, n={})", geoCoord.lat, geoCoord.lon, coord.proj, coord.easting, coord.northing);
|
||||
// 195828.000 673108.000
|
||||
|
||||
// puwgCoord.easting = 253974;
|
||||
// puwgCoord.northing = 476879;
|
||||
puwgCoord.easting = 500000;
|
||||
puwgCoord.northing = 500000;
|
||||
logger.debug("----------------------------------");
|
||||
Coord.convertPUWG1992ToWGS84(puwgCoord.northing, puwgCoord.easting, geoCoord);
|
||||
logger.debug("PUWG (e,n)=({}, {}) => Lat={}, Lon={}", puwgCoord.easting, puwgCoord.northing, geoCoord.lat, geoCoord.lon);
|
||||
Coord.convertWGS84ToPUWG1992(geoCoord.lat, geoCoord.lon, puwgCoord);
|
||||
logger.debug("Lat={}, Lon={} => PUWG (e,n)=({}, {})", geoCoord.lat, geoCoord.lon, puwgCoord.easting, puwgCoord.northing);
|
||||
|
||||
|
||||
puwgCoord.easting = 100000;
|
||||
puwgCoord.northing = 470642;
|
||||
Coord.convertPUWG1992ToWGS84(puwgCoord.northing, puwgCoord.easting, geoCoord);
|
||||
logger.debug("PUWG (e,n)=({}, {}) => Lat={}, Lon={}", puwgCoord.easting, puwgCoord.northing, geoCoord.lat, geoCoord.lon);
|
||||
Coord.convertWGS84ToPUWG1992(geoCoord.lat, geoCoord.lon, puwgCoord);
|
||||
logger.debug("Lat={}, Lon={} => PUWG (e,n)=({}, {})", geoCoord.lat, geoCoord.lon, puwgCoord.easting, puwgCoord.northing);
|
||||
|
||||
puwgCoord.easting = 821310;
|
||||
puwgCoord.northing = 369750;
|
||||
Coord.convertPUWG1992ToWGS84(puwgCoord.northing, puwgCoord.easting, geoCoord);
|
||||
logger.debug("PUWG (e,n)=({}, {}) => Lat={}, Lon={}", puwgCoord.easting, puwgCoord.northing, geoCoord.lat, geoCoord.lon);
|
||||
Coord.convertWGS84ToPUWG1992(geoCoord.lat, geoCoord.lon, puwgCoord);
|
||||
logger.debug("Lat={}, Lon={} => PUWG (e,n)=({}, {})", geoCoord.lat, geoCoord.lon, puwgCoord.easting, puwgCoord.northing);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
116
src/main/java/pl/wat/ms4ds/terrain/osm/CoordUtils.java
Normal file
116
src/main/java/pl/wat/ms4ds/terrain/osm/CoordUtils.java
Normal file
@@ -0,0 +1,116 @@
|
||||
package pl.wat.ms4ds.terrain.osm;
|
||||
|
||||
import pl.wat.ms4ds.terrain.Coord;
|
||||
import pl.wat.ms4ds.terrain.Teren;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import pl.wat.ms4ds.terrain.nmt.NmtData;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* Odczyt danych wysokościowych z numerycznego modelu terenu (NMT_100).
|
||||
* <p>
|
||||
* Kod źródłowy funkcji do transformacji współrzędnych elipsoidalnych na płaskie odwzorowań kartograficznych UTM, 1992, 2000
|
||||
*/
|
||||
public class CoordUtils {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CoordUtils.class);
|
||||
|
||||
static String dataDir = "d:/Workspace2/dane_wysok/";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
|
||||
HashMap<Coord.Grid, NmtData> daneWysokHashMap = new HashMap();
|
||||
if (args.length > 0) {
|
||||
dataDir = args[0];
|
||||
}
|
||||
for (int i = 1; i < args.length; i++) {
|
||||
String nmt_fn = args[i];
|
||||
daneWysokHashMap.clear();
|
||||
readData(nmt_fn, daneWysokHashMap);
|
||||
for (NmtData daneWysok : daneWysokHashMap.values()) {
|
||||
// Square kw = Teren.getKwadrat(daneWysok.idKw.x, daneWysok.idKw.y);
|
||||
// kw.setWysokoscSrednia((int) (daneWysok.suma / daneWysok.licz + 0.5));
|
||||
}
|
||||
logger.debug("Poczatek zapisu danych dla regionu " + nmt_fn + " >> " + i + "/" + (args.length - 1));
|
||||
Teren.saveToFiles(null);
|
||||
logger.debug("Koniec zapisu danych dla regionu " + nmt_fn + " >> " + i + "/" + (args.length - 1));
|
||||
Teren.reset();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private static void readData(String fileName, HashMap<Coord.Grid, NmtData> daneWysokHashMap) throws IOException {
|
||||
try {
|
||||
StringBuilder sb = new StringBuilder(100);
|
||||
sb.append(dataDir);
|
||||
sb.append(fileName);
|
||||
sb.append(".txt");
|
||||
FileReader fis = new FileReader(sb.toString());
|
||||
// PUWG 1992
|
||||
Coord.Puwg puwgCoord = new Coord.Puwg();
|
||||
Coord.Geo latLon = new Coord.Geo();
|
||||
double wysokosc = 0.0;
|
||||
StringTokenizer st = null;
|
||||
String line = null;
|
||||
BufferedReader br = new BufferedReader(fis);
|
||||
if (br.ready()) {
|
||||
line = br.readLine();
|
||||
int m = 1;
|
||||
while (line != null) {
|
||||
st = new StringTokenizer(line, " ");
|
||||
if (st.countTokens() != 3) {
|
||||
continue;
|
||||
}
|
||||
String[] tokTable = new String[st.countTokens()];
|
||||
for (int i = 0; st.hasMoreTokens(); i++) {
|
||||
tokTable[i] = st.nextToken();
|
||||
}
|
||||
try {
|
||||
puwgCoord.easting = Double.parseDouble(tokTable[0]);
|
||||
} catch (NumberFormatException e) {
|
||||
logger.warn("Bledne dane w pliku: " + fileName);
|
||||
}
|
||||
try {
|
||||
puwgCoord.northing = Double.parseDouble(tokTable[1]);
|
||||
} catch (NumberFormatException e) {
|
||||
logger.warn("Bledne dane w pliku: " + fileName);
|
||||
}
|
||||
try {
|
||||
wysokosc = Double.parseDouble(tokTable[2]);
|
||||
} catch (NumberFormatException e) {
|
||||
logger.warn("Bledne dane w pliku: " + fileName);
|
||||
}
|
||||
Coord.convertPUWG1992ToWGS84(puwgCoord.northing, puwgCoord.easting, latLon);
|
||||
Coord.Grid idKw = new Coord.Grid(latLon.lon, latLon.lat);
|
||||
NmtData daneWysok = daneWysokHashMap.get(idKw);
|
||||
if (daneWysok == null) {
|
||||
daneWysok = new NmtData(idKw.x, idKw.y, wysokosc, 1);
|
||||
daneWysokHashMap.put(idKw, daneWysok);
|
||||
} else {
|
||||
daneWysok.sum += wysokosc;
|
||||
daneWysok.count++;
|
||||
}
|
||||
line = br.readLine();
|
||||
if (m++ % 100000 == 0) {
|
||||
System.out.print('-');
|
||||
}
|
||||
}
|
||||
}
|
||||
br.close();
|
||||
System.out.println();
|
||||
logger.debug("Koniec odczytu pliku: " + fileName);
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
9
src/main/java/pl/wat/ms4ds/terrain/osm/EAreaFeature.java
Normal file
9
src/main/java/pl/wat/ms4ds/terrain/osm/EAreaFeature.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package pl.wat.ms4ds.terrain.osm;
|
||||
|
||||
public enum EAreaFeature {
|
||||
|
||||
FOREST,
|
||||
SWAMP,
|
||||
WATER,
|
||||
BUILDINGS
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package pl.wat.ms4ds.terrain.osm;
|
||||
|
||||
public enum ELinearFeature {
|
||||
|
||||
ROAD,
|
||||
WATER_WAY,
|
||||
DITCH
|
||||
}
|
||||
47
src/main/java/pl/wat/ms4ds/terrain/osm/EOSMAmenity.java
Normal file
47
src/main/java/pl/wat/ms4ds/terrain/osm/EOSMAmenity.java
Normal file
@@ -0,0 +1,47 @@
|
||||
package pl.wat.ms4ds.terrain.osm;
|
||||
|
||||
public enum EOSMAmenity {
|
||||
|
||||
/**
|
||||
* v="hospital" | v="school" | v="post_office" | v="police" | v="marketplace" | v="fire_station" |
|
||||
* v="theatre" | v="cinema" | v="pharmacy" | v="nursing_home" | v="bank" | v="fuel"
|
||||
* v="university" | v="library" | v="clinic"
|
||||
*/
|
||||
HOSPITAL,
|
||||
SCHOOL,
|
||||
POST_OFFICE,
|
||||
POLICE,
|
||||
MARKETPLACE,
|
||||
FIRE_STATION,
|
||||
THEATRE,
|
||||
CINEMA,
|
||||
PHARMACY,
|
||||
NURSING_HOME,
|
||||
BANK,
|
||||
FUEL,
|
||||
UNIVERSITY,
|
||||
LIBRARY,
|
||||
CLINIC;
|
||||
|
||||
public static EOSMAmenity getValue(String str) {
|
||||
switch (str) {
|
||||
case "hospital": return HOSPITAL;
|
||||
case "school": return SCHOOL;
|
||||
case "post_office": return POST_OFFICE;
|
||||
case "police": return POLICE;
|
||||
case "marketplace": return MARKETPLACE;
|
||||
case "fire_station": return FIRE_STATION;
|
||||
case "theatre": return THEATRE;
|
||||
case "cinema": return CINEMA;
|
||||
case "pharmacy": return PHARMACY;
|
||||
case "nursing_home": return NURSING_HOME;
|
||||
case "bank": return BANK;
|
||||
case "fuel": return FUEL;
|
||||
case "university": return UNIVERSITY;
|
||||
case "library": return LIBRARY;
|
||||
case "clinic": return CLINIC;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
19
src/main/java/pl/wat/ms4ds/terrain/osm/EOSMBridge.java
Normal file
19
src/main/java/pl/wat/ms4ds/terrain/osm/EOSMBridge.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package pl.wat.ms4ds.terrain.osm;
|
||||
|
||||
public enum EOSMBridge {
|
||||
|
||||
/**
|
||||
* v="yes" | "viaduct"
|
||||
*/
|
||||
YES,
|
||||
VIADUCT;
|
||||
|
||||
public static EOSMBridge getValue(String str) {
|
||||
switch (str) {
|
||||
case "yes": return YES;
|
||||
case "viaduct": return VIADUCT;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
29
src/main/java/pl/wat/ms4ds/terrain/osm/EOSMBuilding.java
Normal file
29
src/main/java/pl/wat/ms4ds/terrain/osm/EOSMBuilding.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package pl.wat.ms4ds.terrain.osm;
|
||||
|
||||
public enum EOSMBuilding {
|
||||
|
||||
/**
|
||||
* v="yes" | v="chapel" | v="church" | v="house" | v="office" | v="manufacture" | v="industrial"
|
||||
*/
|
||||
YES,
|
||||
CHAPEL,
|
||||
CHURCH,
|
||||
HOUSE,
|
||||
OFFICE,
|
||||
MANUFACTURE,
|
||||
INDUSTRIAL;
|
||||
|
||||
|
||||
public static EOSMBuilding getValue(String str) {
|
||||
switch (str) {
|
||||
case "yes": return YES;
|
||||
case "chapel": return CHAPEL;
|
||||
case "church": return CHURCH;
|
||||
case "house": return HOUSE;
|
||||
case "office": return OFFICE;
|
||||
case "manufacture": return MANUFACTURE;
|
||||
case "industrial": return INDUSTRIAL;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
50
src/main/java/pl/wat/ms4ds/terrain/osm/EOSMHighway.java
Normal file
50
src/main/java/pl/wat/ms4ds/terrain/osm/EOSMHighway.java
Normal file
@@ -0,0 +1,50 @@
|
||||
package pl.wat.ms4ds.terrain.osm;
|
||||
|
||||
public enum EOSMHighway {
|
||||
|
||||
/**
|
||||
* v="motorway" | v="trunk" | v="primary" | v="secondary" | v="tertiary" | v="unclassified"
|
||||
* | v="residential" | v="pedestrian" | v="track"
|
||||
* | v="motorway_link" | v="trunk_link" | v="primary_link" | v="secondary_link" | v="tertiary_link"
|
||||
* | v="living_street" | v="service"
|
||||
*/
|
||||
MOTORWAY,
|
||||
TRUNCK,
|
||||
PRIMARY,
|
||||
SECONDARY,
|
||||
TERTIARY,
|
||||
UNCLASSIFIED,
|
||||
RESIDENTIAL,
|
||||
PEDESTRIAN,
|
||||
TRACK,
|
||||
MOTORWAY_LINK,
|
||||
TRUNCK_LINK,
|
||||
PRIMARY_LINK,
|
||||
SECONDARY_LINK,
|
||||
TERTIARY_LINK,
|
||||
LIVING_STREET,
|
||||
SERVICE;
|
||||
|
||||
public static EOSMHighway getValue(String str) {
|
||||
switch (str) {
|
||||
case "motorway": return MOTORWAY;
|
||||
case "trunk": return TRUNCK;
|
||||
case "primary": return PRIMARY;
|
||||
case "secondary": return SECONDARY;
|
||||
case "tertiary": return TERTIARY;
|
||||
case "unclassified": return UNCLASSIFIED;
|
||||
case "residential": return RESIDENTIAL;
|
||||
case "pedestrian": return PEDESTRIAN;
|
||||
case "track": return TRACK;
|
||||
case "motorway_link": return MOTORWAY_LINK;
|
||||
case "trunk_link": return TRUNCK_LINK;
|
||||
case "primary_link": return PRIMARY_LINK;
|
||||
case "secondary_link": return SECONDARY_LINK;
|
||||
case "tertiary_link": return TERTIARY_LINK;
|
||||
case "living_street": return LIVING_STREET;
|
||||
case "service": return SERVICE;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
21
src/main/java/pl/wat/ms4ds/terrain/osm/EOSMLandcover.java
Normal file
21
src/main/java/pl/wat/ms4ds/terrain/osm/EOSMLandcover.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package pl.wat.ms4ds.terrain.osm;
|
||||
|
||||
public enum EOSMLandcover {
|
||||
|
||||
/**
|
||||
* v="trees" | v="water" | v="grass"
|
||||
*/
|
||||
TREES,
|
||||
WATER,
|
||||
GRASS;
|
||||
|
||||
public static EOSMLandcover getValue(String str) {
|
||||
switch (str) {
|
||||
case "trees": return TREES;
|
||||
case "water": return WATER;
|
||||
case "grass": return GRASS;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
21
src/main/java/pl/wat/ms4ds/terrain/osm/EOSMLanduse.java
Normal file
21
src/main/java/pl/wat/ms4ds/terrain/osm/EOSMLanduse.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package pl.wat.ms4ds.terrain.osm;
|
||||
|
||||
public enum EOSMLanduse {
|
||||
|
||||
/**
|
||||
* v="forest" | v="residential" | v="commercial"
|
||||
*/
|
||||
FOREST,
|
||||
RESIDENTIAL,
|
||||
COMMERCIAL;
|
||||
|
||||
public static EOSMLanduse getValue(String str) {
|
||||
switch (str) {
|
||||
case "forest": return FOREST;
|
||||
case "residential": return RESIDENTIAL;
|
||||
case "commercial": return COMMERCIAL;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
23
src/main/java/pl/wat/ms4ds/terrain/osm/EOSMNatural.java
Normal file
23
src/main/java/pl/wat/ms4ds/terrain/osm/EOSMNatural.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package pl.wat.ms4ds.terrain.osm;
|
||||
|
||||
public enum EOSMNatural {
|
||||
|
||||
/**
|
||||
* v="water" | v="reservoir" | v="wetland" | v="wood"
|
||||
*/
|
||||
WATER,
|
||||
RESERVOIR,
|
||||
WETLAND,
|
||||
WOOD;
|
||||
|
||||
public static EOSMNatural getValue(String str) {
|
||||
switch (str) {
|
||||
case "water": return WATER;
|
||||
case "reservoir": return RESERVOIR;
|
||||
case "wetland": return WETLAND;
|
||||
case "wood": return WOOD;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
29
src/main/java/pl/wat/ms4ds/terrain/osm/EOSMWater.java
Normal file
29
src/main/java/pl/wat/ms4ds/terrain/osm/EOSMWater.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package pl.wat.ms4ds.terrain.osm;
|
||||
|
||||
public enum EOSMWater {
|
||||
|
||||
/**
|
||||
* v="lake" | v="reservoir" | v="river" | v="canal" | v="cove" | v="lagoon" | v="pond"
|
||||
*/
|
||||
LAKE,
|
||||
RESERVOIR,
|
||||
RIVER,
|
||||
CANAL,
|
||||
COVE,
|
||||
LAGOON,
|
||||
POND;
|
||||
|
||||
public static EOSMWater getValue(String str) {
|
||||
switch (str) {
|
||||
case "lake": return LAKE;
|
||||
case "reservoir": return RESERVOIR;
|
||||
case "river": return RIVER;
|
||||
case "canal": return CANAL;
|
||||
case "cove": return COVE;
|
||||
case "lagoon": return LAGOON;
|
||||
case "pond": return POND;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
27
src/main/java/pl/wat/ms4ds/terrain/osm/EOSMWaterway.java
Normal file
27
src/main/java/pl/wat/ms4ds/terrain/osm/EOSMWaterway.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package pl.wat.ms4ds.terrain.osm;
|
||||
|
||||
public enum EOSMWaterway {
|
||||
|
||||
/**
|
||||
* v="river" | v="riverbank" | v="stream" | v="canal" | v="drain" | v="ditch"
|
||||
*/
|
||||
RIVER,
|
||||
RIVERBANK,
|
||||
STREAM,
|
||||
CANAL,
|
||||
DRAIN,
|
||||
DITCH;
|
||||
|
||||
public static EOSMWaterway getValue(String str) {
|
||||
switch (str) {
|
||||
case "river": return RIVER;
|
||||
case "riverbank": return RIVERBANK;
|
||||
case "stream": return STREAM;
|
||||
case "canal": return CANAL;
|
||||
case "drain": return DRAIN;
|
||||
case "ditch": return DITCH;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
211
src/main/java/pl/wat/ms4ds/terrain/osm/EsriFileReader.java
Normal file
211
src/main/java/pl/wat/ms4ds/terrain/osm/EsriFileReader.java
Normal file
@@ -0,0 +1,211 @@
|
||||
package pl.wat.ms4ds.terrain.osm;
|
||||
|
||||
import org.nocrala.tools.gis.data.esri.shapefile.ShapeFileReader;
|
||||
import org.nocrala.tools.gis.data.esri.shapefile.ValidationPreferences;
|
||||
import org.nocrala.tools.gis.data.esri.shapefile.exception.InvalidShapeFileException;
|
||||
import org.nocrala.tools.gis.data.esri.shapefile.header.ShapeFileHeader;
|
||||
import org.nocrala.tools.gis.data.esri.shapefile.shape.AbstractShape;
|
||||
import org.nocrala.tools.gis.data.esri.shapefile.shape.PointData;
|
||||
import org.nocrala.tools.gis.data.esri.shapefile.shape.shapes.MultiPointZShape;
|
||||
import org.nocrala.tools.gis.data.esri.shapefile.shape.shapes.PointShape;
|
||||
import org.nocrala.tools.gis.data.esri.shapefile.shape.shapes.PolygonShape;
|
||||
import org.nocrala.tools.gis.data.esri.shapefile.shape.shapes.PolylineShape;
|
||||
import pl.wat.ms4ds.terrain.Coord;
|
||||
import pl.wat.ms4ds.terrain.MapConsts;
|
||||
import pl.wat.ms4ds.terrain.Teren;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class EsriFileReader {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(EsriFileReader.class);
|
||||
|
||||
public static void main(String[] args) throws IOException, InvalidShapeFileException {
|
||||
String fn = "C:/Workspace/osm/dolnoslaskie-251217-free.shp/gis_osm_water_a_free_1.shp";
|
||||
if (args.length > 0) {
|
||||
fn = args[0];
|
||||
}
|
||||
FileInputStream is = new FileInputStream(fn);
|
||||
ValidationPreferences prefs = new ValidationPreferences();
|
||||
prefs.setMaxNumberOfPointsPerShape(50000);
|
||||
// ShapeFileReader r = new ShapeFileReader(is);
|
||||
ShapeFileReader r = new ShapeFileReader(is, prefs);
|
||||
|
||||
ShapeFileHeader h = r.getHeader();
|
||||
// System.out.println("The shape type of this files is " + h.getShapeType());
|
||||
|
||||
HashMap<String, Relation> relationsMap = new HashMap<>();
|
||||
HashMap<String, Way> waysMap = new HashMap<>();
|
||||
|
||||
LOGGER.debug("Poczatek odczytu danych o pokryciu wodami z pliku: " + fn);
|
||||
|
||||
int count = 0;
|
||||
AbstractShape s;
|
||||
int relId = 0;
|
||||
int wayId = 0;
|
||||
int nodeId = 0;
|
||||
while ((s = r.next()) != null) {
|
||||
count++;
|
||||
switch (s.getShapeType()) {
|
||||
case POINT:
|
||||
PointShape aPoint = (PointShape) s;
|
||||
// Do something with the point shape...
|
||||
break;
|
||||
case MULTIPOINT_Z:
|
||||
MultiPointZShape aMultiPointZ = (MultiPointZShape) s;
|
||||
// Do something with the MultiPointZ shape...
|
||||
break;
|
||||
case POLYLINE:
|
||||
if (s instanceof PolylineShape) {
|
||||
PolylineShape aPolyline = (PolylineShape) s;
|
||||
if (aPolyline.getBoxMinX() > 10 && aPolyline.getBoxMaxX() < 30
|
||||
&& aPolyline.getBoxMinY() > 40 && aPolyline.getBoxMaxY() < 58) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case POLYGON:
|
||||
PolygonShape aPolygon = (PolygonShape) s;
|
||||
if (aPolygon.getBoxMinX() > 10 && aPolygon.getBoxMaxX() < 30
|
||||
&& aPolygon.getBoxMinY() > 40 && aPolygon.getBoxMaxY() < 58) {
|
||||
// System.out.println("I read a Polygon with "
|
||||
// + aPolygon.getNumberOfParts() + " parts and "
|
||||
// + aPolygon.getNumberOfPoints() + " points");
|
||||
Relation currRelation = new Relation("" + relId);
|
||||
currRelation.natural = EOSMNatural.WATER;
|
||||
relId++;
|
||||
for (int i = 0; i < aPolygon.getNumberOfParts(); i++) {
|
||||
PointData[] points = aPolygon.getPointsOfPart(i);
|
||||
Way currWay = new Way("" + wayId);
|
||||
wayId++;
|
||||
boolean jest_wezel_z_obszaru = false;
|
||||
for (int j = 0; j < points.length; j++) {
|
||||
Node currNode = new Node("" + nodeId);
|
||||
nodeId++;
|
||||
currNode.lon = points[j].getX() + 180;
|
||||
currNode.lat = points[j].getY() + 90;
|
||||
if (currNode.lon >= MapConsts.REF_LON && currNode.lon <= MapConsts.REF_LON + MapConsts.DELTA_LON_REF
|
||||
&& currNode.lat >= MapConsts.REF_LAT && currNode.lat <= MapConsts.REF_LAT + MapConsts.DELTA_LAT_REF) {
|
||||
jest_wezel_z_obszaru = true;
|
||||
}
|
||||
currNode.lon = Math.max(currNode.lon, MapConsts.REF_LON);
|
||||
currNode.lon = Math.min(currNode.lon, MapConsts.REF_LON + MapConsts.DELTA_LON_REF);
|
||||
currNode.lon -= 180;
|
||||
currNode.lat = Math.max(currNode.lat, MapConsts.REF_LAT);
|
||||
currNode.lat = Math.min(currNode.lat, MapConsts.REF_LAT + MapConsts.DELTA_LAT_REF);
|
||||
currNode.lat -= 90;
|
||||
|
||||
currNode.idX = Coord.convertLonToGridX(currNode.lon);
|
||||
currNode.idY = Coord.convertLatToGridY(currNode.lat);
|
||||
if (currNode.idX > 0 || currNode.idY > 0) {
|
||||
currWay.nodes.add(currNode);
|
||||
}
|
||||
}
|
||||
if (jest_wezel_z_obszaru) {
|
||||
boolean clockwise = clockwiseOrientedPolygon(points);
|
||||
if (clockwise) {
|
||||
if (currWay.nodes.size() > 0) {
|
||||
currRelation.outerWays.add(currWay);
|
||||
currWay.natural = EOSMNatural.WATER;
|
||||
}
|
||||
} else {
|
||||
currRelation.innerWays.add(currWay);
|
||||
}
|
||||
}
|
||||
// String orient = clockwise ? clockwiseStr : counterclockwiseStr;
|
||||
// System.out.println("- part " + i + " has " + points.length
|
||||
// + " points. - orientation= " + orient);
|
||||
}
|
||||
if (currRelation.outerWays.size() > 0) {
|
||||
relationsMap.put(currRelation.id, currRelation);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// System.out.println("Read other type of shape.");
|
||||
}
|
||||
if (count % 1000 == 0) {
|
||||
LOGGER.debug("shape count= " + count);
|
||||
}
|
||||
}
|
||||
// System.out.println("Total shapes read: " + total);
|
||||
is.close();
|
||||
LOGGER.debug("Koniec odczytu danych o pokryciu wodami z pliku: " + fn);
|
||||
try {
|
||||
LOGGER.debug("Poczatek przetwarzania danych o pokryciu wodami");
|
||||
OpenStreetMapReader.generujDaneTerenowe("wody", relationsMap, waysMap, null);
|
||||
LOGGER.debug("Koniec przetwarzania danych o pokryciu wodami");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
for (int i = 0; i < Worker.workers.size(); i++) {
|
||||
try {
|
||||
Worker.workers.get(i).join();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
LOGGER.debug("Poczatek zapisu danych o pokryciu wodami");
|
||||
Teren.saveToFiles(null);
|
||||
// Teren.setBinarnyFormatPliku(false);
|
||||
// Teren.zapisBuforaMapyDoPliku();
|
||||
Teren.reset();
|
||||
LOGGER.debug("Koniec zapisu danych o pokryciu wodami");
|
||||
}
|
||||
|
||||
public static boolean clockwiseOrientedPolygon(PointData[] points) {
|
||||
PointData[] vertices = new PointData[points.length - 1];
|
||||
for (int i = 0; i < vertices.length; i++) {
|
||||
vertices[i] = points[i];
|
||||
}
|
||||
int smallest = 0;
|
||||
for (int i = 1; i < vertices.length; i++) {
|
||||
if (lexicographicalCompare(vertices[i].getX(), vertices[i].getY(),
|
||||
vertices[smallest].getX(), vertices[smallest].getY()) == -1) {
|
||||
smallest = i;
|
||||
}
|
||||
}
|
||||
PointData center = vertices[smallest];
|
||||
PointData first = vertices[(smallest - 1 + vertices.length) % vertices.length];
|
||||
PointData last = vertices[(smallest + 1) % vertices.length];
|
||||
// first == a, center == b, last == c
|
||||
// (xb - xa) * (yc - ya) - (xc - xa) * (yb - ya)
|
||||
double det = (center.getX() - first.getX()) * (last.getY() - first.getY())
|
||||
- (last.getX() - first.getX()) * (center.getY() - first.getY());
|
||||
|
||||
return (det < 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Porównuje dwa punkty leksykograficznie.
|
||||
* <p>Jeżeli (x1, y1) mniejsze od (x2, y2) to zwraca -1
|
||||
* <p>Jeżeli (x1, y1) rowne (x2, y2) to zwraca 0
|
||||
* <p>Jeżeli (x1, y1) wieksze od (x2, y2) to zwraca 1
|
||||
*
|
||||
* @param x1 współrzędna x pierwszego punktu
|
||||
* @param y1 współrzędna y pierwszego punktu
|
||||
* @param x2 współrzędna x drugiego punktu
|
||||
* @param y2 współrzędna y drugiego punktu
|
||||
* @return -1 gdy pierwszy punkt mniejszy, 0 gdy punkty rowne, 1 gdy pierwszy punkt wiekszy
|
||||
*/
|
||||
public static int lexicographicalCompare(double x1, double y1, double x2, double y2) {
|
||||
if (x1 < x2) {
|
||||
return -1;
|
||||
}
|
||||
if (x1 > x2) {
|
||||
return 1;
|
||||
}
|
||||
if (y1 < y2) {
|
||||
return -1;
|
||||
}
|
||||
if (y1 > y2) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
11
src/main/java/pl/wat/ms4ds/terrain/osm/MapBounds.java
Normal file
11
src/main/java/pl/wat/ms4ds/terrain/osm/MapBounds.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package pl.wat.ms4ds.terrain.osm;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class MapBounds {
|
||||
double minLat;
|
||||
double minLon;
|
||||
double maxLat;
|
||||
double maxLon;
|
||||
}
|
||||
105
src/main/java/pl/wat/ms4ds/terrain/osm/Node.java
Normal file
105
src/main/java/pl/wat/ms4ds/terrain/osm/Node.java
Normal file
@@ -0,0 +1,105 @@
|
||||
package pl.wat.ms4ds.terrain.osm;
|
||||
|
||||
import pl.wat.ms4ds.terrain.Square;
|
||||
import pl.wat.ms4ds.terrain.MapConsts;
|
||||
import pl.wat.ms4ds.terrain.Teren;
|
||||
import pl.wat.ms4ds.terrain.TerrainType;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class Node {
|
||||
String id;
|
||||
double lon = 0; // x
|
||||
double lat = 0; // y
|
||||
int idX = -1;
|
||||
int idY = -1;
|
||||
int buildingsCount = 0;
|
||||
|
||||
// GridCoord idKw;
|
||||
|
||||
/**
|
||||
* k="amenity" - v="hospital" | v="school" | v="post_office" | v="police" | v="marketplace" | v="fire_station" |
|
||||
* v="theatre" | v="cinema" | v="pharmacy" | v="nursing_home" | v="bank" | v="fuel"
|
||||
* v="university" | v="library"
|
||||
*/
|
||||
public EOSMAmenity amenity;
|
||||
|
||||
/**
|
||||
* k="building" - v="yes" | v="chapel" | v="church" | v="house" | v="office" | v="manufacture" | v="industrial"
|
||||
*/
|
||||
public EOSMBuilding building;
|
||||
|
||||
/**
|
||||
* k="bridge" - v="yes" | "viaduct"
|
||||
*/
|
||||
public EOSMBridge bridge;
|
||||
|
||||
public Node(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Node(Node oryg) {
|
||||
this.id = oryg.id;
|
||||
lon = oryg.lon;
|
||||
lat = oryg.lat;
|
||||
idX = oryg.idX;
|
||||
idY = oryg.idY;
|
||||
}
|
||||
|
||||
static final int BUILDINGS_COUNT;
|
||||
static {
|
||||
switch (MapConsts.SS_SIZE) {
|
||||
case 200:
|
||||
BUILDINGS_COUNT = 8;
|
||||
break;
|
||||
case 100:
|
||||
BUILDINGS_COUNT = 4;
|
||||
break;
|
||||
case 50:
|
||||
BUILDINGS_COUNT = 2;
|
||||
break;
|
||||
case 25:
|
||||
BUILDINGS_COUNT = 1;
|
||||
break;
|
||||
default:
|
||||
BUILDINGS_COUNT = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void writeAreaFeatureIntoSquare(EAreaFeature type) {
|
||||
if (buildingsCount >= BUILDINGS_COUNT) {
|
||||
Square kw = Teren.getSquare(idX, idY);
|
||||
kw.terrainType = TerrainType.BUILDINGS;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Node{" +
|
||||
"id=" + id + '\'' +
|
||||
", lat='" + lat + '\'' +
|
||||
", lon='" + lon + '\'' +
|
||||
", idKw=(" + idX + ", " + idY + ")}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Node node = (Node) o;
|
||||
|
||||
if (idX != node.idX) return false;
|
||||
return idY == node.idY;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = idX;
|
||||
result = 31 * result + idY;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
979
src/main/java/pl/wat/ms4ds/terrain/osm/OpenStreetMapReader.java
Normal file
979
src/main/java/pl/wat/ms4ds/terrain/osm/OpenStreetMapReader.java
Normal file
@@ -0,0 +1,979 @@
|
||||
package pl.wat.ms4ds.terrain.osm;
|
||||
|
||||
import pl.wat.ms4ds.terrain.Coord;
|
||||
import pl.wat.ms4ds.terrain.Teren;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import java.io.FileInputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import javax.xml.stream.*;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class OpenStreetMapReader {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(OpenStreetMapReader.class);
|
||||
|
||||
private static final String DATA_DIR = "c:/Workspace/openstreetmap-data-20160925/";
|
||||
|
||||
static final Object synch = new Object();
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("OpenStreetMapReader - Working Directory = " +
|
||||
System.getProperty("user.dir"));
|
||||
String osm_fn = DATA_DIR + args[0] + "-latest.osm";
|
||||
HashMap<String, Relation> relationsMap = new HashMap<>(8000);
|
||||
HashMap<String, Way> relationWaysMap = new HashMap<>(50000);
|
||||
HashMap<String, Node> nodesMap = new HashMap<>(5000000);
|
||||
HashMap<String, Node> buildingNodesMap = new HashMap<>(500000);
|
||||
HashMap<String, Way> waysMap = new HashMap<>(800000);
|
||||
String[] goals = {"lasy", "wody", "bagna", "zabudowa", "drogi", "rzeki", "rowy"};
|
||||
ArrayList<String> toDo = new ArrayList<>();
|
||||
for (int i = 1; i < args.length; i++) {
|
||||
for (int j = 0; j < goals.length; j++) {
|
||||
if (goals[j].equals(args[i])) {
|
||||
toDo.add(goals[j]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
MapBounds mapBounds = new MapBounds();
|
||||
// readMapBounds(mapBounds, osm_fn);
|
||||
for (int i = 0; i < toDo.size(); i++) {
|
||||
relationsMap.clear();
|
||||
relationWaysMap.clear();
|
||||
nodesMap.clear();
|
||||
buildingNodesMap.clear();
|
||||
waysMap.clear();
|
||||
readRelations(relationsMap, relationWaysMap, osm_fn, toDo.get(i));
|
||||
readWays(nodesMap, relationWaysMap, waysMap, osm_fn, toDo.get(i));
|
||||
readNodes(nodesMap, buildingNodesMap, mapBounds, osm_fn, toDo.get(i));
|
||||
if (nodesMap.size() > 0) {
|
||||
String nodes_poland_fn = DATA_DIR + "poland-latest_nodes.osm";
|
||||
readNodes(nodesMap, null, mapBounds, nodes_poland_fn, toDo.get(i));
|
||||
}
|
||||
for (Relation rel : relationsMap.values()) {
|
||||
rel.outerWays = rel.generatePolygons(rel.outerWays);
|
||||
rel.innerWays = rel.generatePolygons(rel.innerWays);
|
||||
}
|
||||
LOGGER.debug("Poczatek przetwarzania danych dla regionu " + osm_fn + " - cel: " + toDo.get(i));
|
||||
generujDaneTerenowe(toDo.get(i), relationsMap, waysMap, buildingNodesMap);
|
||||
LOGGER.debug("Koniec przetwarzania danych dla regionu " + osm_fn + " - cel: " + toDo.get(i));
|
||||
// Teren.setBinarnyFormatPliku(false);
|
||||
// Teren.zapisBuforaMapyDoPliku();
|
||||
// Teren.reset();
|
||||
// Teren.setBinarnyFormatPliku(true);
|
||||
}
|
||||
LOGGER.debug("Poczatek zapisu danych dla regionu " + osm_fn);
|
||||
Teren.saveToFiles(null);
|
||||
LOGGER.debug("Koniec zapisu danych dla regionu " + osm_fn);
|
||||
}
|
||||
|
||||
|
||||
// XMLOutputFactory outFactory = XMLOutputFactory.newInstance();
|
||||
//
|
||||
// try {
|
||||
// XMLStreamWriter writer = outFactory.createXMLStreamWriter(new FileWriter("au2data\\output2.xml"));
|
||||
//
|
||||
// writer.writeStartDocument();
|
||||
// writer.writeStartElement("document");
|
||||
// writer.writeStartElement("data");
|
||||
// writer.writeAttribute("name", "value");
|
||||
// writer.writeEndElement();
|
||||
// writer.writeEndElement();
|
||||
// writer.writeEndDocument();
|
||||
//
|
||||
// writer.flush();
|
||||
// writer.close();
|
||||
//
|
||||
// } catch (XMLStreamException e) {
|
||||
// e.printStackTrace();
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
|
||||
private static void readMapBounds(MapBounds mapBounds, String fn) throws Exception {
|
||||
XMLInputFactory factory = XMLInputFactory.newInstance();
|
||||
// FileInputStream is = new FileInputStream(fn);
|
||||
FileInputStream is = new FileInputStream(fn);
|
||||
// XMLStreamReader reader = factory.createXMLStreamReader(ClassLoader.getSystemResourceAsStream(fn));
|
||||
XMLStreamReader reader = factory.createXMLStreamReader(is);
|
||||
String val;
|
||||
while (reader.hasNext()) {
|
||||
int eventType = reader.next();
|
||||
switch (eventType) {
|
||||
case XMLStreamConstants.START_ELEMENT:
|
||||
if ("bounds".equals(reader.getLocalName())) {
|
||||
for (int i = 0; i < reader.getAttributeCount(); i++) {
|
||||
val = reader.getAttributeLocalName(i);
|
||||
switch (val) {
|
||||
case "minlat":
|
||||
val = reader.getAttributeValue(i);
|
||||
mapBounds.minLat = Double.parseDouble(val);
|
||||
break;
|
||||
case "minlon":
|
||||
val = reader.getAttributeValue(i);
|
||||
mapBounds.minLon = Double.parseDouble(val);
|
||||
break;
|
||||
case "maxlat":
|
||||
val = reader.getAttributeValue(i);
|
||||
mapBounds.maxLat = Double.parseDouble(val);
|
||||
break;
|
||||
case "maxlon":
|
||||
val = reader.getAttributeValue(i);
|
||||
mapBounds.maxLon = Double.parseDouble(val);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
reader.close();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
reader.close();
|
||||
}
|
||||
|
||||
private static void readNodes(HashMap<String, Node> nodesMap, HashMap<String, Node> buildingNodesMap, MapBounds mapBounds, String fn, String genGoal) throws Exception {
|
||||
Node currNode = null;
|
||||
XMLInputFactory factory = XMLInputFactory.newInstance();
|
||||
FileInputStream is = new FileInputStream(fn);
|
||||
// XMLStreamReader reader = factory.createXMLStreamReader(ClassLoader.getSystemResourceAsStream(fn));
|
||||
XMLStreamReader reader = factory.createXMLStreamReader(is);
|
||||
String val;
|
||||
int count = 1;
|
||||
LOGGER.debug("Poczatek odczytu wezlow z pliku: " + fn);
|
||||
while (reader.hasNext()) {
|
||||
int eventType = reader.next();
|
||||
switch (eventType) {
|
||||
case XMLStreamConstants.START_ELEMENT:
|
||||
if ("node".equals(reader.getLocalName())) {
|
||||
val = reader.getAttributeValue(0);
|
||||
// if ("3206180317".equals(val)) {
|
||||
// logger.debug("!!!!!!!!!!! niepoprawny wezel id= " + val);
|
||||
// }
|
||||
if (count % 100000 == 0) {
|
||||
LOGGER.debug("+-+-+-+-+-+-+-+- liczba odczytanych wezlow= " + count / 1000 + " [tys.], ostatni wezel id= " + val);
|
||||
}
|
||||
currNode = nodesMap.remove(val);
|
||||
if (!"zabudowa".equals(genGoal)) {
|
||||
if (currNode != null) {
|
||||
int c = 0;
|
||||
for (int i = 1; i < reader.getAttributeCount() && c < 2; i++) {
|
||||
val = reader.getAttributeLocalName(i);
|
||||
switch (val) {
|
||||
case "lat":
|
||||
val = reader.getAttributeValue(i);
|
||||
currNode.lat = Double.parseDouble(val);
|
||||
c++;
|
||||
break;
|
||||
case "lon":
|
||||
val = reader.getAttributeValue(i);
|
||||
currNode.lon = Double.parseDouble(val);
|
||||
c++;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (buildingNodesMap != null) {
|
||||
if (currNode == null) {
|
||||
currNode = buildingNodesMap.get(val);
|
||||
if (currNode == null) {
|
||||
currNode = new Node(val);
|
||||
}
|
||||
}
|
||||
int c = 0;
|
||||
for (int i = 1; i < reader.getAttributeCount() && c < 2; i++) {
|
||||
val = reader.getAttributeLocalName(i);
|
||||
switch (val) {
|
||||
case "lat":
|
||||
val = reader.getAttributeValue(i);
|
||||
currNode.lat = Double.parseDouble(val);
|
||||
c++;
|
||||
break;
|
||||
case "lon":
|
||||
val = reader.getAttributeValue(i);
|
||||
currNode.lon = Double.parseDouble(val);
|
||||
c++;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ("tag".equals(reader.getLocalName())) {
|
||||
if (currNode != null) {
|
||||
String k = reader.getAttributeValue(0);
|
||||
String v = reader.getAttributeValue(1);
|
||||
switch (k) {
|
||||
case "building":
|
||||
currNode.building = EOSMBuilding.getValue(v);
|
||||
break;
|
||||
case "amenity":
|
||||
currNode.amenity = EOSMAmenity.getValue(v);
|
||||
break;
|
||||
case "addr:housenumber":
|
||||
currNode.buildingsCount++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if ("way".equals(reader.getLocalName())) {
|
||||
reader.close();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case XMLStreamConstants.CHARACTERS:
|
||||
// tagContent = reader.getText().trim();
|
||||
break;
|
||||
|
||||
case XMLStreamConstants.END_ELEMENT:
|
||||
switch (reader.getLocalName()) {
|
||||
case "node":
|
||||
if (currNode != null) {
|
||||
currNode.idX = Coord.convertLonToGridX(currNode.lon);
|
||||
currNode.idY = Coord.convertLatToGridY(currNode.lat);
|
||||
if ("zabudowa".equals(genGoal) && currNode.buildingsCount > 0) {
|
||||
buildingNodesMap.put(currNode.id, currNode);
|
||||
}
|
||||
count++;
|
||||
currNode = null;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
reader.close();
|
||||
}
|
||||
|
||||
private static void readWays(HashMap<String, Node> nodesMap, HashMap<String, Way> relationWaysMap,
|
||||
HashMap<String, Way> goalWaysMap, String fn, String genGoal) throws Exception {
|
||||
Way currWay = null;
|
||||
String tagContent = null;
|
||||
XMLInputFactory factory = XMLInputFactory.newInstance();
|
||||
// FileInputStream is = new FileInputStream(fn);
|
||||
FileInputStream is = new FileInputStream(fn);
|
||||
// XMLStreamReader reader = factory.createXMLStreamReader(ClassLoader.getSystemResourceAsStream(fn));
|
||||
XMLStreamReader reader = factory.createXMLStreamReader(is);
|
||||
String val;
|
||||
int count = 0;
|
||||
LOGGER.debug("Poczatek odczytu lamanych z pliku: " + fn + " - cel: " + genGoal);
|
||||
while (reader.hasNext()) {
|
||||
int eventType = reader.next();
|
||||
switch (eventType) {
|
||||
case XMLStreamConstants.START_ELEMENT:
|
||||
if ("way".equals(reader.getLocalName())) {
|
||||
val = reader.getAttributeValue(0);
|
||||
currWay = relationWaysMap.get(val);
|
||||
if (currWay == null) {
|
||||
currWay = new Way(val);
|
||||
}
|
||||
// if ("314575560".equals(val)) {
|
||||
// logger.debug("!!!!!");
|
||||
// }
|
||||
count++;
|
||||
if (count % 10000 == 0) {
|
||||
LOGGER.debug("=================== liczba odczytanych lamanych= " + count / 1000 + " [tys.], ostatnia lamana id= " + val);
|
||||
LOGGER.debug("=>liczba lamanych celu=" + goalWaysMap.size() + ", liczba lamanych relacji=" + relationWaysMap.size() + ", liczba wezlow=" + nodesMap.size());
|
||||
}
|
||||
} else if ("nd".equals(reader.getLocalName())) {
|
||||
if (currWay != null) {
|
||||
// odczyt id wezla wchodzacego w sklad lamanej
|
||||
val = reader.getAttributeValue(0);
|
||||
Node node = nodesMap.get(val);
|
||||
if (node == null) {
|
||||
for (int i = 0; i < currWay.nodes.size(); i++) {
|
||||
if (val.equals(currWay.nodes.get(i).id)) {
|
||||
node = currWay.nodes.get(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (node == null) {
|
||||
node = new Node(val);
|
||||
}
|
||||
}
|
||||
currWay.nodes.add(node);
|
||||
}
|
||||
} else if ("tag".equals(reader.getLocalName())) {
|
||||
if (currWay != null) {
|
||||
String k = reader.getAttributeValue(0);
|
||||
String v = reader.getAttributeValue(1);
|
||||
switch (k) {
|
||||
case "highway":
|
||||
currWay.highway = EOSMHighway.getValue(v);
|
||||
break;
|
||||
case "waterway":
|
||||
currWay.waterway = EOSMWaterway.getValue(v);
|
||||
break;
|
||||
case "natural":
|
||||
currWay.natural = EOSMNatural.getValue(v);
|
||||
break;
|
||||
case "water":
|
||||
currWay.water = EOSMWater.getValue(v);
|
||||
break;
|
||||
case "landuse":
|
||||
currWay.landuse = EOSMLanduse.getValue(v);
|
||||
break;
|
||||
case "landcover":
|
||||
currWay.landcover = EOSMLandcover.getValue(v);
|
||||
break;
|
||||
case "bridge":
|
||||
currWay.bridge = EOSMBridge.getValue(v);
|
||||
break;
|
||||
case "building":
|
||||
currWay.building = EOSMBuilding.getValue(v);
|
||||
break;
|
||||
case "amenity":
|
||||
currWay.amenity = EOSMAmenity.getValue(v);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case XMLStreamConstants.CHARACTERS:
|
||||
// tagContent = reader.getText().trim();
|
||||
break;
|
||||
|
||||
case XMLStreamConstants.END_ELEMENT:
|
||||
if (currWay != null) {
|
||||
switch (reader.getLocalName()) {
|
||||
case "way":
|
||||
if ("lasy".equals(genGoal)) {
|
||||
// LASY
|
||||
if (relationWaysMap.containsKey(currWay.id)) {
|
||||
for (Node node : currWay.nodes) {
|
||||
nodesMap.put(node.id, node);
|
||||
}
|
||||
} else if ((currWay.landuse != null) && currWay.landuse == EOSMLanduse.FOREST) {
|
||||
goalWaysMap.put(currWay.id, currWay);
|
||||
for (Node node : currWay.nodes) {
|
||||
nodesMap.put(node.id, node);
|
||||
}
|
||||
} else if ((currWay.landcover != null) && currWay.landcover == EOSMLandcover.TREES) {
|
||||
goalWaysMap.put(currWay.id, currWay);
|
||||
for (Node node : currWay.nodes) {
|
||||
nodesMap.put(node.id, node);
|
||||
}
|
||||
} else if ((currWay.natural != null) && currWay.natural == EOSMNatural.WOOD) {
|
||||
goalWaysMap.put(currWay.id, currWay);
|
||||
for (Node node : currWay.nodes) {
|
||||
nodesMap.put(node.id, node);
|
||||
}
|
||||
}
|
||||
} else if ("wody".equals(genGoal)) {
|
||||
// SZEROKIE RZEKI, JEZIORA I ZBIORNIKI WODNE
|
||||
if (relationWaysMap.containsKey(currWay.id)) {
|
||||
for (Node node : currWay.nodes) {
|
||||
nodesMap.put(node.id, node);
|
||||
}
|
||||
} else if (currWay.natural != null && currWay.natural == EOSMNatural.WATER) {
|
||||
goalWaysMap.put(currWay.id, currWay);
|
||||
for (Node node : currWay.nodes) {
|
||||
nodesMap.put(node.id, node);
|
||||
}
|
||||
} else if (currWay.waterway != null && currWay.waterway == EOSMWaterway.RIVERBANK) {
|
||||
goalWaysMap.put(currWay.id, currWay);
|
||||
for (Node node : currWay.nodes) {
|
||||
nodesMap.put(node.id, node);
|
||||
}
|
||||
}
|
||||
} else if ("drogi".equals(genGoal)) {
|
||||
// DROGI
|
||||
if (currWay.highway != null) {
|
||||
switch (currWay.highway) {
|
||||
case MOTORWAY:
|
||||
case TRUNCK:
|
||||
case PRIMARY:
|
||||
case SECONDARY:
|
||||
case TERTIARY:
|
||||
case UNCLASSIFIED:
|
||||
case RESIDENTIAL:
|
||||
case PEDESTRIAN:
|
||||
case TRACK:
|
||||
case MOTORWAY_LINK:
|
||||
case TRUNCK_LINK:
|
||||
case PRIMARY_LINK:
|
||||
case SECONDARY_LINK:
|
||||
case TERTIARY_LINK:
|
||||
case SERVICE:
|
||||
case LIVING_STREET:
|
||||
goalWaysMap.put(currWay.id, currWay);
|
||||
for (Node node : currWay.nodes) {
|
||||
nodesMap.put(node.id, node);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// case "footway":
|
||||
// case "bridleway":
|
||||
// case "steps":
|
||||
// case "cycleway":
|
||||
// case "PATH":
|
||||
// case "proposed":
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if ("rzeki".equals(genGoal)) {
|
||||
// RZEKI (LINIOWE, NIESZEROKIE)
|
||||
if (currWay.waterway != null) {
|
||||
switch (currWay.waterway) {
|
||||
case RIVER:
|
||||
case CANAL:
|
||||
goalWaysMap.put(currWay.id, currWay);
|
||||
for (Node node : currWay.nodes) {
|
||||
nodesMap.put(node.id, node);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
} else if ("rowy".equals(genGoal)) {
|
||||
// ROWY
|
||||
if (currWay.waterway != null) {
|
||||
switch (currWay.waterway) {
|
||||
case STREAM:
|
||||
case DRAIN:
|
||||
case DITCH:
|
||||
goalWaysMap.put(currWay.id, currWay);
|
||||
for (Node node : currWay.nodes) {
|
||||
nodesMap.put(node.id, node);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
} else if ("bagna".equals(genGoal)) {
|
||||
// BAGNA
|
||||
if (currWay.natural != null) {
|
||||
switch (currWay.natural) {
|
||||
case WETLAND:
|
||||
goalWaysMap.put(currWay.id, currWay);
|
||||
for (Node node : currWay.nodes) {
|
||||
nodesMap.put(node.id, node);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
} else if ("zabudowa".equals(genGoal)) {
|
||||
// ZABUDOWA
|
||||
if (currWay.landuse != null) {
|
||||
switch (currWay.landuse) {
|
||||
case RESIDENTIAL:
|
||||
case COMMERCIAL:
|
||||
goalWaysMap.put(currWay.id, currWay);
|
||||
for (Node node : currWay.nodes) {
|
||||
nodesMap.put(node.id, node);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
} else if (currWay.building != null) {
|
||||
goalWaysMap.put(currWay.id, currWay);
|
||||
for (Node node : currWay.nodes) {
|
||||
nodesMap.put(node.id, node);
|
||||
}
|
||||
} else if (currWay.amenity != null) {
|
||||
switch (currWay.amenity) {
|
||||
case HOSPITAL:
|
||||
case CLINIC:
|
||||
case POST_OFFICE:
|
||||
case POLICE:
|
||||
case FIRE_STATION:
|
||||
case MARKETPLACE:
|
||||
goalWaysMap.put(currWay.id, currWay);
|
||||
for (Node node : currWay.nodes) {
|
||||
nodesMap.put(node.id, node);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
currWay = null;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
}
|
||||
}
|
||||
reader.close();
|
||||
}
|
||||
|
||||
private static void readRelations(HashMap<String, Relation> relationsMap, HashMap<String, Way> relationWaysMap,
|
||||
String fn, String genGoal) throws Exception {
|
||||
Relation currRelation = null;
|
||||
String tagContent = null;
|
||||
if (!("lasy".equals(genGoal)) && !("wody".equals(genGoal))) {
|
||||
return;
|
||||
}
|
||||
// fn += "-latest_relations.osm";
|
||||
XMLInputFactory factory = XMLInputFactory.newInstance();
|
||||
// XMLStreamReader reader = factory.createXMLStreamReader(ClassLoader.getSystemResourceAsStream(fn));
|
||||
// BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(fn));
|
||||
// XMLStreamReader reader = factory.createXMLStreamReader(inputStream);
|
||||
|
||||
FileInputStream is = new FileInputStream(fn);
|
||||
// XMLStreamReader reader = factory.createXMLStreamReader(ClassLoader.getSystemResourceAsStream(fn));
|
||||
XMLStreamReader reader = factory.createXMLStreamReader(is);
|
||||
|
||||
String val;
|
||||
int count = 0;
|
||||
LOGGER.debug("Poczatek odczytu relacji z pliku: " + fn + " - cel: " + genGoal);
|
||||
while (reader.hasNext()) {
|
||||
int eventType = reader.next();
|
||||
switch (eventType) {
|
||||
case XMLStreamConstants.START_ELEMENT:
|
||||
if ("relation".equals(reader.getLocalName())) {
|
||||
val = reader.getAttributeValue(0);
|
||||
currRelation = new Relation(val);
|
||||
count++;
|
||||
if (count % 1000 == 0) {
|
||||
LOGGER.debug("+-+-+-+-+-+-+-+- liczba odczytanych relacji= " + count / 1000 + " [tys.], ostatnia relacja id= " + val);
|
||||
}
|
||||
} else if ("member".equals(reader.getLocalName())) {
|
||||
if (currRelation != null) {
|
||||
String v = reader.getAttributeValue(0);
|
||||
if ("way".equals(v)) {
|
||||
// identyfikator łamanej
|
||||
String v1 = reader.getAttributeValue(1);
|
||||
// rola łamanej w relacji
|
||||
String v2 = reader.getAttributeValue(2);
|
||||
if ("outer".equals(v2)) {
|
||||
Way way = new Way(v1);
|
||||
if (way != null) {
|
||||
currRelation.outerWays.add(way);
|
||||
}
|
||||
} else if ("inner".equals(v2)) {
|
||||
Way way = new Way(v1);
|
||||
if (way != null) {
|
||||
currRelation.innerWays.add(way);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ("tag".equals(reader.getLocalName())) {
|
||||
if (currRelation != null) {
|
||||
String k = reader.getAttributeValue(0);
|
||||
String v = reader.getAttributeValue(1);
|
||||
switch (k) {
|
||||
case "waterway":
|
||||
currRelation.waterway = EOSMWaterway.getValue(v);
|
||||
break;
|
||||
case "natural":
|
||||
currRelation.natural = EOSMNatural.getValue(v);
|
||||
break;
|
||||
case "landuse":
|
||||
currRelation.landuse = EOSMLanduse.getValue(v);
|
||||
break;
|
||||
case "landcover":
|
||||
currRelation.landcover = EOSMLandcover.getValue(v);
|
||||
break;
|
||||
case "type":
|
||||
if (!"multipolygon".equals(v)) {
|
||||
currRelation = null;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case XMLStreamConstants.CHARACTERS:
|
||||
// tagContent = reader.getText().trim();
|
||||
break;
|
||||
|
||||
case XMLStreamConstants.END_ELEMENT:
|
||||
switch (reader.getLocalName()) {
|
||||
case "relation":
|
||||
if (currRelation != null) {
|
||||
if (currRelation.outerWays.size() > 0) {
|
||||
if ("lasy".equals(genGoal)) {
|
||||
if (((currRelation.landuse != null) && currRelation.landuse == EOSMLanduse.FOREST)
|
||||
|| ((currRelation.natural != null) && currRelation.natural == EOSMNatural.WOOD)) {
|
||||
|
||||
relationsMap.put(currRelation.id, currRelation);
|
||||
for (Way way : currRelation.outerWays) {
|
||||
// kopiuje tagi dla lamanych zewnetrznych
|
||||
way.copyTags(currRelation);
|
||||
relationWaysMap.put(way.id, way);
|
||||
}
|
||||
for (Way way : currRelation.innerWays) {
|
||||
relationWaysMap.put(way.id, way);
|
||||
// nie kopiuje tagow dla lamanych wewnetrznych, gdyz one maja wlasne tagi
|
||||
}
|
||||
}
|
||||
} else if ("wody".equals(genGoal)) {
|
||||
if (((currRelation.natural != null) && currRelation.natural == EOSMNatural.WATER)
|
||||
|| ((currRelation.waterway != null) && currRelation.waterway == EOSMWaterway.RIVERBANK)) {
|
||||
|
||||
relationsMap.put(currRelation.id, currRelation);
|
||||
for (Way way : currRelation.outerWays) {
|
||||
// kopiuje tagi dla lamanych zewnetrznych
|
||||
way.copyTags(currRelation);
|
||||
relationWaysMap.put(way.id, way);
|
||||
}
|
||||
for (Way way : currRelation.innerWays) {
|
||||
relationWaysMap.put(way.id, way);
|
||||
// nie kopiuje tagow dla lamanych wewnetrznych, gdyz one maja wlasne tagi
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
currRelation = null;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
reader.close();
|
||||
}
|
||||
|
||||
static void generujDaneTerenowe(String genGoal, HashMap<String, Relation> relationsMap,
|
||||
HashMap<String, Way> waysMap, HashMap<String, Node> buildingNodesMap) {
|
||||
int count = 0;
|
||||
int m1 = relationsMap.size() / 100;
|
||||
m1 = (m1 == 0) ? 1 : m1;
|
||||
int m2 = waysMap.size() / 100;
|
||||
m2 = (m2 == 0) ? 1 : m2;
|
||||
ArrayList<Way> wayList = new ArrayList<>(waysMap.values());
|
||||
// określenie formatu odczytu danych terenowych przed uaktualnieniem
|
||||
if ("lasy".equals(genGoal)) {
|
||||
for (Relation rel : relationsMap.values()) {
|
||||
count++;
|
||||
rel.removeLastNodes();
|
||||
rel.removeSimilarNodes();
|
||||
rel.removeCollinearNodes(true);
|
||||
rel.writeAreaFeatureIntoSquares(EAreaFeature.FOREST);
|
||||
if (count % m1 == 0) {
|
||||
LOGGER.debug(">><<>><<>><<: rel count= " + count + ", " + genGoal);
|
||||
}
|
||||
}
|
||||
count = 0;
|
||||
for (Way way : wayList) {
|
||||
count++;
|
||||
// usunięcie powtórzenia węzła z łamanej definiującej obszar
|
||||
if (way.nodes.size() > 1) {
|
||||
way.nodes.remove(way.nodes.size() - 1);
|
||||
}
|
||||
way.removeSimilarNodes();
|
||||
way.removeCollinearNodes(true);
|
||||
way.writeAreaFeatureIntoSquares(EAreaFeature.FOREST, false);
|
||||
if (count % m2 == 0) {
|
||||
LOGGER.debug("<><><><><><>: way count= " + count + ", " + genGoal);
|
||||
}
|
||||
}
|
||||
} else if ("wody".equals(genGoal)) {
|
||||
for (Relation rel : relationsMap.values()) {
|
||||
count++;
|
||||
rel.removeLastNodes();
|
||||
rel.removeSimilarNodes();
|
||||
rel.removeCollinearNodes(true);
|
||||
rel.writeAreaFeatureIntoSquares(EAreaFeature.WATER);
|
||||
if (count % m1 == 0) {
|
||||
LOGGER.debug(">><<>><<>><<: rel count= " + count + ", " + genGoal);
|
||||
}
|
||||
}
|
||||
count = 0;
|
||||
for (Way way : wayList) {
|
||||
count++;
|
||||
// usunięcie powtórzenia węzła z łamanej definiującej obszar
|
||||
if (way.nodes.size() > 1) {
|
||||
way.nodes.remove(way.nodes.size() - 1);
|
||||
}
|
||||
way.removeSimilarNodes();
|
||||
way.removeCollinearNodes(true);
|
||||
way.writeAreaFeatureIntoSquares(EAreaFeature.WATER, false);
|
||||
if (count % m2 == 0) {
|
||||
LOGGER.debug("<><><><><><>: way count= " + count + ", " + genGoal);
|
||||
}
|
||||
}
|
||||
} else if ("bagna".equals(genGoal)) {
|
||||
for (Way way : wayList) {
|
||||
count++;
|
||||
// usunięcie powtórzenia węzła z łamanej definiującej obszar
|
||||
if (way.nodes.size() > 1) {
|
||||
way.nodes.remove(way.nodes.size() - 1);
|
||||
}
|
||||
way.removeSimilarNodes();
|
||||
way.removeCollinearNodes(true);
|
||||
way.writeAreaFeatureIntoSquares(EAreaFeature.SWAMP, false);
|
||||
if (count % m2 == 0) {
|
||||
LOGGER.debug("<><><><><><>: way count= " + count + ", " + genGoal);
|
||||
}
|
||||
}
|
||||
} else if ("zabudowa".equals(genGoal)) {
|
||||
// wygenerowanie danych o stopniu zabudowy na podstawie danych adresowych
|
||||
// HashMap<Node, Node> newNodesMap = new HashMap<>();
|
||||
// for (Node node : buildingNodesMap.values()) {
|
||||
// Node node1 = newNodesMap.get(node);
|
||||
// if (node1 != null) {
|
||||
// node1.buildingsCount += node.buildingsCount;
|
||||
// } else {
|
||||
// newNodesMap.put(node, node);
|
||||
// }
|
||||
// }
|
||||
// buildingNodesMap.clear();
|
||||
|
||||
for (Node node : buildingNodesMap.values()) {
|
||||
node.writeAreaFeatureIntoSquare(EAreaFeature.BUILDINGS);
|
||||
}
|
||||
for (Way way : wayList) {
|
||||
count++;
|
||||
// usunięcie powtórzenia węzła z łamanej definiującej obszar
|
||||
if (way.nodes.size() > 1) {
|
||||
way.nodes.remove(way.nodes.size() - 1);
|
||||
}
|
||||
// for (int i = 0; i < way.nodes.size(); i++) {
|
||||
// Node node = way.nodes.get(i);
|
||||
// if (node.idX <= 0 || node.idY <= 0) {
|
||||
// logger.debug("!!!! niepoprawny wezel id= " + node.id + ", lamana id= " + way.id);
|
||||
// }
|
||||
// }
|
||||
way.removeSimilarNodes();
|
||||
way.removeCollinearNodes(true);
|
||||
way.writeAreaFeatureIntoSquares(EAreaFeature.BUILDINGS, false);
|
||||
if (count % m2 == 0) {
|
||||
LOGGER.debug("<><><><><><>: way count= " + count + ", " + genGoal);
|
||||
}
|
||||
}
|
||||
} else if ("drogi".equals(genGoal)) {
|
||||
for (Way way : wayList) {
|
||||
count++;
|
||||
// if ("249908111".equals(way.id) || "238353558".equals(way.id)) {
|
||||
// logger.debug("!!!!!");
|
||||
// }
|
||||
way.removeSimilarNodes();
|
||||
way.removeCollinearNodes(false);
|
||||
way.removeSteps();
|
||||
if (way.nodes.size() > 1) {
|
||||
way.writeLinearFeatureIntoSquares(ELinearFeature.ROAD);
|
||||
}
|
||||
// if (count % 10000 == 0) {
|
||||
// logger.debug("-*-*-*-*-");
|
||||
// logger.debug("maxMemory=" + java.lang.Runtime.getRuntime().maxMemory()
|
||||
// + ", totalMemory=" + java.lang.Runtime.getRuntime().totalMemory()
|
||||
// + ", freeMemory=" + java.lang.Runtime.getRuntime().freeMemory());
|
||||
// }
|
||||
// count++;
|
||||
if (count % m2 == 0) {
|
||||
LOGGER.debug("<><><><><><>: way count= " + count + ", " + genGoal);
|
||||
}
|
||||
}
|
||||
} else if ("rzeki".equals(genGoal)) {
|
||||
for (Way way : wayList) {
|
||||
count++;
|
||||
way.removeSimilarNodes();
|
||||
way.removeCollinearNodes(false);
|
||||
way.removeSteps();
|
||||
if (way.nodes.size() > 1) {
|
||||
way.writeLinearFeatureIntoSquares(ELinearFeature.WATER_WAY);
|
||||
}
|
||||
if (count % m2 == 0) {
|
||||
LOGGER.debug("<><><><><><>: way count= " + count + ", " + genGoal);
|
||||
}
|
||||
}
|
||||
} else if ("rowy".equals(genGoal)) {
|
||||
for (Way way : wayList) {
|
||||
count++;
|
||||
way.removeSimilarNodes();
|
||||
way.removeCollinearNodes(false);
|
||||
way.removeSteps();
|
||||
if (way.nodes.size() > 1) {
|
||||
way.writeLinearFeatureIntoSquares(ELinearFeature.DITCH);
|
||||
}
|
||||
if (count % m2 == 0) {
|
||||
LOGGER.debug("<><><><><><>: way count= " + count + ", " + genGoal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void generujDaneTerenowe2(String genGoal, HashMap<String, Relation> relationsMap,
|
||||
HashMap<String, Way> waysMap, HashMap<String, Node> buildingNodesMap) {
|
||||
int count = 0;
|
||||
int m1 = relationsMap.size() / 100;
|
||||
m1 = (m1 == 0) ? 1 : m1;
|
||||
ArrayList<Way> wayList = new ArrayList<>(waysMap.values());
|
||||
// określenie formatu odczytu danych terenowych przed uaktualnieniem
|
||||
if ("lasy".equals(genGoal)) {
|
||||
for (Relation rel : relationsMap.values()) {
|
||||
count++;
|
||||
rel.removeLastNodes();
|
||||
rel.removeSimilarNodes();
|
||||
rel.removeCollinearNodes(true);
|
||||
rel.writeAreaFeatureIntoSquares(EAreaFeature.FOREST);
|
||||
if (count % m1 == 0) {
|
||||
synchronized (synch) {
|
||||
LOGGER.debug(Thread.currentThread().getName() + " >><<>><<>><<: rel count= " + count + ", " + genGoal);
|
||||
}
|
||||
}
|
||||
}
|
||||
count = 0;
|
||||
for (Way way : wayList) {
|
||||
count++;
|
||||
// usunięcie powtórzenia węzła z łamanej definiującej obszar
|
||||
if (way.nodes.size() > 1) {
|
||||
way.nodes.remove(way.nodes.size() - 1);
|
||||
}
|
||||
way.removeSimilarNodes();
|
||||
way.removeCollinearNodes(true);
|
||||
way.writeAreaFeatureIntoSquares(EAreaFeature.FOREST, false);
|
||||
synchronized (synch) {
|
||||
LOGGER.debug(Thread.currentThread().getName() + " <><><><><><>: way count= " + count + ", " + genGoal);
|
||||
}
|
||||
}
|
||||
} else if ("wody".equals(genGoal)) {
|
||||
for (Relation rel : relationsMap.values()) {
|
||||
count++;
|
||||
rel.removeLastNodes();
|
||||
rel.removeSimilarNodes();
|
||||
rel.removeCollinearNodes(true);
|
||||
rel.writeAreaFeatureIntoSquares(EAreaFeature.WATER);
|
||||
synchronized (synch) {
|
||||
LOGGER.debug(Thread.currentThread().getName() + " >><<>><<>><<: rel count= " + count + ", " + genGoal);
|
||||
}
|
||||
}
|
||||
count = 0;
|
||||
for (Way way : wayList) {
|
||||
count++;
|
||||
// usunięcie powtórzenia węzła z łamanej definiującej obszar
|
||||
if (way.nodes.size() > 1) {
|
||||
way.nodes.remove(way.nodes.size() - 1);
|
||||
}
|
||||
way.removeSimilarNodes();
|
||||
way.removeCollinearNodes(true);
|
||||
way.writeAreaFeatureIntoSquares(EAreaFeature.WATER, false);
|
||||
synchronized (synch) {
|
||||
LOGGER.debug(Thread.currentThread().getName() + " <><><><><><>: way count= " + count + ", " + genGoal);
|
||||
}
|
||||
}
|
||||
} else if ("bagna".equals(genGoal)) {
|
||||
for (Way way : wayList) {
|
||||
count++;
|
||||
// usunięcie powtórzenia węzła z łamanej definiującej obszar
|
||||
if (way.nodes.size() > 1) {
|
||||
way.nodes.remove(way.nodes.size() - 1);
|
||||
}
|
||||
way.removeSimilarNodes();
|
||||
way.removeCollinearNodes(true);
|
||||
way.writeAreaFeatureIntoSquares(EAreaFeature.SWAMP, false);
|
||||
synchronized (synch) {
|
||||
LOGGER.debug(Thread.currentThread().getName() + " <><><><><><>: way count= " + count + ", " + genGoal);
|
||||
}
|
||||
}
|
||||
} else if ("zabudowa".equals(genGoal)) {
|
||||
// wygenerowanie danych o stopniu zabudowy na podstawie danych adresowych
|
||||
// HashMap<Node, Node> newNodesMap = new HashMap<>();
|
||||
// for (Node node : buildingNodesMap.values()) {
|
||||
// Node node1 = newNodesMap.get(node);
|
||||
// if (node1 != null) {
|
||||
// node1.buildingsCount += node.buildingsCount;
|
||||
// } else {
|
||||
// newNodesMap.put(node, node);
|
||||
// }
|
||||
// }
|
||||
// buildingNodesMap.clear();
|
||||
|
||||
for (Node node : buildingNodesMap.values()) {
|
||||
node.writeAreaFeatureIntoSquare(EAreaFeature.BUILDINGS);
|
||||
}
|
||||
for (Way way : wayList) {
|
||||
count++;
|
||||
// usunięcie powtórzenia węzła z łamanej definiującej obszar
|
||||
if (way.nodes.size() > 1) {
|
||||
way.nodes.remove(way.nodes.size() - 1);
|
||||
}
|
||||
// for (int i = 0; i < way.nodes.size(); i++) {
|
||||
// Node node = way.nodes.get(i);
|
||||
// if (node.idX <= 0 || node.idY <= 0) {
|
||||
// logger.debug("!!!! niepoprawny wezel id= " + node.id + ", lamana id= " + way.id);
|
||||
// }
|
||||
// }
|
||||
way.removeSimilarNodes();
|
||||
way.removeCollinearNodes(true);
|
||||
way.writeAreaFeatureIntoSquares(EAreaFeature.BUILDINGS, false);
|
||||
synchronized (synch) {
|
||||
LOGGER.debug(Thread.currentThread().getName() + " <><><><><><>: way count= " + count + ", " + genGoal);
|
||||
}
|
||||
}
|
||||
} else if ("drogi".equals(genGoal)) {
|
||||
for (Way way : wayList) {
|
||||
count++;
|
||||
// if ("249908111".equals(way.id) || "238353558".equals(way.id)) {
|
||||
// logger.debug("!!!!!");
|
||||
// }
|
||||
way.removeSimilarNodes();
|
||||
way.removeCollinearNodes(false);
|
||||
way.removeSteps();
|
||||
if (way.nodes.size() > 1) {
|
||||
way.writeLinearFeatureIntoSquares(ELinearFeature.ROAD);
|
||||
}
|
||||
// if (count % 10000 == 0) {
|
||||
// logger.debug("-*-*-*-*-");
|
||||
// logger.debug("maxMemory=" + java.lang.Runtime.getRuntime().maxMemory()
|
||||
// + ", totalMemory=" + java.lang.Runtime.getRuntime().totalMemory()
|
||||
// + ", freeMemory=" + java.lang.Runtime.getRuntime().freeMemory());
|
||||
// }
|
||||
// count++;
|
||||
synchronized (synch) {
|
||||
LOGGER.debug(Thread.currentThread().getName() + " <><><><><><>: way count= " + count + ", " + genGoal);
|
||||
}
|
||||
}
|
||||
} else if ("rzeki".equals(genGoal)) {
|
||||
for (Way way : wayList) {
|
||||
count++;
|
||||
way.removeSimilarNodes();
|
||||
way.removeCollinearNodes(false);
|
||||
way.removeSteps();
|
||||
if (way.nodes.size() > 1) {
|
||||
way.writeLinearFeatureIntoSquares(ELinearFeature.WATER_WAY);
|
||||
}
|
||||
synchronized (synch) {
|
||||
LOGGER.debug(Thread.currentThread().getName() + " <><><><><><>: way count= " + count + ", " + genGoal);
|
||||
}
|
||||
}
|
||||
} else if ("rowy".equals(genGoal)) {
|
||||
for (Way way : wayList) {
|
||||
count++;
|
||||
way.removeSimilarNodes();
|
||||
way.removeCollinearNodes(false);
|
||||
way.removeSteps();
|
||||
if (way.nodes.size() > 1) {
|
||||
way.writeLinearFeatureIntoSquares(ELinearFeature.DITCH);
|
||||
}
|
||||
synchronized (synch) {
|
||||
LOGGER.debug(Thread.currentThread().getName() + " <><><><><><>: way count= " + count + ", " + genGoal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
204
src/main/java/pl/wat/ms4ds/terrain/osm/Relation.java
Normal file
204
src/main/java/pl/wat/ms4ds/terrain/osm/Relation.java
Normal file
@@ -0,0 +1,204 @@
|
||||
package pl.wat.ms4ds.terrain.osm;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Bazowa klasa dla obiektów OpenStreetMap.
|
||||
*/
|
||||
public class Relation {
|
||||
private static final Logger logger = LoggerFactory.getLogger(Relation.class);
|
||||
|
||||
public String id;
|
||||
/**
|
||||
* Tag oznacza obiekt obszarowy. <p>
|
||||
* k="natural" - v="water" | v="reservoir" | v="wetland" | v="wood"
|
||||
*/
|
||||
public EOSMNatural natural;
|
||||
|
||||
/**
|
||||
* Tag ten oznacza rzekę lub ciek wodny opisywany liniowo.
|
||||
* <p> Wyjątek: waterway=riverbank, który opisuje obszar.
|
||||
* <p> k="waterway" - v="river" | v="riverbank" | v="stream" | v="canal" | v="drain" | v="ditch"
|
||||
*/
|
||||
public EOSMWaterway waterway;
|
||||
|
||||
/**
|
||||
* Tag stosowany w połączeniu z tagiem obszarowym: natural=water. <p>
|
||||
* k="water" - v="lake" | v="reservoir" | v="river" | v="canal" | v="cove" | v="lagoon" | v="pond"
|
||||
*/
|
||||
public EOSMWater water;
|
||||
|
||||
/**
|
||||
* Tag oznacza obiekt obszarowy. <p>
|
||||
* k="landuse" - v="forest" | v="residential" | v="commercial"
|
||||
*/
|
||||
public EOSMLanduse landuse;
|
||||
|
||||
/**
|
||||
* Tag oznacza obiekt obszarowy. <p>
|
||||
* k="landcover" - v="trees" | v="water" | v="grass"
|
||||
*/
|
||||
public EOSMLandcover landcover;
|
||||
|
||||
ArrayList<Way> outerWays = new ArrayList<Way>();
|
||||
ArrayList<Way> innerWays = new ArrayList<Way>();
|
||||
|
||||
public Relation(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Relation(Relation oryg) {
|
||||
this.id = oryg.id;
|
||||
}
|
||||
|
||||
public void copyTags(Relation oryg) {
|
||||
this.id = oryg.id;
|
||||
this.natural = oryg.natural;
|
||||
this.waterway = oryg.waterway;
|
||||
this.water = oryg.water;
|
||||
this.landuse = oryg.landuse;
|
||||
this.landcover = oryg.landcover;
|
||||
}
|
||||
|
||||
ArrayList<Way> generatePolygons(ArrayList<Way> wayList) {
|
||||
ArrayList<Way> polygons = new ArrayList<Way>();
|
||||
Way newPolygon = new Way((String)null);
|
||||
int prevLast = -1;
|
||||
for (int iWay = 0; iWay < wayList.size(); iWay++) {
|
||||
Way testWay = wayList.get(iWay);
|
||||
if (testWay.nodes.size() < 2) {
|
||||
continue;
|
||||
}
|
||||
int currLast = testWay.nodes.size() - 1;
|
||||
Node currFirstNode = testWay.nodes.get(0);
|
||||
Node currLastNode = testWay.nodes.get(currLast);
|
||||
if (prevLast < 0) {
|
||||
// biezacy wielokat jeszcze nie zawiera wezlow
|
||||
// newPolygon = new Way((String)null);
|
||||
newPolygon.nodes = testWay.nodes;
|
||||
newPolygon.copyTags(testWay);
|
||||
if (currFirstNode == currLastNode) {
|
||||
// lamana jest wielokatem
|
||||
polygons.add(newPolygon);
|
||||
prevLast = -1;
|
||||
newPolygon = new Way((String)null);
|
||||
} else {
|
||||
prevLast = newPolygon.nodes.size() - 1;
|
||||
}
|
||||
} else {
|
||||
if (currFirstNode == currLastNode) {
|
||||
// !! Blad w danych - brak ciaglosci lamanych: poprzedni wielokat sie nie zamknal
|
||||
// lamana jest wielokatem,
|
||||
// newPolygon = new Way((String)null);
|
||||
newPolygon.nodes = testWay.nodes;
|
||||
newPolygon.copyTags(testWay);
|
||||
polygons.add(newPolygon);
|
||||
prevLast = -1;
|
||||
newPolygon = new Way((String)null);
|
||||
} else {
|
||||
// biezacy wielokat zawiera juz wezly
|
||||
Node prevFirstNode = newPolygon.nodes.get(0);
|
||||
Node prevLastNode = newPolygon.nodes.get(prevLast);
|
||||
if (currFirstNode == prevLastNode) {
|
||||
for (int jNode = 1; jNode < testWay.nodes.size(); jNode++) {
|
||||
newPolygon.nodes.add(testWay.nodes.get(jNode));
|
||||
}
|
||||
if (currLastNode == prevFirstNode) {
|
||||
// lamana zamyka wielokat
|
||||
polygons.add(newPolygon);
|
||||
prevLast = -1;
|
||||
newPolygon = new Way((String)null);
|
||||
} else {
|
||||
// lamana nie zamyka jeszcze wielokata
|
||||
prevLast = newPolygon.nodes.size() - 1;
|
||||
}
|
||||
} else if (currLastNode == prevFirstNode) {
|
||||
// odwracam kolejnosc dodawanych wezlow z biezacej lamanej
|
||||
for (int jNode = 1; jNode < newPolygon.nodes.size(); jNode++) {
|
||||
testWay.nodes.add(newPolygon.nodes.get(jNode));
|
||||
}
|
||||
newPolygon.nodes = testWay.nodes;
|
||||
// for (int jNode = currLast - 1; jNode >= 0; jNode--) {
|
||||
// newPolygon.nodes.add(testWay.nodes.get(jNode));
|
||||
// }
|
||||
if (currFirstNode == prevLastNode) {
|
||||
// lamana zamyka wielokat
|
||||
polygons.add(newPolygon);
|
||||
prevLast = -1;
|
||||
newPolygon = new Way((String)null);
|
||||
} else {
|
||||
// lamana nie zamyka jeszcze wielokata
|
||||
prevLast = newPolygon.nodes.size() - 1;
|
||||
}
|
||||
} else {
|
||||
// !! Blad w danych - brak ciaglosci lamanych: poprzedni wielokat sie nie zamknal
|
||||
// lamana nowego obszaru
|
||||
// newPolygon = new Way((String)null);
|
||||
newPolygon.nodes = testWay.nodes;
|
||||
newPolygon.copyTags(testWay);
|
||||
prevLast = newPolygon.nodes.size() - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return polygons;
|
||||
}
|
||||
|
||||
void writeAreaFeatureIntoSquares(EAreaFeature type) {
|
||||
for (Way way : outerWays) {
|
||||
// wpisanie w kwadraty danej cechy dla wielokatow opisujacych zewnetrzna powloke obszaru
|
||||
way.writeAreaFeatureIntoSquares(type, false);
|
||||
}
|
||||
for (Way way : innerWays) {
|
||||
// wykreslenie z kwadratow danej cechy dla wielokatow opisujacych wewnetrzne podobszary
|
||||
way.writeAreaFeatureIntoSquares(type, true);
|
||||
}
|
||||
}
|
||||
|
||||
void removeSimilarNodes() {
|
||||
for (Way way : outerWays) {
|
||||
// wpisanie w kwadraty danej cechy dla wielokatow opisujacych zewnetrzna powloke obszaru
|
||||
way.removeSimilarNodes();
|
||||
}
|
||||
for (Way way : innerWays) {
|
||||
// wykreslenie z kwadratow danej cechy dla wielokatow opisujacych wewnetrzne podobszary
|
||||
way.removeSimilarNodes();
|
||||
}
|
||||
}
|
||||
|
||||
void removeCollinearNodes(boolean isPolygon) {
|
||||
for (Way way : outerWays) {
|
||||
// wpisanie w kwadraty danej cechy dla wielokatow opisujacych zewnetrzna powloke obszaru
|
||||
way.removeCollinearNodes(isPolygon);
|
||||
}
|
||||
for (Way way : innerWays) {
|
||||
// wykreslenie z kwadratow danej cechy dla wielokatow opisujacych wewnetrzne podobszary
|
||||
way.removeCollinearNodes(isPolygon);
|
||||
}
|
||||
}
|
||||
|
||||
void removeLastNodes() {
|
||||
for (Way way : outerWays) {
|
||||
// usunięcie powtórzenia węzła z wielokata definiującego obszar
|
||||
if (way.nodes.size() > 1) {
|
||||
way.nodes.remove(way.nodes.size() - 1);
|
||||
}
|
||||
}
|
||||
for (Way way : innerWays) {
|
||||
// usunięcie powtórzenia węzła z wielokata definiującego obszar
|
||||
if (way.nodes.size() > 1) {
|
||||
way.nodes.remove(way.nodes.size() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Relation{id=" + id +
|
||||
", outerWays.len=" + outerWays.size() +
|
||||
", innerWays.len=" + innerWays.size() +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
595
src/main/java/pl/wat/ms4ds/terrain/osm/Way.java
Normal file
595
src/main/java/pl/wat/ms4ds/terrain/osm/Way.java
Normal file
@@ -0,0 +1,595 @@
|
||||
package pl.wat.ms4ds.terrain.osm;
|
||||
|
||||
import pl.wat.ms4ds.common.EGeoDirection;
|
||||
import pl.wat.ms4ds.terrain.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Bazowa klasa dla obiektów OpenStreetMap.
|
||||
*/
|
||||
public class Way {
|
||||
private static final Logger logger = LoggerFactory.getLogger(Way.class);
|
||||
|
||||
public String id;
|
||||
|
||||
ArrayList<Node> nodes = new ArrayList<Node>();
|
||||
|
||||
/**
|
||||
* k="highway" - v="motorway" | v="trunk" | v="primary" | v="secondary" | v="tertiary" | v="unclassified"
|
||||
* | v="residential" | v="pedestrian" | v="track"
|
||||
* | v="motorway_link" | v="trunk_link" | v="primary_link" | v="secondary_link" | v="tertiary_link"
|
||||
*/
|
||||
public EOSMHighway highway;
|
||||
|
||||
/**
|
||||
* Tag oznacza obiekt obszarowy. <p>
|
||||
* k="natural" - v="water" | v="reservoir" | v="wetland" | v="wood"
|
||||
*/
|
||||
public EOSMNatural natural;
|
||||
|
||||
/**
|
||||
* Tag ten oznacza rzekę lub ciek wodny opisywany liniowo.
|
||||
* <p> Wyjątek: waterway=riverbank, który opisuje obszar.
|
||||
* <p> k="waterway" - v="river" | v="riverbank" | v="stream" | v="canal" | v="drain" | v="ditch"
|
||||
*/
|
||||
public EOSMWaterway waterway;
|
||||
|
||||
/**
|
||||
* Tag stosowany w połączeniu z tagiem obszarowym: natural=water. <p>
|
||||
* k="water" - v="lake" | v="reservoir" | v="river" | v="canal" | v="cove" | v="lagoon" | v="pond"
|
||||
*/
|
||||
public EOSMWater water;
|
||||
|
||||
/**
|
||||
* Tag oznacza obiekt obszarowy. <p>
|
||||
* k="landuse" - v="forest" | v="residential" | v="commercial"
|
||||
*/
|
||||
public EOSMLanduse landuse;
|
||||
|
||||
/**
|
||||
* k="amenity" - v="hospital" | v="school" | v="post_office" | v="police" | v="marketplace" | v="fire_station" |
|
||||
* v="theatre" | v="cinema" | v="pharmacy" | v="nursing_home" | v="bank" | v="fuel"
|
||||
* v="university" | v="library"
|
||||
*/
|
||||
public EOSMAmenity amenity;
|
||||
|
||||
/**
|
||||
* k="building" - v="yes" | v="chapel" | v="church" | v="house" | v="office" | v="manufacture" | v="industrial"
|
||||
*/
|
||||
public EOSMBuilding building;
|
||||
|
||||
/**
|
||||
* k="bridge" - v="yes" | "viaduct"
|
||||
*/
|
||||
public EOSMBridge bridge;
|
||||
|
||||
/**
|
||||
* Tag oznacza obiekt obszarowy. <p>
|
||||
* k="landcover" - v="trees" | v="water" | v="grass"
|
||||
*/
|
||||
public EOSMLandcover landcover;
|
||||
|
||||
public Way(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Way(Way oryg) {
|
||||
this.id = oryg.id;
|
||||
}
|
||||
|
||||
public void copyTags(Way oryg) {
|
||||
this.highway = oryg.highway;
|
||||
this.natural = oryg.natural;
|
||||
this.waterway = oryg.waterway;
|
||||
this.water = oryg.water;
|
||||
this.landuse = oryg.landuse;
|
||||
this.amenity = oryg.amenity;
|
||||
this.building = oryg.building;
|
||||
this.bridge = oryg.bridge;
|
||||
this.landcover = oryg.landcover;
|
||||
}
|
||||
|
||||
public void copyTags(Relation oryg) {
|
||||
this.natural = oryg.natural;
|
||||
this.waterway = oryg.waterway;
|
||||
this.water = oryg.water;
|
||||
this.landuse = oryg.landuse;
|
||||
this.landcover = oryg.landcover;
|
||||
}
|
||||
|
||||
public boolean tagged() {
|
||||
if (landuse != null || natural != null || landcover != null
|
||||
|| highway != null || waterway != null
|
||||
|| building != null || amenity != null || bridge != null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void removeSimilarNodes() {
|
||||
if (nodes.size() == 0) {
|
||||
return;
|
||||
}
|
||||
Node node_i;
|
||||
Node node_j;
|
||||
Node similarToNode[] = new Node[nodes.size()];
|
||||
boolean similarFound = false;
|
||||
for (int i = 0; i < nodes.size() - 1; i++) {
|
||||
node_i = nodes.get(i);
|
||||
if (similarToNode[i] != null) {
|
||||
continue;
|
||||
}
|
||||
for (int j = i + 1; j < nodes.size(); j++) {
|
||||
node_j = nodes.get(j);
|
||||
if (node_i.idX == node_j.idX && node_i.idY == node_j.idY) {
|
||||
similarToNode[j] = node_i;
|
||||
node_i.buildingsCount += node_j.buildingsCount;
|
||||
similarFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (similarFound) {
|
||||
ArrayList<Node> newList = new ArrayList<>();
|
||||
for (int i = 0; i < nodes.size(); i++) {
|
||||
node_i = nodes.get(i);
|
||||
if (similarToNode[i] == null) {
|
||||
newList.add(node_i);
|
||||
}
|
||||
}
|
||||
nodes = newList;
|
||||
removeSimilarNodes();
|
||||
}
|
||||
}
|
||||
|
||||
void removeCollinearNodes(boolean isPolygon) {
|
||||
if (nodes.size() < 3) {
|
||||
return;
|
||||
}
|
||||
boolean[] toDelete = new boolean[nodes.size()];
|
||||
Node curr_node;
|
||||
Node next_node;
|
||||
Node prev_node;
|
||||
boolean collinearFound = false;
|
||||
int lenMax = nodes.size();
|
||||
int iStart = 0;
|
||||
if (!isPolygon) {
|
||||
// łamana otwarta
|
||||
lenMax = nodes.size() - 1;
|
||||
iStart = 1;
|
||||
}
|
||||
for (int curr = iStart; curr < lenMax; curr++) {
|
||||
int next = (curr + 1) % nodes.size();
|
||||
int prev = (curr + nodes.size() - 1) % nodes.size();
|
||||
curr_node = nodes.get(curr);
|
||||
next_node = nodes.get(next);
|
||||
prev_node = nodes.get(prev);
|
||||
if (GeomUtils.include(prev_node.idX, prev_node.idY, next_node.idX, next_node.idY,
|
||||
curr_node.idX, curr_node.idY)) {
|
||||
// i-ty do usuniecia
|
||||
toDelete[curr] = true;
|
||||
collinearFound = true;
|
||||
} else if (GeomUtils.include(curr_node.idX, curr_node.idY, next_node.idX, next_node.idY,
|
||||
prev_node.idX, prev_node.idY)) {
|
||||
// i-1-ty do usuniecia
|
||||
toDelete[prev] = true;
|
||||
collinearFound = true;
|
||||
} else if (GeomUtils.include(prev_node.idX, prev_node.idY, curr_node.idX, curr_node.idY,
|
||||
next_node.idX, next_node.idY)) {
|
||||
// i+1-ty do usuniecia
|
||||
toDelete[next] = true;
|
||||
collinearFound = true;
|
||||
}
|
||||
}
|
||||
if (collinearFound) {
|
||||
ArrayList<Node> newList = new ArrayList<Node>();
|
||||
for (int i = 0; i < nodes.size(); i++) {
|
||||
curr_node = nodes.get(i);
|
||||
if (!toDelete[i]) {
|
||||
newList.add(curr_node);
|
||||
}
|
||||
}
|
||||
// logger.trace("Liczba oryg. wezlow= {}, liczba niewspolliniowych wezlow= {}, roznica= {}", nodes.size(), newList.size(), nodes.size() - newList.size());
|
||||
nodes = newList;
|
||||
removeCollinearNodes(isPolygon);
|
||||
}
|
||||
}
|
||||
|
||||
void removeSteps() {
|
||||
if (nodes.size() < 3) {
|
||||
return;
|
||||
}
|
||||
boolean toDelete[] = new boolean[nodes.size()];
|
||||
Node node_i;
|
||||
Node node_ii;
|
||||
Node node_iii;
|
||||
boolean bylSchodek = false;
|
||||
for (int i = 0; i < nodes.size() - 2; i++) {
|
||||
node_i = nodes.get(i);
|
||||
node_ii = nodes.get(i + 1);
|
||||
node_iii = nodes.get(i + 2);
|
||||
int absX_i_ii = Math.abs(node_ii.idX - node_i.idX);
|
||||
int absY_i_ii = Math.abs(node_ii.idY - node_i.idY);
|
||||
int absX_ii_iii = Math.abs(node_iii.idX - node_ii.idX);
|
||||
int absY_ii_iii = Math.abs(node_iii.idY - node_ii.idY);
|
||||
if (absX_i_ii + absY_i_ii + absX_ii_iii + absY_ii_iii == 2) {
|
||||
// wezly moga tworzyc schodek
|
||||
if (absX_i_ii + absX_ii_iii == 1) {
|
||||
// wezly tworza schodek, zatem srodkowy wezel schodka do usuniecia
|
||||
toDelete[i + 1] = true;
|
||||
bylSchodek = true;
|
||||
// przeskok o usuwany wezel
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bylSchodek) {
|
||||
ArrayList<Node> newList = new ArrayList<Node>();
|
||||
for (int i = 0; i < nodes.size(); i++) {
|
||||
if (!toDelete[i]) {
|
||||
newList.add(nodes.get(i));
|
||||
}
|
||||
}
|
||||
if (nodes.size() > newList.size()) {
|
||||
// logger.trace("Liczba oryg. wezlow= {}, liczba roznych wezlow= {}, roznica= {}", nodes.size(), newList.size(), nodes.size() - newList.size());
|
||||
}
|
||||
nodes = newList;
|
||||
removeSteps();
|
||||
}
|
||||
}
|
||||
|
||||
void writeLinearFeatureIntoSquares(ELinearFeature type) {
|
||||
if (nodes.size() == 0) {
|
||||
return;
|
||||
}
|
||||
Coord.Grid[] punktyLamanej = new Coord.Grid[nodes.size()];
|
||||
for (int i = 0; i < nodes.size(); i++) {
|
||||
punktyLamanej[i] = new Coord.Grid(nodes.get(i).idX, nodes.get(i).idY);
|
||||
}
|
||||
Square kw0;
|
||||
Square kw1;
|
||||
Coord.Grid id0;
|
||||
Coord.Grid id1;
|
||||
EGeoDirection kier;
|
||||
Coord.Grid[] kwadraty = GeomUtils.generateSquaresOfSegments(punktyLamanej);
|
||||
// float dlug = GeomUtils.dlugoscDrogiPoKwadratch(kwadraty);
|
||||
for (int i = 0; i < kwadraty.length - 1; i++) {
|
||||
try {
|
||||
id0 = kwadraty[i];
|
||||
kw0 = Teren.getSquare(id0.x, id0.y);
|
||||
id1 = kwadraty[i + 1];
|
||||
kw1 = Teren.getSquare(id1.x, id1.y);
|
||||
kier = GeomUtils.kierunekDlaSasiada(id0, id1);
|
||||
switch (type) {
|
||||
case ROAD:
|
||||
kw0.roads[kier.id] = 2;
|
||||
kw0.roads[kier.oppositeDirect().id] = 2;
|
||||
break;
|
||||
case WATER_WAY:
|
||||
kw0.watercourses[kier.id] = 3;
|
||||
kw0.watercourses[kier.oppositeDirect().id] = 3;
|
||||
break;
|
||||
case DITCH:
|
||||
kw0.watercourses[kier.id] = 1;
|
||||
kw0.watercourses[kier.oppositeDirect().id] = 1;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeAreaFeatureIntoSquares2(EAreaFeature type, boolean clearFeature, Coord.Grid[] polygon) {
|
||||
if (polygon.length > 20) {
|
||||
// podział wielokata na dwa mniejsze
|
||||
int m = 2;
|
||||
Coord.Grid pocz = polygon[0];
|
||||
boolean poprawnyPodzial = false;
|
||||
while (m < polygon.length - 1 && !poprawnyPodzial) {
|
||||
// sprawdzenie, czy punkty wielokata po podziale sa po jednej stronie wektora podzialu
|
||||
poprawnyPodzial = true;
|
||||
Coord.Grid kon = polygon[m];
|
||||
for (int i = 0; i < polygon.length; i++) {
|
||||
int i_puls_1 = (i + 1) % polygon.length;
|
||||
boolean przeciecie = GeomUtils.intersection(pocz, kon, polygon[i], polygon[i_puls_1]);
|
||||
if (przeciecie) {
|
||||
// sprawdzenie, czy jakiś koniec jednego odcinka jest równy końcowi drugiego odcinka
|
||||
boolean b = pocz.equals(polygon[i]) ||
|
||||
pocz.equals(polygon[i_puls_1]) ||
|
||||
kon.equals(polygon[i]) ||
|
||||
kon.equals(polygon[i_puls_1]);
|
||||
if (!b) {
|
||||
poprawnyPodzial = false;
|
||||
m++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (poprawnyPodzial) {
|
||||
// punkt podziału wielokąta jest poprawny, zatem dzielę wielokąt na dwa
|
||||
Coord.Grid[] polygon1 = new Coord.Grid[m + 1];
|
||||
for (int i = 0; i < polygon1.length; i++) {
|
||||
polygon1[i] = polygon[i];
|
||||
}
|
||||
writeAreaFeatureIntoSquares2(type, clearFeature, polygon1);
|
||||
|
||||
Coord.Grid[] polygon2 = new Coord.Grid[polygon.length - m + 1];
|
||||
polygon2[0] = polygon[0];
|
||||
for (int i = m; i < polygon.length; i++) {
|
||||
polygon2[i - m + 1] = polygon[i];
|
||||
}
|
||||
writeAreaFeatureIntoSquares2(type, clearFeature, polygon2);
|
||||
} else {
|
||||
// nie udało się poprawnie podzielić wielokąta, zatem przesuwam wierzchołki, aby zmienić wierzchołek
|
||||
// startowy, który jest wierchołkiem referencyjnym podziału (drugi wierzchołek podziału jest szukany)
|
||||
Coord.Grid temp = polygon[0];
|
||||
for (int i = 0; i < polygon.length - 1; i++) {
|
||||
polygon[i] = polygon[i + 1];
|
||||
}
|
||||
polygon[polygon.length - 1] = temp;
|
||||
writeAreaFeatureIntoSquares2(type, clearFeature, polygon);
|
||||
}
|
||||
return;
|
||||
}
|
||||
float val = (clearFeature) ? 0.0f : 1.0f;
|
||||
int minX = polygon[0].x;
|
||||
int minY = polygon[0].y;
|
||||
int maxX = polygon[0].x;
|
||||
int maxY = polygon[0].y;
|
||||
for (int i = 1; i < polygon.length; i++) {
|
||||
minX = Math.min(polygon[i].x, minX);
|
||||
minY = Math.min(polygon[i].y, minY);
|
||||
maxX = Math.max(polygon[i].x, maxX);
|
||||
maxY = Math.max(polygon[i].y, maxY);
|
||||
}
|
||||
boolean inside;
|
||||
for (int y = maxY; y >= minY; y--) {
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
Square kw = Teren.getSquare(x, y);
|
||||
if (kw == Square.EMPTY) {
|
||||
continue;
|
||||
}
|
||||
inside = GeomUtils.insidePolygon(polygon, x, y);
|
||||
if (inside) {
|
||||
switch (type) {
|
||||
case FOREST:
|
||||
kw.terrainType = TerrainType.FOREST;
|
||||
break;
|
||||
case WATER:
|
||||
kw.terrainType = TerrainType.WATER;
|
||||
break;
|
||||
case SWAMP:
|
||||
kw.terrainType = TerrainType.SWAMP;
|
||||
break;
|
||||
case BUILDINGS:
|
||||
kw.terrainType = TerrainType.BUILDINGS;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeAreaFeatureIntoSquares(EAreaFeature type, boolean clearFeature, Coord.Grid[] polygon,
|
||||
int minX, int maxX, int minY, int maxY) {
|
||||
float val = (clearFeature) ? 0.0f : 1.0f;
|
||||
boolean inside;
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
Square kw = Teren.getSquare(x, y);
|
||||
if (kw == Square.EMPTY) {
|
||||
continue;
|
||||
}
|
||||
inside = GeomUtils.insidePolygon(polygon, x, y);
|
||||
if (inside) {
|
||||
switch (type) {
|
||||
case FOREST:
|
||||
kw.terrainType = TerrainType.FOREST;
|
||||
break;
|
||||
case WATER:
|
||||
kw.terrainType = TerrainType.WATER;
|
||||
break;
|
||||
case SWAMP:
|
||||
kw.terrainType = TerrainType.SWAMP;
|
||||
break;
|
||||
case BUILDINGS:
|
||||
kw.terrainType = TerrainType.BUILDINGS;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void writeAreaFeatureIntoSquares2(EAreaFeature type, boolean clearFeature) {
|
||||
if (nodes.size() == 0) {
|
||||
return;
|
||||
}
|
||||
Square kw;
|
||||
float val = (clearFeature) ? 0.0f : 1.0f;
|
||||
if (nodes.size() == 1) {
|
||||
kw = Teren.getSquare(nodes.get(0).idX, nodes.get(0).idY);
|
||||
switch (type) {
|
||||
case FOREST:
|
||||
kw.terrainType = TerrainType.FOREST;
|
||||
break;
|
||||
case WATER:
|
||||
kw.terrainType = TerrainType.WATER;
|
||||
break;
|
||||
case SWAMP:
|
||||
kw.terrainType = TerrainType.SWAMP;
|
||||
break;
|
||||
case BUILDINGS:
|
||||
kw.terrainType = TerrainType.BUILDINGS;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (nodes.size() == 2) {
|
||||
Coord.Grid[] kwadraty = GeomUtils.generateSquaresOfSegment(nodes.get(0).idX, nodes.get(0).idY,
|
||||
nodes.get(1).idX, nodes.get(1).idY);
|
||||
for (int i = 0; i < kwadraty.length; i++) {
|
||||
kw = Teren.getSquare(kwadraty[i].x, kwadraty[i].y);
|
||||
switch (type) {
|
||||
case FOREST:
|
||||
kw.terrainType = TerrainType.FOREST;
|
||||
break;
|
||||
case WATER:
|
||||
kw.terrainType = TerrainType.WATER;
|
||||
break;
|
||||
case SWAMP:
|
||||
kw.terrainType = TerrainType.SWAMP;
|
||||
break;
|
||||
case BUILDINGS:
|
||||
kw.terrainType = TerrainType.BUILDINGS;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
Coord.Grid[] wielokat = new Coord.Grid[nodes.size()];
|
||||
for (int i = 0; i < nodes.size(); i++) {
|
||||
wielokat[i] = new Coord.Grid(nodes.get(i).idX, nodes.get(i).idY);
|
||||
}
|
||||
writeAreaFeatureIntoSquares2(type, clearFeature, wielokat);
|
||||
}
|
||||
|
||||
void writeAreaFeatureIntoSquares(EAreaFeature type, boolean clearFeature) {
|
||||
if (nodes.size() == 0) {
|
||||
return;
|
||||
}
|
||||
Square kw;
|
||||
float val = (clearFeature) ? 0.0f : 1.0f;
|
||||
if (nodes.size() == 1) {
|
||||
kw = Teren.getSquare(nodes.get(0).idX, nodes.get(0).idY);
|
||||
switch (type) {
|
||||
case FOREST:
|
||||
kw.terrainType = TerrainType.FOREST;
|
||||
break;
|
||||
case WATER:
|
||||
kw.terrainType = TerrainType.WATER;
|
||||
break;
|
||||
case SWAMP:
|
||||
kw.terrainType = TerrainType.SWAMP;
|
||||
break;
|
||||
case BUILDINGS:
|
||||
kw.terrainType = TerrainType.BUILDINGS;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (nodes.size() == 2) {
|
||||
Coord.Grid[] kwadraty = GeomUtils.generateSquaresOfSegment(nodes.get(0).idX, nodes.get(0).idY,
|
||||
nodes.get(1).idX, nodes.get(1).idY);
|
||||
for (int i = 0; i < kwadraty.length; i++) {
|
||||
kw = Teren.getSquare(kwadraty[i].x, kwadraty[i].y);
|
||||
switch (type) {
|
||||
case FOREST:
|
||||
kw.terrainType = TerrainType.FOREST;
|
||||
break;
|
||||
case WATER:
|
||||
kw.terrainType = TerrainType.WATER;
|
||||
break;
|
||||
case SWAMP:
|
||||
kw.terrainType = TerrainType.SWAMP;
|
||||
break;
|
||||
case BUILDINGS:
|
||||
kw.terrainType = TerrainType.BUILDINGS;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
Coord.Grid[] wielokat = new Coord.Grid[nodes.size()];
|
||||
int minX = nodes.get(0).idX;
|
||||
int minY = nodes.get(0).idY;
|
||||
int maxX = nodes.get(0).idX;
|
||||
int maxY = nodes.get(0).idY;
|
||||
for (int i = 0; i < nodes.size(); i++) {
|
||||
wielokat[i] = new Coord.Grid(nodes.get(i).idX, nodes.get(i).idY);
|
||||
minX = Math.min(wielokat[i].x, minX);
|
||||
minY = Math.min(wielokat[i].y, minY);
|
||||
maxX = Math.max(wielokat[i].x, maxX);
|
||||
maxY = Math.max(wielokat[i].y, maxY);
|
||||
}
|
||||
int ileKwTest = (maxX - minX) * (maxY - minY);
|
||||
if (ileKwTest > 100000) {
|
||||
int dx = maxX - minX;
|
||||
int dy = maxY - minY;
|
||||
Worker[] workers = new Worker[4];
|
||||
workers[0] = new Worker(type, clearFeature, wielokat, minX, minX + dx / 2, minY, minY + dy / 2);
|
||||
workers[1] = new Worker(type, clearFeature, wielokat, minX + dx / 2 + 1, maxX, minY, minY + dy / 2);
|
||||
workers[2] = new Worker(type, clearFeature, wielokat, minX, minX + dx / 2, minY + dy / 2 + 1, maxY);
|
||||
workers[3] = new Worker(type, clearFeature, wielokat, minX + dx / 2 + 1, maxX, minY + dy / 2 + 1, maxY);
|
||||
for (int i = 0; i < workers.length; i++) {
|
||||
workers[i].start();
|
||||
}
|
||||
return;
|
||||
}
|
||||
boolean nalezyDoWielokata;
|
||||
// int liczKw = 0;
|
||||
// int liczKwObszaru = 0;
|
||||
// for (int j = maxY; j >= minY; j--) {
|
||||
// for (int i = minX; i <= maxX; i++) {
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
// char c = ' ';
|
||||
// liczKw++;
|
||||
kw = Teren.getSquare(x, y);
|
||||
if (kw == Square.EMPTY) {
|
||||
continue;
|
||||
}
|
||||
nalezyDoWielokata = GeomUtils.insidePolygon(wielokat, x, y);
|
||||
if (nalezyDoWielokata) {
|
||||
// c = 'O';
|
||||
switch (type) {
|
||||
case FOREST:
|
||||
kw.terrainType = TerrainType.FOREST;
|
||||
break;
|
||||
case WATER:
|
||||
kw.terrainType = TerrainType.WATER;
|
||||
break;
|
||||
case SWAMP:
|
||||
kw.terrainType = TerrainType.SWAMP;
|
||||
break;
|
||||
case BUILDINGS:
|
||||
kw.terrainType = TerrainType.BUILDINGS;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
// liczKwObszaru++;
|
||||
}
|
||||
// rysowanie wielokata
|
||||
// for (int k = 0; k < wielokat.length; k++) {
|
||||
// if (wielokat[k].equals(idTest)) {
|
||||
// c = 'X';
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// System.out.print(c);
|
||||
// System.out.print(' ');
|
||||
}
|
||||
// System.out.println();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Way{id=" + id +
|
||||
", len=" + nodes.size() +
|
||||
", nodes=" + nodes +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
||||
51
src/main/java/pl/wat/ms4ds/terrain/osm/Worker.java
Normal file
51
src/main/java/pl/wat/ms4ds/terrain/osm/Worker.java
Normal file
@@ -0,0 +1,51 @@
|
||||
package pl.wat.ms4ds.terrain.osm;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import pl.wat.ms4ds.terrain.Coord;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class Worker extends Thread {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(Worker.class);
|
||||
|
||||
static ArrayList<Worker> workers = new ArrayList<>();
|
||||
|
||||
static Integer nr = 0;
|
||||
|
||||
EAreaFeature type;
|
||||
boolean clearFeature;
|
||||
Coord.Grid[] polygon;
|
||||
int minX;
|
||||
int maxX;
|
||||
int minY;
|
||||
int maxY;
|
||||
|
||||
public Worker(EAreaFeature type, boolean clearFeature, Coord.Grid[] polygon, int minX, int maxX, int minY, int maxY) {
|
||||
super("Worker_" + nr++);
|
||||
this.type = type;
|
||||
this.clearFeature = clearFeature;
|
||||
this.polygon = polygon;
|
||||
this.minX = minX;
|
||||
this.maxX = maxX;
|
||||
this.minY = minY;
|
||||
this.maxY = maxY;
|
||||
workers.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
int ileKwTest = (maxX - minX + 1) * (maxY - minY + 1);
|
||||
logger.debug("{} >>> polygon.lent= {}, ileKwTest= {}", Thread.currentThread().getName(), polygon.length, ileKwTest);
|
||||
Way.writeAreaFeatureIntoSquares(type, clearFeature, polygon, minX, maxX, minY, maxY);
|
||||
logger.debug("{} <<< polygon.lent= {}, ileKwTest= {}", Thread.currentThread().getName(), polygon.length, ileKwTest);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
37
src/main/java/pl/wat/ms4ds/terrain/osmshp/DbfField.java
Normal file
37
src/main/java/pl/wat/ms4ds/terrain/osmshp/DbfField.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package pl.wat.ms4ds.terrain.osmshp;
|
||||
|
||||
public class DbfField {
|
||||
|
||||
/**
|
||||
* Field name with a maximum of 10 characters. If less than 10, it is padded with null characters (0x00).
|
||||
*/
|
||||
String name;
|
||||
|
||||
/**
|
||||
* Field type:
|
||||
* C – Character/String
|
||||
* Y – Currency
|
||||
* N – Numeric/integer
|
||||
* F – Float
|
||||
* D – Date
|
||||
* T – DateTime
|
||||
* B – Double
|
||||
* I – Integer
|
||||
* L – Logical
|
||||
* M – Memo
|
||||
* G – General
|
||||
* M – Memo (binary) P – Picture Q – Varbinary V – Varchar (binary)
|
||||
*/
|
||||
char type;
|
||||
|
||||
/**
|
||||
* Number of decimal places.
|
||||
*/
|
||||
int size;
|
||||
|
||||
DbfField(String name, char type, int size) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.size = size;
|
||||
}
|
||||
}
|
||||
80
src/main/java/pl/wat/ms4ds/terrain/osmshp/DbfHeader.java
Normal file
80
src/main/java/pl/wat/ms4ds/terrain/osmshp/DbfHeader.java
Normal file
@@ -0,0 +1,80 @@
|
||||
package pl.wat.ms4ds.terrain.osmshp;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* Shape File Header Reader.<br><br>
|
||||
* used for *.dbf-files.<br>
|
||||
*
|
||||
* @author jrulka
|
||||
*/
|
||||
public class DbfHeader {
|
||||
int fileType;
|
||||
int dateY;
|
||||
int dateM;
|
||||
int dateD;
|
||||
int numberOfRecords;
|
||||
/**
|
||||
* Position of first data record
|
||||
*/
|
||||
int dataPos;
|
||||
/**
|
||||
* Length of one data record, including delete flag
|
||||
*/
|
||||
int recordSize;
|
||||
|
||||
static final int SIZE_BYTES = 32;
|
||||
|
||||
DbfField[] fields;
|
||||
|
||||
/**
|
||||
* Constructs a new ShapeFileHeader.
|
||||
*
|
||||
*/
|
||||
public DbfHeader(BufferedInputStream bis) throws Exception {
|
||||
byte[] data = new byte[32];
|
||||
if (bis.read(data) != 32) {
|
||||
throw new Exception("Invalid dbf file");
|
||||
}
|
||||
ByteBuffer bb = ByteBuffer.wrap(data);
|
||||
// MAIN FILE HEADER
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
fileType = bb.get(0);
|
||||
dateY = bb.get(1) + 1900;
|
||||
dateM = bb.get(2);
|
||||
dateD = bb.get(3);
|
||||
numberOfRecords = bb.getInt(4);
|
||||
dataPos = bb.getShort(8);
|
||||
recordSize = bb.getShort(10);
|
||||
// start of fields
|
||||
int numFields = (dataPos - 32 - 1) / SIZE_BYTES;
|
||||
fields = new DbfField[numFields];
|
||||
for (int i = 0; i < numFields; i++) {
|
||||
if (bis.read(data) != 32) {
|
||||
throw new Exception("Invalid dbf file");
|
||||
}
|
||||
bb = ByteBuffer.wrap(data);
|
||||
byte[] fieldData = new byte[11]; //0-11
|
||||
bb.get(fieldData);
|
||||
String name = null;
|
||||
try {
|
||||
name = new String(fieldData, "UTF-8");
|
||||
name = name.substring(0, name.indexOf('\0')); // get proper name
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
char type = (char) bb.get();
|
||||
bb.getInt();
|
||||
int size = bb.get() & 0xFF; // so we get values from 0-255.
|
||||
fields[i] = new DbfField(name, type, size);
|
||||
}
|
||||
data = new byte[1];
|
||||
if (bis.read(data) != 1) {
|
||||
throw new Exception("Invalid dbf file");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
130
src/main/java/pl/wat/ms4ds/terrain/osmshp/DbfRecord.java
Normal file
130
src/main/java/pl/wat/ms4ds/terrain/osmshp/DbfRecord.java
Normal file
@@ -0,0 +1,130 @@
|
||||
package pl.wat.ms4ds.terrain.osmshp;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class DbfRecord {
|
||||
|
||||
/**
|
||||
* OSM Id taken from the Id of this feature (node_id, way_id, or relation_id) in the
|
||||
* OSM database.
|
||||
* VARCHAR (10 Bytes)
|
||||
*/
|
||||
String osmId;
|
||||
|
||||
/**
|
||||
* Digit code (between 1000 and 9999) defining the feature class. The first one or
|
||||
* two digits define the layer, the last two or three digits the class inside a layer.
|
||||
*/
|
||||
int code;
|
||||
|
||||
/**
|
||||
* Class name of this feature. This does not add any information that is not already
|
||||
* in the “code” field but it is better readable.
|
||||
*/
|
||||
String fclass;
|
||||
|
||||
/**
|
||||
* Name of this feature, like a street or place name.
|
||||
*/
|
||||
String name;
|
||||
|
||||
String roadRef;
|
||||
boolean oneway;
|
||||
int roadMaxSpeed;
|
||||
int roadLayer;
|
||||
boolean bridge;
|
||||
boolean tunnel;
|
||||
|
||||
int waterwayWidth;
|
||||
String buildingType;
|
||||
|
||||
|
||||
public DbfRecord() throws Exception {
|
||||
}
|
||||
|
||||
public void read(BufferedInputStream bis, DbfHeader header) throws Exception {
|
||||
byte[] data = new byte[header.recordSize];
|
||||
if (bis.read(data) != header.recordSize) {
|
||||
throw new Exception("Invalid dbf file");
|
||||
}
|
||||
// Zamiana znaków spoza zakresu UTF-8 (ujemnych) na spację.
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
if (data[i] < 0) {
|
||||
data[i] = 32;
|
||||
}
|
||||
}
|
||||
String str = new String(data, StandardCharsets.UTF_8);
|
||||
// Na pozycji 0 jest tzw. flag byte, dane startują od pozycji 1.
|
||||
int from = 1;
|
||||
int to = from + header.fields[0].size;
|
||||
// Pomijam czytanie osm id, gdyż nie jest wykorzystywane.
|
||||
// osmId = str.substring(from, to);
|
||||
// int endPos = osmId.indexOf(' ');
|
||||
// osmId = osmId.substring(0, endPos);
|
||||
from = to;
|
||||
to += header.fields[1].size;
|
||||
String codeStr = str.substring(from, to);
|
||||
code = Integer.parseInt(codeStr);
|
||||
from = to;
|
||||
to += header.fields[2].size;
|
||||
fclass = str.substring(from, to);
|
||||
fclass = fclass.substring(0, fclass.indexOf(' '));
|
||||
from = to;
|
||||
to += header.fields[3].size;
|
||||
name = str.substring(from, to);
|
||||
if (header.fields.length > 4) {
|
||||
String s;
|
||||
for (int i = 4; i < header.fields.length; i++) {
|
||||
from = to;
|
||||
to += header.fields[i].size;
|
||||
s = str.substring(from, to);
|
||||
if (header.fields[i].type == 'N') {
|
||||
// Wartość numeryczna (int), zatem usuwam poprzedzające spacje
|
||||
s = s.stripLeading();
|
||||
}
|
||||
switch (header.fields[i].name) {
|
||||
case "ref":
|
||||
roadRef = s;
|
||||
break;
|
||||
case "oneway":
|
||||
oneway = !s.equals("B");
|
||||
break;
|
||||
case "maxspeed":
|
||||
roadMaxSpeed = Integer.parseInt(s);
|
||||
break;
|
||||
case "layer":
|
||||
roadLayer = Integer.parseInt(s);
|
||||
break;
|
||||
case "bridge":
|
||||
bridge = s.equals("T");
|
||||
break;
|
||||
case "tunnel":
|
||||
tunnel = s.equals("T");
|
||||
break;
|
||||
case "width":
|
||||
waterwayWidth = Integer.parseInt(s);
|
||||
break;
|
||||
case "type":
|
||||
buildingType = s;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Additional attributes for roads
|
||||
//ref - VARCHAR(20) Reference number of this road ('A 5', 'L 605', ...) ref=*
|
||||
//oneway VARCHAR(1) Is this a oneway road? “F” means that only driving
|
||||
//in direction of the linestring is allowed. “T” means
|
||||
//that only the opposite direction is allowed. “B”
|
||||
//(default value) means that both directions are ok.
|
||||
//oneway=*
|
||||
//maxspeed SMALLINT Max allowed speed in km/h maxspeed=*
|
||||
//layer SMALLINT Relative layering of roads (-5, ..., 0, ..., 5) layer=*
|
||||
//bridge VARCHAR(1) Is this road on a bridge? (“T” = true, “F” = false) bridge=*
|
||||
//tunnel VARCHAR(1) Is this road in a tunnel? (“T” = true, “F” = false) tunnel=*
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package pl.wat.ms4ds.terrain.osmshp;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A Shapefile (SHP) is a common geospatial vector data format for GIS software, developed by Esri.
|
||||
* It allaws to store geographic features (points, lines, polygons) and their attributes in a collection of
|
||||
* linked files, including .shp (geometry), .shx (index), and .dbf (attributes).
|
||||
* <p>
|
||||
* All these files must be in the same folder and start with the same name.<br>
|
||||
* example: "my_shapefile.dbf", "my_shapefile.shp", "my_shapefile.shx"<br>
|
||||
* <br>
|
||||
* <a href="http://en.wikipedia.org/wiki/Shapefile" target=blank>http://en.wikipedia.org/wiki/Shapefile"</a><br>
|
||||
*
|
||||
* @author jrulka
|
||||
*
|
||||
*/
|
||||
public class OsmShapeFileReader {
|
||||
|
||||
ShpHeader shpHeader;
|
||||
DbfHeader dbfHeader;
|
||||
BufferedInputStream bisShp;
|
||||
BufferedInputStream bisDbf;
|
||||
|
||||
// pollyline:
|
||||
// layer roads:
|
||||
// layer waterways:
|
||||
// layer railway:
|
||||
//
|
||||
// pollygon:
|
||||
// layer buildings: fclass: 15xx: buildings
|
||||
// layer landuse:
|
||||
// fclass code
|
||||
// forest 7201
|
||||
// park 7202
|
||||
// residential 7203
|
||||
// industrial 7204
|
||||
|
||||
// layer water:
|
||||
// fclass code
|
||||
// water 8000
|
||||
// reservoir 8201
|
||||
// river 8202
|
||||
// dock 8203
|
||||
// glacier 8211
|
||||
// wetland 8221
|
||||
|
||||
/**
|
||||
* Konstruktor obiektu readera danych OSM Shp.
|
||||
*
|
||||
* <pre>
|
||||
* init the ShapeFile, and load the following files:
|
||||
* "path + filename.dbf",
|
||||
* "path + filename.shp"
|
||||
* </pre>
|
||||
*
|
||||
* @param path
|
||||
* @param filename
|
||||
* @throws Exception
|
||||
*/
|
||||
public OsmShapeFileReader(String path, String filename) throws Exception {
|
||||
File dir = new File(path);
|
||||
File shpFile = new File(dir, filename + ".shp");
|
||||
bisShp = new BufferedInputStream(new FileInputStream(shpFile));
|
||||
shpHeader = new ShpHeader(bisShp);
|
||||
File dbfFile = new File(dir, filename + ".dbf");
|
||||
bisDbf = new BufferedInputStream(new FileInputStream(dbfFile));
|
||||
dbfHeader = new DbfHeader(bisDbf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Metoda odczytuje i zwraca obiekt reprezentujący określony kształt wraz z dodatkową informacją.
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public ShpShape nextShape() throws Exception {
|
||||
boolean hasNext;
|
||||
try {
|
||||
hasNext = hasNextShape();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (!hasNext) {
|
||||
return null;
|
||||
}
|
||||
ShpShape shape = null;
|
||||
DbfRecord info;
|
||||
switch (shpHeader.shapeType) {
|
||||
case Point, PointZ, PointM:
|
||||
shape = new ShpPoint(shpHeader.shapeType);
|
||||
break;
|
||||
case PolyLine, PolyLineZ, PolyLineM:
|
||||
shape = new ShpPolyLine(shpHeader.shapeType);
|
||||
break;
|
||||
case Polygon, PolygonZ, PolygonM:
|
||||
shape = new ShpPolygon(shpHeader.shapeType);
|
||||
break;
|
||||
case MultiPoint, MultiPointZ, MultiPointM:
|
||||
shape = new ShpMultiPoint(shpHeader.shapeType);
|
||||
break;
|
||||
default:
|
||||
return shape;
|
||||
}
|
||||
shape.read(bisShp);
|
||||
info = new DbfRecord();
|
||||
info.read(bisDbf, dbfHeader);
|
||||
shape.setInfo(info);
|
||||
return shape;
|
||||
}
|
||||
|
||||
public boolean hasNextShape() throws IOException {
|
||||
return bisShp.available() > 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,581 @@
|
||||
package pl.wat.ms4ds.terrain.osmshp;
|
||||
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import pl.wat.ms4ds.common.EGeoDirection;
|
||||
import pl.wat.ms4ds.terrain.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class OsmShpDataGenerator {
|
||||
private static final Logger logger = LoggerFactory.getLogger(OsmShpDataGenerator.class);
|
||||
|
||||
static void main(String[] args) {
|
||||
try {
|
||||
// GET DIRECTORY
|
||||
// "C:/Workspace/osm/warminsko-mazurskie-251217-free.shp/"
|
||||
// "dolnoslaskie"
|
||||
// "kujawsko-pomorskie"
|
||||
// "lodzkie"
|
||||
// "lubelskie"
|
||||
// "lubuskie"
|
||||
// "malopolskie"
|
||||
// "mazowieckie"
|
||||
// "opolskie"
|
||||
// "podkarpackie"
|
||||
// "podlaskie"
|
||||
// "pomorskie"
|
||||
// "slaskie"
|
||||
// "swietokrzyskie"
|
||||
// "warminsko-mazurskie"
|
||||
// "wielkopolskie"
|
||||
// "zachodniopomorskie"
|
||||
// String[] regions = new String[]{"dolnoslaskie", "kujawsko-pomorskie", "lodzkie", "lubelskie",
|
||||
// "lubuskie", "malopolskie", "mazowieckie", "opolskie",
|
||||
// "podkarpackie", "podlaskie", "pomorskie", "slaskie",
|
||||
// "swietokrzyskie", "warminsko-mazurskie", "wielkopolskie", "zachodniopomorskie"};
|
||||
|
||||
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
|
||||
String ext = "-251217-free.shp/";
|
||||
String inDir = "C:/Workspace/osm/";
|
||||
String outDir = "D:/work/kwadraty_nmt/temp/100m/";
|
||||
|
||||
// final String[] areaLayers = new String[]{"landuse_a", "buildings_a", "water_a", "pois_a", "pofw_a"};
|
||||
// final String[] pointLayers = new String[]{"pois", "pofw"};
|
||||
// final String[] linearLayers = new String[]{"waterways", "roads"};
|
||||
final String[] areaLayers = new String[]{"landuse_a", "buildings_a", "water_a"};
|
||||
final String[] pointLayers = new String[]{"pois", "pofw"};
|
||||
final String[] linearLayers = new String[]{"waterways", "roads"};
|
||||
double d = 3 * MapConsts.SS_DELTA_LON;
|
||||
|
||||
// final int concurrency = 2;
|
||||
//// String layerName = "gis_osm_" + areaLayers[0] + "_free_1";
|
||||
// for (int j = 0; j < 8; j++) {
|
||||
// Future[] futures = new Future[concurrency];
|
||||
// for (int i = 0; i < concurrency; i++) {
|
||||
// final int ii = concurrency * j + i;
|
||||
// futures[i] = executor.submit(() -> {
|
||||
// for (int k = 0; k < areaLayers.length; k++) {
|
||||
// logger.info("Work started: region= {}, layer= {}", regions[ii], areaLayers[k]);
|
||||
// String ln = "gis_osm_" + areaLayers[k] + "_free_1";
|
||||
// HashSet<ArrayList<Coord.Grid[]>>[] data = generateDataFromAreaLayer(inDir + regions[ii] + ext, ln);
|
||||
// writeAreaFeatures(data);
|
||||
// int size = 0;
|
||||
// for (HashSet<ArrayList<Coord.Grid[]>> datum : data) {
|
||||
// if (datum != null) {
|
||||
// size += datum.size();
|
||||
// datum.clear();
|
||||
// }
|
||||
// }
|
||||
// logger.info("Work finished: region= {}, layer= {}, data.size= {}", regions[ii], areaLayers[k]);
|
||||
// }
|
||||
// for (int k = 0; k < pointLayers.length; k++) {
|
||||
// logger.info("Work started: region= {}, layer= {}", regions[ii], pointLayers[k]);
|
||||
// String ln = "gis_osm_" + pointLayers[k] + "_free_1";
|
||||
// HashSet<Coord.Grid> data = generateDataFromPointLayer(inDir + regions[ii] + ext, ln);
|
||||
// writeAreaFeatureIntoSquares(TerrainType.BUILDINGS, false, data);
|
||||
// int size = data.size();
|
||||
// data.clear();
|
||||
// logger.info("Work finished: region= {}, layer= {}, data.size= {}", regions[ii], pointLayers[k], size);
|
||||
// }
|
||||
// for (int k = 0; k < linearLayers.length; k++) {
|
||||
// logger.info("Work started: region= {}, layer= {}", regions[ii], linearLayers[k]);
|
||||
// String ln = "gis_osm_" + linearLayers[k] + "_free_1";
|
||||
// HashSet<ArrayList<Coord.Grid[]>>[] data = generateDataFromLinearLayer(inDir + regions[ii] + ext, ln);
|
||||
// writeLinearFeatures(data, k);
|
||||
// int size = 0;
|
||||
// for (HashSet<ArrayList<Coord.Grid[]>> datum : data) {
|
||||
// if (datum != null) {
|
||||
// size += datum.size();
|
||||
// datum.clear();
|
||||
// }
|
||||
// }
|
||||
// logger.info("Work finished: region= {}, layer= {}, data.size= {}", regions[ii], linearLayers[k], size);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// for (Future future : futures) {
|
||||
// future.get();
|
||||
// }
|
||||
// Teren.saveToFiles(outDir);
|
||||
// }
|
||||
|
||||
// String layerName = "gis_osm_" + areaLayers[0] + "_free_1";
|
||||
String[] regions = new String[]{"dolnoslaskie", "kujawsko-pomorskie", "lodzkie", "lubelskie",
|
||||
"lubuskie", "malopolskie", "opolskie", "mazowieckie", "warminsko-mazurskie",
|
||||
"podkarpackie", "podlaskie", "pomorskie", "slaskie",
|
||||
"swietokrzyskie", "wielkopolskie", "zachodniopomorskie"};
|
||||
// String[] regions = new String[]{"mazowieckie", "warminsko-mazurskie"};
|
||||
for (int i = 0; i < regions.length; i++) {
|
||||
for (int k = 0; k < areaLayers.length; k++) {
|
||||
logger.info("Work started: region= {}, layer= {}", regions[i], areaLayers[k]);
|
||||
String ln = "gis_osm_" + areaLayers[k] + "_free_1";
|
||||
HashSet<ArrayList<Coord.Grid[]>>[] data = generateDataFromAreaLayer(inDir + regions[i] + ext, ln);
|
||||
writeAreaFeatures(data);
|
||||
for (HashSet<ArrayList<Coord.Grid[]>> datum : data) {
|
||||
if (datum != null) {
|
||||
datum.clear();
|
||||
}
|
||||
}
|
||||
logger.info("Work finished: region= {}, layer= {}", regions[i], areaLayers[k]);
|
||||
}
|
||||
for (int k = 0; k < pointLayers.length; k++) {
|
||||
logger.info("Work started: region= {}, layer= {}", regions[i], pointLayers[k]);
|
||||
String ln = "gis_osm_" + pointLayers[k] + "_free_1";
|
||||
HashSet<Coord.Grid> data = generateDataFromPointLayer(inDir + regions[i] + ext, ln);
|
||||
writeAreaFeatureIntoSquares(TerrainType.BUILDINGS, false, data);
|
||||
data.clear();
|
||||
logger.info("Work finished: region= {}, layer= {}", regions[i], pointLayers[k]);
|
||||
}
|
||||
for (int k = 0; k < linearLayers.length; k++) {
|
||||
logger.info("Work started: region= {}, layer= {}", regions[i], linearLayers[k]);
|
||||
String ln = "gis_osm_" + linearLayers[k] + "_free_1";
|
||||
HashSet<ArrayList<Coord.Grid[]>>[] data = generateDataFromLinearLayer(inDir + regions[i] + ext, ln);
|
||||
writeLinearFeatures(data, k);
|
||||
for (HashSet<ArrayList<Coord.Grid[]>> datum : data) {
|
||||
if (datum != null) {
|
||||
datum.clear();
|
||||
}
|
||||
}
|
||||
logger.info("Work finished: region= {}, layer= {}", regions[i], linearLayers[k]);
|
||||
}
|
||||
Teren.saveToFiles(outDir);
|
||||
}
|
||||
|
||||
// HashSet<ArrayList<Coord.Grid[]>>[] data = generateDataFromAreaLayer(inDir + regions[0] + ext, "gis_osm_pois_a_free_1");
|
||||
// writeAreaFeatures(data);
|
||||
// String ln = "gis_osm_" + pointLayers[1] + "_free_1";
|
||||
// HashSet<Coord.Grid> data2 = generateDataFromPointLayer(inDir + regions[0] + ext, ln);
|
||||
// writeAreaFeatureIntoSquares(TerrainType.BUILDINGS, false, data2);
|
||||
|
||||
// writeLinearFeatures(data, 1);
|
||||
// Teren.saveToFiles(outDir);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Funkcja zapisuje dane dotyczace określonych charakterystyk terenowych
|
||||
* (odpowiadające indeksom głównej tablicy) do kwadratów.
|
||||
* <p></p>
|
||||
* Każda cecha przetwarzana jest osobno (indeks tablicy). W ramach cechy przetwarzane są obszary.
|
||||
* Każdy obszar opisany jest listą wielokątów określających zewnętrzne granice oraz opcjonalnie dziury.
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
public static void writeAreaFeatures(HashSet<ArrayList<Coord.Grid[]>>[] data) {
|
||||
HashSet<Coord.Grid> squareSet = new HashSet<>();
|
||||
// Indeksy odpowiadają numeracji (id) wartości w TerrainType.
|
||||
for (int typeId = 1; typeId < data.length; typeId++) {
|
||||
HashSet<ArrayList<Coord.Grid[]>> set = data[typeId];
|
||||
if (set == null || set.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
TerrainType terrainType = TerrainType.valueFromId(typeId);
|
||||
for (ArrayList<Coord.Grid[]> area : set) {
|
||||
collectSquaresOfArea(area, squareSet, true);
|
||||
writeAreaFeatureIntoSquares(terrainType, false, squareSet);
|
||||
squareSet.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Funkcja gromadzi współrzędne (gridowe) kwadratów należących do obszaru opisanego wielokątami.
|
||||
* Pierwszy wielokąt opisuje zewnętrzne granice obszaru.
|
||||
* Kolejne wielokąty opisują granice obszarów wewnętrznych, będących dziurami.
|
||||
*
|
||||
* @param area
|
||||
* @param squareSet
|
||||
*/
|
||||
public static void collectSquaresOfArea(ArrayList<Coord.Grid[]> area, HashSet<Coord.Grid> squareSet, boolean onlyOuter) {
|
||||
Coord.Grid[] outerPolygon = area.getFirst();
|
||||
if (outerPolygon == null) {
|
||||
return;
|
||||
}
|
||||
int[] bounds = GeomUtils.getBounds(outerPolygon);
|
||||
int minX = bounds[0];
|
||||
int minY = bounds[1];
|
||||
int maxX = bounds[2];
|
||||
int maxY = bounds[3];
|
||||
boolean inside;
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
inside = GeomUtils.insidePolygon(outerPolygon, x, y);
|
||||
if (inside) {
|
||||
squareSet.add(new Coord.Grid(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (onlyOuter) {
|
||||
return;
|
||||
}
|
||||
int count = squareSet.size();
|
||||
// Pozostałe wielokąty opisują obszary wewnętrzne będące tzw. dziurami.
|
||||
boolean removed;
|
||||
Coord.Grid[] innerPolygon;
|
||||
Coord.Grid test;
|
||||
for (int i = 1; i < area.size(); i++) {
|
||||
innerPolygon = area.get(i);
|
||||
bounds = GeomUtils.getBounds(innerPolygon);
|
||||
minX = bounds[0];
|
||||
minY = bounds[1];
|
||||
maxX = bounds[2];
|
||||
maxY = bounds[3];
|
||||
test = new Coord.Grid();
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
inside = GeomUtils.insidePolygon(outerPolygon, x, y);
|
||||
if (inside) {
|
||||
test.x = x;
|
||||
test.y = y;
|
||||
removed = squareSet.remove(test);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int countOfRemoved = count - squareSet.size();
|
||||
logger.trace("Num of outer= {}, num of inner= {}", count, countOfRemoved);
|
||||
|
||||
}
|
||||
|
||||
public static void writeAreaFeatureIntoSquares(TerrainType type, boolean clearFeature, HashSet<Coord.Grid> squareSet) {
|
||||
TerrainType val = (clearFeature) ? TerrainType.NONE : type;
|
||||
for (Coord.Grid coord : squareSet) {
|
||||
Square square = Teren.getSquare(coord.x, coord.y);
|
||||
if (square == Square.EMPTY) {
|
||||
continue;
|
||||
}
|
||||
synchronized (square) {
|
||||
square.terrainType = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Funkcja zwraca id wartości typu wyliczeniowego {@link TerrainType} dla obiektów obszarowych.
|
||||
* <p>Wartość 0 - NONE, 1 - GRASS, 2 - SWAMP, 3 - WATER, 4 - SCRUB_BUSHES, 5 - BUILDINGS, 6 - FOREST.
|
||||
*
|
||||
* @param shpShape
|
||||
* @return
|
||||
*/
|
||||
public static int mapFclassToTerrainType(ShpShape shpShape) {
|
||||
if (shpShape.info.code == 1500) {
|
||||
return TerrainType.BUILDINGS.id;
|
||||
}
|
||||
return switch (shpShape.info.fclass) {
|
||||
// case "residential", "industrial", "commercial", "retail", "farmyard" -> TerrainType.BUILDINGS.id;
|
||||
case "police", "fire_station", "post_office", "library", "town_hall", "courthouse", "prison", "embassy",
|
||||
"theatre", "nightclub", "cinema", "nursing_home", "market_place", "university", "school",
|
||||
"kindergarten", "college", "public_building", "pharmacy", "hospital", "clinic", "doctors", "dentist",
|
||||
"veterinary", "restaurant", "fast_food", "cafe", "pub", "hotel", "motel", "bed_and_breakfast",
|
||||
"guesthouse", "hostel", "supermarket", "bakery", "mall", "department_store", "bank", "museum",
|
||||
"castle", "bookshop", "clothes", "general", "hairdresser",
|
||||
"jeweller", "optician" -> TerrainType.BUILDINGS.id;
|
||||
case "christian", "christian_anglican", "christian_catholic", "christian_evangelical",
|
||||
"christian_lutheran", "christian_methodist", "christian_orthodox", "christian_protestant",
|
||||
"christian_baptist", "christian_mormon" -> TerrainType.BUILDINGS.id;
|
||||
case "forest", "woodland", "park", "orchard" -> TerrainType.FOREST.id;
|
||||
case "grass", "meadow", "farmland", "recreation_ground", "heath" -> TerrainType.GRASS.id;
|
||||
case "scrub", "vineyard", "allotments" -> TerrainType.SCRUB_BUSHES.id;
|
||||
case "water", "reservoir", "river", "dock" -> TerrainType.WATER.id;
|
||||
case "wetland" -> TerrainType.SWAMP.id;
|
||||
default -> TerrainType.NONE.id;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generuje dane obszarowe w zakresie typu terenu {@link TerrainType}.
|
||||
* <p>
|
||||
* "gis_osm_landuse_a_free_1", "gis_osm_water_a_free_1", "gis_osm_buildings_a_free_1", "gis_osm_pois_a_free_1", "gis_osm_pofw_a_free_1"
|
||||
*
|
||||
* @param path
|
||||
*/
|
||||
static HashSet<ArrayList<Coord.Grid[]>>[] generateDataFromAreaLayer(String path, String filename) {
|
||||
HashSet<ArrayList<Coord.Grid[]>>[] result = new HashSet[TerrainType.values().length];
|
||||
result[1] = new HashSet<>();
|
||||
result[2] = new HashSet<>();
|
||||
result[3] = new HashSet<>();
|
||||
result[4] = new HashSet<>();
|
||||
result[5] = new HashSet<>();
|
||||
result[6] = new HashSet<>();
|
||||
try {
|
||||
OsmShapeFileReader osmShapeFileReader = new OsmShapeFileReader(path, filename);
|
||||
int pos = 0;
|
||||
int typeId;
|
||||
while (osmShapeFileReader.hasNextShape()) {
|
||||
ShpShape shape = osmShapeFileReader.nextShape();
|
||||
if (shape instanceof ShpPolygon shpPolygon) {
|
||||
typeId = mapFclassToTerrainType(shpPolygon);
|
||||
String fclass = shpPolygon.info.fclass;
|
||||
if (shpPolygon.info.code == 1500) {
|
||||
// Warstwa obszarowa dot. budynków nie ma zdefiniowanej fclass, zatem sprawdzam code
|
||||
// i ewentualnie zmieniam typeId.
|
||||
typeId = TerrainType.BUILDINGS.id;
|
||||
fclass = "building1500";
|
||||
}
|
||||
if (typeId == 0) {
|
||||
continue;
|
||||
}
|
||||
logger.trace("Shape pos = {}, shape type = {}, fclass= {}, numParts= {}", pos, shape.getShapeType(), fclass, shpPolygon.numberOfParts);
|
||||
ArrayList<Coord.Grid[]> polygons = generatePolylines(shpPolygon);
|
||||
result[typeId].add(polygons);
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
logger.info("End, num={}", pos);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
enum WatercourseType {
|
||||
NONE(0), DITCH_DRAIN(1), STREAM(2), RIVER(3);
|
||||
|
||||
public final int id;
|
||||
|
||||
WatercourseType(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static WatercourseType valueFromId(int id) {
|
||||
return values[id];
|
||||
}
|
||||
|
||||
static final WatercourseType[] values = WatercourseType.values();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Funkcja zwraca id wartości typu wyliczeniowego dla obiektów liniowych typu cieki wodne oraz drogi.
|
||||
* <p>Wartość 0 - brak, 1 - DITCH_DRAIN/SMALL, 2 - STREAM/MINOR, 3 - RIVER/MAJOR
|
||||
*
|
||||
* @param shpShape
|
||||
* @return typeId of linear feature: 0 - NONE, 1 - DITCH_DRAIN/SMALL, 2 - STREAM/MINOR, 3 - RIVER/MAJOR
|
||||
*/
|
||||
public static int mapFclassToLineTypeId(ShpShape shpShape) {
|
||||
return switch (shpShape.info.fclass) {
|
||||
case "river" -> WatercourseType.RIVER.id;
|
||||
case "stream", "canal" -> WatercourseType.STREAM.id;
|
||||
case "drain" -> WatercourseType.DITCH_DRAIN.id;
|
||||
case "motorway", "trunk", "primary", "secondary", "tertiary", "motorway_link", "trunk_link", "primary_link",
|
||||
"secondary_link", "tertiary_link" -> RoadType.MAJOR.id;
|
||||
case "unclassified", "residential", "living_street" -> RoadType.MINOR.id;
|
||||
case "service", "track", "track_grade1", "track_grade2", "track_grade3", "track_grade4", "track_grade5" ->
|
||||
RoadType.SMALL.id;
|
||||
default -> 0;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generuje dane liniowe w zakresie cieków/przeszkód wodnych.
|
||||
* (RIVER, STREAM, DITCH_DRAIN).
|
||||
* (MAJOR_ROADS, MINOR_ROADS, SMALL_ROADS)
|
||||
* <p>
|
||||
* "gis_osm_waterways_free_1", "gis_osm_roads_free_1"
|
||||
*
|
||||
* @param path
|
||||
*/
|
||||
static HashSet<ArrayList<Coord.Grid[]>>[] generateDataFromLinearLayer(String path, String filename) {
|
||||
HashSet<ArrayList<Coord.Grid[]>>[] result = new HashSet[]{new HashSet<>(), new HashSet<>(), new HashSet<>(), new HashSet<>()};
|
||||
int width;
|
||||
try {
|
||||
OsmShapeFileReader osmShapeFileReader = new OsmShapeFileReader(path, filename);
|
||||
int pos = 0;
|
||||
int typeId;
|
||||
while (osmShapeFileReader.hasNextShape()) {
|
||||
ShpShape shape = osmShapeFileReader.nextShape();
|
||||
typeId = mapFclassToLineTypeId(shape);
|
||||
if (typeId == 0) {
|
||||
continue;
|
||||
}
|
||||
if (shape instanceof ShpPolyLine shpPolyLine) {
|
||||
width = shpPolyLine.info.waterwayWidth;
|
||||
logger.trace("Shape pos = {}, shape type = {}, fclass= {}, numParts= {}, width= {}", pos, shape.getShapeType(), shape.info.fclass, shpPolyLine.numberOfParts, width);
|
||||
ArrayList<Coord.Grid[]> polylines = generatePolylines(shpPolyLine);
|
||||
result[typeId].add(polylines);
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
logger.info("End, num={}", pos);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
enum RoadType {
|
||||
NONE(0), SMALL(1), MINOR(2), MAJOR(3);
|
||||
|
||||
public final int id;
|
||||
|
||||
RoadType(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static RoadType valueFromId(int id) {
|
||||
return values[id];
|
||||
}
|
||||
|
||||
static final RoadType[] values = RoadType.values();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Funkcja generalna odpowiedzialna za przekształcenie danych liniowych i zapis do kwadratów.
|
||||
*
|
||||
* @param data
|
||||
* @param featureCategory kategoria danych liniowych (0 - cieki wodne, 1 - drogi)
|
||||
*/
|
||||
public static void writeLinearFeatures(HashSet<ArrayList<Coord.Grid[]>>[] data, int featureCategory) {
|
||||
ArrayList<Coord.Grid[]> polylineList = new ArrayList<>();
|
||||
// Indeksy odpowiadają numeracji (id) wartości w typach wyliczeniowych danej charakterystyki.
|
||||
for (int typeId = 0; typeId < data.length; typeId++) {
|
||||
HashSet<ArrayList<Coord.Grid[]>> set = data[typeId];
|
||||
if (set == null || set.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
for (ArrayList<Coord.Grid[]> polylines : set) {
|
||||
collectSquaresOfPolylines(polylines, polylineList);
|
||||
writeLinearFeatureIntoSquares((byte) typeId, false, polylineList, featureCategory);
|
||||
polylineList.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Funkcja gromadzi sekwencje współrzędnych kwadratów tworzących łamane.
|
||||
*
|
||||
* @param polylines list of polylines defined by vertices
|
||||
* @param polylineList set of detailed polylines defined by squares sequances
|
||||
*/
|
||||
public static void collectSquaresOfPolylines(ArrayList<Coord.Grid[]> polylines, ArrayList<Coord.Grid[]> polylineList) {
|
||||
Coord.Grid[] squares;
|
||||
for (Coord.Grid[] polyline : polylines) {
|
||||
squares = GeomUtils.generateSquaresOfSegments(polyline);
|
||||
squares = GeomUtils.removeSteps(squares);
|
||||
polylineList.add(squares);
|
||||
}
|
||||
logger.trace("Num of polylines= {}", polylines.size());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param type type of feature (depends on the feature category)
|
||||
* @param clearFeature
|
||||
* @param polylineList polylines defined by squares sequences
|
||||
* @param featureCategory feature category to write (0 - watercourses, 1 - roads)
|
||||
*/
|
||||
public static void writeLinearFeatureIntoSquares(byte type, boolean clearFeature, ArrayList<Coord.Grid[]> polylineList, int featureCategory) {
|
||||
byte val = (clearFeature) ? 0 : type;
|
||||
for (Coord.Grid[] grids : polylineList) {
|
||||
for (int i = 0; i < grids.length - 1; i++) {
|
||||
int x0 = grids[i].x;
|
||||
int y0 = grids[i].y;
|
||||
int x1 = grids[i + 1].x;
|
||||
int y1 = grids[i + 1].y;
|
||||
Square curr_square = Teren.getSquare(x0, y0);
|
||||
EGeoDirection outDirection = GeomUtils.neighborDirection(x0, y0, x1, y1);
|
||||
if (curr_square != Square.EMPTY) {
|
||||
synchronized (curr_square) {
|
||||
if (featureCategory == 0) {
|
||||
curr_square.watercourses[outDirection.id] = val;
|
||||
} else {
|
||||
curr_square.roads[outDirection.id] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
EGeoDirection inDirection = outDirection.oppositeDirect();
|
||||
Square next_square = Teren.getSquare(x1, y1);
|
||||
if (next_square != Square.EMPTY) {
|
||||
synchronized (next_square) {
|
||||
if (featureCategory == 0) {
|
||||
next_square.watercourses[inDirection.id] = val;
|
||||
} else {
|
||||
next_square.roads[inDirection.id] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generuje dane obszarowe w zakresie zabudowy {@link TerrainType}.
|
||||
* <p>
|
||||
* "gis_osm_pois_free_1", "gis_osm_pofw_free_1"
|
||||
*
|
||||
* @param path
|
||||
*/
|
||||
static HashSet<Coord.Grid> generateDataFromPointLayer(String path, String filename) {
|
||||
HashSet<Coord.Grid> result = new HashSet<>();
|
||||
try {
|
||||
OsmShapeFileReader osmShapeFileReader = new OsmShapeFileReader(path, filename);
|
||||
int pos = 0;
|
||||
int typeId;
|
||||
int x;
|
||||
int y;
|
||||
while (osmShapeFileReader.hasNextShape()) {
|
||||
ShpShape shape = osmShapeFileReader.nextShape();
|
||||
if (shape instanceof ShpPoint shpPoint) {
|
||||
typeId = mapFclassToTerrainType(shpPoint);
|
||||
if (typeId != TerrainType.BUILDINGS.id) {
|
||||
continue;
|
||||
}
|
||||
logger.trace("Shape pos = {}, shape type = {}, fclass= {}", pos, shape.getShapeType(), shape.info.fclass);
|
||||
x = Coord.convertLonToGridX(shpPoint.x);
|
||||
y = Coord.convertLatToGridY(shpPoint.y);
|
||||
Coord.Grid coord = new Coord.Grid(x, y);
|
||||
result.add(coord);
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
logger.info("End, num={}", pos);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Funkcja generuje dane geometryczne na siatce kwadratów.
|
||||
* <p> Lista łamanych (otwartych lub zamkniętych) opisujących kształt obiektu klasy {@link ShpPolyShape}.
|
||||
* <p> W przypadku obiektów obszarowych pierwszy element opisuje zewnętrzną powłokę, kolejne tzw. dziury.</p>
|
||||
* <p> W przypadku obiektów liniowych zawiera jedną łamaną.</p>
|
||||
*
|
||||
* @param shpPolyShape
|
||||
* @return
|
||||
*/
|
||||
static ArrayList<Coord.Grid[]> generatePolylines(ShpPolyShape shpPolyShape) {
|
||||
ArrayList<Coord.Grid[]> polygons = new ArrayList<>();
|
||||
int start;
|
||||
int stop;
|
||||
Coord.Grid[] polygon;
|
||||
for (int i = 0; i < shpPolyShape.numberOfParts; i++) {
|
||||
start = shpPolyShape.partsPos[i];
|
||||
int next = i + 1;
|
||||
if (next < shpPolyShape.numberOfParts) {
|
||||
stop = shpPolyShape.partsPos[next];
|
||||
} else {
|
||||
stop = shpPolyShape.numberOfPoints;
|
||||
}
|
||||
polygon = new Coord.Grid[stop - start];
|
||||
for (int j = 0; j < polygon.length; j++) {
|
||||
int x = Coord.convertLonToGridX(shpPolyShape.pointsX[start + j]);
|
||||
int y = Coord.convertLatToGridY(shpPolyShape.pointsY[start + j]);
|
||||
polygon[j] = new Coord.Grid(x, y);
|
||||
}
|
||||
// boolean b1 = GeomUtils.isClockwise(polygon);
|
||||
polygon = GeomUtils.removeAdjacentDuplicates(polygon);
|
||||
polygon = GeomUtils.removeCollinearity(polygon, true);
|
||||
// boolean b2 = GeomUtils.isClockwise(polygon);
|
||||
polygons.add(polygon);
|
||||
logger.trace("Part id = {}, numOfPoints= {}", i, polygon.length);
|
||||
}
|
||||
return polygons;
|
||||
}
|
||||
|
||||
}
|
||||
126
src/main/java/pl/wat/ms4ds/terrain/osmshp/ShpHeader.java
Normal file
126
src/main/java/pl/wat/ms4ds/terrain/osmshp/ShpHeader.java
Normal file
@@ -0,0 +1,126 @@
|
||||
package pl.wat.ms4ds.terrain.osmshp;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* Shape File Header Reader.<br><br>
|
||||
* used for *.shp-files and *.shx-files.<br>
|
||||
* contains information about:<br>
|
||||
* ...<br>
|
||||
* Shape-Type<br>
|
||||
* boundingbox<br>
|
||||
* measure-range<br>
|
||||
* ...<br>
|
||||
*
|
||||
* @author jrulka
|
||||
*/
|
||||
public class ShpHeader {
|
||||
final static int SHAPE_FILE_CODE = 9994;
|
||||
final static int SHAPE_FILE_VERSION = 1000;
|
||||
|
||||
int fileLength;
|
||||
int shapeTypeCode;
|
||||
double[][] bbox = new double[3][2]; // [x, y, z][min, max]
|
||||
double[] rangeM = new double[2]; // [min, max]
|
||||
|
||||
ShpShape.Type shapeType = null;
|
||||
|
||||
/**
|
||||
* Constructs a new ShapeFileHeader.
|
||||
*
|
||||
*/
|
||||
public ShpHeader(BufferedInputStream bis) throws Exception {
|
||||
byte[] data = new byte[100];
|
||||
if (bis.read(data) != 100) {
|
||||
throw new Exception("Invalid shp file");
|
||||
}
|
||||
ByteBuffer bb = ByteBuffer.wrap(data);
|
||||
// MAIN FILE HEADER
|
||||
bb.order(ByteOrder.BIG_ENDIAN);
|
||||
// magic number
|
||||
if (bb.getInt(0) != SHAPE_FILE_CODE) {
|
||||
throw new IOException("(ShapeFile) error: SHP_MAGIC = " + SHAPE_FILE_CODE);
|
||||
}
|
||||
// file length
|
||||
fileLength = bb.getInt(24);
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
// shp version
|
||||
if (bb.getInt(28) != SHAPE_FILE_VERSION) {
|
||||
throw new IOException("(ShapeFile) error: SHP_VERSION = " + SHAPE_FILE_VERSION);
|
||||
}
|
||||
shapeTypeCode = bb.getInt(32);
|
||||
try {
|
||||
shapeType = ShpShape.Type.getByCode(shapeTypeCode);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
bbox[0][0] = bb.getDouble(36); // x-min
|
||||
bbox[1][0] = bb.getDouble(44); // y-min
|
||||
bbox[0][1] = bb.getDouble(52); // x-max
|
||||
bbox[1][1] = bb.getDouble(60); // y-max
|
||||
bbox[2][0] = bb.getDouble(68); // z-min
|
||||
bbox[2][1] = bb.getDouble(76); // z-max
|
||||
rangeM[0] = bb.getDouble(84); // m-min
|
||||
rangeM[1] = bb.getDouble(92); // m-max
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ShapeType the shapeFile contains.<br>
|
||||
* A shapeFile contains only one type of shape.<br>
|
||||
*
|
||||
* @return the type of shape
|
||||
*/
|
||||
public ShpShape.Type getShapeType() {
|
||||
return shapeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data storage: [3][2] --> [x,y,z][min, max].
|
||||
*
|
||||
* @return boundingbox as double[][]
|
||||
*/
|
||||
public double[][] getBoundingBox() {
|
||||
return bbox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get measure range.<br>
|
||||
* [min, max]
|
||||
*
|
||||
* @return measure range as double[]
|
||||
*/
|
||||
public double[] getMeasureRange() {
|
||||
return rangeM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get length in bytes of the shapeFile.
|
||||
*
|
||||
* @return length in bytes
|
||||
*/
|
||||
public int getFileLength() {
|
||||
return fileLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Verions on the shapeFile.
|
||||
*
|
||||
* @return should return 1000
|
||||
*/
|
||||
public int getVersion() {
|
||||
return SHAPE_FILE_VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get MAGIC NUMBER of shapeFile.
|
||||
*
|
||||
* @return should return 9994
|
||||
*/
|
||||
public int getMagicNumber() {
|
||||
return SHAPE_FILE_CODE;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
70
src/main/java/pl/wat/ms4ds/terrain/osmshp/ShpMultiPoint.java
Normal file
70
src/main/java/pl/wat/ms4ds/terrain/osmshp/ShpMultiPoint.java
Normal file
@@ -0,0 +1,70 @@
|
||||
package pl.wat.ms4ds.terrain.osmshp;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Shape: MultiPoint.<br>
|
||||
* <pre>
|
||||
* A MultiPoint represents a set of points.
|
||||
* Possible ShapeTypes:
|
||||
* MultiPoint ( 8 ),
|
||||
* MultiPointZ ( 18 ),
|
||||
* MultiPointM ( 28 ),
|
||||
* </pre>
|
||||
*
|
||||
* @author jrulka
|
||||
*
|
||||
*/
|
||||
public class ShpMultiPoint extends ShpShape {
|
||||
double xMin;
|
||||
double yMin;
|
||||
double zMin;
|
||||
double mMin;
|
||||
double xMax;
|
||||
double yMax;
|
||||
double zMax;
|
||||
double mMax;
|
||||
int numberOfPoints;
|
||||
double[] pointsX;
|
||||
double[] pointsY;
|
||||
double[] pointsZ;
|
||||
double[] valuesM;
|
||||
|
||||
public ShpMultiPoint(ShpShape.Type shapeType) {
|
||||
super(shapeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readContent(ByteBuffer bb) {
|
||||
xMin = bb.getDouble(); // x-min
|
||||
yMin = bb.getDouble(); // y-min
|
||||
xMax = bb.getDouble(); // x-max
|
||||
yMax = bb.getDouble(); // y-max
|
||||
numberOfPoints = bb.getInt(); // number of points (total of all parts)
|
||||
pointsX = new double[numberOfPoints];
|
||||
pointsY = new double[numberOfPoints];
|
||||
pointsZ = new double[numberOfPoints];
|
||||
for (int i = 0; i < numberOfPoints; i++) {
|
||||
pointsX[i] = bb.getDouble(); // x - coordinate
|
||||
pointsY[i] = bb.getDouble(); // y - coordinate
|
||||
}
|
||||
// if SHAPE-TYPE: 18
|
||||
if (type.hasZ()) {
|
||||
zMin = bb.getDouble(); // z-min
|
||||
zMax = bb.getDouble(); // z-max
|
||||
for (int i = 0; i < numberOfPoints; i++) {
|
||||
pointsZ[i] = bb.getDouble(); // z - coordinate
|
||||
}
|
||||
}
|
||||
// if SHAPE-TYPE: 18 | 28
|
||||
if (type.hasM()) {
|
||||
mMin = bb.getDouble(); // m-min
|
||||
mMax = bb.getDouble(); // m-max
|
||||
valuesM = new double[numberOfPoints];
|
||||
for (int i = 0; i < numberOfPoints; i++) {
|
||||
valuesM[i] = bb.getDouble(); // m - value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
45
src/main/java/pl/wat/ms4ds/terrain/osmshp/ShpPoint.java
Normal file
45
src/main/java/pl/wat/ms4ds/terrain/osmshp/ShpPoint.java
Normal file
@@ -0,0 +1,45 @@
|
||||
package pl.wat.ms4ds.terrain.osmshp;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Shape: Point.<br>
|
||||
* <pre>
|
||||
* possible ShapeTypes:
|
||||
* Point ( 1 ),
|
||||
* PointZ ( 11 ),
|
||||
* PointM ( 21 ),
|
||||
* </pre>
|
||||
*
|
||||
* @author jrulka
|
||||
*
|
||||
*/
|
||||
|
||||
public class ShpPoint extends ShpShape {
|
||||
|
||||
// SHAPE RECORD CONTENT
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
double m; //[m-value]
|
||||
|
||||
public ShpPoint(ShpShape.Type shapeType) {
|
||||
super(shapeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readContent(ByteBuffer bb) {
|
||||
x = bb.getDouble(); // x - coordinate
|
||||
y = bb.getDouble(); // y - coordinate
|
||||
// if SHAPE-TYPE: 11
|
||||
if (type.hasZ()) {
|
||||
z = bb.getDouble(); // z - coordinate
|
||||
}
|
||||
// if SHAPE-TYPE: 11 | 21
|
||||
if (type.hasM()) {
|
||||
m = bb.getDouble(); // m - value
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
25
src/main/java/pl/wat/ms4ds/terrain/osmshp/ShpPolyLine.java
Normal file
25
src/main/java/pl/wat/ms4ds/terrain/osmshp/ShpPolyLine.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package pl.wat.ms4ds.terrain.osmshp;
|
||||
|
||||
/**
|
||||
* Shape: PolyLine.<br>
|
||||
* <pre>
|
||||
* polyline: consists of one or more parts.
|
||||
* part: connected sequence of two or more points.
|
||||
* may or may not be connected to one another.
|
||||
* may or may not intersect one another.
|
||||
* same content as polygon.
|
||||
* possible ShapeTypes:
|
||||
* PolyLine ( 8 ),
|
||||
* PolyLineZ ( 18 ),
|
||||
* PolyLineM ( 28 ),
|
||||
* </pre>
|
||||
*
|
||||
* @author jrulka
|
||||
*
|
||||
*/
|
||||
public class ShpPolyLine extends ShpPolyShape {
|
||||
|
||||
public ShpPolyLine(Type shape_type) {
|
||||
super(shape_type);
|
||||
}
|
||||
}
|
||||
67
src/main/java/pl/wat/ms4ds/terrain/osmshp/ShpPolyShape.java
Normal file
67
src/main/java/pl/wat/ms4ds/terrain/osmshp/ShpPolyShape.java
Normal file
@@ -0,0 +1,67 @@
|
||||
package pl.wat.ms4ds.terrain.osmshp;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Base class for {@link ShpPolyLine}, {@link ShpPolygon}.
|
||||
* <p></p> Contains common attributes and methods.
|
||||
*/
|
||||
public abstract class ShpPolyShape extends ShpShape {
|
||||
// SHAPE RECORD CONTENT
|
||||
double xMin;
|
||||
double yMin;
|
||||
double zMin;
|
||||
double mMin;
|
||||
double xMax;
|
||||
double yMax;
|
||||
double zMax;
|
||||
double mMax;
|
||||
int numberOfParts;
|
||||
int numberOfPoints;
|
||||
int[] partsPos;
|
||||
double[] pointsX; // [number of points][x,y,z]
|
||||
double[] pointsY;
|
||||
double[] pointsZ;
|
||||
double[] valuesM; // [number of points][m-value]
|
||||
|
||||
public ShpPolyShape(ShpShape.Type shape_type) {
|
||||
super(shape_type);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readContent(ByteBuffer bb) {
|
||||
xMin = bb.getDouble(); // x-min
|
||||
yMin = bb.getDouble(); // y-min
|
||||
xMax = bb.getDouble(); // x-max
|
||||
yMax = bb.getDouble(); // y-max
|
||||
numberOfParts = bb.getInt(); // number of polygon-parts / rings
|
||||
numberOfPoints = bb.getInt(); // number of points (total of all parts)
|
||||
partsPos = new int[numberOfParts];
|
||||
for (int i = 0; i < numberOfParts; i++) {
|
||||
partsPos[i] = bb.getInt(); // index of the point-list (indicates start-point of a polygon)
|
||||
}
|
||||
pointsX = new double[numberOfPoints];
|
||||
pointsY = new double[numberOfPoints];
|
||||
for (int i = 0; i < numberOfPoints; i++) {
|
||||
pointsX[i] = bb.getDouble(); // x - coordinate
|
||||
pointsY[i] = bb.getDouble(); // y - coordinate
|
||||
}
|
||||
// if SHAPE-TYPE: 13
|
||||
if (type.hasZ()) {
|
||||
zMin = bb.getDouble(); // z-min
|
||||
zMax = bb.getDouble(); // z-max
|
||||
for (int i = 0; i < numberOfPoints; i++) {
|
||||
pointsZ[i] = bb.getDouble(); // z - coordinate
|
||||
}
|
||||
}
|
||||
// if SHAPE-TYPE: 13 | 23
|
||||
if (type.hasM()) {
|
||||
mMin = bb.getDouble(); // m-min
|
||||
mMax = bb.getDouble(); // m-max
|
||||
valuesM = new double[numberOfPoints];
|
||||
for (int i = 0; i < numberOfPoints; i++) {
|
||||
valuesM[i] = bb.getDouble(); // m - value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
25
src/main/java/pl/wat/ms4ds/terrain/osmshp/ShpPolygon.java
Normal file
25
src/main/java/pl/wat/ms4ds/terrain/osmshp/ShpPolygon.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package pl.wat.ms4ds.terrain.osmshp;
|
||||
|
||||
|
||||
/**
|
||||
* Shape: Polygon.<br>
|
||||
* <pre>
|
||||
* polygon: consists of one or more rings (multiple outer rings).
|
||||
* ring: four or more points ... closed, non-self-intersecting loop.
|
||||
* interiour: clockwise order of vertices.
|
||||
* same content as PolyLine.
|
||||
* possible ShapeTypes:
|
||||
* Polygon ( 8 ),
|
||||
* PolygonZ ( 18 ),
|
||||
* PolygonM ( 28 ),
|
||||
* </pre>
|
||||
*
|
||||
* @author jrulka
|
||||
*
|
||||
*/
|
||||
public class ShpPolygon extends ShpPolyShape {
|
||||
|
||||
public ShpPolygon(Type shape_type) {
|
||||
super(shape_type);
|
||||
}
|
||||
}
|
||||
200
src/main/java/pl/wat/ms4ds/terrain/osmshp/ShpShape.java
Normal file
200
src/main/java/pl/wat/ms4ds/terrain/osmshp/ShpShape.java
Normal file
@@ -0,0 +1,200 @@
|
||||
package pl.wat.ms4ds.terrain.osmshp;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* Klasa bazowa reprezentująca kształt w formacie SHP wraz z dodatkową informacją opisową.
|
||||
* Mozliwe typy kształtów zawiera klasa enumeratora {@link Type}
|
||||
*
|
||||
* @author jrulka
|
||||
*
|
||||
*/
|
||||
public abstract class ShpShape {
|
||||
protected Type type;
|
||||
|
||||
//RECORD HEADER
|
||||
protected int recordNumber;
|
||||
protected int contentLength;
|
||||
protected int shapeTypeCode;
|
||||
|
||||
DbfRecord info;
|
||||
|
||||
protected ShpShape(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* read the shape-data from the bytebuffer (buffer-position has to be defined before).<br>
|
||||
*
|
||||
*/
|
||||
public void read(BufferedInputStream bis) throws Exception {
|
||||
byte[] data = new byte[8];
|
||||
if (bis.read(data) != 8) {
|
||||
throw new Exception("Invalid shp file");
|
||||
}
|
||||
ByteBuffer bb = ByteBuffer.wrap(data);
|
||||
// 1) READ RECORD HEADER
|
||||
readHeader(bb);
|
||||
// Content length in words (16 bits)
|
||||
byte[] dataContent = new byte[contentLength * 2];
|
||||
if (bis.read(dataContent) != contentLength * 2) {
|
||||
throw new Exception("Invalid shp file");
|
||||
}
|
||||
bb = ByteBuffer.wrap(dataContent);
|
||||
// 2) READ RECORD CONTENT
|
||||
// 2.1) check Shape Type
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
shapeTypeCode = bb.getInt();
|
||||
try {
|
||||
Type shape_type = Type.getByCode(shapeTypeCode);
|
||||
if (shape_type == type) {
|
||||
readContent(bb);
|
||||
} else if (shape_type != type) {
|
||||
throw new Exception("(Shape) shape_type = " + shape_type + ", but expected " + type);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
protected void readHeader(ByteBuffer bb) {
|
||||
bb.order(ByteOrder.BIG_ENDIAN);
|
||||
recordNumber = bb.getInt();
|
||||
contentLength = bb.getInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads geometric data from buffer.
|
||||
* @param bb
|
||||
*/
|
||||
protected abstract void readContent(ByteBuffer bb);
|
||||
|
||||
void setInfo(DbfRecord info) {
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the record number of the shape.
|
||||
*
|
||||
* @return record number
|
||||
*/
|
||||
public int getRecordNumber() {
|
||||
return recordNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of the shape.
|
||||
*
|
||||
* @return {@link Type}
|
||||
*/
|
||||
public Type getShapeType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shape types.
|
||||
*/
|
||||
public enum Type {
|
||||
/**
|
||||
* ID= 0
|
||||
*/
|
||||
NullShape(0, false, false),
|
||||
/**
|
||||
* ID= 1
|
||||
*/
|
||||
Point(1, false, false),
|
||||
/**
|
||||
* ID=11
|
||||
*/
|
||||
PointZ(11, true, true),
|
||||
/**
|
||||
* ID=21
|
||||
*/
|
||||
PointM(21, false, true),
|
||||
/**
|
||||
* ID= 3
|
||||
*/
|
||||
PolyLine(3, false, false),
|
||||
/**
|
||||
* ID=13
|
||||
*/
|
||||
PolyLineZ(13, true, true),
|
||||
/**
|
||||
* ID=23
|
||||
*/
|
||||
PolyLineM(23, false, true),
|
||||
/**
|
||||
* ID= 5
|
||||
*/
|
||||
Polygon(5, false, false),
|
||||
/**
|
||||
* ID=15
|
||||
*/
|
||||
PolygonZ(15, true, true),
|
||||
/**
|
||||
* ID=25
|
||||
*/
|
||||
PolygonM(25, false, true),
|
||||
/**
|
||||
* ID= 8
|
||||
*/
|
||||
MultiPoint(8, false, false),
|
||||
/**
|
||||
* ID=18
|
||||
*/
|
||||
MultiPointZ(18, true, true),
|
||||
/**
|
||||
* ID=28
|
||||
*/
|
||||
MultiPointM(28, false, true),
|
||||
/**
|
||||
* ID=31
|
||||
*/
|
||||
MultiPatch(31, true, true);
|
||||
|
||||
|
||||
public final int code;
|
||||
boolean hasZ;
|
||||
boolean hasM;
|
||||
|
||||
Type(int code, boolean hasZ, boolean hasM) {
|
||||
this.hasZ = hasZ;
|
||||
this.hasM = hasM;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public static Type getByCode(int code) throws Exception {
|
||||
for (Type st : Type.values())
|
||||
if (st.code == code)
|
||||
return st;
|
||||
throw new Exception("ShapeType: " + code + " does not exist");
|
||||
}
|
||||
|
||||
public boolean hasZ() {
|
||||
return hasZ;
|
||||
}
|
||||
|
||||
public boolean hasM() {
|
||||
return hasM;
|
||||
}
|
||||
|
||||
public boolean isTypeOfPolygon() {
|
||||
return (this == Type.Polygon | this == Type.PolygonM | this == Type.PolygonZ);
|
||||
}
|
||||
|
||||
public boolean isTypeOfPolyLine() {
|
||||
return (this == Type.PolyLine | this == Type.PolyLineM | this == Type.PolyLineZ);
|
||||
}
|
||||
|
||||
public boolean isTypeOfPoint() {
|
||||
return (this == Type.Point | this == Type.PointM | this == Type.PointZ);
|
||||
}
|
||||
|
||||
public boolean isTypeOfMultiPoint() {
|
||||
return (this == Type.MultiPoint | this == Type.MultiPointM | this == Type.MultiPointZ);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
68
teren.properties
Normal file
68
teren.properties
Normal file
@@ -0,0 +1,68 @@
|
||||
#Polska
|
||||
#Wspolrzedne referencyjne i wielkosc obszaru
|
||||
x_ref=14
|
||||
y_ref=49
|
||||
dx_ref=11
|
||||
dy_ref=7
|
||||
#kwadraty_dir=D:/work/terrain/
|
||||
kwadraty_dir=D:/work/kwadraty_nmt/temp/
|
||||
#kwadraty_dir=C:/Workspace/_data/swdt/ms4ds/teren/kwadraty/
|
||||
drogi_dir=au2data/new_teren/Polska/drogi/
|
||||
#
|
||||
#Rozdzielczosc terenu dl_mk=200 | 100 | 50 | 25 | 20
|
||||
dl_mk=100
|
||||
#
|
||||
#W celu wymuszenia (mimo jej braku) przejezdności terenu nalezy ustawić na: on
|
||||
przejezdnosc_zawsze=off
|
||||
minimalny_stopien_przejezdnosci=0.1
|
||||
#
|
||||
#Minimalny stopień przejezdności dla ruchu na przełaj dla kwadratów przejezdnych
|
||||
#dla algorytmów wyznaczania dróg dla działań typu: atak, obrona, rozmieszczenie, ...
|
||||
stopien_przejezdnosci.minimalny_na_przelaj=0.7
|
||||
#Minimalny stopień przejezdności dla ruchu po drodze z uwzględnieniem nachylenia terenu
|
||||
stopien_przejezdnosci.minimalny.na_drodze.nachylenie_terenu=0.9
|
||||
#Minimalny stopień przejezdności dla ruchu na przełaj z uwzględnieniem nachylenia terenu
|
||||
#Dla kątów <-alfa_max, alfa_min> stopień przejezdności == 1
|
||||
#Dla kątów <alfa_min, alfa_max> stopień przejezdności == liniowo (względem tangensa kąta) maleje od 1 do tej wartości
|
||||
#w p.p. stopień przejezdności == 0
|
||||
stopien_przejezdnosci.minimalny.na_przelaj.nachylenie_terenu=0.1
|
||||
#Minimalny kąt nachylenia terenu wpływający na stopień przejezdności (alfa_min) dla ruchu na drodze [stopnie]
|
||||
stopien_przejezdnosci.na_drodze.nachylenie_terenu.kat_minimalny=15
|
||||
#Maksymalny kąt nachylenia terenu wpływający na stopień przejezdności (alfa_max) dla ruchu na drodze [stopnie]
|
||||
stopien_przejezdnosci.na_drodze.nachylenie_terenu.kat_maksymalny=50
|
||||
#Minimalny kąt nachylenia terenu wpływający na stopień przejezdności (alfa_min) dla ruchu na przełaj [stopnie]
|
||||
stopien_przejezdnosci.na_przelaj.nachylenie_terenu.kat_minimalny=15
|
||||
#Maksymalny kąt nachylenia terenu wpływający na stopień przejezdności (alfa_min) dla ruchu na przełaj [stopnie]
|
||||
stopien_przejezdnosci.na_przelaj.nachylenie_terenu.kat_maksymalny=45
|
||||
#
|
||||
#stopień przejezdności - parametr dla symulacji ruchu
|
||||
stopien_przejezdnosci.podwozie_gasienicowe.teren_zabudowany=0.8
|
||||
stopien_przejezdnosci.podwozie_gasienicowe.teren_zalesiony=0.25
|
||||
stopien_przejezdnosci.podwozie_gasienicowe.teren_zabagniony=0.2
|
||||
stopien_przejezdnosci.podwozie_gasienicowe.teren_zawodniony=0.0
|
||||
stopien_przejezdnosci.podwozie_gasienicowe.teren_czysty=1.0
|
||||
#
|
||||
stopien_przejezdnosci.podwozie_kolowo_gasienicowe.teren_zabudowany=0.7
|
||||
stopien_przejezdnosci.podwozie_kolowo_gasienicowe.teren_zalesiony=0.15
|
||||
stopien_przejezdnosci.podwozie_kolowo_gasienicowe.teren_zabagniony=0.1
|
||||
stopien_przejezdnosci.podwozie_kolowo_gasienicowe.teren_zawodniony=0.0
|
||||
stopien_przejezdnosci.podwozie_kolowo_gasienicowe.teren_czysty=0.9
|
||||
#
|
||||
stopien_przejezdnosci.podwozie_kolowe.teren_zabudowany=0.6
|
||||
stopien_przejezdnosci.podwozie_kolowe.teren_zalesiony=0.1
|
||||
stopien_przejezdnosci.podwozie_kolowe.teren_zabagniony=0.05
|
||||
stopien_przejezdnosci.podwozie_kolowe.teren_zawodniony=0.0
|
||||
stopien_przejezdnosci.podwozie_kolowe.teren_czysty=0.8
|
||||
#
|
||||
stopien_przejezdnosci.podwozie_poduszka.teren_zabudowany=0.7
|
||||
stopien_przejezdnosci.podwozie_poduszka.teren_zalesiony=0.1
|
||||
stopien_przejezdnosci.podwozie_poduszka.teren_zabagniony=0.9
|
||||
stopien_przejezdnosci.podwozie_poduszka.teren_zawodniony=1.0
|
||||
stopien_przejezdnosci.podwozie_poduszka.teren_czysty=1.0
|
||||
#
|
||||
stopien_przejezdnosci.podwozie_plozy.teren_zabudowany=0.1
|
||||
stopien_przejezdnosci.podwozie_plozy.teren_zalesiony=0.1
|
||||
stopien_przejezdnosci.podwozie_plozy.teren_zabagniony=0.1
|
||||
stopien_przejezdnosci.podwozie_plozy.teren_zawodniony=0.0
|
||||
stopien_przejezdnosci.podwozie_plozy.teren_czysty=1.0
|
||||
|
||||
Reference in New Issue
Block a user