kwadraty = kwadratyLamanej(rejon);
+// System.out.println(kwadraty);
+
+
+// try {
+// BufferedWriter wyj = new BufferedWriter(new FileWriter("A.txt"));
+ // if (args.length == 5 ) {
+ // int xp = Integer.parseInt(args[1]);
+ // int yp = Integer.parseInt(args[2]);
+ // int xk = Integer.parseInt(args[3]);
+ // int yk = Integer.parseInt(args[4]);
+
+ /*
+ * int xp = 50000; int yp = 8000; int xk = 20; int yk = 1;
+ */
+// GridCoord[] rejon = new GridCoord[4];
+// rejon[0] = new GridCoord();
+// rejon[0].x = 20;
+// rejon[0].y = 18;
+// rejon[1] = new GridCoord();
+// rejon[1].x = 27;
+// rejon[1].y = 9;
+// rejon[2] = new GridCoord();
+// rejon[2].x = 9;
+// rejon[2].y = 1;
+// rejon[3] = new GridCoord();
+// rejon[3].x = 2;
+// rejon[3].y = 15;
+// GridCoord[] kwadraty = kwadratyObszaru(rejon);
+
+ /*
+ * WspXY[] kwadraty = kwadratyOdcinka(xp, yp, xk, yk);
+ * wyj.write("pocz: ("); wyj.write(Integer.toString(xp));
+ * wyj.write(", "); wyj.write(Integer.toString(yp)); wyj.write(")");
+ * wyj.newLine(); wyj.write("kon: (");
+ * wyj.write(Integer.toString(xk)); wyj.write(", ");
+ * wyj.write(Integer.toString(yk)); wyj.write(")"); wyj.newLine();
+ */
+// wyj.write(Integer.toString(kwadraty.length));
+// wyj.newLine();
+// for (int i = 0; i < kwadraty.length; i++) {
+// wyj.write("(");
+// wyj.write(Integer.toString(kwadraty[i].x));
+// wyj.write(", ");
+// wyj.write(Integer.toString(kwadraty[i].y));
+// wyj.write(")");
+// wyj.newLine();
+// }
+//
+// wyj.close();
+// } catch (IOException e) {
+// e.printStackTrace();
+// }
+ }
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/GridCoord.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/GridCoord.java
new file mode 100644
index 0000000..6268c0e
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/GridCoord.java
@@ -0,0 +1,689 @@
+package pl.wat.ms4ds.terenfunkcje;
+
+//import pl.wat.wcy.exception.IdKwadratuException;
+
+
+import pl.wat.ms4ds.common.EGeoDirection;
+
+public class GridCoord {
+
+ public int x;
+ public int y;
+
+ /**
+ * Konstruktor klasy na bazie współrzędnych geograficznych.
+ *
+ * @param lon długość geograficzna
+ * @param lat szerokość geograficzna
+ */
+ public GridCoord(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);
+ }
+
+ /**
+ * 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 < 0) || (xms >= 360 * MapConsts.DEG_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) * ODWROT_SS_DX_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) || (yms > MapConsts.Y_REF_MS + MapConsts.DY_REF_MS)) {
+// // poza zakresem
+// return -1;
+// }
+ 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) * ODWROT_SS_DY_MS;
+// long y = (yms - MapConsts.Y_REF_MS) / MapConsts.SS_DY_MS;
+ return (int) yy;
+ }
+
+ /**
+ * Zamienia długość geograficzną na współrzędna x GridCoord.
+ *
+ * @param lon długość geograficzna
+ * @return współrzędna x klasy GridCoord
+ */
+ public static int zamienDlugoscGeoNaIdKwadratuX(double lon) {
+ double xms_f = (lon + 180) * MapConsts.DEG_MS;
+ return zamienWspXmsNaIdKwadratuX((long) xms_f);
+ }
+
+ /**
+ * Zamienia szerokość geograficzną na współrzędna y GridCoord.
+ *
+ * @param lat szerokość geograficzna
+ * @return współrzędna y klasy GridCoord
+ */
+ public static int zamienSzerokoscGeoNaIdKwadratuY(double lat) {
+ double yms_f = (lat + 90) * MapConsts.DEG_MS;
+ return zamienWspYmsNaIdKwadratuY((long) yms_f);
+ }
+
+ public GridCoord kwadratSasiedni(EGeoDirection kier) {
+ GridCoord idKwSasiedni = new GridCoord();
+ switch (kier) {
+ case NORTH:
+ idKwSasiedni.x = x;
+ idKwSasiedni.y = y + 1;
+ break;
+ case NORTHEAST:
+ idKwSasiedni.x = x + 1;
+ idKwSasiedni.y = y + 1;
+ break;
+ case EAST:
+ idKwSasiedni.x = x + 1;
+ idKwSasiedni.y = y;
+ break;
+ case SOUTHEAST:
+ idKwSasiedni.x = x + 1;
+ idKwSasiedni.y = y - 1;
+ break;
+ case SOUTH:
+ idKwSasiedni.x = x;
+ idKwSasiedni.y = y - 1;
+ break;
+ case SOUTHWEST:
+ idKwSasiedni.x = x - 1;
+ idKwSasiedni.y = y - 1;
+ break;
+ case WEST:
+ idKwSasiedni.x = x - 1;
+ idKwSasiedni.y = y;
+ break;
+ case NORTHWEST:
+ idKwSasiedni.x = x - 1;
+ idKwSasiedni.y = y + 1;
+ break;
+ default:
+ }
+ return idKwSasiedni;
+ }
+
+ public void kwadratSasiedni(GridCoord idKwSasiedni, EGeoDirection kier) {
+ switch (kier) {
+ case NORTH:
+ idKwSasiedni.x = x;
+ idKwSasiedni.y = y + 1;
+ break;
+ case NORTHEAST:
+ idKwSasiedni.x = x + 1;
+ idKwSasiedni.y = y + 1;
+ break;
+ case EAST:
+ idKwSasiedni.x = x + 1;
+ idKwSasiedni.y = y;
+ break;
+ case SOUTHEAST:
+ idKwSasiedni.x = x + 1;
+ idKwSasiedni.y = y - 1;
+ break;
+ case SOUTH:
+ idKwSasiedni.x = x;
+ idKwSasiedni.y = y - 1;
+ break;
+ case SOUTHWEST:
+ idKwSasiedni.x = x - 1;
+ idKwSasiedni.y = y - 1;
+ break;
+ case WEST:
+ idKwSasiedni.x = x - 1;
+ idKwSasiedni.y = y;
+ break;
+ case NORTHWEST:
+ idKwSasiedni.x = x - 1;
+ idKwSasiedni.y = y + 1;
+ break;
+ default:
+ }
+ }
+
+ public GridCoord[] dajSasiadow() {
+ GridCoord[] sasiedzi = new GridCoord[8];
+ sasiedzi[0] = new GridCoord(x, y + 1);
+ sasiedzi[1] = new GridCoord(x + 1, y + 1);
+ sasiedzi[2] = new GridCoord(x + 1, y);
+ sasiedzi[3] = new GridCoord(x + 1, y - 1);
+ sasiedzi[4] = new GridCoord(x, y - 1);
+ sasiedzi[5] = new GridCoord(x - 1, y - 1);
+ sasiedzi[6] = new GridCoord(x - 1, y);
+ sasiedzi[7] = new GridCoord(x - 1, y + 1);
+ return sasiedzi;
+ }
+
+ public static GridCoord[] dajSasiadow(int x, int y) {
+ GridCoord[] sasiedzi = new GridCoord[8];
+ sasiedzi[0] = new GridCoord(x, y + 1);
+ sasiedzi[1] = new GridCoord(x + 1, y + 1);
+ sasiedzi[2] = new GridCoord(x + 1, y);
+ sasiedzi[3] = new GridCoord(x + 1, y - 1);
+ sasiedzi[4] = new GridCoord(x, y - 1);
+ sasiedzi[5] = new GridCoord(x - 1, y - 1);
+ sasiedzi[6] = new GridCoord(x - 1, y);
+ sasiedzi[7] = new GridCoord(x - 1, y + 1);
+ return sasiedzi;
+ }
+
+ public static GridCoord[] dajSasiadow(GridCoord centralny) {
+ GridCoord[] sasiedzi = new GridCoord[8];
+ sasiedzi[0] = new GridCoord(centralny.x, centralny.y + 1);
+ sasiedzi[1] = new GridCoord(centralny.x + 1, centralny.y + 1);
+ sasiedzi[2] = new GridCoord(centralny.x + 1, centralny.y);
+ sasiedzi[3] = new GridCoord(centralny.x + 1, centralny.y - 1);
+ sasiedzi[4] = new GridCoord(centralny.x, centralny.y - 1);
+ sasiedzi[5] = new GridCoord(centralny.x - 1, centralny.y - 1);
+ sasiedzi[6] = new GridCoord(centralny.x - 1, centralny.y);
+ sasiedzi[7] = new GridCoord(centralny.x - 1, centralny.y + 1);
+ return sasiedzi;
+ }
+
+ public GridCoord[] dajOtoczenie() {
+ GridCoord[] sasiedzi = new GridCoord[9];
+ sasiedzi[0] = new GridCoord(x, y);
+ sasiedzi[1] = new GridCoord(x, y + 1);
+ sasiedzi[2] = new GridCoord(x + 1, y + 1);
+ sasiedzi[3] = new GridCoord(x + 1, y);
+ sasiedzi[4] = new GridCoord(x + 1, y - 1);
+ sasiedzi[5] = new GridCoord(x, y - 1);
+ sasiedzi[6] = new GridCoord(x - 1, y - 1);
+ sasiedzi[7] = new GridCoord(x - 1, y);
+ sasiedzi[8] = new GridCoord(x - 1, y + 1);
+ return sasiedzi;
+ }
+
+ public static GridCoord[] dajOtoczenie(int x, int y) {
+ GridCoord[] sasiedzi = new GridCoord[9];
+ sasiedzi[0] = new GridCoord(x, y);
+ sasiedzi[1] = new GridCoord(x, y + 1);
+ sasiedzi[2] = new GridCoord(x + 1, y + 1);
+ sasiedzi[3] = new GridCoord(x + 1, y);
+ sasiedzi[4] = new GridCoord(x + 1, y - 1);
+ sasiedzi[5] = new GridCoord(x, y - 1);
+ sasiedzi[6] = new GridCoord(x - 1, y - 1);
+ sasiedzi[7] = new GridCoord(x - 1, y);
+ sasiedzi[8] = new GridCoord(x - 1, y + 1);
+ return sasiedzi;
+ }
+
+ public static GridCoord[] dajOtoczenie(GridCoord centralny) {
+ GridCoord[] sasiedzi = new GridCoord[8];
+ sasiedzi[0] = new GridCoord(centralny.x, centralny.y);
+ sasiedzi[1] = new GridCoord(centralny.x, centralny.y + 1);
+ sasiedzi[2] = new GridCoord(centralny.x + 1, centralny.y + 1);
+ sasiedzi[3] = new GridCoord(centralny.x + 1, centralny.y);
+ sasiedzi[4] = new GridCoord(centralny.x + 1, centralny.y - 1);
+ sasiedzi[5] = new GridCoord(centralny.x, centralny.y - 1);
+ sasiedzi[6] = new GridCoord(centralny.x - 1, centralny.y - 1);
+ sasiedzi[7] = new GridCoord(centralny.x - 1, centralny.y);
+ sasiedzi[8] = new GridCoord(centralny.x - 1, centralny.y + 1);
+ return sasiedzi;
+ }
+
+ public boolean rowne(int x, int y) {
+ return this.x == x && this.y == y;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder("(x= ");
+ sb.append(x);
+ sb.append(", y= ");
+ sb.append(y);
+ sb.append(')');
+// String s = "(x= " + Integer.toString(x) + ", y= " + Integer.toString(y) + ")";
+ return sb.toString();
+ }
+
+ /**
+ * 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 zamienIdKwadratuXNaDlugoscGeo(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 zamienIdKwadratuYNaSzerokoscGeo(int idY) {
+ long yms = zamienIdKwadratuYNaWspYms(idY);
+ double lat = (double) yms / (double) MapConsts.DEG_MS - 90;
+ return (float) lat;
+ }
+
+ /**
+ * Zamienia współrzęną GridCoord.x na długość geograficzną lewego dolnego rogu małego kwadratu
+ *
+ * @param idX współrzęna x GridCoord
+ * @return długość geograficzna
+ */
+ public static float zamienIdKwadratuXNaDlugoscGeoLD(int idX) {
+ long xms = zamienIdKwadratuXNaWspXmsLD(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 zamienIdKwadratuYNaSzerokoscGeoLD(int idY) {
+ long yms = zamienIdKwadratuYNaWspYmsLD(idY);
+ double lat = (double) yms / (double) MapConsts.DEG_MS - 90;
+ return (float) lat;
+ }
+
+ public static int zamienWspUtmNaIdkwadratuX(String wspolrzedneUtm) {
+ // //////////////////////////////////
+ // wspolrzedne - znaki w formacie 522644N0154232E
+ // wyznaczenie numeru kwadraty Au2 dla wspolrzednej X
+ // np.: '153200' to 304
+
+ int xms = Teren.zamienWspUtmNaWspXms(wspolrzedneUtm);
+ int idKwX = GridCoord.zamienWspXmsNaIdKwadratuX(xms);
+ return idKwX;
+ }
+
+ public static int zamienWspUtmNaIdkwadratuY(String wspolrzedneUtm) {
+ // //////////////////////////////////
+ // wspolrzedne - znaki w formacie 522644N0154232E
+ // wyznaczenie numeru kwadraty Au2 dla wspolrzednej Y
+ // np.: '153200' to 304
+ int yms = Teren.zamienWspUtmNaWspYms(wspolrzedneUtm);
+ int idKwY = GridCoord.zamienWspYmsNaIdKwadratuY(yms);
+ return idKwY;
+ }
+
+ public GridCoord(String wspolrzedne) {
+ this.x = zamienWspUtmNaIdkwadratuX(wspolrzedne);
+ this.y = zamienWspUtmNaIdkwadratuY(wspolrzedne);
+ }
+
+ public static GridCoord zamienWspUtmNaIdKwadratu(String wspolrzedne) {
+ // Utworzenie obiektu GridCoord ze wspolrzednych UTM
+ GridCoord kwadrat = new GridCoord(wspolrzedne);
+ return kwadrat;
+ }
+
+ public static String zamienIdKwadratuNaWspUtm(GridCoord kwadrat) {
+ long xms = zamienIdKwadratuXNaWspXms(kwadrat.x);
+ long yms = zamienIdKwadratuYNaWspYms(kwadrat.y);
+ return Teren.zamienWspXmsYmsNaWspUtm(xms, yms);
+ }
+
+ /**
+ * 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_DX_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_DY_MS);
+ return yms;
+ }
+
+ /**
+ * Funkcja zamienia wsp. X GridCoord na wsp. geo xms w milisekundach lewego dolnego rogu malego kwadratu.
+ * Zwracana wspolrzedna lezy w srodku kwadratu.
+ */
+ public static long zamienIdKwadratuXNaWspXmsLD(int idKwX) {
+ // indeksowanie kwadratow pola walki zaczyna sie od (0, 0)
+ // przesuniecie wspolrzednych do srodka kwadratu
+ long xms = MapConsts.X_REF_MS + (long) (idKwX * MapConsts.SS_DX_MS);
+ xms %= MapConsts.ANGLE_360_MS;
+ return xms;
+ }
+
+ /**
+ * Funkcja zamienia wsp. Y GridCoord na wsp. geo yms w milisekundach lewego dolnego rogu malego kwadratu.
+ * Zwracana wspolrzedna lezy w srodku kwadratu.
+ */
+ public static long zamienIdKwadratuYNaWspYmsLD(int idKwY) {
+ // indeksowanie kwadratow pola walki zaczyna sie od (0, 0)
+ // przesuniecie wspolrzednych do srodka kwadratu
+ long yms = MapConsts.Y_REF_MS + (long) (idKwY * MapConsts.SS_DY_MS);
+ return yms;
+ }
+
+ private static final double ODWROT_SS_DX_MS = 1.0 / MapConsts.SS_DX_MS;
+ private static final double ODWROT_SS_DY_MS = 1.0 / MapConsts.SS_DY_MS;
+
+ /**
+ * Funkcja sprawdza, czy kwadraty sa takie same.
+ *
+ * @param id1
+ * @param id2
+ * @return
+ */
+ public static boolean czyIdentyczne(GridCoord id1, GridCoord id2) {
+ if (null == id1 || null == id2) {
+ return false;
+ }
+ if (id1.x != id2.x || id1.y != id2.y) {
+ return false;
+ } else
+ return true;
+ }
+
+ /**
+ * Funkcja zwraca odleglosc miedzy srodkami malych kwadratow [m].
+ *
+ * @param p1 współrzędna malego kwadratu pocz.
+ * @param p2 współrzędna malego kwadratu konc.
+ * @return Odległość między środkami małych kwadratów [m].
+ */
+ public static float odleglosc(GridCoord p1, GridCoord p2) {
+ // odleglosc miedzy srodkami malych kwadratow
+ if (null == p1 || null == p2) {
+ return -1.0f;
+ }
+ int xx = p1.x - p2.x;
+ xx *= xx;
+ int yy = p1.y - p2.y;
+ yy *= yy;
+ float odl = (float) Math.sqrt(xx + yy);
+ odl *= MapConsts.DL_MK;
+ return odl;
+ }
+
+ /**
+ * Funkcja zwraca 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 odleglosc(int x1, int y1, int x2, int y2) {
+ // odleglosc miedzy srodkami malych kwadratow
+ int xx = x1 - x2;
+ xx *= xx;
+ int yy = y1 - y2;
+ yy *= yy;
+ float odl = (float) Math.sqrt(xx + yy);
+ odl *= MapConsts.DL_MK;
+ return odl;
+ }
+
+ /**
+ * Funkcja zwraca odległość między środkami małych kwadratów [m].
+ *
+ * @param dx odległość w kwadratach na osi OX.
+ * @param dy odległość w kwadratach na osi OY.
+ * @return Odległość miedzy srodkami malych kwadratow [m].
+ */
+ public static float odleglosc(int dx, int dy) {
+ float odl = (float) Math.sqrt(dx * dx + dy * dy);
+ odl *= MapConsts.DL_MK;
+ return odl;
+ }
+
+ private static final float DL_MK2 = MapConsts.DL_MK * 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 odlegloscApprox(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 static int iloczynSkalarny(GridCoord p1, GridCoord p2) {
+ int wynik;
+ wynik = p1.x * p2.x + p1.y * p2.y;
+ return wynik;
+ }
+
+ // funkcja sprawdza, czy dwa obszary skierowane maja czesc wspolna
+ public static boolean majaCzescWspolna(GridCoord[] rejon1, GridCoord[] rejon2) {
+ if ((rejon1 == null) || (rejon2 == null)) {
+ return false;
+ }
+ for (int i = 0; i < rejon2.length; i++) {
+ if (GeomUtils.insidePolygon(rejon1, rejon2[i].x, rejon2[i].y)) {
+ return true;
+ }
+ }
+ for (int i = 0; i < rejon1.length; i++) {
+ if (GeomUtils.insidePolygon(rejon2, rejon1[i].x, rejon1[i].y)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // wyznacza stosunek czesci wspolnej obszarow do obszaru bazowego
+ public static float stosunekCzesciWspolnej(GridCoord[] rejon_bazowy, GridCoord[] rejon2) {
+ if ((rejon_bazowy == null) || (rejon2 == null)) {
+ return 0.0f;
+ }
+ boolean majaCzescWspolna = majaCzescWspolna(rejon_bazowy, rejon2);
+ if (!majaCzescWspolna) {
+ return 0.0f;
+ }
+ GridCoord[] kwadraty1 = GeomUtils.kwadratyObszaru(rejon_bazowy);
+ GridCoord[] kwadraty2 = GeomUtils.kwadratyObszaru(rejon2);
+ int maxWspolnych = 0;
+ if (kwadraty1.length <= kwadraty2.length) {
+ maxWspolnych = kwadraty1.length;
+ } else {
+ maxWspolnych = kwadraty2.length;
+ }
+ if ((kwadraty1 == null) || (kwadraty2 == null)) {
+ return 0.0f;
+ }
+ int wspolnych = 0;
+ for (int i = 0; i < kwadraty1.length; i++) {
+ for (int j = 0; j < kwadraty2.length; j++) {
+ if (czyIdentyczne(kwadraty1[i], kwadraty2[j])) {
+ wspolnych++;
+ }
+ }
+ }
+ return ((float) wspolnych) / ((float) (maxWspolnych));
+ }
+
+ // wyznacza wspolrzedne lewego dolnego wierzcholka oraz
+ // prawego gornego wierzcholka prostokata opisanego na obszarze: rejon
+ public static void minMaxIdKwadratu(GridCoord[] rejon, GridCoord min, GridCoord max) {
+ if (rejon == null) {
+ return;
+ }
+ if (min == null) {
+ min = new GridCoord(rejon[0].x, rejon[0].y);
+ }
+ if (max == null) {
+ max = new GridCoord(rejon[0].x, rejon[0].y);
+ }
+ for (int i = 1; i < rejon.length; i++) {
+ if (min.x > rejon[i].x) {
+ min.x = rejon[i].x;
+ }
+ if (min.y > rejon[i].y) {
+ min.y = rejon[i].y;
+ }
+ if (max.x < rejon[i].x) {
+ max.x = rejon[i].x;
+ }
+ if (max.y < rejon[i].y) {
+ max.y = rejon[i].y;
+ }
+ }
+ }
+
+ public void update(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);
+ }
+
+ public GridCoord() {
+ x = -1;
+ y = -1;
+ }
+
+ public GridCoord(int x, int y) {
+/* try {
+ if (x < 0 || y < 0)
+ throw new IdKwadratuException();
+ }
+ catch (IdKwadratuException e) {
+ System.out.print(e.opis);
+ }
+*/
+ this.x = x;
+ this.y = y;
+ }
+
+ public GridCoord(GridCoord oryginal) {
+ this.x = oryginal.x;
+ this.y = oryginal.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(GridCoord oryginal) {
+ x = oryginal.x;
+ y = oryginal.y;
+ }
+
+ public void set(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ @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 GridCoord)) {
+ return false;
+ }
+ GridCoord other = (GridCoord) obj;
+ if (x != other.x) {
+ return false;
+ }
+ if (y != other.y) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/Kwadrat.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/Kwadrat.java
new file mode 100644
index 0000000..55bbfb9
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/Kwadrat.java
@@ -0,0 +1,358 @@
+package pl.wat.ms4ds.terenfunkcje;
+
+
+import pl.wat.ms4ds.common.EGeoDirection;
+
+public class Kwadrat {
+
+ public static final Kwadrat EMPTY_SQUARE = new Kwadrat(null, 0.0f, 0.0f, 0.0f, 0.0f, 200, 0,
+ new boolean[8], new boolean[8], new boolean[8]);
+
+ float stopienZabudowy;
+ float stopienZalesienia;
+ float stopienZawodnienia;
+ float stopienZabagnienia;
+ boolean jestDroga[];
+ boolean jestRow[];
+ boolean jestPrzeszkodaWodna[];
+ int roznicaWzniesien;
+ int wysokoscSrednia;
+
+ /**
+ * The height above the level of the sea.
+ */
+ short elevation;
+ /**
+ * 0 - BARE_GROUND
+ * 1 - GRASS
+ * 2 - SWAMP
+ * 3 - WATER
+ * 4 - SCRUB, BUSHES
+ * 5 - BUILDINGS
+ * 6 - FOREST
+ */
+ short terrainType;
+ /**
+ * Rodzaj drogi na danym kierunku.
+ * 0 - no road, 1 - small roads, 2 - minor roads, 3 - major roads
+ */
+ byte[] roads;
+ /**
+ * Rodzaj przeszkody wodnej na danym kierunku.
+ * 0 - no watercourse, 1 - drain, ditch, 2 - canal, stream, 3 - river
+ */
+ byte[] waterWays;
+
+
+
+ transient RightBigSquare bs;
+
+ public float getStopienZabudowy() {
+ return stopienZabudowy;
+ }
+
+ public float getStopienZalesienia() {
+ return stopienZalesienia;
+ }
+
+ public float getStopienZawodnienia() {
+ return stopienZawodnienia;
+ }
+
+ public float getStopienZabagnienia() {
+ return stopienZabagnienia;
+ }
+
+ public int getRoznicaWzniesien() {
+ return roznicaWzniesien;
+ }
+
+ public int getWysokoscSrednia() {
+ return wysokoscSrednia;
+ }
+
+ public boolean[] getJestDroga() {
+ return jestDroga;
+ }
+
+ public boolean jestOdcinekDrogi() {
+ for (int i = 0; i < 8; i++) {
+ if (jestDroga[i])
+ return true;
+ }
+ return false;
+ }
+
+ public boolean getJestDroga(EGeoDirection naKierunku) {
+ if (naKierunku == EGeoDirection.UNDEFINED) {
+ return false;
+ }
+ return jestDroga[naKierunku.id];
+ }
+
+ public boolean[] getJestRow() {
+ return jestRow;
+ }
+
+ public boolean[] getJestPrzeszkodaWodna() {
+ return jestPrzeszkodaWodna;
+ }
+
+ public void setStopienZabudowy(float stopienZabudowy) {
+ this.stopienZabudowy = stopienZabudowy;
+ normalizujDanePokrycia();
+// try {
+// if (null != bs) {
+// bs.updateFile(false);
+// }
+// } catch (IOException e) {
+// }
+ }
+
+ public void setStopienZalesienia(float stopienZalesienia) {
+ this.stopienZalesienia = stopienZalesienia;
+ normalizujDanePokrycia();
+// try {
+// if (null != bs) {
+// bs.updateFile(false);
+// }
+// } catch (IOException e) {
+// }
+ }
+
+ public void setStopienZawodnienia(float stopienZawodnienia) {
+ this.stopienZawodnienia = stopienZawodnienia;
+ normalizujDanePokrycia();
+// try {
+// if (null != bs) {
+// bs.updateFile(false);
+// }
+// } catch (IOException e) {
+// }
+ }
+
+ public void setStopienZabagnienia(float stopienZabagnienia) {
+ this.stopienZabagnienia = stopienZabagnienia;
+ normalizujDanePokrycia();
+// try {
+// if (null != bs) {
+// bs.updateFile(false);
+// }
+// } catch (IOException e) {
+// }
+ }
+
+ public void normalizujDanePokrycia() {
+ float suma = stopienZalesienia + stopienZawodnienia + stopienZabudowy + stopienZabagnienia;
+ if (suma > 1.0f) {
+ stopienZalesienia /= suma;
+ stopienZawodnienia /= suma;
+ stopienZabudowy /= suma;
+ stopienZabagnienia = 1.0f - stopienZalesienia - stopienZawodnienia - stopienZabudowy;
+ }
+ }
+
+ public void setRoznicaWzniesien(int roznicaWzniesien) {
+ this.roznicaWzniesien = roznicaWzniesien;
+// try {
+// if (null != bs) {
+// bs.updateFile(false);
+// }
+// } catch (IOException e) {
+// }
+ }
+
+ public void setWysokoscSrednia(int wysokoscSrednia) {
+ this.wysokoscSrednia = wysokoscSrednia;
+// try {
+// if (null != bs) {
+// bs.updateFile(false);
+// }
+// } catch (IOException e) {
+// }
+ }
+
+ public void setJestDroga(boolean[] czyJestDroga) {
+ this.jestDroga = czyJestDroga;
+// try {
+// if (null != bs) {
+// bs.updateFile(false);
+// }
+// } catch (IOException e) {
+// }
+ }
+
+ public void setJestDroga(EGeoDirection naKierunku, boolean czyJest) {
+ if (naKierunku == EGeoDirection.UNDEFINED) {
+ return;
+ }
+ this.jestDroga[naKierunku.id] = czyJest;
+// try {
+// if (null != bs) {
+// bs.updateFile(false);
+// }
+// } catch (IOException e) {
+// }
+ }
+
+ public void setJestPrzeszkodaWodna(EGeoDirection naKierunku, boolean czyJest) {
+ if (naKierunku == EGeoDirection.UNDEFINED) {
+ return;
+ }
+ this.jestPrzeszkodaWodna[naKierunku.id] = czyJest;
+// try {
+// if (null != bs) {
+// bs.updateFile(false);
+// }
+// } catch (IOException e) {
+// }
+ }
+
+ public void setJestRow(EGeoDirection naKierunku, boolean czyJest) {
+ if (naKierunku == EGeoDirection.UNDEFINED) {
+ return;
+ }
+ this.jestRow[naKierunku.id] = czyJest;
+// try {
+// if (null != bs) {
+// bs.updateFile(false);
+// }
+// } catch (IOException e) {
+// }
+ }
+
+ public void setJestRow(boolean[] czyJestRow) {
+ this.jestRow = czyJestRow;
+// try {
+// if (null != bs) {
+// bs.updateFile(false);
+// }
+// } catch (IOException e) {
+// }
+ }
+
+ public void setJestPrzeszkodaWodna(boolean[] czyJestPrzeszkodaWodna) {
+ this.jestPrzeszkodaWodna = czyJestPrzeszkodaWodna;
+// try {
+// if (null != bs) {
+// bs.updateFile(false);
+// }
+// } catch (IOException e) {
+// }
+ }
+
+ public float getStopienPofaldowania() {
+ // TODO: dodac do normatywow w klasie Teren (parametr kalibracyjny)
+ float stopienPofaldowania = 0.0f;
+ if (this.roznicaWzniesien >= 50)
+ stopienPofaldowania = 1.0f;
+ else if (this.roznicaWzniesien >= 10)
+ stopienPofaldowania = 0.6f;
+ else if (this.roznicaWzniesien >= 5)
+ stopienPofaldowania = 0.4f;
+ else if (this.roznicaWzniesien >= 3)
+ stopienPofaldowania = 0.2f;
+ return stopienPofaldowania;
+ }
+
+ public Kwadrat() {
+ jestDroga = new boolean[8];
+ jestPrzeszkodaWodna = new boolean[8];
+ jestRow = new boolean[8];
+ }
+
+ public Kwadrat(RightBigSquare _bs, float _stopienZabudowy, float _stopienZalesienia, float _stopienZabagnienia, float _stopienZawodnienia,
+ int _wysokoscSrednia, int _roznicaWzniesien, boolean _czyJestDroga[], boolean _czyJestRow[], boolean _czyJestPrzeszkodaWodna[]){
+ bs = _bs;
+ stopienZabudowy = _stopienZabudowy;
+ stopienZalesienia = _stopienZalesienia;
+ stopienZabagnienia = _stopienZabagnienia;
+ stopienZawodnienia = _stopienZawodnienia;
+ wysokoscSrednia = _wysokoscSrednia;
+ roznicaWzniesien = _roznicaWzniesien;
+ jestDroga = new boolean[8];
+ jestRow = new boolean[8];
+ jestPrzeszkodaWodna = new boolean[8];
+ for (int i = 0; i < _czyJestDroga.length; i++) {
+ jestDroga[i]=_czyJestDroga[i];
+ }
+ for (int i = 0; i < jestRow.length; i++) {
+ jestRow[i]=_czyJestRow[i];
+ }
+ for (int i = 0; i < _czyJestPrzeszkodaWodna.length; i++) {
+ jestPrzeszkodaWodna[i]=_czyJestPrzeszkodaWodna[i];
+ }
+ }
+
+ public String toString() {
+ float f = this.stopienZabudowy * 255.0f;
+ int hex = (int)f;
+ String s = String.format("%02X", hex);
+ String linia = s;
+ linia += " ";
+
+ f = this.stopienZalesienia * 255.0f;
+ hex = (int)f;
+ s = String.format("%02X", hex);
+ linia += s;
+ linia += " ";
+
+ f = this.stopienZabagnienia * 255.0f;
+ hex = (int)f;
+ s = String.format("%02X", hex);
+ linia += s;
+ linia += " ";
+
+ f = this.stopienZawodnienia * 255.0f;
+ hex = (int)f;
+ s = String.format("%02X", hex);
+ linia += s;
+ linia += " ";
+
+ s = String.format("%4d", this.wysokoscSrednia);
+ linia += s;
+ linia += " ";
+
+ s = String.format("%4d", this.roznicaWzniesien);
+ linia += s;
+ linia += " ";
+
+ int bity = 0;
+ int bit_1 = 1;
+ for (int i = 0; i < this.jestDroga.length; i++) {
+ if (this.jestDroga[i]) // jest odcinek drogi na tym kierunku
+ bity += bit_1;
+
+ bit_1 = bit_1 << 1;
+ }
+ s = String.format("%02X", bity);
+ linia += s;
+ linia += " ";
+
+ bity = 0;
+ bit_1 = 1;
+ for (int i = 0; i < this.jestPrzeszkodaWodna.length; i++) {
+ if (this.jestPrzeszkodaWodna[i]) // jest przeszkod na tym kierunku
+ bity += bit_1;
+
+ bit_1 = bit_1 << 1;
+ }
+ s = String.format("%02X", bity);
+ linia += s;
+ linia += " ";
+
+ bity = 0;
+ bit_1 = 1;
+ for (int i = 0; i < this.jestRow.length; i++) {
+ if (this.jestRow[i]) // jest row na tym kierunku
+ bity += bit_1;
+
+ bit_1 = bit_1 << 1;
+ }
+ s = String.format("%02X", bity);
+ linia += s;
+ return linia;
+ }
+
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/LukDrogowy.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/LukDrogowy.java
new file mode 100644
index 0000000..bf3d98d
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/LukDrogowy.java
@@ -0,0 +1,113 @@
+package pl.wat.ms4ds.terenfunkcje;
+
+import java.util.StringTokenizer;
+
+public class LukDrogowy {
+
+ private WezelDrogowy[] wezly = new WezelDrogowy[2];
+ int id = -1;
+ int dlugosc = 0;
+ int szerokosc = 0;
+ int rodzajNawierzchni = 0;
+ boolean jestMostem = false;
+
+ LukDrogowy() {}
+
+ LukDrogowy(String opis) {
+ if (null == opis || opis.length() == 0){
+ SiecDrogowa.logger.debug("Pusty ciag opis w konstruktorze Luku Drogowego.");
+ return;
+ }
+ StringTokenizer st = new StringTokenizer(opis, " \t");
+ String[] tokenTable = new String[st.countTokens()];
+ for (int i = 0; st.hasMoreTokens(); i++) {
+ tokenTable[i] = st.nextToken();
+ }
+ if (tokenTable.length == 6) {
+ try {
+ int id = Integer.parseInt(tokenTable[0]);
+ WezelDrogowy wezel = SiecDrogowa.instancja.wezly.get(id);
+ if (null == wezel)
+ SiecDrogowa.logger.warn("Brak wierzcholka (1) poczatkowego luku. [" + opis + "].");
+ this.getWezly()[0] = wezel;
+ wezel.luki.add(this);
+ } catch (NumberFormatException e) {
+ SiecDrogowa.logger.warn("Bledne dane w pliku z lukami [Wezel 1].");
+ }
+ try {
+ int id = Integer.parseInt(tokenTable[1]);
+ WezelDrogowy wezel = SiecDrogowa.instancja.wezly.get(id);
+ if (null == wezel)
+ SiecDrogowa.logger.warn("Brak wierzcholka (2) koncowego luku. [" + opis + "].");
+ this.getWezly()[1] = wezel;
+ wezel.luki.add(this);
+ } catch (NumberFormatException e) {
+ SiecDrogowa.logger.warn("Bledne dane w pliku z lukami [Wezel 2].");
+ }
+ if (this.wezly[0].id == this.wezly[1].id) {
+ SiecDrogowa.logger.warn("Bledne dane w pliku z lukami [wezly sa identyczne].");
+ }
+ if (GridCoord.czyIdentyczne(this.wezly[0].idKw, this.wezly[1].idKw)) {
+ SiecDrogowa.logger.warn("Bledne dane w pliku z lukami [wezly sa identyczne].");
+ }
+ try {
+ this.dlugosc = Integer.parseInt(tokenTable[2]);
+ } catch (NumberFormatException e) {
+ SiecDrogowa.logger.warn("Bledne dane w pliku z lukami [Dlugosc].");
+ }
+ try {
+ this.szerokosc = Integer.parseInt(tokenTable[3]);
+ } catch (NumberFormatException e) {
+ SiecDrogowa.logger.warn("Bledne dane w pliku z lukami [Szerokosc].");
+ }
+ try {
+ this.rodzajNawierzchni = Integer.parseInt(tokenTable[4]);
+ } catch (NumberFormatException e) {
+ SiecDrogowa.logger.warn("Bledne dane w pliku z lukami [RodzajNawierzchni].");
+ }
+ try {
+ int b = Integer.parseInt(tokenTable[5]);
+ this.jestMostem = (b != 0);
+ } catch (NumberFormatException e) {
+ SiecDrogowa.logger.warn("Bledne dane w pliku z lukami [CzyJestMost].");
+ }
+ }
+ }
+
+ public int getDlugosc() {
+ return dlugosc;
+ }
+
+ public void setDlugosc(int dlugosc) {
+ this.dlugosc = dlugosc;
+ }
+
+ public int getSzerokosc() {
+ return szerokosc;
+ }
+
+ public void setSzerokosc(int szerokosc) {
+ this.szerokosc = szerokosc;
+ }
+
+ public int getRodzajNawierzchni() {
+ return rodzajNawierzchni;
+ }
+
+ public void setRodzajNawierzchni(int rodzajNawierzchni) {
+ this.rodzajNawierzchni = rodzajNawierzchni;
+ }
+
+ public boolean isJestMostem() {
+ return jestMostem;
+ }
+
+ public void setJestMostem(boolean jestMostem) {
+ this.jestMostem = jestMostem;
+ }
+
+ public WezelDrogowy[] getWezly() {
+ return wezly;
+ }
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/MapConsts.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/MapConsts.java
new file mode 100644
index 0000000..382835c
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/MapConsts.java
@@ -0,0 +1,242 @@
+package pl.wat.ms4ds.terenfunkcje;
+
+import org.apache.log4j.Logger;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Properties;
+
+public final class MapConsts {
+
+ private static final Logger LOGGER = Logger.getLogger(MapConsts.class);
+
+ /**
+ * Umowny uklad odniesienia dla lokalizacji geograficznej:
+ * Długość geograficzna (wsp. X) przyjmuje wartości: [0, 360) odpowiadające [-180, 180]
+ * Szerokość geograficzna (wsp. Y) przyjmuje wartości: [0, 180] odpowadające [-90, 90]
+ */
+ public static final int X_REF;
+ /**
+ * Umowny uklad odniesienia dla lokalizacji geograficznej:
+ * Długość geograficzna (wsp. X) przyjmuje wartości: [0, 360) odpowiadające [-180, 180]
+ * Szerokość geograficzna (wsp. Y) przyjmuje wartości: [0, 180] odpowadające [-90, 90]
+ */
+ public static final int Y_REF;
+ public static final int DX_REF;
+ public static final int DY_REF;
+
+ public static final String KWADRATY_DIR;
+ public static final String DROGI_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 PLIK_Z_USTAWIENIAMI = "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 DL_MK;
+ /**
+ * Powierzchnia malego kwadratu w metrach.
+ */
+ public static final int POW_MK;
+ /**
+ * Szerokość małego kwadratu w stopniach.
+ */
+ public static final double DELTA_X;
+ /**
+ * Wysokość małego kwadratu w stopniach.
+ */
+ public static final double DELTA_Y;
+ /**
+ * 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_DX;
+ /**
+ * Wysokość duzych kwadratow w stopniach geograficznych po osi OY (szerokosc geograficzna).
+ */
+ public static final double BS_DY;
+
+ static Properties ustawienia;
+
+ /**
+ * Odczytanie ustawien z pliku konfiguracyjnego.
+ */
+ static {
+ String propertiesFileName = System.getProperty("user.dir") + "\\" + PLIK_Z_USTAWIENIAMI;
+
+ ustawienia = new Properties();
+ try {
+ LOGGER.debug("Odczyt ustawien z pliku " + propertiesFileName + ".");
+ ustawienia.load(new FileInputStream(propertiesFileName));
+ LOGGER.debug("Ustawienia wczytane.");
+ } catch (FileNotFoundException e) {
+ LOGGER.error(e.getLocalizedMessage());
+ } catch (IOException e) {
+ LOGGER.error(e.getLocalizedMessage());
+ }
+// logger.debug("Ustawienia wczytane.");
+ // 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)
+ X_REF = Integer.parseInt(ustawienia.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>
+ Y_REF = Integer.parseInt(ustawienia.getProperty("y_ref")) + 90;
+ DX_REF = Integer.parseInt(ustawienia.getProperty("dx_ref"));
+ DY_REF = Integer.parseInt(ustawienia.getProperty("dy_ref"));
+ String val = ustawienia.getProperty("dl_mk");
+ switch (val) {
+ case "20":
+ DL_MK = 20;
+ break;
+ case "25":
+ DL_MK = 25;
+ break;
+ case "50":
+ DL_MK = 50;
+ break;
+ case "100":
+ DL_MK = 100;
+ break;
+ default:
+ DL_MK = 200;
+ break;
+ }
+ POW_MK = DL_MK * DL_MK;
+ DROGI_DIR = ustawienia.getProperty("drogi_dir");
+ if (DL_MK == 20) {
+ SS_PER_BS_X = 83 * 10;
+ SS_PER_BS_Y = 93 * 10;
+ DELTA_X = 1.0 / (double) (BS_PER_DEG_X * SS_PER_BS_X);
+ DELTA_Y = 1.0 / (double) (BS_PER_DEG_Y * SS_PER_BS_Y);
+ KWADRATY_DIR = ustawienia.getProperty("kwadraty_dir") + "20m/";
+ } else if (DL_MK == 25) {
+ SS_PER_BS_X = 83 * 8;
+ SS_PER_BS_Y = 93 * 8;
+ DELTA_X = 1.0 / (double) (BS_PER_DEG_X * SS_PER_BS_X);
+ DELTA_Y = 1.0 / (double) (BS_PER_DEG_Y * SS_PER_BS_Y);
+ KWADRATY_DIR = ustawienia.getProperty("kwadraty_dir") + "25m/";
+ } else if (DL_MK == 50) {
+ SS_PER_BS_X = 83 * 4;
+ SS_PER_BS_Y = 93 * 4;
+ DELTA_X = 1.0 / (double) (BS_PER_DEG_X * SS_PER_BS_X);
+ DELTA_Y = 1.0 / (double) (BS_PER_DEG_Y * SS_PER_BS_Y);
+ KWADRATY_DIR = ustawienia.getProperty("kwadraty_dir") + "50m/";
+ } else if (DL_MK == 100) {
+ SS_PER_BS_X = 83 * 2;
+ SS_PER_BS_Y = 93 * 2;
+ DELTA_X = 1.0 / (double) (BS_PER_DEG_X * SS_PER_BS_X);
+ DELTA_Y = 1.0 / (double) (BS_PER_DEG_Y * SS_PER_BS_Y);
+ KWADRATY_DIR = ustawienia.getProperty("kwadraty_dir") + "100m/";
+ } else {
+ // domyslnie dlugosc kwadratu 200m
+ SS_PER_BS_X = 83;
+ SS_PER_BS_Y = 93;
+ DELTA_X = 1.0 / (double) (BS_PER_DEG_X * SS_PER_BS_X);
+ DELTA_Y = 1.0 / (double) (BS_PER_DEG_Y * SS_PER_BS_Y);
+ KWADRATY_DIR = ustawienia.getProperty("kwadraty_dir") + "200m/";
+ }
+ BS_DX = 1.0 / (double) BS_PER_DEG_X;
+ BS_DY = 1.0 / (double) BS_PER_DEG_Y;
+ }
+
+ /**
+ * Liczba milisekund na stopien.
+ */
+ public static final int DEG_MS = 3600000;
+ /**
+ * Liczba milisekund na 360 stopni.
+ */
+ public static final long ANGLE_360_MS = 3600000 * 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 X_REF;
+ }
+
+ /**
+ * Wspolrzedna referencyjna Y (szerokosc geograficzna) lewego dolnego rogu mapy w stopniach geograficznych.
+ * @return
+ */
+ public static int getY_REF() {
+ return Y_REF;
+ }
+
+ /**
+ * Szerokosc referencyjna prostokata pola walki w stopniach na osi OX (dlugosc geograficzna).
+ * @return
+ */
+ public static int getDX_REF() {
+ return DX_REF;
+ }
+
+ /**
+ * Wysokosc referencyjna prostokata pola walki w stopniach na osi OY (szerokosc geograficzna).
+ * @return
+ */
+ public static int getDY_REF() {
+ return DY_REF;
+ }
+
+ public static String getKwadratyDir() {
+ return KWADRATY_DIR;
+ }
+
+ public static String getDrogiDir() {
+ return DROGI_DIR;
+ }
+ /**
+ * Dlugosci bokow malego kwadratu w milisekundach geograficznych po osi OX (dlugosc geograficzna).
+ */
+ public static final double SS_DX_MS = DELTA_X * DEG_MS;
+ /**
+ * Dlugosci bokow malego kwadratu w milisekundach geograficznych po osi OY (szerokosc geograficzna).
+ */
+ public static final double SS_DY_MS = DELTA_Y * 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 = X_REF * DEG_MS;
+ public static final int Y_REF_MS = Y_REF * DEG_MS;
+ public static final int DX_REF_MS = DEG_MS * DX_REF; // szerokosc pola walki w stopniach
+ public static final int DY_REF_MS = DEG_MS * DY_REF; // wysokosc polwa walki w stopniach
+
+ public static final int BS_DX_MS = (int) (BS_DX * DEG_MS);
+ public static final int BS_DY_MS = (int) (BS_DY * DEG_MS);
+
+ /**
+ * Liczba malych kwadratow przypadajaca na bok arkusza mapy drogowej.
+ */
+ public static final int SS_PER_SHEET = 20;
+
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/RightBigSquare.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/RightBigSquare.java
new file mode 100644
index 0000000..7f1d224
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/RightBigSquare.java
@@ -0,0 +1,640 @@
+package pl.wat.ms4ds.terenfunkcje;
+
+import org.apache.log4j.Logger;
+
+import java.io.*;
+
+public class RightBigSquare extends BigSquare implements Serializable {
+
+ private static final Logger logger = Logger.getLogger(RightBigSquare.class);
+
+ private Kwadrat kwadraty[][];
+
+ Kwadrat getKwadrat(int ssX, int ssY) {
+ return kwadraty[ssX][ssY];
+ }
+
+ /**
+ * Funkcja zapisująca do pliku duży kwadrat.
+ * Zapis następuje w trybie wskazywanym przez atrybut: RightBigSquare.binary.
+ *
+ * @param wymuszony flag informujacy o trybie zapisu pliku
+ * @param fName nazwa pliku
+ * @throws IOException generowany wyjątek
+ */
+ void updateFile(boolean wymuszony, String fName) throws IOException {
+ if (wymuszony) {
+ if (this.liczbaZmian == 0) {
+ // nie bylo modyfikacji od ostatniego zapisu
+ return;
+ }
+ this.liczbaZmian = -1;
+ }
+ this.liczbaZmian++;
+ this.liczbaZmian %= LICZBA_ZMIAN_DO_ZAPISU;
+ if (this.liczbaZmian > 0) {
+ return;
+ }
+ if (fName != null) {
+ fileName = fName;
+ }
+ StringBuilder sb = new StringBuilder(100);
+ sb.append(MapConsts.KWADRATY_DIR);
+ sb.append(fileName);
+ sb.append(".bin");
+ ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(sb.toString()));
+ for (int x = 0; x < MapConsts.SS_PER_BS_X; x++) {
+ for (int y = 0; y < MapConsts.SS_PER_BS_Y; y++) {
+ float f = kwadraty[x][y].stopienZalesienia * 100.0f;
+ int hex = (int) f;
+ hex = (hex > 100) ? 100 : hex;
+ hex = (hex < 0) ? 0 : hex;
+ out.writeByte(hex);
+ f = kwadraty[x][y].stopienZawodnienia * 100.0f;
+ hex = (int) f;
+ hex = (hex > 100) ? 100 : hex;
+ hex = (hex < 0) ? 0 : hex;
+ out.writeByte(hex);
+ f = kwadraty[x][y].stopienZabudowy * 100.0f;
+ hex = (int) f;
+ hex = (hex > 100) ? 100 : hex;
+ hex = (hex < 0) ? 0 : hex;
+ out.writeByte(hex);
+ f = kwadraty[x][y].stopienZabagnienia * 100.0f;
+ hex = (int) f;
+ hex = (hex > 100) ? 100 : hex;
+ hex = (hex < 0) ? 0 : hex;
+ out.writeByte(hex);
+ out.writeInt(kwadraty[x][y].wysokoscSrednia);
+ out.writeInt(kwadraty[x][y].roznicaWzniesien);
+
+ hex = 0;
+ int bit_1 = 1;
+ for (int i = 0; i < kwadraty[x][y].jestDroga.length; i++) {
+ // jest odcinek drogi na tym kierunku
+ if (kwadraty[x][y].jestDroga[i]) {
+ hex |= bit_1;
+ }
+ bit_1 <<= 1;
+ }
+ out.writeByte(hex);
+
+ hex = 0;
+ bit_1 = 1;
+ for (int i = 0; i < kwadraty[x][y].jestPrzeszkodaWodna.length; i++) {
+ // jest odcinek przeszkody wodnej na tym kierunku
+ if (kwadraty[x][y].jestPrzeszkodaWodna[i]) {
+ hex |= bit_1;
+ }
+ bit_1 <<= 1;
+ }
+ out.writeByte(hex);
+
+ hex = 0;
+ bit_1 = 1;
+ for (int i = 0; i < kwadraty[x][y].jestRow.length; i++) {
+ // jest odcinek rowu na tym kierunku
+ if (kwadraty[x][y].jestRow[i]) {
+ hex |= bit_1;
+ }
+ bit_1 <<= 1;
+ }
+ out.writeByte(hex);
+ }
+ }
+ out.close();
+ logger.debug("Zapisano plik mapy: " + sb.toString());
+ }
+
+ static final int NORTH = 0;
+ static final int NORTH_EAST = 1;
+ static final int EAST = 2;
+ static final int SOUTH_EAST = 3;
+ static final int SOUTH = 4;
+ static final int SOUTH_WEST = 5;
+ static final int WEST = 6;
+ static final int NORTH_WEST = 7;
+ static final byte NORTH_CODE = 1;
+ static final byte NORTH_EAST_CODE = 2;
+ static final byte EAST_CODE = 4;
+ static final byte SOUTH_EAST_CODE = 8;
+ static final byte SOUTH_CODE = 16;
+ static final byte SOUTH_WEST_CODE = 32;
+ static final byte WEST_CODE = 64;
+ static final byte NORTH_WEST_CODE = -128;
+
+
+ /**
+ * Funkcja generuje nowy plik z danymi na podstawie danych z pliku referencyjnego (kwadraty o rozm. 200m).
+ *
Nowy plik moze byc z danymi w innej skali (kwadraty o rozmiarach: 100m lub 50m) i/lub innym formacie (binarny, tekstowy).
+ *
+ * @param dir katalog docelowy dla nowego pliku
+ * @param dlmk rozmiar kwadratow generownych danych
+ * @throws IOException generowany wyjątek
+ */
+ public void saveNewFileWithNewScale(String dir, int dlmk) throws IOException {
+ if (MapConsts.DL_MK != 100) {
+ // operacja tylko dla danych terenowych o kwadratach 200m
+ return;
+ }
+ int m = 1;
+ 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);
+ sb.append(".bin");
+ ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(sb.toString()));
+
+ SmallSquare[][][][] ss_all = new SmallSquare[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++) {
+ SmallSquare[][] ss = new SmallSquare[m][m];
+ for (int i = 0; i < m; i++) {
+ for (int j = 0; j < m; j++) {
+ ss[i][j] = new SmallSquare();
+ }
+ }
+ ss_all[x][y] = ss;
+ // jest odcinek drogi na tym kierunku
+ if (kwadraty[x][y].jestDroga[NORTH]) {
+ ss[2][2].majorRoads |= NORTH_CODE;
+ ss[2][3].majorRoads |= NORTH_CODE | SOUTH_CODE;
+ ss[2][4].majorRoads |= NORTH_CODE | SOUTH_CODE;
+ }
+ if (kwadraty[x][y].jestDroga[NORTH_EAST]) {
+ ss[2][2].majorRoads |= NORTH_EAST_CODE;
+ ss[3][3].majorRoads |= NORTH_EAST_CODE | SOUTH_WEST_CODE;
+ ss[4][4].majorRoads |= NORTH_EAST_CODE | SOUTH_WEST_CODE;
+ }
+ if (kwadraty[x][y].jestDroga[EAST]) {
+ ss[2][2].majorRoads |= EAST_CODE;
+ ss[3][2].majorRoads |= EAST_CODE | WEST_CODE;
+ ss[4][2].majorRoads |= EAST_CODE | WEST_CODE;
+ }
+ if (kwadraty[x][y].jestDroga[SOUTH_EAST]) {
+ ss[2][2].majorRoads |= SOUTH_EAST_CODE;
+ ss[3][1].majorRoads |= SOUTH_EAST_CODE | NORTH_WEST_CODE;
+ ss[4][0].majorRoads |= SOUTH_EAST_CODE | NORTH_WEST_CODE;
+ }
+ if (kwadraty[x][y].jestDroga[SOUTH]) {
+ ss[2][2].majorRoads |= SOUTH_CODE;
+ ss[2][1].majorRoads |= SOUTH_CODE | NORTH_CODE;
+ ss[2][0].majorRoads |= SOUTH_CODE | NORTH_CODE;
+ }
+ if (kwadraty[x][y].jestDroga[SOUTH_WEST]) {
+ ss[2][2].majorRoads |= SOUTH_WEST_CODE;
+ ss[1][1].majorRoads |= SOUTH_WEST_CODE | NORTH_EAST_CODE;
+ ss[0][0].majorRoads |= SOUTH_WEST_CODE | NORTH_EAST_CODE;
+ }
+ if (kwadraty[x][y].jestDroga[WEST]) {
+ ss[2][2].majorRoads |= WEST_CODE;
+ ss[1][2].majorRoads |= WEST_CODE | EAST_CODE;
+ ss[0][2].majorRoads |= WEST_CODE | EAST_CODE;
+ }
+ if (kwadraty[x][y].jestDroga[NORTH_WEST]) {
+ ss[2][2].majorRoads |= NORTH_WEST_CODE;
+ ss[1][3].majorRoads |= NORTH_WEST_CODE | SOUTH_EAST_CODE;
+ ss[0][4].majorRoads |= NORTH_WEST_CODE | SOUTH_EAST_CODE;
+ }
+
+ // jest odcinek rzeki na tym kierunku
+ if (kwadraty[x][y].jestPrzeszkodaWodna[NORTH]) {
+ ss[2][2].rivers |= NORTH_CODE;
+ ss[2][3].rivers |= NORTH_CODE | SOUTH_CODE;
+ ss[2][4].rivers |= NORTH_CODE | SOUTH_CODE;
+ }
+ if (kwadraty[x][y].jestPrzeszkodaWodna[NORTH_EAST]) {
+ ss[2][2].rivers |= NORTH_EAST_CODE;
+ ss[3][3].rivers |= NORTH_EAST_CODE | SOUTH_WEST_CODE;
+ ss[4][4].rivers |= NORTH_EAST_CODE | SOUTH_WEST_CODE;
+ }
+ if (kwadraty[x][y].jestPrzeszkodaWodna[EAST]) {
+ ss[2][2].rivers |= EAST_CODE;
+ ss[3][2].rivers |= EAST_CODE | WEST_CODE;
+ ss[4][2].rivers |= EAST_CODE | WEST_CODE;
+ }
+ if (kwadraty[x][y].jestPrzeszkodaWodna[SOUTH_EAST]) {
+ ss[2][2].rivers |= SOUTH_EAST_CODE;
+ ss[3][1].rivers |= SOUTH_EAST_CODE | NORTH_WEST_CODE;
+ ss[4][0].rivers |= SOUTH_EAST_CODE | NORTH_WEST_CODE;
+ }
+ if (kwadraty[x][y].jestPrzeszkodaWodna[SOUTH]) {
+ ss[2][2].rivers |= SOUTH_CODE;
+ ss[2][1].rivers |= SOUTH_CODE | NORTH_CODE;
+ ss[2][0].rivers |= SOUTH_CODE | NORTH_CODE;
+ }
+ if (kwadraty[x][y].jestPrzeszkodaWodna[SOUTH_WEST]) {
+ ss[2][2].rivers |= SOUTH_WEST_CODE;
+ ss[1][1].rivers |= SOUTH_WEST_CODE | NORTH_EAST_CODE;
+ ss[0][0].rivers |= SOUTH_WEST_CODE | NORTH_EAST_CODE;
+ }
+ if (kwadraty[x][y].jestPrzeszkodaWodna[WEST]) {
+ ss[2][2].rivers |= WEST_CODE;
+ ss[1][2].rivers |= WEST_CODE | EAST_CODE;
+ ss[0][2].rivers |= WEST_CODE | EAST_CODE;
+ }
+ if (kwadraty[x][y].jestPrzeszkodaWodna[NORTH_WEST]) {
+ ss[2][2].rivers |= NORTH_WEST_CODE;
+ ss[1][3].rivers |= NORTH_WEST_CODE | SOUTH_EAST_CODE;
+ ss[0][4].rivers |= NORTH_WEST_CODE | SOUTH_EAST_CODE;
+ }
+
+ // jest odcinek rowu na tym kierunku
+ if (kwadraty[x][y].jestRow[NORTH]) {
+ ss[2][2].drains |= NORTH_CODE;
+ ss[2][3].drains |= NORTH_CODE | SOUTH_CODE;
+ ss[2][4].drains |= NORTH_CODE | SOUTH_CODE;
+ }
+ if (kwadraty[x][y].jestRow[NORTH_EAST]) {
+ ss[2][2].drains |= NORTH_EAST_CODE;
+ ss[3][3].drains |= NORTH_EAST_CODE | SOUTH_WEST_CODE;
+ ss[4][4].drains |= NORTH_EAST_CODE | SOUTH_WEST_CODE;
+ }
+ if (kwadraty[x][y].jestRow[EAST]) {
+ ss[2][2].drains |= EAST_CODE;
+ ss[3][2].drains |= EAST_CODE | WEST_CODE;
+ ss[4][2].drains |= EAST_CODE | WEST_CODE;
+ }
+ if (kwadraty[x][y].jestRow[SOUTH_EAST]) {
+ ss[2][2].drains |= SOUTH_EAST_CODE;
+ ss[3][1].drains |= SOUTH_EAST_CODE | NORTH_WEST_CODE;
+ ss[4][0].drains |= SOUTH_EAST_CODE | NORTH_WEST_CODE;
+ }
+ if (kwadraty[x][y].jestRow[SOUTH]) {
+ ss[2][2].drains |= SOUTH_CODE;
+ ss[2][1].drains |= SOUTH_CODE | NORTH_CODE;
+ ss[2][0].drains |= SOUTH_CODE | NORTH_CODE;
+ }
+ if (kwadraty[x][y].jestRow[SOUTH_WEST]) {
+ ss[2][2].drains |= SOUTH_WEST_CODE;
+ ss[1][1].drains |= SOUTH_WEST_CODE | NORTH_EAST_CODE;
+ ss[0][0].drains |= SOUTH_WEST_CODE | NORTH_EAST_CODE;
+ }
+ if (kwadraty[x][y].jestRow[WEST]) {
+ ss[2][2].drains |= WEST_CODE;
+ ss[1][2].drains |= WEST_CODE | EAST_CODE;
+ ss[0][2].drains |= WEST_CODE | EAST_CODE;
+ }
+ if (kwadraty[x][y].jestRow[NORTH_WEST]) {
+ ss[2][2].drains |= NORTH_WEST_CODE;
+ ss[1][3].drains |= NORTH_WEST_CODE | SOUTH_EAST_CODE;
+ ss[0][4].drains |= NORTH_WEST_CODE | SOUTH_EAST_CODE;
+ }
+
+ for (int i = 0; i < m; i++) {
+ for (int j = 0; j < m; j++) {
+ int hex = 0;
+ if (kwadraty[x][y].stopienZalesienia > 0) {
+ hex = TerrainType.FOREST.ID;
+ } else if (kwadraty[x][y].stopienZawodnienia > 0) {
+ hex = TerrainType.WATER.ID;
+ } else if (kwadraty[x][y].stopienZabudowy > 0) {
+ hex = TerrainType.BUILDINGS.ID;
+ } else if (kwadraty[x][y].stopienZabagnienia > 0) {
+ hex = TerrainType.SWAMP.ID;
+ }
+ ss[i][j].terrainType = (byte) hex;
+ ss[i][j].elevation = (short) kwadraty[x][y].wysokoscSrednia;
+ }
+ }
+ }
+ }
+ for (int x = 0; x < MapConsts.SS_PER_BS_X; x++) {
+ for (int i = 0; i < m; i++) {
+ for (int y = 0; y < MapConsts.SS_PER_BS_Y; y++) {
+ for (int j = 0; j < m; j++) {
+ ss_all[x][y][i][j].save(out);
+ }
+ }
+ }
+ }
+ out.close();
+ logger.debug("Zapisano nowy plik mapy: " + sb + " dla rozmiaru MK= " + dlmk);
+ }
+
+ void load(String FName) throws IOException {
+ try {
+ fileName = FName;
+ StringBuilder sb = new StringBuilder(100);
+ sb.append(MapConsts.KWADRATY_DIR);
+ sb.append(fileName);
+ sb.append(".bin");
+ SmallSquare ss = new SmallSquare();
+ ObjectInputStream in = new ObjectInputStream(new FileInputStream(sb.toString()));
+ kwadraty = new Kwadrat[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++) {
+ kwadraty[x][y] = new Kwadrat();
+ ss.load(in);
+ switch (ss.terrainType) {
+ case 0:
+ break;
+ case 1:
+ break;
+ case 4:
+ break;
+ case 2:
+ kwadraty[x][y].stopienZabagnienia = 1.f;
+ break;
+ case 3:
+ kwadraty[x][y].stopienZawodnienia = 1.f;
+ break;
+ case 5:
+ kwadraty[x][y].stopienZabudowy = 1.f;
+ break;
+ case 6:
+ kwadraty[x][y].stopienZalesienia = 1.f;
+ break;
+ }
+
+ kwadraty[x][y].wysokoscSrednia = ss.elevation;
+ kwadraty[x][y].roznicaWzniesien = 0;
+
+ int bit_1 = 1;
+ int hex = ss.majorRoads;
+ for (int i = 0; i < kwadraty[x][y].jestDroga.length; i++) {
+ // jest odcinek rowu na tym kierunku
+ if ((hex & bit_1) != 0) {
+ kwadraty[x][y].jestDroga[i] = true;
+ }
+ bit_1 <<= 1;
+ }
+ bit_1 = 1;
+ hex = ss.rivers;
+ for (int i = 0; i < kwadraty[x][y].jestPrzeszkodaWodna.length; i++) {
+ // jest odcinek rowu na tym kierunku
+ if ((hex & bit_1) != 0) {
+ kwadraty[x][y].jestPrzeszkodaWodna[i] = true;
+ }
+ bit_1 <<= 1;
+ }
+ bit_1 = 1;
+ hex = ss.drains;
+ for (int i = 0; i < kwadraty[x][y].jestRow.length; i++) {
+ // jest odcinek rowu na tym kierunku
+ if ((hex & bit_1) != 0) {
+ kwadraty[x][y].jestRow[i] = true;
+ }
+ bit_1 <<= 1;
+ }
+ kwadraty[x][y].bs = this;
+ }
+ }
+ in.close();
+ logger.debug("Doczytano plik mapy: " + sb.toString());
+ } catch (IOException e) {
+ kwadraty = null;
+ throw e;
+ }
+ }
+
+ /**
+ * Funkcja generuje nowy plik z danymi na podstawie danych z pliku referencyjnego (kwadraty o rozm. 200m).
+ *
Nowy plik moze byc z danymi w innej skali (kwadraty o rozmiarach: 100m lub 50m) i/lub innym formacie (binarny, tekstowy).
+ *
+ * @param dir katalog docelowy dla nowego pliku
+ * @param dlmk rozmiar kwadratow generownych danych
+ * @throws IOException generowany wyjątek
+ */
+ public void saveNewFileWithNewScale_old_format(String dir, int dlmk,
+ boolean zalesienie, boolean zawodnienie, boolean zabudowa, boolean zabagnienie,
+ boolean wysokosc, boolean roznicaWzniesien, boolean drogi,
+ boolean rzeki, boolean rowy) throws IOException {
+ if (MapConsts.DL_MK != 200) {
+ // operacja tylko dla danych terenowych o kwadratach 200m
+ return;
+ }
+ int m = 1;
+ String s = "";
+ if (dlmk == 200) {
+ m = 1;
+ s = "200m/";
+ } else if (dlmk == 100) {
+ m = 2;
+ s = "100m/";
+ } else if (dlmk == 50) {
+ m = 4;
+ s = "50m/";
+ } else if (dlmk == 25) {
+ m = 8;
+ s = "25m/";
+ } 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);
+ sb.append(".bin");
+ ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(sb.toString()));
+ for (int x = 0; x < MapConsts.SS_PER_BS_X; x++) {
+ for (int y = 0; y < MapConsts.SS_PER_BS_Y; y++) {
+ for (int k = 0; k < m * m; k++) {
+ float f;
+ int hex = 0;
+ if (zalesienie) {
+ f = kwadraty[x][y].stopienZalesienia * 100.0f;
+ hex = (int) f;
+ hex = (hex > 100) ? 100 : hex;
+ hex = (hex < 0) ? 0 : hex;
+ }
+ out.writeByte(hex);
+ hex = 0;
+ if (zawodnienie) {
+ f = kwadraty[x][y].stopienZawodnienia * 100.0f;
+ hex = (int) f;
+ hex = (hex > 100) ? 100 : hex;
+ hex = (hex < 0) ? 0 : hex;
+ }
+ out.writeByte(hex);
+ hex = 0;
+ if (zabudowa) {
+ f = kwadraty[x][y].stopienZabudowy * 100.0f;
+ hex = (int) f;
+ hex = (hex > 100) ? 100 : hex;
+ hex = (hex < 0) ? 0 : hex;
+ }
+ out.writeByte(hex);
+ hex = 0;
+ if (zabagnienie) {
+ f = kwadraty[x][y].stopienZabagnienia * 100.0f;
+ hex = (int) f;
+ hex = (hex > 100) ? 100 : hex;
+ hex = (hex < 0) ? 0 : hex;
+ }
+ out.writeByte(hex);
+ if (wysokosc) {
+ out.writeInt(kwadraty[x][y].wysokoscSrednia);
+ } else {
+ out.writeInt(0);
+ }
+ if (roznicaWzniesien) {
+ out.writeInt(kwadraty[x][y].roznicaWzniesien);
+ } else {
+ out.writeInt(0);
+ }
+ int bit_1;
+ hex = 0;
+ if (drogi) {
+ bit_1 = 1;
+ for (int i = 0; i < kwadraty[x][y].jestDroga.length; i++) {
+ // jest odcinek drogi na tym kierunku
+ if (kwadraty[x][y].jestDroga[i]) {
+ hex |= bit_1;
+ }
+ bit_1 <<= 1;
+ }
+ }
+ out.writeByte(hex);
+ hex = 0;
+ if (rzeki) {
+ bit_1 = 1;
+ for (int i = 0; i < kwadraty[x][y].jestPrzeszkodaWodna.length; i++) {
+ // jest odcinek przeszkody wodnej na tym kierunku
+ if (kwadraty[x][y].jestPrzeszkodaWodna[i]) {
+ hex |= bit_1;
+ }
+ bit_1 <<= 1;
+ }
+ }
+ out.writeByte(hex);
+ hex = 0;
+ if (rowy) {
+ bit_1 = 1;
+ for (int i = 0; i < kwadraty[x][y].jestRow.length; i++) {
+ // jest odcinek rowu na tym kierunku
+ if (kwadraty[x][y].jestRow[i]) {
+ hex |= bit_1;
+ }
+ bit_1 <<= 1;
+ }
+ }
+ out.writeByte(hex);
+ }
+ }
+ }
+ out.close();
+ logger.debug("Zapisano nowy plik mapy: " + sb.toString() + " dla rozmiaru MK= " + dlmk);
+ }
+
+
+ public RightBigSquare() {
+ }
+
+ // konstruktor ladujacy duzy kwadrat z pliku binarnego
+ RightBigSquare(String FName) throws IOException {
+ try {
+ fileName = FName;
+ StringBuilder sb = new StringBuilder(100);
+ sb.append(MapConsts.KWADRATY_DIR);
+ sb.append(fileName);
+ sb.append(".bin");
+ ObjectInputStream in = new ObjectInputStream(new FileInputStream(sb.toString()));
+ kwadraty = new Kwadrat[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++) {
+ kwadraty[x][y] = new Kwadrat();
+ int hex = in.readByte();
+ kwadraty[x][y].stopienZalesienia = (float) hex * (1.0f / 100.f);
+ hex = in.readByte();
+ kwadraty[x][y].stopienZawodnienia = (float) hex * (1.0f / 100.f);
+ hex = in.readByte();
+ kwadraty[x][y].stopienZabudowy = (float) hex * (1.0f / 100.f);
+ hex = in.readByte();
+ kwadraty[x][y].stopienZabagnienia = (float) hex * (1.0f / 100.f);
+ kwadraty[x][y].wysokoscSrednia = in.readInt();
+ kwadraty[x][y].roznicaWzniesien = in.readInt();
+ int bit_1 = 1;
+ hex = in.readByte();
+ for (int i = 0; i < kwadraty[x][y].jestDroga.length; i++) {
+ // jest odcinek rowu na tym kierunku
+ if ((hex & bit_1) != 0) {
+ kwadraty[x][y].jestDroga[i] = true;
+ }
+ bit_1 <<= 1;
+ }
+ bit_1 = 1;
+ hex = in.readByte();
+ for (int i = 0; i < kwadraty[x][y].jestPrzeszkodaWodna.length; i++) {
+ // jest odcinek rowu na tym kierunku
+ if ((hex & bit_1) != 0) {
+ kwadraty[x][y].jestPrzeszkodaWodna[i] = true;
+ }
+ bit_1 <<= 1;
+ }
+ bit_1 = 1;
+ hex = in.readByte();
+ for (int i = 0; i < kwadraty[x][y].jestRow.length; i++) {
+ // jest odcinek rowu na tym kierunku
+ if ((hex & bit_1) != 0) {
+ kwadraty[x][y].jestRow[i] = true;
+ }
+ bit_1 <<= 1;
+ }
+ kwadraty[x][y].bs = this;
+ }
+ }
+ in.close();
+ logger.debug("Doczytano plik mapy: " + sb.toString());
+ } catch (IOException e) {
+ kwadraty = null;
+ throw e;
+ }
+ }
+
+ void resetSquares(boolean zalesienie, boolean zawodnienie, boolean zabudowa, boolean zabagnienie,
+ boolean wysokosc, boolean roznicaWzniesien, boolean drogi, boolean rzeki, boolean rowy) {
+ for (int x = 0; x < MapConsts.SS_PER_BS_X; x++) {
+ for (int y = 0; y < MapConsts.SS_PER_BS_Y; y++) {
+ kwadraty[x][y].stopienZalesienia = (zalesienie) ? 0 : kwadraty[x][y].stopienZalesienia;
+ kwadraty[x][y].stopienZawodnienia = (zawodnienie) ? 0 : kwadraty[x][y].stopienZawodnienia;
+ kwadraty[x][y].stopienZabudowy = (zabudowa) ? 0 : kwadraty[x][y].stopienZabudowy;
+ kwadraty[x][y].stopienZabagnienia = (zabagnienie) ? 0 : kwadraty[x][y].stopienZabagnienia;
+ kwadraty[x][y].wysokoscSrednia = (wysokosc) ? 0 : kwadraty[x][y].wysokoscSrednia;
+ kwadraty[x][y].roznicaWzniesien = (roznicaWzniesien) ? 0 : kwadraty[x][y].roznicaWzniesien;
+ if (drogi) {
+ for (int i = 0; i < kwadraty[x][y].jestDroga.length; i++) {
+ kwadraty[x][y].jestDroga[i] = false;
+ }
+ }
+ if (rzeki) {
+ for (int i = 0; i < kwadraty[x][y].jestPrzeszkodaWodna.length; i++) {
+ kwadraty[x][y].jestPrzeszkodaWodna[i] = false;
+ }
+ }
+ if (rowy) {
+ for (int i = 0; i < kwadraty[x][y].jestRow.length; i++) {
+ kwadraty[x][y].jestRow[i] = false;
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "RightBigSquare{" + this.fileName + '}';
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/SiecDrogowa.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/SiecDrogowa.java
new file mode 100644
index 0000000..e46eae4
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/SiecDrogowa.java
@@ -0,0 +1,364 @@
+package pl.wat.ms4ds.terenfunkcje;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+
+import org.apache.log4j.Logger;
+import pl.wat.ms4ds.common.EGeoDirection;
+
+public class SiecDrogowa {
+
+ static final Logger logger = Logger.getLogger(SiecDrogowa.class);
+
+ ArrayList luki;
+ ArrayList wezly;
+ static SiecDrogowa instancja;
+ static String path;
+
+ Arkusz[][] arkusze;
+
+ public int liczbaZmian = 0;
+ static final int LICZBA_ZMIAN = 50;
+
+ SiecDrogowa(String dataPath) {
+ instancja = this;
+// File wd = new File(".");
+// PATH = wd.getPath();
+ path = dataPath;
+ this.odczytajWezly(path + "/nodes.txt");
+ logger.debug("wczytano " + this.wezly.size() + " wezlow.");
+ this.odczytajLuki(path + "/arcs.txt");
+ logger.debug("wczytano " + this.luki.size() + " lukow.");
+ stworzArkusze();
+
+
+// logger.debug("Liczba lukow w arkuszach:");
+// int ll = 0;
+// for (int i = 0; i < Arkusz.lx; i++) {
+// for (int j = 0; j < Arkusz.ly; j++) {
+// logger.debug(String.format("(%1$2d, %2$2d) - %3$6d", i, j, this.arkusze[i][j].luki.size()));
+// ll += this.arkusze[i][j].luki.size();
+// }
+// }
+// logger.debug("Sum. liczba lukow w arkuszach:" + ll);
+ }
+
+ void odczytajWezly(String fname) {
+ try {
+ FileReader fis = new FileReader(fname);
+ BufferedReader br = new BufferedReader(fis);
+ if (br.ready()) {
+ String line = br.readLine().trim();
+ int licz = Integer.parseInt(line);
+ this.wezly = new ArrayList(licz);// + 1000);
+ while (null != (line = br.readLine())) {
+ WezelDrogowy nowyWezel = new WezelDrogowy(line);
+ nowyWezel.id = this.wezly.size(); //Indeksowanie od 0
+ this.wezly.add(nowyWezel);
+ }
+ }
+ br.close();
+ } catch (IOException e) {
+ logger.warn("Brak pliku z wezlami: " + fname);
+ }
+ }
+
+ void odczytajLuki(String fname) {
+ try {
+ FileReader fis = new FileReader(fname);
+ BufferedReader br = new BufferedReader(fis);
+ if (br.ready()) {
+ String line = br.readLine().trim();
+ int licz = Integer.parseInt(line);
+ this.luki = new ArrayList(licz);// + 1000);
+ while (null != (line = br.readLine())) {
+ LukDrogowy nowyLuk = new LukDrogowy(line);
+ nowyLuk.id = this.luki.size(); //Indeksowanie od 0
+ this.luki.add(nowyLuk);
+ }
+ }
+ br.close();
+ } catch (IOException e) {
+ logger.warn("Brak pliku z lukami: " + fname);
+ }
+ }
+
+ void stworzArkusze() {
+ // wyznaczenie wymiarow pola walki w malych kwadratach
+ Arkusz.lx = MapConsts.getDX_REF() * MapConsts.BS_PER_DEG_X * MapConsts.SS_PER_BS_X;
+ Arkusz.ly = MapConsts.getDY_REF() * MapConsts.BS_PER_DEG_Y * MapConsts.SS_PER_BS_Y;
+ // wyznacznie liczby arkuszy mapy w obu wymiarach
+ Arkusz.lx = Arkusz.lx / MapConsts.SS_PER_SHEET + 1;
+ Arkusz.ly = Arkusz.ly / MapConsts.SS_PER_SHEET + 1;
+ this.arkusze = new Arkusz[Arkusz.lx][Arkusz.ly];
+ for (int i = 0; i < Arkusz.lx; i++) {
+ for (int j = 0; j < Arkusz.ly; j++) {
+ this.arkusze[i][j] = new Arkusz();
+ }
+ }
+ // wspolrzedne arkusza mapy
+ int xa, ya;
+ for (int i = 0; i < this.wezly.size(); i++) {
+ WezelDrogowy wezel = this.wezly.get(i);
+ xa = wezel.idKw.x / MapConsts.SS_PER_SHEET;
+ ya = wezel.idKw.y / MapConsts.SS_PER_SHEET;
+ this.arkusze[xa][ya].wezly.add(wezel);
+ }
+ int xa2, ya2;
+ for (int i = 0; i < this.luki.size(); i++) {
+ LukDrogowy luk = this.luki.get(i);
+ xa = luk.getWezly()[0].idKw.x / MapConsts.SS_PER_SHEET;
+ ya = luk.getWezly()[0].idKw.y / MapConsts.SS_PER_SHEET;
+ xa2 = luk.getWezly()[1].idKw.x / MapConsts.SS_PER_SHEET;
+ ya2 = luk.getWezly()[1].idKw.y / MapConsts.SS_PER_SHEET;
+ boolean b = Arkusz.mniejszeWspolrzedne(xa, ya, xa2, ya2);
+ if (b) {
+ this.arkusze[xa][ya].luki.add(luk);
+ } else {
+ this.arkusze[xa2][ya2].luki.add(luk);
+ }
+ }
+ }
+
+ public static void utworzSiecDrogowa(){
+// if (null == instancja){
+// instancja = new SiecDrogowa(MapConsts.DROGI_DIR);
+// }
+ }
+
+ public static LukDrogowy dodajLuk(WezelDrogowy wezel1, WezelDrogowy wezel2) {
+ utworzSiecDrogowa();
+ LukDrogowy nowyLuk = new LukDrogowy();
+ nowyLuk.getWezly()[0] = wezel1;
+ wezel1.luki.add(nowyLuk);
+ nowyLuk.getWezly()[1] = wezel2;
+ wezel2.luki.add(nowyLuk);
+ instancja.luki.add(nowyLuk);
+ nowyLuk.id = instancja.luki.size() - 1;
+ return nowyLuk;
+ }
+
+ public static WezelDrogowy dodajWezel(String wspUTM) {
+ utworzSiecDrogowa();
+ // TODO dodac weryfikacje poprawnosci wspolrzednych UTM
+ WezelDrogowy nowyWezel = new WezelDrogowy();
+ nowyWezel.setXms(Teren.zamienWspUtmNaWspXms(wspUTM.substring(0, 6)));
+ nowyWezel.setYms(Teren.zamienWspUtmNaWspXms(wspUTM.substring(8, 14)));
+ int x = GridCoord.zamienWspXmsNaIdKwadratuX(nowyWezel.getXms());
+ int y = GridCoord.zamienWspYmsNaIdKwadratuY(nowyWezel.getYms());
+ nowyWezel.idKw = new GridCoord(x, y);
+ nowyWezel.luki = new ArrayList();
+ instancja.wezly.add(nowyWezel);
+ nowyWezel.id = instancja.wezly.size() - 1;
+ return nowyWezel;
+ }
+
+ public static void usunLuk(LukDrogowy usuwanyLuk) {
+ utworzSiecDrogowa();
+ if (usuwanyLuk.id < 0 || usuwanyLuk.id >= instancja.luki.size()) {
+ return;
+ }
+ int ostatniId = instancja.luki.size() - 1;
+ LukDrogowy lukOstatni = instancja.luki.get(ostatniId);
+ lukOstatni.id = usuwanyLuk.id;
+ instancja.luki.set(lukOstatni.id, lukOstatni);
+ instancja.luki.remove(ostatniId);
+ // aktualizacja wezlow luku
+ usuwanyLuk.getWezly()[0].luki.remove(usuwanyLuk);
+ usuwanyLuk.getWezly()[1].luki.remove(usuwanyLuk);
+ if (usuwanyLuk.getWezly()[0].luki.size() == 0) {
+ usunWezel(usuwanyLuk.getWezly()[0]);
+ }
+ if (usuwanyLuk.getWezly()[1].luki.size() == 0) {
+ usunWezel(usuwanyLuk.getWezly()[1]);
+ }
+ }
+
+ public static void usunWezel(WezelDrogowy usuwanyWezel) {
+ utworzSiecDrogowa();
+ if (usuwanyWezel.id < 0 || usuwanyWezel.id >= instancja.wezly.size()) {
+ return;
+ }
+ int ostatniId = instancja.wezly.size() - 1;
+ WezelDrogowy wezelOstatni = instancja.wezly.get(ostatniId);
+ wezelOstatni.id = usuwanyWezel.id;
+ instancja.wezly.set(wezelOstatni.id, wezelOstatni);
+ instancja.wezly.remove(ostatniId);
+ }
+
+ public static void wpiszDrogiWKwadraty() {
+ utworzSiecDrogowa();
+ GridCoord[] kwadratyOdcinka;
+ for (int i = 0; i < instancja.luki.size(); i++) {
+ LukDrogowy luk = instancja.luki.get(i);
+ GridCoord kw1 = luk.getWezly()[0].idKw;
+ GridCoord kw2 = luk.getWezly()[1].idKw;
+ kwadratyOdcinka = GeomUtils.kwadratyOdcinka(kw1, kw2);
+ wpiszOdcinekDrogiWKwadraty(kwadratyOdcinka);
+ }
+ Teren.zapisBuforaMapyDoPliku();
+ }
+
+ static void wpiszOdcinekDrogiWKwadraty(GridCoord[] kwadratyOdcinka) {
+ if (null == kwadratyOdcinka) {
+ return;
+ }
+ for (int i = 0; i < kwadratyOdcinka.length - 1; i++) {
+ GridCoord idkw1 = kwadratyOdcinka[i];
+ GridCoord idkw2 = kwadratyOdcinka[i + 1];
+ EGeoDirection kier = GeomUtils.kierunekDlaSasiada(idkw1, idkw2);
+ Kwadrat kw = Teren.getKwadrat(idkw1.x, idkw1.y);
+ if (null != kw) {
+ kw.setJestDroga(kier, true);
+ }
+ kw = Teren.getKwadrat(idkw2.x, idkw2.y);
+ if (null != kw) {
+ // wyznaczam kierunek przeciwny
+ kier = kier.oppositeDirect();
+ kw.setJestDroga(kier, true);
+ }
+ }
+ }
+
+ public void aktualizujPliki(boolean wymuszony) throws IOException {
+ if (wymuszony) {
+ if (this.liczbaZmian == 0)
+ // nie bylo modyfikacji od ostatniej zapisu
+ return;
+ this.liczbaZmian = -1;
+ }
+ this.liczbaZmian++;
+ this.liczbaZmian %= LICZBA_ZMIAN;
+ if (0 == this.liczbaZmian) {
+ try {
+ // zapisanie wezlow
+ BufferedWriter bw = new BufferedWriter(new FileWriter(path + "\\nodes.txt"));
+ String linia = Integer.toString(this.wezly.size());
+ bw.write(linia, 0, linia.length());
+ bw.newLine();
+ String s;
+ for (int i = 0; i < this.wezly.size(); i++) {
+ WezelDrogowy wezel = this.wezly.get(i);
+ s = String.format("%07d", wezel.id);
+ linia = s;
+ linia += " ";
+ s = String.format("%010d", wezel.getXms());
+ linia += s;
+ linia += " ";
+ s = String.format("%010d", wezel.getYms());
+ linia += s;
+ linia += " ";
+ int most = 0;
+ if (wezel.jestMostem) {
+ most = 1;
+ }
+ s = String.format("%01d", most);
+ linia += s;
+ bw.write(linia, 0, linia.length());
+ bw.newLine();
+ }
+ bw.close();
+ logger.info("Zapisano plik wezlow sieci drogowej: " + path + "\\nodes.txt");
+ } catch (IOException e) {
+ logger.warn("Blad zapisu pliku wezlow sieci drogowej: " + path + "\\nodes.txt");
+ }
+ try {
+ // zapisanie lukow
+ BufferedWriter bw = new BufferedWriter(new FileWriter(path + "\\arcs.txt"));
+ String linia = Integer.toString(this.luki.size());
+ bw.write(linia, 0, linia.length());
+ bw.newLine();
+ String s;
+ for (int i = 0; i < this.luki.size(); i++) {
+ LukDrogowy luk = this.luki.get(i);
+ s = String.format("%07d", luk.getWezly()[0].id);
+ linia = s;
+ linia += " ";
+ s = String.format("%07d", luk.getWezly()[1].id);
+ linia += s;
+ linia += " ";
+ s = String.format("%05d", luk.dlugosc);
+ linia += s;
+ linia += " ";
+ s = String.format("%02d", luk.szerokosc);
+ linia += s;
+ linia += " ";
+ int most = 0;
+ if (luk.jestMostem) {
+ most = 1;
+ }
+ s = String.format("%01d", most);
+ linia += s;
+ bw.write(linia, 0, linia.length());
+ bw.newLine();
+ }
+ bw.close();
+ logger.info("Zapisano plik lukow sieci drogowej: " + path + "\\arcs.txt");
+ } catch (IOException e) {
+ logger.warn("Blad zapisu pliku lukow sieci drogowej: " + path + "\\arcs.txt");
+ }
+ }
+ }
+
+ // funkcja zwraca kolekcje lukow wewnatrz prostokata
+ // zawartego miedzy lewym dolnym i prawym gornym punktem
+ public static ArrayList dajLukiWObszarze(String wspUtmLD, String wspUtmPG) {
+ utworzSiecDrogowa();
+ int xms = Teren.zamienWspUtmNaWspXms(wspUtmLD);
+ int yms = Teren.zamienWspUtmNaWspYms(wspUtmLD);
+ int xa_ld = GridCoord.zamienWspXmsNaIdKwadratuX(xms);
+ xa_ld /= MapConsts.SS_PER_SHEET;
+ int ya_ld = GridCoord.zamienWspYmsNaIdKwadratuY(yms);
+ ya_ld /= MapConsts.SS_PER_SHEET;
+
+ xms = Teren.zamienWspUtmNaWspXms(wspUtmPG);
+ yms = Teren.zamienWspUtmNaWspYms(wspUtmPG);
+ int xa_pg = GridCoord.zamienWspXmsNaIdKwadratuX(xms);
+ xa_pg /= MapConsts.SS_PER_SHEET;
+ int ya_pg = GridCoord.zamienWspYmsNaIdKwadratuY(yms);
+ ya_pg /= MapConsts.SS_PER_SHEET;
+
+ //if (xa_ld > xa_pg || ya_ld > ya_pg) {
+ // return null;
+ //}
+ if (xa_ld > xa_pg){
+ int tmp = xa_ld;
+ xa_ld = xa_pg;
+ xa_pg = tmp;
+ }
+ if (ya_ld > ya_pg){
+ int tmp = ya_ld;
+ ya_ld = ya_pg;
+ ya_pg = tmp;
+ }
+ ArrayList luki = new ArrayList();
+ // wspolrzedne arkusza mapy
+ for (int xa = xa_ld; xa <= xa_pg; xa++) {
+ for (int ya = ya_ld; ya <= ya_pg; ya++) {
+ if (instancja.arkusze[xa][ya].luki != null) {
+ luki.addAll(instancja.arkusze[xa][ya].luki);
+ }
+ }
+ }
+ return luki;
+ }
+
+ public static void main(String[] args) {
+// GridCoord idKw = GridCoord.zamienWspUtmNaIdKwadratu("520101N0160202E");
+// String utm = GridCoord.zamienIdKwadratuNaWspUtm(idKw);
+// int xms = GridCoord.zamienIdKwadratuXNaWspXms(idKw.x);
+// int yms = GridCoord.zamienIdKwadratuYNaWspYms(idKw.y);
+// utm = Teren.zamienWspXmsYmsNaWspUtm(xms, yms);
+// float lon = GridCoord.zamienIdKwadratuXNaDlugoscGeo(idKw.x);
+// float lat = GridCoord.zamienIdKwadratuYNaSzerokoscGeo(idKw.y);
+// idKw.x = GridCoord.zamienDlugoscGeoNaIdKwadratuX(lon);
+// idKw.y = GridCoord.zamienSzerokoscGeoNaIdKwadratuY(lat);
+ utworzSiecDrogowa();
+ SiecDrogowa.wpiszDrogiWKwadraty();
+ }
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/SmallSquare.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/SmallSquare.java
new file mode 100644
index 0000000..ae90151
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/SmallSquare.java
@@ -0,0 +1,83 @@
+package pl.wat.ms4ds.terenfunkcje;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+public class SmallSquare {
+
+
+ /**
+ * The height above the level of the sea.
+ */
+ short elevation;
+ /**
+ * 0 - BARE_GROUND
+ * 1 - GRASS
+ * 2 - SWAMP
+ * 3 - WATER
+ * 4 - SCRUB, BUSHES
+ * 5 - BUILDINGS
+ * 6 - FOREST
+ */
+ byte terrainType;
+ /**
+ * Rodzaj drogi na danym kierunku.
+ * 0 - no road, 1 - small roads, 2 - minor roads, 3 - major roads
+ */
+// byte[] roads;
+ byte smallRoads;
+ byte minorRoads;
+ byte majorRoads;
+
+ /**
+ * Rodzaj przeszkody wodnej na danym kierunku.
+ * 0 - no watercourse, 1 - drain, ditch, 2 - canal, stream, 3 - river
+ */
+// byte[] waterWays;
+ byte drains;
+ byte streams;
+ byte rivers;
+
+
+ public void reset() {
+ elevation = 0;
+ terrainType = 0;
+ smallRoads = 0;
+ minorRoads = 0;
+ majorRoads = 0;
+ drains = 0;
+ streams = 0;
+ rivers = 0;
+ }
+
+ public void save(ObjectOutputStream out) throws IOException {
+ out.writeShort(elevation);
+ out.writeByte(terrainType);
+ out.writeByte(smallRoads);
+ out.writeByte(minorRoads);
+ out.writeByte(majorRoads);
+ out.writeByte(drains);
+ out.writeByte(streams);
+ out.writeByte(rivers);
+ }
+
+ public void load(ObjectInputStream in) throws IOException {
+ elevation = in.readShort();
+ terrainType = in.readByte();
+ smallRoads = in.readByte();
+ minorRoads = in.readByte();
+ majorRoads = in.readByte();
+ drains = in.readByte();
+ streams = in.readByte();
+ rivers = in.readByte();
+ }
+
+ public SmallSquare(short elevation, byte terrainType) {
+ this.elevation = elevation;
+ this.terrainType = terrainType;
+ }
+
+ public SmallSquare() {
+ }
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/Teren.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/Teren.java
new file mode 100644
index 0000000..2478285
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/Teren.java
@@ -0,0 +1,1103 @@
+package pl.wat.ms4ds.terenfunkcje;
+
+import java.io.*;
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.log4j.Logger;
+import pl.wat.ms4ds.common.EGeoDirection;
+import pl.wat.ms4ds.common.ERodzajPodwozia;
+import pl.wat.ms4ds.common.ERodzajTerenuPokrycie;
+import pl.wat.ms4ds.terenfunkcje.nmt.NMTDataProvider;
+
+import static pl.wat.ms4ds.terenfunkcje.Kwadrat.EMPTY_SQUARE;
+
+public class Teren {
+
+ private static final Logger LOGGER = Logger.getLogger(Teren.class);
+
+ private static final int BIG_X_MAX = 100;
+ private static final int BIG_Y_MAX = 100;
+
+ private static 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[BIG_X_MAX][BIG_Y_MAX];
+
+ private static final float[][] STOPIEN_PRZEJEZDNOSCI;
+
+ private static final String LITERALS = "ABCDEF";
+
+ /**
+ * 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 PLIK_Z_USTAWIENIAMI = "teren.properties";
+
+ 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
+ */
+ public static void zapisBuforaMapyDoPliku() {
+ for (int i = 0; i < bigSquares.length; i++) {
+ for (int j = 0; j < bigSquares[i].length; j++) {
+ BigSquare bs = bigSquares[i][j];
+ if (null != bs && bs instanceof RightBigSquare) {
+ RightBigSquare rbs = (RightBigSquare) bigSquares[i][j];
+ try {
+ rbs.liczbaZmian++;
+ rbs.updateFile(true, null);
+ } catch (IOException e) {
+ LOGGER.warn("Błąd zapisu pliku mapy: " + rbs.fileName);
+ }
+ }
+ }
+ }
+ }
+
+ public static void reset() {
+ for (int i = 0; i < bigSquares.length; i++) {
+ for (int j = 0; j < bigSquares[i].length; j++) {
+ bigSquares[i][j] = null;
+ }
+ }
+ bigSquaresInMemory = 0;
+ for (int i = 0; i < history.length; i++) {
+ history[i].set(-1, -1);
+ }
+ System.gc();
+ }
+
+ // funkcja zwraca reprezentacje danej wspolrzednej UTM w milisekundach
+ public static int zamienWspUtmNaWspXms(String wspolrzedneUtm) {
+ String d = wspolrzedneUtm.substring(8, 10);
+ int ms = Integer.parseInt(d) * MapConsts.DEG_MS;
+ d = wspolrzedneUtm.substring(10, 12);
+ ms += Integer.parseInt(d) * 60000;
+ d = wspolrzedneUtm.substring(12, 14);
+ ms += Integer.parseInt(d) * 1000;
+ if (wspolrzedneUtm.charAt(14) == 'W') {
+ ms = -ms;
+ }
+ ms += 180 * MapConsts.DEG_MS;
+ return ms;
+ }
+
+ // funkcja zwraca reprezentacje danej wspolrzednej UTM w milisekundach
+ public static int zamienWspUtmNaWspYms(String wspolrzedneUtm) {
+ String d = wspolrzedneUtm.substring(0, 2);
+ int ms = Integer.parseInt(d) * MapConsts.DEG_MS;
+ d = wspolrzedneUtm.substring(2, 4);
+ ms += Integer.parseInt(d) * 60000;
+ d = wspolrzedneUtm.substring(4, 6);
+ ms += Integer.parseInt(d) * 1000;
+ if (wspolrzedneUtm.charAt(6) == 'S') {
+ ms = -ms;
+ }
+ ms += 90 * MapConsts.DEG_MS;
+ return ms;
+ }
+
+ public static String zamienWspXmsYmsNaWspUtm(long xms, long yms) {
+ char cx = 'E';
+ // stopnie dlugosci geograficznej
+ long x_st = xms / MapConsts.DEG_MS - 180;
+ if (x_st < 0) {
+ x_st = -x_st;
+ cx = 'W';
+ }
+ long reszta = xms % MapConsts.DEG_MS;
+ // minuty dlugosci geograficznej
+ long x_m = reszta / 60000;
+ // sekundy dlugosci geograficznej
+ long x_s = reszta % 60000;
+ x_s /= 1000;
+
+ char cy = 'N';
+ // stopnie szerokosci geograficznej
+ long y_st = yms / MapConsts.DEG_MS - 90;
+ if (y_st < 0) {
+ y_st = -y_st;
+ cy = 'S';
+ }
+ reszta = yms % MapConsts.DEG_MS;
+ // minuty szerokosci geograficznej
+ long y_m = reszta / 60000;
+ // sekundy szerokosci geograficznej
+ long y_s = reszta % 60000;
+ y_s /= 1000;
+
+ return String.format(
+ "%1$02d%2$02d%3$02d%4$c%5$03d%6$02d%7$02d%8$c", y_st, y_m, y_s, cy, x_st, x_m, x_s, cx);
+ }
+
+ // funkcja wyznacza wspolrzedne UTM ze wspolrzednych dziesietnych
+ // Zalozenie: wspolrzedne w zakresie dlugosc wschodnia do 100 stopni, szerokosc polnocna
+ public static String zamienWspGeoDziesietnieNaWspUtm(float lon, float lat) {
+ int x_st = (int) lon;
+ int y_st = (int) lat;
+
+ float s = (lon - x_st) * 3600;
+ int x_s = (int) s;
+ int x_m = x_s / 60;
+ x_s = x_s % 60;
+
+ s = (lat - y_st) * 3600;
+ int y_s = (int) s;
+ int y_m = y_s / 60;
+ y_s = y_s % 60;
+
+ return String.format("%1$02d%2$02d%3$02dN%4$03d%5$02d%6$02dE", y_st, y_m, y_s, x_st, x_m, x_s);
+ }
+
+ /**
+ * 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 = GridCoord.zamienDlugoscGeoNaIdKwadratuX(lon);
+ int idY = GridCoord.zamienSzerokoscGeoNaIdKwadratuY(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) {
+ if ((bsX < 0) || (bsY < 0)) {
+ return null;
+ }
+ int x_stop = MapConsts.X_REF + 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.Y_REF + 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(MapConsts.KWADRATY_DIR);
+ sb.append(cLon);
+ if (x_stop < 100) {
+ sb.append('0');
+ }
+ if (x_stop < 10) {
+ 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(int bsX, int bsY) {
+ String fName = getFileName(bsX, bsY);
+ try {
+ return new RightBigSquare(fName);
+ } catch (IOException e) {
+ LOGGER.warn("Brak pliku mapy: " + MapConsts.KWADRATY_DIR + fName + ".bin");
+ return EmptyBigSquare.EMPTY_BIG_SQUARE;
+ }
+ }
+
+ private static BigSquare loadAreaNew(int bsX, int bsY) {
+ String fName = getFileName(bsX, bsY);
+ try {
+ RightBigSquare bs = new RightBigSquare();
+ bs.load(fName);
+ return bs;
+ } catch (IOException e) {
+ LOGGER.warn("Brak pliku mapy: " + MapConsts.KWADRATY_DIR + fName + ".bin");
+ return EmptyBigSquare.EMPTY_BIG_SQUARE;
+ }
+ }
+
+ private static ReentrantLock synchr;
+
+ public static Kwadrat getKwadrat(int idX, int idY) {
+ if (idX < 0 || idY < 0) {
+ return EMPTY_SQUARE;
+ }
+ // wspolrzędna x dużego kwadratu
+ int bsX = idX / MapConsts.SS_PER_BS_X;
+ // wspolrzędna y dużego kwadratu
+ int bsY = idY / MapConsts.SS_PER_BS_Y;
+ if (bsX < 0 || bsX >= BIG_X_MAX || bsY < 0 || bsY >= BIG_Y_MAX) {
+ return EMPTY_SQUARE;
+ }
+ // wspolrzędna x małego kwadratu w ramach dużego kwadratu
+ int ssX = idX % MapConsts.SS_PER_BS_X;
+ // wspolrzędna y małego kwadratu w ramach dużego kwadratu
+ int ssY = idY % MapConsts.SS_PER_BS_Y;
+ synchronized (bsSynch[bsX][bsY]) {
+ if (bigSquares[bsX][bsY] == null) {
+ makeRoom(bsX, bsY);
+ bigSquares[bsX][bsY] = loadAreaNew(bsX, bsY);
+ }
+ }
+ return bigSquares[bsX][bsY].getKwadrat(ssX, ssY);
+ }
+
+ public static Kwadrat getKwadrat2(int idX, int idY) {
+ if (idX < 0 || idY < 0) {
+ return EMPTY_SQUARE;
+ }
+ // wspolrzędna x dużego kwadratu
+ int bsX = idX / MapConsts.SS_PER_BS_X;
+ // wspolrzędna y dużego kwadratu
+ int bsY = idY / MapConsts.SS_PER_BS_Y;
+ if (bsX < 0 || bsX >= BIG_X_MAX || bsY < 0 || bsY >= BIG_Y_MAX) {
+ return EMPTY_SQUARE;
+ }
+ // wspolrzędna x małego kwadratu w ramach dużego kwadratu
+ int ssX = idX % MapConsts.SS_PER_BS_X;
+ // wspolrzędna y małego kwadratu w ramach dużego kwadratu
+ int ssY = idY % MapConsts.SS_PER_BS_Y;
+ if (bigSquares[bsX][bsY] == null) {
+ makeRoom(bsX, bsY);
+ bigSquares[bsX][bsY] = loadAreaNew(bsX, bsY);
+ }
+ return bigSquares[bsX][bsY].getKwadrat(ssX, ssY);
+ }
+
+ private static GridCoord[] history = new GridCoord[MapConsts.MAX_BIG_SQUARES_IN_MEMORY];
+ private static int bigSquaresInMemory = 0;
+
+ private static void makeRoom(int bigX, int bigY) {
+ if (bigSquaresInMemory >= MapConsts.MAX_BIG_SQUARES_IN_MEMORY) {
+ // najpierw zapisuję w pliku dokonane zmiany
+ if (bigSquares[history[0].x][history[0].y] instanceof RightBigSquare) {
+ RightBigSquare rbs = (RightBigSquare) bigSquares[history[0].x][history[0].y];
+ try {
+ //!! dla potrzeb generowania danych
+ rbs.liczbaZmian = 1;
+ rbs.updateFile(true, null);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ // następnie usuwam duzy kwadrat z pamięci
+ bigSquares[history[0].x][history[0].y] = null;
+ for (int i = 1; i < history.length; i++) {
+ // przesuwam elementy w lewo
+ history[i - 1].set(history[i]);
+ }
+ // uaktualniam indeksy duzego kwadratu w historii (ostatni == najnowszy element)
+ history[MapConsts.MAX_BIG_SQUARES_IN_MEMORY - 1].x = bigX;
+ history[MapConsts.MAX_BIG_SQUARES_IN_MEMORY - 1].y = bigY;
+ } else {
+ history[bigSquaresInMemory].x = bigX;
+ history[bigSquaresInMemory].y = bigY;
+ bigSquaresInMemory++;
+ }
+ }
+
+ public static Kwadrat getKwadrat(String wspUtm) {
+ int idX = GridCoord.zamienWspUtmNaIdkwadratuX(wspUtm);
+ int idY = GridCoord.zamienWspUtmNaIdkwadratuY(wspUtm);
+ return getKwadrat(idX, idY);
+ }
+
+ public static double getStopienPrzejezdnosci(int x, int y, ERodzajPodwozia podwozie) {
+ Kwadrat kwd = Teren.getKwadrat(x, y);
+ if (kwd == EMPTY_SQUARE) {
+ return 0.0f;
+ }
+ if (kwd.getStopienZabudowy() > 0.0f) {
+ return Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_ZABUDOWANY.id];
+ }
+ if (kwd.getStopienZawodnienia() > 0.9f) {
+ return 0.0f;
+ }
+ double pow_czysta_start = 1 - kwd.getStopienZalesienia()
+ - kwd.getStopienZabagnienia() - kwd.getStopienZawodnienia()
+ - kwd.getStopienZabudowy();
+ double sp = pow_czysta_start
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_CZYSTY.id];
+ sp += kwd.getStopienZalesienia()
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_ZALESIONY.id];
+ sp += kwd.getStopienZabagnienia()
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_ZABAGNIONY.id];
+ sp += kwd.getStopienZawodnienia()
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_ZAWODNIONY.id];
+ sp *= (1.0f - kwd.getStopienPofaldowania());
+ return sp;
+ }
+
+ public static double getStopienPrzejezdnosci(GridCoord id, ERodzajPodwozia podwozie) {
+ return Teren.getStopienPrzejezdnosci(id.x, id.y, podwozie);
+ }
+
+ /**
+ * @param idKwStart kwadrat startowy
+ * @param idKwStop kwadrat docelowy
+ * @param podwozie rodzaj podwozia
+ * @return stopien przejezdnosci pomieszy dwoma kwadratami
+ */
+ public static double getStopienPrzejezdnosci(GridCoord idKwStart, GridCoord idKwStop, EGeoDirection zKierunku,
+ ERodzajPodwozia podwozie) {
+ return getStopienPrzejezdnosci(idKwStart.x, idKwStart.y, idKwStop.x, idKwStop.y, zKierunku, podwozie);
+ }
+
+ /**
+ * 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 double a1;
+ private static 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 double a2;
+ private static 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;
+ }
+
+ /**
+ * Funkcja wyznacza stopień przejezdności między dwoma sąsiednimi kwadratami
+ * uwzględniając warunki terenowe oraz możliwości sprzętu w zakresie pokonywania terenu
+ * bez możliwości pokonywania rzek i rowów.
+ *
+ * @param xStart współrzędna GridCoord.X kwadratu startowego
+ * @param yStart współrzędna GridCoord.Y kwadratu startowego
+ * @param xStop współrzędna GridCoord.X kwadratu docelowego
+ * @param yStop współrzędna GridCoord.Y kwadratu docelowego
+ * @param zKierunku parametr informujący, z którego kierunku znaleziono się w kwadracie startowym
+ * @param podwozie rodzaj podwozia
+ * @return stopien przejezdnosci pomiędzy dwoma sąsiednimi kwadratami
+ */
+ public static double getStopienPrzejezdnosci(int xStart, int yStart, int xStop, int yStop, EGeoDirection zKierunku,
+ ERodzajPodwozia podwozie) {
+ if (podwozie == ERodzajPodwozia.NIEOKRESLONE) {
+ return (przejezdnoscZawsze) ? minStopienPrzejezd : 0.0f;
+ }
+ if (xStart == xStop && yStart == yStop) {
+ return getStopienPrzejezdnosci(xStart, yStart, podwozie);
+ }
+ Kwadrat kwStart = Teren.getKwadrat(xStart, yStart);
+ Kwadrat kwStop = Teren.getKwadrat(xStop, yStop);
+ if (kwStart == EMPTY_SQUARE || kwStop == EMPTY_SQUARE) {
+ return (przejezdnoscZawsze) ? minStopienPrzejezd : 0.0f;
+ }
+ EGeoDirection nowyKierunek = GeomUtils.kierunekDlaSasiada(xStart, yStart, xStop, yStop);
+ if (EGeoDirection.UNDEFINED == nowyKierunek) {
+ LOGGER.warn("Błędna wartość kierunku przy wyznaczaniu stopnia przejezdności.");
+ return (przejezdnoscZawsze) ? minStopienPrzejezd : 0.0f;
+ }
+ int roznicaWysokosci = kwStop.wysokoscSrednia - kwStart.wysokoscSrednia;
+ double tangKataNachyl = roznicaWysokosci / GeomUtils.odlegloscKwadratowSasiednich(nowyKierunek);
+ boolean jestPrzeszkoda = Teren.jestPrzeszkodaNaKierunkuRuchu(xStart, yStart, zKierunku, nowyKierunek);
+ if (jestPrzeszkoda) {
+ if (kwStart.jestDroga[zKierunku.oppositeDirectId] && kwStart.jestDroga[nowyKierunek.id]) {
+ // sprawdzam, czy istnieje droga z kierunku wejsciowego (kierunek przeciwny do zKierunku)
+ // do wyjściowego (nowyKierunek), zatem istnieje most
+ return stopienPrzejezdNaDrodzeNachylenie(tangKataNachyl);
+ }
+ return (przejezdnoscZawsze) ? minStopienPrzejezd : 0.0f;
+ }
+ // jezeli jest droga na kierunku to przejezdnosc 1 (zakładam, że dane są kompletne i istnienie drogi
+ // na tym odcinku implikuje istnienie drogi na komplementarnym odcinku kwadratu docelowego) tj.
+ // kwStop.jestDroga[nowyKierunek.oppositeDirectId] == true
+ if (kwStart.jestDroga[nowyKierunek.id]) {
+ return stopienPrzejezdNaDrodzeNachylenie(tangKataNachyl);
+ }
+ double stopPrzejezdNachylenie = stopienPrzejezdNaPrzelajNachylenie(tangKataNachyl);
+ if (stopPrzejezdNachylenie <= 0.0) {
+ return (przejezdnoscZawsze) ? minStopienPrzejezd : 0.0f;
+ }
+ float stop_pow_czysta_kw_start = 1.0f - kwStart.stopienZalesienia
+ - kwStart.stopienZabagnienia - kwStart.stopienZawodnienia - kwStart.stopienZabudowy;
+ float stop_pow_czysta_kw_stop = 1.0f - kwStop.stopienZalesienia
+ - kwStop.stopienZabagnienia - kwStop.stopienZawodnienia - kwStop.stopienZabudowy;
+ double stopienPrzejezdKwadratStart = stop_pow_czysta_kw_start
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_CZYSTY.id];
+ if (stop_pow_czysta_kw_start < 0.5f) {
+ stopienPrzejezdKwadratStart += kwStart.stopienZalesienia
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_ZALESIONY.id];
+ stopienPrzejezdKwadratStart += kwStart.stopienZabudowy
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_ZABUDOWANY.id];
+ stopienPrzejezdKwadratStart += kwStart.stopienZawodnienia
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_ZAWODNIONY.id];
+ stopienPrzejezdKwadratStart += kwStart.stopienZabagnienia
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_ZABAGNIONY.id];
+ }
+ double stopienPrzejezdKwadratStop = stop_pow_czysta_kw_stop
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_CZYSTY.id];
+ if (stop_pow_czysta_kw_stop < 0.5f) {
+ stopienPrzejezdKwadratStop += kwStop.stopienZalesienia
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_ZALESIONY.id];
+ stopienPrzejezdKwadratStop += kwStop.stopienZabudowy
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_ZABUDOWANY.id];
+ stopienPrzejezdKwadratStop += kwStop.stopienZawodnienia
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_ZAWODNIONY.id];
+ stopienPrzejezdKwadratStop += kwStop.stopienZabagnienia
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_ZABAGNIONY.id];
+ }
+ if (stopienPrzejezdKwadratStart < 0.05 || stopienPrzejezdKwadratStop < 0.05) {
+ return (przejezdnoscZawsze) ? minStopienPrzejezd : 0.0f;
+ }
+ double wynik = (stopienPrzejezdKwadratStart + stopienPrzejezdKwadratStop) * 0.5f;
+ wynik *= stopPrzejezdNachylenie;
+ return (przejezdnoscZawsze) ? Math.max(minStopienPrzejezd, wynik) : wynik;
+ }
+
+ /**
+ * Funkcja wyznacza stopień przejezdności między dwoma sąsiednimi kwadratami
+ * uwzględniając warunki terenowe oraz możliwości sprzętu w zakresie pokonywania terenu, w tym rzek i rowów.
+ *
+ * @param xStart współrzędna GridCoord.X kwadratu startowego
+ * @param yStart współrzędna GridCoord.Y kwadratu startowego
+ * @param xStop współrzędna GridCoord.X kwadratu docelowego
+ * @param yStop współrzędna GridCoord.Y kwadratu docelowego
+ * @param zKierunku parametr informujący, z którego kierunku znaleziono się w kwadracie startowym
+ * @param podwozie rodzaj podwozia
+ * @param szerokoscPokonywRowow szerokość pokonywanych rowów [m]
+ * @param glebokoscBrodzenia maksymalna głębokość brodzenia [m]
+ * @param predkoscPlywania maksymalna predkość pływania [m] (value == 0, to brak możliwości pływania)
+ * @return stopień przejezdności pomiędzy dwoma sąsiednimi kwadratami (wartości z przedziału [0.0, 1.0])
+ */
+ public static double getStopienPrzejezdnosciNew(int xStart, int yStart, int xStop, int yStop, EGeoDirection zKierunku,
+ ERodzajPodwozia podwozie,
+ double szerokoscPokonywRowow,
+ double glebokoscBrodzenia,
+ double predkoscPlywania) {
+ if (podwozie == ERodzajPodwozia.NIEOKRESLONE) {
+ return (przejezdnoscZawsze) ? minStopienPrzejezd : 0.0f;
+ }
+ if (xStart == xStop && yStart == yStop) {
+ return getStopienPrzejezdnosci(xStart, yStart, podwozie);
+ }
+ Kwadrat kwStart = Teren.getKwadrat(xStart, yStart);
+ Kwadrat kwStop = Teren.getKwadrat(xStop, yStop);
+ if (kwStart == EMPTY_SQUARE || kwStop == EMPTY_SQUARE) {
+ return (przejezdnoscZawsze) ? minStopienPrzejezd : 0.0f;
+ }
+ EGeoDirection nowyKierunek = GeomUtils.kierunekDlaSasiada(xStart, yStart, xStop, yStop);
+ if (EGeoDirection.UNDEFINED == nowyKierunek) {
+ LOGGER.warn("Błędna wartość kierunku przy wyznaczaniu stopnia przejezdności.");
+ return (przejezdnoscZawsze) ? minStopienPrzejezd : 0.0f;
+ }
+ int roznicaWysokosci = kwStop.wysokoscSrednia - kwStart.wysokoscSrednia;
+ double odleglosc = GeomUtils.odlegloscKwadratowSasiednich(nowyKierunek);
+ double tangKataNachyl = roznicaWysokosci / odleglosc;
+ double stopienPrzejezdKwadratStart = 1.0;
+ double stopienPrzejezdKwadratStop = 1.0;
+ if (podwozie != ERodzajPodwozia.PODUSZKA_POW) {
+ if (kwStart.stopienZawodnienia > 0.0f) {
+ if (predkoscPlywania > 0.0) {
+ stopienPrzejezdKwadratStart = 0.1;
+ } else {
+ return (przejezdnoscZawsze) ? minStopienPrzejezd : 0.0f;
+ }
+ }
+ if (kwStop.stopienZawodnienia > 0.0f) {
+ if (predkoscPlywania > 0.0) {
+ stopienPrzejezdKwadratStop = 0.1;
+ } else {
+ return (przejezdnoscZawsze) ? minStopienPrzejezd : 0.0f;
+ }
+ }
+ if (stopienPrzejezdKwadratStart + stopienPrzejezdKwadratStop >= 2.0) {
+ // uwzględnienie przeszkodów wodnych tylko gdy badane kwadraty bez pokrycia wodami powierzchniowymi
+ boolean jestPrzeszkoda = Teren.jestPrzeszkodaNaKierunkuRuchu(xStart, yStart, zKierunku, nowyKierunek);
+ if (jestPrzeszkoda) {
+ if (kwStart.jestDroga[zKierunku.oppositeDirectId] && kwStart.jestDroga[nowyKierunek.id]) {
+ // sprawdzam, czy istnieje droga z kierunku wejsciowego (kierunek przeciwny do "zKierunku")
+ // do wyjściowego "nowyKierunek", zatem istnieje most
+ return stopienPrzejezdNaDrodzeNachylenie(tangKataNachyl);
+ } else {
+ // jeśli jest przeszkoda wodna i nie ma mostu, to sprawdzam możliwości przeprawowe sprzętu
+ //TODO wyznaczyć przejezdność na podstawie możliwości przeprawowych sprzętu
+ if (predkoscPlywania > 0.0) {
+ stopienPrzejezdKwadratStart = 0.1;
+ } else {
+ return (przejezdnoscZawsze) ? minStopienPrzejezd : 0.0f;
+ }
+ }
+ }
+ }
+ }
+ // jezeli jest droga na kierunku to przejezdnosc 1 (zakładam, że dane są kompletne i istnienie drogi
+ // na tym odcinku implikuje istnienie drogi na komplementarnym odcinku kwadratu docelowego) tj.
+ // kwStop.jestDroga[nowyKierunek.oppositeDirectId] == true
+ if (kwStart.jestDroga[nowyKierunek.id]) {
+ return stopienPrzejezdNaDrodzeNachylenie(tangKataNachyl);
+ }
+ double stopPrzejezdNachylenie = stopienPrzejezdNaPrzelajNachylenie(tangKataNachyl);
+ if (stopPrzejezdNachylenie <= 0.0) {
+ return (przejezdnoscZawsze) ? minStopienPrzejezd : 0.0f;
+ }
+ if (stopienPrzejezdKwadratStart >= 1.0) {
+ float stop_pow_czysta_kw_start = 1.0f - kwStart.stopienZalesienia
+ - kwStart.stopienZabagnienia - kwStart.stopienZawodnienia - kwStart.stopienZabudowy;
+ stopienPrzejezdKwadratStart = stop_pow_czysta_kw_start
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_CZYSTY.id];
+ if (stop_pow_czysta_kw_start < 0.5f) {
+ stopienPrzejezdKwadratStart += kwStart.stopienZalesienia
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_ZALESIONY.id];
+ stopienPrzejezdKwadratStart += kwStart.stopienZabudowy
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_ZABUDOWANY.id];
+ stopienPrzejezdKwadratStart += kwStart.stopienZawodnienia
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_ZAWODNIONY.id];
+ stopienPrzejezdKwadratStart += kwStart.stopienZabagnienia
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_ZABAGNIONY.id];
+ }
+ }
+ if (stopienPrzejezdKwadratStop >= 1.0) {
+ float stop_pow_czysta_kw_stop = 1.0f - kwStop.stopienZalesienia
+ - kwStop.stopienZabagnienia - kwStop.stopienZawodnienia - kwStop.stopienZabudowy;
+ stopienPrzejezdKwadratStop = stop_pow_czysta_kw_stop
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_CZYSTY.id];
+ if (stop_pow_czysta_kw_stop < 0.5f) {
+ stopienPrzejezdKwadratStop += kwStop.stopienZalesienia
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_ZALESIONY.id];
+ stopienPrzejezdKwadratStop += kwStop.stopienZabudowy
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_ZABUDOWANY.id];
+ stopienPrzejezdKwadratStop += kwStop.stopienZawodnienia
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_ZAWODNIONY.id];
+ stopienPrzejezdKwadratStop += kwStop.stopienZabagnienia
+ * Teren.STOPIEN_PRZEJEZDNOSCI[podwozie.id][ERodzajTerenuPokrycie.TEREN_ZABAGNIONY.id];
+ }
+ }
+ if (stopienPrzejezdKwadratStart < 0.05 || stopienPrzejezdKwadratStop < 0.05) {
+ return (przejezdnoscZawsze) ? minStopienPrzejezd : 0.0f;
+ }
+ double wynik = (stopienPrzejezdKwadratStart + stopienPrzejezdKwadratStop) * 0.5f;
+ wynik *= stopPrzejezdNachylenie;
+ return (przejezdnoscZawsze) ? Math.max(minStopienPrzejezd, wynik) : wynik;
+ }
+
+ /**
+ * Funkcja sprawdza, czy w danym kwadracie na danym, złożonym kierunku ruchu
+ * zadanym przez staryKier-nowyKierunek znajduje się przeszkoda.
+ *
+ * @param xStart współrzędna X kwadratu startowego przemieszczenia
+ * @param yStart współrzędna Y kwadratu startowego przemieszczenia
+ * @param staryKier stary kierunek ruchu
+ * @param nowyKierunek nowy kierunek ruchu
+ * @return true, jeśli jest przeszkoda w danym kwadracie na danym kierunku ruchu zadanym przez staryKier-nowyKierunek
+ */
+ public static boolean jestPrzeszkodaNaKierunkuRuchu(int xStart, int yStart, EGeoDirection staryKier, EGeoDirection nowyKierunek) {
+ // Najpierw sprawdzenie, czy przechodząc po przekątnej nie przecinam przeszkody wodnej lub rowu prostopadłej do ruchu
+ // przechodzącej przez kwadraty sąsiednie bokami np. dla NORTHEAST -> NORTH i EAST
+ Kwadrat kwSasiedni;
+ boolean jestPrzeszkoda = false;
+ switch (nowyKierunek) {
+ case NORTHEAST:
+ kwSasiedni = getKwadrat(xStart, yStart + 1);
+ jestPrzeszkoda = kwSasiedni.jestPrzeszkodaWodna[EGeoDirection.SOUTHEAST.id];
+ break;
+ case SOUTHEAST:
+ kwSasiedni = getKwadrat(xStart, yStart - 1);
+ jestPrzeszkoda = kwSasiedni.jestPrzeszkodaWodna[EGeoDirection.NORTHEAST.id];
+ break;
+ case SOUTHWEST:
+ kwSasiedni = getKwadrat(xStart, yStart - 1);
+ jestPrzeszkoda = kwSasiedni.jestPrzeszkodaWodna[EGeoDirection.NORTHWEST.id];
+ break;
+ case NORTHWEST:
+ kwSasiedni = getKwadrat(xStart, yStart + 1);
+ jestPrzeszkoda = kwSasiedni.jestPrzeszkodaWodna[EGeoDirection.SOUTHWEST.id];
+ break;
+ default:
+ }
+ if (jestPrzeszkoda) {
+ return true;
+ }
+ Kwadrat kwStart = getKwadrat(xStart, yStart);
+ boolean[] przeszkodaWodna = kwStart.jestPrzeszkodaWodna;
+ boolean[] row = ROWY_DLA_PRZEJEZDNOSCI;
+ if (nowyKierunek == EGeoDirection.UNDEFINED) {
+ // przeszkoda
+ return true;
+ }
+ // zmieniam zwrot poprzedniego wektora ruchu, aby oba wektory wychodziły z tego samego punktu
+ staryKier = staryKier.oppositeDirect();
+ if (staryKier == nowyKierunek) {
+ // brak przeszkody na drodze powrotnej
+ return false;
+ }
+ if (przeszkodaWodna[nowyKierunek.id] || row[nowyKierunek.id]) {
+ // przeszkoda na kierunku ruchu
+ return true;
+ }
+ if (staryKier == EGeoDirection.UNDEFINED) {
+ // brak przeszkody
+ return false;
+ }
+ EGeoDirection kierSasiedni = staryKier;
+ // sprawdzam kierunki sąsiędnie idąc zgodnie z ruchem wskazówek zegara
+ do {
+ kierSasiedni = kierSasiedni.rightNextDirect();
+ if (przeszkodaWodna[kierSasiedni.id] || row[kierSasiedni.id]) {
+ // wychodzę z petli, aby sprawdzić kierunki sąsiędnie idąc przeciwnie do ruchu wskazówek zegara
+ break;
+ }
+ } while (kierSasiedni != nowyKierunek);
+ if (kierSasiedni == nowyKierunek) {
+ // brak przeszkody na kierunku ruchu
+ return false;
+ }
+ // sprawdzam kierunki sąsiędnie idąc przeciwnie do ruchu wskazówek zegara
+ kierSasiedni = staryKier;
+ do {
+ kierSasiedni = kierSasiedni.leftNextDirect();
+ if (przeszkodaWodna[kierSasiedni.id] || row[kierSasiedni.id]) {
+ // przeszkoda na kierunku ruchu
+ return true;
+ }
+ } while (kierSasiedni != nowyKierunek);
+ // brak przeszkody
+ return false;
+ }
+
+ /**
+ * Funkcja sprawdza, czy kwadrat przejezdny
+ *
+ * @param gridCoord testowany kwadrat
+ * @return true, jeśli jest przejezdny
+ */
+ public static boolean czyKwadratPrzyjezdny(GridCoord gridCoord) {
+ return getStopienPrzejezdnosci(gridCoord, ERodzajPodwozia.GASIENICE) > 0.01;
+ }
+
+ private Teren() {
+ }
+
+ static {
+ for (int i = 0; i < history.length; i++) {
+ history[i] = new GridCoord();
+ }
+ przejezdnoscZawsze = MapConsts.ustawienia.getProperty("przejezdnosc_zawsze").equals("on");
+ minStopienPrzejezd = Double.parseDouble(MapConsts.ustawienia.getProperty("minimalny_stopien_przejezdnosci"));
+
+ minStopienPrzejezdNaPrzelaj = Double.parseDouble(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.minimalny_na_przelaj"));
+ minStopienPrzejezdNaDrodzeNachylenie = Double.parseDouble(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.minimalny.na_drodze.nachylenie_terenu"));
+ minStopienPrzejezdNaPrzelajNachylenie = Double.parseDouble(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.minimalny.na_przelaj.nachylenie_terenu"));
+
+ minKatNachylTerenuNaDrodze = Double.parseDouble(MapConsts.ustawienia.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.ustawienia.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.ustawienia.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.ustawienia.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.ustawienia.getProperty("stopien_przejezdnosci.podwozie_gasienicowe.teren_zabudowany"));
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.GASIENICE.id][ERodzajTerenuPokrycie.TEREN_ZALESIONY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_gasienicowe.teren_zalesiony"));
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.GASIENICE.id][ERodzajTerenuPokrycie.TEREN_ZABAGNIONY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_gasienicowe.teren_zabagniony"));
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.GASIENICE.id][ERodzajTerenuPokrycie.TEREN_ZAWODNIONY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_gasienicowe.teren_zawodniony"));
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.GASIENICE.id][ERodzajTerenuPokrycie.TEREN_CZYSTY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_gasienicowe.teren_czysty"));
+
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.KOLA_GASIENICE.id][ERodzajTerenuPokrycie.TEREN_ZABUDOWANY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_kolowo_gasienicowe.teren_zabudowany"));
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.KOLA_GASIENICE.id][ERodzajTerenuPokrycie.TEREN_ZALESIONY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_kolowo_gasienicowe.teren_zalesiony"));
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.KOLA_GASIENICE.id][ERodzajTerenuPokrycie.TEREN_ZABAGNIONY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_kolowo_gasienicowe.teren_zabagniony"));
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.KOLA_GASIENICE.id][ERodzajTerenuPokrycie.TEREN_ZAWODNIONY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_kolowo_gasienicowe.teren_zawodniony"));
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.KOLA_GASIENICE.id][ERodzajTerenuPokrycie.TEREN_CZYSTY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_kolowo_gasienicowe.teren_czysty"));
+
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.KOLA.id][ERodzajTerenuPokrycie.TEREN_ZABUDOWANY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_kolowe.teren_zabudowany"));
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.KOLA.id][ERodzajTerenuPokrycie.TEREN_ZALESIONY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_kolowe.teren_zalesiony"));
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.KOLA.id][ERodzajTerenuPokrycie.TEREN_ZABAGNIONY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_kolowe.teren_zabagniony"));
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.KOLA.id][ERodzajTerenuPokrycie.TEREN_ZAWODNIONY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_kolowe.teren_zawodniony"));
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.KOLA.id][ERodzajTerenuPokrycie.TEREN_CZYSTY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_kolowe.teren_czysty"));
+
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.PODUSZKA_POW.id][ERodzajTerenuPokrycie.TEREN_ZABUDOWANY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_poduszka.teren_zabudowany"));
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.PODUSZKA_POW.id][ERodzajTerenuPokrycie.TEREN_ZALESIONY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_poduszka.teren_zalesiony"));
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.PODUSZKA_POW.id][ERodzajTerenuPokrycie.TEREN_ZABAGNIONY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_poduszka.teren_zabagniony"));
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.PODUSZKA_POW.id][ERodzajTerenuPokrycie.TEREN_ZAWODNIONY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_poduszka.teren_zawodniony"));
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.PODUSZKA_POW.id][ERodzajTerenuPokrycie.TEREN_CZYSTY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_poduszka.teren_czysty"));
+
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.PLOZY.id][ERodzajTerenuPokrycie.TEREN_ZABUDOWANY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_plozy.teren_zabudowany"));
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.PLOZY.id][ERodzajTerenuPokrycie.TEREN_ZALESIONY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_plozy.teren_zalesiony"));
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.PLOZY.id][ERodzajTerenuPokrycie.TEREN_ZABAGNIONY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_plozy.teren_zabagniony"));
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.PLOZY.id][ERodzajTerenuPokrycie.TEREN_ZAWODNIONY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_plozy.teren_zawodniony"));
+ STOPIEN_PRZEJEZDNOSCI[ERodzajPodwozia.PLOZY.id][ERodzajTerenuPokrycie.TEREN_CZYSTY.id] =
+ Float.parseFloat(MapConsts.ustawienia.getProperty("stopien_przejezdnosci.podwozie_plozy.teren_czysty"));
+ for (int i = 0; i < BIG_X_MAX; i++) {
+ for (int j = 0; j < BIG_Y_MAX; j++) {
+ bsSynch[i][j] = new Object();
+ }
+ }
+ }
+
+ 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 dir = "C:/users/jrulka/Workspace/_data/new/";
+// Set fileNames = NMTDataProvider.listFiles("C:/Workspace/_data/swdt/ms4ds/teren/kwadraty/100m/");
+// Teren.wygenerujCzysteDane(100, false, false, false, false, true, false, false, false, false);
+ Teren.wygenerujNoweDane(dir, 20);
+// Teren.wygenerujCzysteDane(dir, 25, false, false, false, false, true, false, false, false, false);
+// Teren.wyzerujDane();
+// Teren.zapisBuforaMapyDoPliku();
+
+ // test zapisu i odczytu danych w formacie byte (dane są w kodzie uzupelnieniowym do dwóch tzn. -128..127)
+// StringBuilder sb = new StringBuilder(100);
+// sb.append(MapConsts.KWADRATY_DIR);
+// sb.append("aaa.bin");
+// ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(sb.toString()));
+// int hex = (int) (1.0f * 255.0f);
+//// hex = (hex > 255) ? 255 : hex;
+//// out.writeByte(hex);
+// int hex1 = (int) (0.0f * 255.0f);
+//// out.writeByte(hex1);
+// int hex2 = (int) (0.99 * 255.0f);
+// out.writeByte(0);
+// out.writeByte(1);
+// out.writeByte(20);
+// out.writeByte(100);
+// out.writeByte(5);
+// out.writeByte(127);
+// out.writeByte(128);
+// out.close();
+//
+// ObjectInputStream in = new ObjectInputStream(new FileInputStream(sb.toString()));
+// hex = in.readByte();
+// hex1 = in.readByte();
+// hex2 = in.readByte();
+// hex2 = in.readByte();
+// hex2 = in.readByte();
+// hex2 = in.readByte();
+// byte b = in.readByte();
+// in.close();
+
+
+// WYZEROWANIE DROG W TERENIE
+// for (int x = 14; x < 14 + 11; x++) {
+// for (int dx = 0; dx < 4; dx++) {
+// char cx = LITERALS.charAt(dx);
+// for (int y = 139; y < 139 + 7; y++) {
+// for (int dy = 0; dy < 6; dy++) {
+// char cy = LITERALS.charAt(dy);
+// String fn = String.format("%1$s%2$03d%3$c%4$03d%5$c", PATH, x, cx, y, cy);
+// try {
+// RightBigSquare bs = new RightBigSquare(fn);
+// for (int i = 0; i < bs.kwadraty.length; i++) {
+// for (int j = 0; j < bs.kwadraty[i].length; j++) {
+// Kwadrat kw = bs.kwadraty[i][j];
+//// kw.jestDroga = new boolean[8];
+// kw.stopienZalesienia = 0;
+// }
+// }
+// bs.liczbaZmian = 1;
+// bs.updateFile(true);
+// } catch (IOException e) {
+//// e.printStackTrace();
+// }
+// }
+// }
+// }
+// }
+
+// try {
+// RightBigSquare bs = new RightBigSquare("au2data/new_teren/Polska/kwadraty/50m/014A142D", true);
+//
+// bs.liczbaZmian = 1;
+//// bs.updateFile(true, true);
+// bs.writeFileBinary(true, 50);
+// } catch (IOException e) {
+//// e.printStackTrace();
+// }
+
+
+// WYZEROWANIE WYBRANYCH DANYCH KWADRATOW I ZAPIS W PLIKU WYBRANYM FORMACIE I NAZWIE
+// for (int x = 14; x < 14 + 11; x++) {
+// for (int dx = 0; dx < 4; dx++) {
+// char cx = LITERALS.charAt(dx);
+// for (int y = 49; y < 49 + 7; y++) {
+//// for (int y = 139; y < 139 + 7; y++) {
+// for (int dy = 0; dy < 6; dy++) {
+// char cy = LITERALS.charAt(dy);
+// // NOWY FORMAT NAZWY PLIKU
+//// String fn = String.format("%1$s%2$03d%3$s%4$02d%5$c", "E", x, cx + "_N", y, cy);
+// // STARY FORMAT NAZWY PLIKU
+// String fn = String.format("%1$03d%2$c%3$03d%4$c", x, cx, y + 90, cy);
+// try {
+// RightBigSquare.binary = false;
+// RightBigSquare bs = new RightBigSquare(fn);
+// // wyzerowanie tylko drog
+// bs.resetSquares(false, false, false, false, true, false, false);
+// bs.liczbaZmian = 1;
+// // NOWY FORMAT NAZWY PLIKU
+//// fn = String.format("%1$s%2$03d%3$s%4$02d%5$c", "E", x, cx + "_N", y, cy);
+// RightBigSquare.binary = false;
+// bs.updateFile(true, fn);
+// } catch (IOException e) {
+//// e.printStackTrace();
+// }
+// }
+// }
+// }
+// }
+
+ }
+
+ public static void wyzerujDane() {
+ // WYGENEROWANIE CZYSTYCH PLIKÓW DANYCH
+ for (int x = 0; x < bigSquares.length; x++) {
+ for (int y = 0; y < bigSquares[x].length; y++) {
+ try {
+ BigSquare bs = loadArea(x, y);
+ if (bs != null && bs instanceof RightBigSquare) {
+ RightBigSquare rbs = (RightBigSquare) bs;
+ // wyzerowanie wszystkiego poza wysokością i różnicą wzniesień
+ rbs.resetSquares(true, true, true, true, true, true, true, true, true);
+ rbs.liczbaZmian = 1;
+ rbs.updateFile(true, null);
+ }
+ } catch (IOException e) {
+// e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ * Funkcja uzupełnia brakujące dane wysokosciowe jako średnia kwadratów sąsiednich o niezerowych wysokosciach.
+ * Funkcja powinna być wywoływana dla danych zawierających informacje o wodach morskich.
+ */
+ public static void poprawDaneWysokosciowe() {
+ int maxX = MapConsts.SS_PER_BS_X * MapConsts.BS_PER_DEG_X * MapConsts.DX_REF;
+ int maxY = MapConsts.SS_PER_BS_Y * MapConsts.BS_PER_DEG_Y * MapConsts.DY_REF;
+ for (int x = 0; x < maxX; x++) {
+ for (int y = 0; y < maxY; y++) {
+ Kwadrat kw = getKwadrat(x, y);
+ if (kw == EMPTY_SQUARE) {
+ continue;
+ }
+ if (kw.stopienZawodnienia == 0 && kw.wysokoscSrednia == 0) {
+ // operacja dla kwadratów lądowych
+ int licz = 0;
+ int suma = 0;
+ for (int i = -1; i < 1; i++) {
+ for (int j = -1; j < 1; j++) {
+ if (i == 0 && j == 0) {
+ // pomijam dane bieżącego kwadratu
+ continue;
+ }
+ int xx = x + i;
+ int yy = y + j;
+ Kwadrat kwSasiad = getKwadrat(xx, yy);
+ if (kwSasiad == EMPTY_SQUARE) {
+ // pomijam kwadraty poza mapą
+ continue;
+ }
+ if (kwSasiad.wysokoscSrednia > 0) {
+ // uśredniam tylko po kwadratach o niezerowej wysokości
+ suma += kwSasiad.wysokoscSrednia;
+ licz++;
+ }
+ }
+ }
+ float wys = (float) suma / (float) licz;
+ kw.wysokoscSrednia = (int) wys;
+ }
+ }
+ }
+ for (int x = 0; x < bigSquares.length; x++) {
+ for (int y = 0; y < bigSquares[x].length; y++) {
+ try {
+ BigSquare bs = bigSquares[x][y];
+ if (bs != null && bs instanceof RightBigSquare) {
+ RightBigSquare rbs = (RightBigSquare) bs;
+ rbs.liczbaZmian = 1;
+ rbs.updateFile(true, null);
+ }
+ } catch (IOException e) {
+// e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ * Funkcja poprawia dane o pokryciu, aby dane sumowały się do jedynki.
+ */
+ static void normalizujDanePokrycia() {
+ int maxX = MapConsts.SS_PER_BS_X * MapConsts.BS_PER_DEG_X * MapConsts.DX_REF;
+ int maxY = MapConsts.SS_PER_BS_Y * MapConsts.BS_PER_DEG_Y * MapConsts.DY_REF;
+ for (int x = 0; x < maxX; x++) {
+ for (int y = 0; y < maxY; y++) {
+ Kwadrat kw = getKwadrat(x, y);
+ if (kw == EMPTY_SQUARE) {
+ continue;
+ }
+ float suma = kw.stopienZalesienia + kw.stopienZawodnienia + kw.stopienZabudowy + kw.stopienZabagnienia;
+ if (suma > 1.0f) {
+ kw.stopienZalesienia /= suma;
+ kw.stopienZawodnienia /= suma;
+ kw.stopienZabudowy /= suma;
+ kw.stopienZabagnienia = 1.0f - kw.stopienZalesienia - kw.stopienZawodnienia - kw.stopienZabudowy;
+ }
+ }
+ }
+ for (int x = 0; x < bigSquares.length; x++) {
+ for (int y = 0; y < bigSquares[x].length; y++) {
+ try {
+ BigSquare bs = bigSquares[x][y];
+ if (bs != null && bs instanceof RightBigSquare) {
+ RightBigSquare rbs = (RightBigSquare) bs;
+ rbs.liczbaZmian = 1;
+ rbs.updateFile(true, null);
+ }
+ } catch (IOException e) {
+// e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ * @param dir katalog z danymi terenowymi np. "d:/Workspace2/kwadraty/czyste-wysokosc/"
+ * @param dlmk docelowy rozmiar generowanych kwadratów terenu
+ */
+ public static void wygenerujNoweDane(String dir, int dlmk) {
+ // WYGENEROWANIE CZYSTYCH PLIKÓW DANYCH Z ZACHOWANIEM TYLKO WYSOKOSCI I ROZNICY POZIOMOW WZNIESIEN
+ for (int x = 0; x < bigSquares.length; x++) {
+ for (int y = 0; y < bigSquares[x].length; y++) {
+ try {
+ BigSquare bs = loadArea(x, y);
+ if (bs instanceof RightBigSquare ) {
+ RightBigSquare rbs = (RightBigSquare) bs;
+ // wyzerowanie wszystkiego poza wysokością i różnicą wzniesień
+// rbs.resetSquares(true, true, true, true, true, true, true, true, true);
+ rbs.saveNewFileWithNewScale(dir, dlmk);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/TerrainType.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/TerrainType.java
new file mode 100644
index 0000000..decb47b
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/TerrainType.java
@@ -0,0 +1,38 @@
+package pl.wat.ms4ds.terenfunkcje;
+
+public enum TerrainType {
+ BARE_GROUND(0),
+ GRASS(1),
+ SWAMP(2),
+ WATER(3),
+ SCRUB_BUSHES(4),
+ BUILDINGS(5),
+ FOREST(6);
+
+ static {
+ BARE_GROUND.height = 0;
+ BARE_GROUND.passability = true;
+
+ }
+
+ public int getHeight(byte terrainType) {
+ return height;
+ }
+
+ public final int ID;
+ private int height;
+ /**
+ * Zdolność przekraczania
+ */
+ private boolean passability;
+
+ TerrainType(int id) {
+ this.ID = id;
+ }
+
+ TerrainType(int id, int height, boolean passability) {
+ this.ID = id;
+ this.height = height;
+ this.passability = passability;
+ }
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/TerrainUtils.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/TerrainUtils.java
new file mode 100644
index 0000000..3f73c6b
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/TerrainUtils.java
@@ -0,0 +1,166 @@
+package pl.wat.ms4ds.terenfunkcje;
+
+import pl.wat.ms4ds.common.EGeoDirection;
+import pl.wat.ms4ds.common.ERodzajPodwozia;
+
+import java.util.ArrayList;
+
+
+public class TerrainUtils {
+
+ // ========================================================================
+
+ public static float widocznoscOptyczna(float wysokoscObserwatora, float wysokoscCelu,
+ int x1, int y1, int x2, int y2) {
+ if ((x1 == x2) && (y1 == y2)) {
+ return 1.0f;
+ }
+ Kwadrat kwDo = Teren.getKwadrat(x1, y1);
+ Kwadrat kwOd = Teren.getKwadrat(x2, y2);
+ if (kwDo == Kwadrat.EMPTY_SQUARE || kwOd == Kwadrat.EMPTY_SQUARE) {
+ return 0.0f;
+ }
+ // roznica wysokosci miedzy skrajnymi kwadratami
+ float roznicaWysokosci = kwDo.wysokoscSrednia + wysokoscCelu - kwOd.wysokoscSrednia - wysokoscObserwatora;
+ float wysBezwzgObserwatora;
+ if (roznicaWysokosci < 0) {
+ // sprawdzanie kwOd -> kwDo
+ int swap = x1;
+ x1 = x2;
+ x2 = swap;
+ swap = y1;
+ y1 = y2;
+ y2 = swap;
+ roznicaWysokosci = -roznicaWysokosci;
+ wysBezwzgObserwatora = kwDo.wysokoscSrednia + wysokoscCelu;
+ } else {
+ wysBezwzgObserwatora = kwOd.wysokoscSrednia + wysokoscObserwatora;
+ }
+ GridCoord[] kwadratyNaOdcinku = Bresenham.generateSegment(x1, y1, x2, y2);
+ float dlugoscOdcinka = GridCoord.odleglosc(x1, y1, x2, y2);
+ float tangAlfa0 = roznicaWysokosci / dlugoscOdcinka;
+
+ float dh_max = 0;
+ for (int i = 1; i < kwadratyNaOdcinku.length - 1; i++) {
+ // badanie wewnetrznych kwadratow nalezacych do odcinka,
+ // czy nie sa powyzej linii widocznosci dla kwadratow skrajnych
+ float wysokoscPrzeszkody = 0.0f;
+ Kwadrat kwAkt = Teren.getKwadrat(kwadratyNaOdcinku[i].x, kwadratyNaOdcinku[i].y);
+ if (kwAkt.stopienZalesienia > 0.5f) {
+ wysokoscPrzeszkody = 10.0f;
+ }
+ if (kwAkt.stopienZabudowy > 0.5f) {
+ wysokoscPrzeszkody = 10.0f;
+ }
+ // wyznaczenie roznicy wysokosci kwadratu badanego i docelowego
+ // uwzgledniajac wysokosc obserwatora oraz wysokosc przeszkody
+ float roznWysAkt = kwAkt.wysokoscSrednia + wysokoscPrzeszkody - wysBezwzgObserwatora;
+ if (dh_max >= roznWysAkt) {
+ continue;
+ }
+
+ float odleg = GridCoord.odleglosc(kwadratyNaOdcinku[i].x, kwadratyNaOdcinku[i].y, x1, y1);
+// float tangAlfa = roznWysAkt / odleg;
+// if (tangAlfa0 < tangAlfa) {
+ if (tangAlfa0 * odleg < roznWysAkt) {
+ // wysokosc aktualnie badanego kwadratu jest powyzej/ponizej
+ // linii poprowadzonej z kwadratu startowego do docelowego (z uwzglednieniem wysokosci obserwatora i celu)
+ // odpowiednio dla katow dodatnich/ujemnych
+
+ return 0.0f;
+ }
+ dh_max = roznWysAkt;
+ }
+ return 1.0f;
+ }
+
+ public static float widocznoscOptyczna(int x, int y) {
+ Kwadrat kw = Teren.getKwadrat(x, y);
+ if (kw.stopienZabudowy > 0.25f || kw.stopienZalesienia > 0.25f) {
+ return 0.3f;
+ }
+ return 1.0f;
+ }
+
+ public static float widocznoscOptyczna2(float wysokoscObserwatora, float wysokoscCelu,
+ int x1, int y1, int x2, int y2) {
+ if ((x1 == x2) && (y1 == y2)) {
+ return 1.0f;
+ }
+ Kwadrat kwDo = Teren.getKwadrat(x1, y1);
+ Kwadrat kwOd = Teren.getKwadrat(x2, y2);
+ if (kwDo == Kwadrat.EMPTY_SQUARE || kwOd == Kwadrat.EMPTY_SQUARE) {
+ return 0.0f;
+ }
+ // roznica wysokosci miedzy skrajnymi kwadratami
+ float roznicaWysokosci = kwDo.wysokoscSrednia + wysokoscCelu - kwOd.wysokoscSrednia - wysokoscObserwatora;
+ GridCoord[] kwadratyNaOdcinku = GeomUtils.kwadratyOdcinka(x1, y1, x2, y2);
+ float dlugoscOdcinka = GridCoord.odleglosc(x1, y1, x2, y2);
+ float tangAlfa0 = roznicaWysokosci / dlugoscOdcinka;
+ for (int i = 1; i < kwadratyNaOdcinku.length - 1; i++) {
+ // badanie wewnetrznych kwadratow nalezacych do odcinka,
+ // czy nie sa powyzej linii widocznosci dla kwadratow skrajnych
+ float wysokoscPrzeszkody = 0.0f;
+ Kwadrat kwAkt = Teren.getKwadrat(kwadratyNaOdcinku[i].x, kwadratyNaOdcinku[i].y);
+ if (kwAkt.stopienZalesienia > 0.5f) {
+ wysokoscPrzeszkody = 10.0f;
+ }
+ if (kwAkt.stopienZabudowy > 0.5f) {
+ wysokoscPrzeszkody = 10.0f;
+ }
+ // wyznaczenie roznicy wysokosci kwadratu badanego i docelowego
+ // uwzgledniajac wysokosc obserwatora oraz wysokosc przeszkody
+ float roznWysAkt = kwAkt.wysokoscSrednia + wysokoscPrzeszkody - kwOd.wysokoscSrednia - wysokoscObserwatora;
+ float odleg = GridCoord.odleglosc(kwadratyNaOdcinku[i].x, kwadratyNaOdcinku[i].y, x1, y1);
+ float tangAlfa = roznWysAkt / odleg;
+ if (tangAlfa0 < tangAlfa) {
+ // wysokosc aktualnie badanego kwadratu jest powyzej/ponizej
+ // linii poprowadzonej z kwadratu startowego do docelowego (z uwzglednieniem wysokosci obserwatora i celu)
+ // odpowiednio dla katow dodatnich/ujemnych
+
+ return 0.0f;
+ }
+ }
+ if (kwDo.stopienZabudowy > 0.25f || kwDo.stopienZalesienia > 0.25f) {
+ return 0.3f;
+ }
+ return 1.0f;
+ }
+
+ public static float sredStopienWidoczOptycznej(float wysokoscObserwatora, float wysokoscCelu,
+ GridCoord kwadratOd, int dl1, GridCoord kwadratDo, int dl2) {
+ float stop = 0.0f;
+ for (int x1 = kwadratOd.x; x1 < kwadratOd.x + dl1; x1++)
+ for (int y1 = kwadratOd.y; y1 < kwadratOd.y + dl1; y1++)
+ for (int x2 = kwadratDo.x; x2 < kwadratDo.x + dl2; x2++)
+ for (int y2 = kwadratDo.y; y2 < kwadratDo.y + dl2; y2++)
+ stop += widocznoscOptyczna(wysokoscObserwatora, wysokoscCelu, x1, y1, x2, y2);
+
+ stop /= (dl1 * dl1 * dl2 * dl2);
+ return stop;
+ }
+
+ public static float sredStopienWidoczOptycznej2(float wysokoscObserwatora, float wysokoscCelu,
+ GridCoord kwadratOd, int dl1, GridCoord kwadratDo, int dl2) {
+ float stop = 0.0f;
+ for (int x1 = kwadratOd.x; x1 < kwadratOd.x + dl1; x1++)
+ for (int y1 = kwadratOd.y; y1 < kwadratOd.y + dl1; y1++)
+ for (int x2 = kwadratDo.x; x2 < kwadratDo.x + dl2; x2++)
+ for (int y2 = kwadratDo.y; y2 < kwadratDo.y + dl2; y2++)
+ stop += widocznoscOptyczna2(wysokoscObserwatora, wysokoscCelu, x1, y1, x2, y2);
+
+ stop /= (dl1 * dl1 * dl2 * dl2);
+ return stop;
+ }
+
+ public static float stopienPrzejezdnosciAktualOdcinkaDrogi(ArrayList droga, int pozycja,
+ EGeoDirection zkierunku, ERodzajPodwozia podwozie) {
+ if ((droga == null) || (droga.size() == 0) || (pozycja < 0) || (pozycja >= droga.size() - 1)) {
+ return 0.0f;
+ }
+ GridCoord idKw1 = droga.get(pozycja);
+ GridCoord idKw2 = droga.get(pozycja + 1);
+ return (float) Teren.getStopienPrzejezdnosci(idKw1.x, idKw1.y, idKw2.x, idKw2.y, zkierunku, podwozie);
+ }
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/WezelDrogowy.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/WezelDrogowy.java
new file mode 100644
index 0000000..d9e165e
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/WezelDrogowy.java
@@ -0,0 +1,96 @@
+package pl.wat.ms4ds.terenfunkcje;
+
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+
+public class WezelDrogowy {
+ int id = -1;
+ private int xms = 0;
+ private int yms = 0;
+ boolean jestMostem = false;
+ GridCoord idKw;
+ ArrayList luki = new ArrayList();
+
+ WezelDrogowy() {
+ }
+
+ WezelDrogowy(String opis) {
+ if (null == opis || opis.length() == 0){
+ SiecDrogowa.logger.debug("Pusty ciag opis w konstruktorze Wezla Drogowego.");
+ return;
+ }
+ StringTokenizer st = new StringTokenizer(opis, " \t");
+ String[] tokenTable = new String[st.countTokens()];
+ for (int i = 0; st.hasMoreTokens(); i++) {
+ tokenTable[i] = st.nextToken();
+ }
+ if (tokenTable.length == 3) {
+ try {
+ this.xms = Integer.parseInt(tokenTable[0]);
+ //TODO KONSULTACJA WYWALAMY/ ODKOMENTOWUJEMY
+// //Zabezpieczenie przed zaokraglaniem na krawedziach mapy
+// if (this.xms < MapConsts.X_REF_MS)
+// this.xms = MapConsts.X_REF_MS;
+// if (this.xms > MapConsts.X_REF_MS + MapConsts.DX_REF_MS)
+// this.xms = MapConsts.X_REF_MS + MapConsts.DX_REF_MS;
+ } catch (NumberFormatException e) {
+ SiecDrogowa.logger.warn("Bledne dane w pliku z wezlami [Wezel: " + this.id + " X].");
+ }
+ try {
+ this.yms = Integer.parseInt(tokenTable[1]);
+// //Zabezpieczenie przed zaokraglaniem na krawedziach mapy
+// if (this.yms < MapConsts.Y_REF_MS)
+// this.yms = MapConsts.Y_REF_MS;
+// if (this.yms > MapConsts.Y_REF_MS + MapConsts.DY_REF_MS)
+// this.yms = MapConsts.Y_REF_MS + MapConsts.DY_REF_MS;
+ } catch (NumberFormatException e) {
+ SiecDrogowa.logger.warn("Bledne dane w pliku z wezlami [Wezel: " + this.id + " Y].");
+ }
+ try {
+ this.jestMostem = Integer.parseInt(tokenTable[2]) != 0 ? true : false;
+ } catch (NumberFormatException e) {
+ SiecDrogowa.logger.warn("Bledne dane w pliku z wezlami [Wezel: " + this.id + " czyJestMost].");
+ }
+ int x = GridCoord.zamienWspXmsNaIdKwadratuX(getXms());
+ int y = GridCoord.zamienWspYmsNaIdKwadratuY(getYms());
+ this.idKw = new GridCoord(x, y);
+ }
+ else
+ {
+ SiecDrogowa.logger.warn("Bledne ilosc tokenow w linii [" + opis + "].");
+ }
+ }
+
+ public boolean isJestMostem() {
+ return jestMostem;
+ }
+
+ public void setJestMostem(boolean jestMostem) {
+ this.jestMostem = jestMostem;
+ }
+
+ public GridCoord getIdKw() {
+ return idKw;
+ }
+
+ public void setIdKw(GridCoord idKw) {
+ this.idKw = new GridCoord(idKw);
+ }
+
+ public void setXms(int xms) {
+ this.xms = xms;
+ }
+
+ public int getXms() {
+ return xms;
+ }
+
+ public void setYms(int yms) {
+ this.yms = yms;
+ }
+
+ public int getYms() {
+ return yms;
+ }
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/CoordUtils.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/CoordUtils.java
new file mode 100644
index 0000000..853e895
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/CoordUtils.java
@@ -0,0 +1,485 @@
+package pl.wat.ms4ds.terenfunkcje.konwersja;
+
+import org.apache.log4j.Logger;
+import pl.wat.ms4ds.terenfunkcje.GeoCoord;
+import pl.wat.ms4ds.terenfunkcje.GridCoord;
+import pl.wat.ms4ds.terenfunkcje.Kwadrat;
+import pl.wat.ms4ds.terenfunkcje.Teren;
+
+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).
+ *
+ * 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 = Logger.getLogger(CoordUtils.class);
+
+ static String dataDir = "d:/Workspace2/dane_wysok/";
+
+ public static void main(String[] args) throws Exception {
+
+ HashMap 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 (DaneWysok daneWysok : daneWysokHashMap.values()) {
+ Kwadrat 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.zapisBuforaMapyDoPliku();
+ logger.debug("Koniec zapisu danych dla regionu " + nmt_fn + " >> " + i + "/" + (args.length - 1));
+ Teren.reset();
+ }
+ logger.debug("Start: poprawy danych wysokosciowych");
+ Teren.poprawDaneWysokosciowe();
+ logger.debug("Koniec: poprawy danych wysokosciowych");
+
+
+// GeoCoord latLon = new GeoCoord();
+// PUWGCoord puwgCoord = new PUWGCoord();
+// puwgCoord.easting = 542800.0;
+// puwgCoord.northing = 732200.0;
+// puwgCoord.proj = 1;
+//
+// convertPuwgToLatLon(puwgCoord, latLon);
+// logger.debug("latLon= (" + latLon.lat + ", " + latLon.lon + ")");
+// puwgCoord.easting = 718500.0;
+// puwgCoord.northing = 663500.0;
+// convertPuwgToLatLon(puwgCoord, latLon);
+// logger.debug("latLon= (" + latLon.lat + ", " + latLon.lon + ")");
+
+ }
+
+ private static void readData(String fileName, HashMap 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
+ PUWGCoord puwgCoord = new PUWGCoord();
+ GeoCoord latLon = new GeoCoord();
+ 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);
+ }
+ convertPuwgToLatLon(puwgCoord, latLon);
+ GridCoord idKw = new GridCoord(latLon.lon, latLon.lat);
+ DaneWysok daneWysok = daneWysokHashMap.get(idKw);
+ if (daneWysok == null) {
+ daneWysok = new DaneWysok(idKw, wysokosc, 1);
+ daneWysokHashMap.put(idKw, daneWysok);
+ } else {
+ daneWysok.suma += wysokosc;
+ daneWysok.licz++;
+ }
+ 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;
+ }
+ }
+
+ private static final double fe = 500000.0;
+
+ //Deklaracja tablicy stref rownoleżnikowych
+ private static final char[] cArray = {'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R',
+ 'S', 'T', 'U', 'V', 'W', 'X'};
+// private static final String LITERALS = "CDEFGHJKLMNPQRSTUVWX";
+
+//------------------------------------------------------------------------------
+////////////////////////////////////////////////////////////////////////////////
+//Funkcje pomocnicze
+
+ /// /////////////////////////////////////////////////////////////////////////////
+//------------------------------------------------------------------------------
+ static double calculateESquared(double a, double b) {
+ a *= a;
+ b *= b;
+ return (a - b) / a;
+// return ((a * a) - (b * b)) / (a * a);
+ }
+
+ static double calculateE2Squared(double a, double b) {
+ a *= a;
+ b *= b;
+ return (a - b) / b;
+// return ((a * a) - (b * b)) / (b * b);
+ }
+
+ static double denom(double es, double sphi) {
+ double sinSphi = Math.sin(sphi);
+ return Math.sqrt(1.0 - es * (sinSphi * sinSphi));
+ }
+
+ static double sphsr(double a, double es, double sphi) {
+ double dn = denom(es, sphi);
+ return a * (1.0 - es) / (dn * dn * dn);
+ }
+
+ static double sphsn(double a, double es, double sphi) {
+ double sinSphi = Math.sin(sphi);
+ return a / Math.sqrt(1.0 - es * (sinSphi * sinSphi));
+ }
+
+ static double sphtmd(double ap, double bp, double cp, double dp, double ep, 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));
+ }
+
+ //=======================================================================
+// Funkcja służy do konwersji współrzednych elipsoidalnych B, L (lat/lon) WGS84 na płaskie X-northing, Y-easting odwzorowania kartograficznego UTM
+//=======================================================================
+// Argumenty wejściowe i wyjściowe:
+// --------------------------------
+// int& utmXZone: nr strefy UTM wg. podziału południkowego (zwracane numery od 1 do 60, każda strefa ma sześć stopni)
+// char& utmYZone: nr strefy wg. podziału równoleżnikowego (zwracane wartości: CDEFGHJKLMNPQRSTUVWX)
+// double& easting: współrzędna Y UTM, w metrach po konwersji [metry]
+// double& northing: współrzędna X UTM, w metrach po konwersji [metry]
+// double lat, double lon: współrzędne lat/lon do konwersji [stopnie]
+//=======================================================================
+
+ /**
+ *
+ * @param lat współrzędna lat (szerokość geograficzna) do konwersji [stopnie] (układ WGS84)
+ * @param lon współrzędna lon (długość geograficzna) do konwersji [stopnie] (układ WGS84)
+ * @param utmCoord współrzędne UTM
+ */
+ public static void convertLatLonToUtm(double lat, double lon, UTMCoord utmCoord) {
+ // Współczynnik zniekształcenia skali w południku osiowym
+ double tmd;
+ double nfn;
+ if (lon <= 0.0) {
+ utmCoord.xZone = 30 + (int) (lon / 6.0);
+ } else {
+ utmCoord.xZone = 31 + (int) (lon / 6.0);
+ }
+ if (lat < 84.0 && lat >= 72.0) {
+ // Specjalne zatrzymanie: strefa X ma 12 stopni od północy do południa, nie 8
+ utmCoord.yZone = cArray[19];
+ } else {
+ utmCoord.yZone = cArray[(int) ((lat + 80.0) / 8.0)];
+ }
+ if (lat >= 84.0 || lat < -80.0) {
+ // Błędna wartość szerokości geograficznej (zwracany znak gwiazdki)
+ utmCoord.yZone = '*';
+ }
+ double latRad = lat * DEG_2_RAD;
+ double lonRad = lon * DEG_2_RAD;
+ double olam = (utmCoord.xZone * 6 - 183) * DEG_2_RAD;
+ double dlam = lonRad - olam;
+ double s = Math.sin(latRad);
+ double c = Math.cos(latRad);
+ double t = s / c;
+ double eta = e2Squared * (c * c);
+ double sn = sphsn(a, eSquared, latRad);
+ tmd = sphtmd(ap, bp, cp, dp, ep, latRad);
+ double t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ t1 = tmd * ok;
+ t2 = sn * s * c * ok / 2.0;
+ t3 = sn * s * (c * c * c) * ok * (5.0 - (t * t) + 9.0 * eta + 4.0 * (eta * eta)) / 24.0;
+ t4 = sn * s * (c * c * c * c * c) * ok * (61.0 - 58.0 * (t * t) + (t * t * t * t) + 270.0 * eta - 330.0 * (t * t) * eta + 445.0 * (eta * eta) + 324.0 * (eta * eta * eta) - 680.0 * (t * t) * (eta * eta) + 88.0 * (eta * eta * eta * eta) - 600.0 * (t * t) * (eta * eta * eta) - 192.0 * (t * t) * (eta * eta * eta * eta)) / 720.0;
+ t5 = sn * s * (c * c * c * c * c * c * c) * ok * (1385.0 - 3111.0 * (t * t) + 543.0 * (t * t * t * t) - (t * t * t * t * t * t)) / 40320.0;
+ if (latRad < 0.0) nfn = 10000000.0;
+ else nfn = 0;
+ utmCoord.northing = nfn + t1 + (dlam * dlam) * t2 + (dlam * dlam * dlam * dlam) * t3 + (dlam * dlam * dlam * dlam * dlam * dlam) * t4 + (dlam * dlam * dlam * dlam * dlam * dlam * dlam * dlam) * t5;
+ t6 = sn * c * ok;
+ t7 = sn * (c * c * c) * ok * (1.0 - (t * t) + eta) / 6.0;
+ t8 = sn * (c * c * c * c * c) * ok * (5.0 - 18.0 * (t * t) + (t * t * t * t) + 14.0 * eta - 58.0 * (t * t) * eta + 13.0 * (eta * eta) + 4.0 * (eta * eta * eta) - 64.0 * (t * t) * (eta * eta) - 24.0 * (t * t) * (eta * eta * eta)) / 120.0;
+ t9 = sn * (c * c * c * c * c * c * c) * ok * (61.0 - 479.0 * (t * t) + 179.0 * (t * t * t * t) - (t * t * t * t * t * t)) / 5040.0;
+ utmCoord.easting = fe + dlam * t6 + (dlam * dlam * dlam) * t7 + (dlam * dlam * dlam * dlam * dlam) * t8 + (dlam * dlam * dlam * dlam * dlam * dlam * dlam) * t9;
+ if (utmCoord.northing >= 9999999.0) utmCoord.northing = 9999999.0;
+ }
+
+ //=======================================================================
+// Funkcja służy do konwersji współrzednych elipsoidalnych WGS84 B, L (lat/lon) na płaskie X-northing, Y-easting odwzorowania kartograficznego 1992 i 2000
+//=======================================================================
+// --------------------------------
+// int& utmXZone: nr strefy UTM wg. podziału południkowego (zwracane numery od 1 do 60, każda strefa ma sześć stopni)
+// char& utmYZone: nr strefy wg. podziału równoleżnikowego (zwracane wartości: CDEFGHJKLMNPQRSTUVWX)
+// double& easting: współrzędna Y UTM, w metrach po konwersji [metry]
+// double& northing: współrzędna X UTM, w metrach po konwersji [metry]
+// double lat, double lon: współrzędne lat/lon do konwersji [stopnie]
+// int proj: odwzorowanie kartograficzne (proj = 1 odpowiada odwzorowaniu 1992, natomiast każda inna odwzorowaniu 2000)
+//=======================================================================
+ public static void convertLatLonToPUWG(PUWGCoord puwgCoord, double lat, double lon) {
+ // Współczynnik zniekształcenia skli mapy w południku osiowym dla odwzorowania kartograficznego 2000
+ //Współczynnik zniekształcenia skli mapy w południku osiowym dla odwzorowania kartograficznego 1992
+ double ok_new = (puwgCoord.proj != 1) ? 0.999923 : 0.9993;
+ double olam = 0.0;
+ double tmd;
+ double nfn;
+ double strf = 0.0;
+ if (lon < 13.5 || lon > 25.5) {
+ //Błędna wartość długości geograficznej (zwracana wartość 99999999999999)
+ puwgCoord.easting = 999999999999999.0;
+ puwgCoord.northing = 999999999999999.0;
+ return;
+ } else {
+ if (puwgCoord.proj == 1) {
+ olam = 19.0 * DEG_2_RAD;
+ strf = 0.0;
+ nfn = -5300000.0;
+ } else {
+ nfn = 0;
+ if (lon >= 13.5 && lon < 16.5) {
+ olam = 15.0 * DEG_2_RAD;
+ strf = 5000000.0;
+ }
+
+ if (lon >= 16.5 && lon < 19.5) {
+ olam = 18.0 * DEG_2_RAD;
+ strf = 6000000.0;
+ }
+
+ if (lon >= 19.5 && lon < 22.5) {
+ olam = 21.0 * DEG_2_RAD;
+ strf = 7000000.0;
+ }
+
+ if (lon >= 22.5 && lon < 25.5) {
+ olam = 24.0 * DEG_2_RAD;
+ strf = 8000000.0;
+ }
+ }
+ }
+ double latRad = lat * DEG_2_RAD;
+ double lonRad = lon * DEG_2_RAD;
+ double dlam = lonRad - olam;
+ double s = Math.sin(latRad);
+ double c = Math.cos(latRad);
+ double t = s / c;
+ double eta = e2Squared * (c * c);
+ double sn = sphsn(a, eSquared, latRad);
+ tmd = sphtmd(ap, bp, cp, dp, ep, latRad);
+ double t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ t1 = tmd * ok_new;
+ t2 = sn * s * c * ok_new / 2.0;
+ t3 = sn * s * (c * c * c) * ok_new * (5.0 - (t * t) + 9.0 * eta + 4.0 * (eta * eta)) / 24.0;
+ t4 = sn * s * (c * c * c * c * c) * ok_new * (61.0 - 58.0 * (t * t) + (t * t * t * t) + 270.0 * eta - 330.0 * (t * t) * eta + 445.0 * (eta * eta) + 324.0 * (eta * eta * eta) - 680.0 * (t * t) * (eta * eta) + 88.0 * (eta * eta * eta * eta) - 600.0 * (t * t) * (eta * eta * eta) - 192.0 * (t * t) * (eta * eta * eta * eta)) / 720.0;
+ t5 = sn * s * (c * c * c * c * c * c * c) * ok_new * (1385.0 - 3111.0 * (t * t) + 543.0 * (t * t * t * t) - (t * t * t * t * t * t)) / 40320.0;
+ puwgCoord.northing = nfn + t1 + (dlam * dlam) * t2 + (dlam * dlam * dlam * dlam) * t3 + (dlam * dlam * dlam * dlam * dlam * dlam) * t4 + (dlam * dlam * dlam * dlam * dlam * dlam * dlam * dlam) * t5;
+ t6 = sn * c * ok_new;
+ t7 = sn * (c * c * c) * ok_new * (1.0 - (t * t) + eta) / 6.0;
+ t8 = sn * (c * c * c * c * c) * ok_new * (5.0 - 18.0 * (t * t) + (t * t * t * t) + 14.0 * eta - 58.0 * (t * t) * eta + 13.0 * (eta * eta) + 4.0 * (eta * eta * eta) - 64.0 * (t * t) * (eta * eta) - 24.0 * (t * t) * (eta * eta * eta)) / 120.0;
+ t9 = sn * (c * c * c * c * c * c * c) * ok_new * (61.0 - 479.0 * (t * t) + 179.0 * (t * t * t * t) - (t * t * t * t * t * t)) / 5040.0;
+ puwgCoord.easting = fe + strf + dlam * t6 + (dlam * dlam * dlam) * t7 + (dlam * dlam * dlam * dlam * dlam) * t8 + (dlam * dlam * dlam * dlam * dlam * dlam * dlam) * t9;// + 0.5;
+ }
+
+
+ //=======================================================================
+// Funkcja do konwersji współrzędnych płaskich X/Y UTM na elipsoidalne lat/lon (dla dowolnej elipsoidy)
+//=======================================================================
+// Wymagania:
+// -------------------------------------
+// utmXZone musi być wartością w garanicach od 1 do 60
+// utmYZone musi być jedną z liter: CDEFGHJKLMNPQRSTUVWX
+// Argumenty wejściowe i wyjściowe:
+// ------------------------------------
+// double a: długość dużej półosi, w metrach (np. dla elipsoidy WGS 84, 6378137.0)
+// double f: spłaszczenie elipsoidalne (np. dla elipsoidy WGS 84, 1 / 298.257223563)
+// int utmXZone: nr strefy UTM wg. podziału południkowego (zwracane numery od 1 do 60, każda strefa ma sześć stopni)
+// char utmYZone: nr strefy wg. podziału równoleżnikowego (zwracane wartości: CDEFGHJKLMNPQRSTUVWX)
+// double easting, double northing: współrzędna X, Y UTM do konwersji [metry]
+// double& lat, double& lon: współrzędne elipsoidalne lat/lon po konwersji [stopnie]
+//=======================================================================
+ public static void convertUtmToLatLon(UTMCoord utmCoord, GeoCoord geoCoord) {
+ double nfn;
+ utmCoord.yZone = Character.toUpperCase(utmCoord.yZone);
+ if (utmCoord.yZone <= 'M' && utmCoord.yZone >= 'C') {
+ nfn = 10000000.0;
+ } else {
+ nfn = 0;
+ }
+ double tmd = (utmCoord.northing - nfn) / ok;
+ double sr = sphsr(a, eSquared, 0.0);
+ double ftphi = tmd / sr;
+ double t10, t11, t12, t13, t14, t15, t16, t17;
+ for (int i = 0; i < 5; i++) {
+ t10 = sphtmd(ap, bp, cp, dp, ep, ftphi);
+ sr = sphsr(a, eSquared, ftphi);
+ ftphi = ftphi + (tmd - t10) / sr;
+ }
+ sr = sphsr(a, eSquared, ftphi);
+ double sn = sphsn(a, eSquared, ftphi);
+ double s = Math.sin(ftphi);
+ double c = Math.cos(ftphi);
+ double t = s / c;
+ double eta = e2Squared * (c * c);
+ double de = utmCoord.easting - fe;
+ t10 = t / (2.0 * sr * sn * (ok * ok));
+ t11 = t * (5.0 + 3.0 * (t * t) + eta - 4.0 * (eta * eta) - 9.0 * (t * t) * eta) / (24.0 * sr * (sn * sn * sn) * (ok * ok * ok * ok));
+ t12 = t * (61.0 + 90.0 * (t * t) + 46.0 * eta + 45.0 * (t * t * t * t) - 252.0 * (t * t) * eta - 3.0 * (eta * eta) + 100.0 * (eta * eta * eta) - 66.0 * (t * t) * (eta * eta) - 90.0 * (t * t * t * t) * eta + 88.0 * (eta * eta * eta * eta) + 225.0 * (t * t * t * t) * (eta * eta) + 84.0 * (t * t) * (eta * eta * eta) - 192.0 * (t * t) * (eta * eta * eta * eta)) / (720.0 * sr * (sn * sn * sn * sn * sn) * (ok * ok * ok * ok * ok * ok));
+ t13 = t * (1385.0 + 3633 * (t * t) + 4095.0 * (t * t * t * t) + 1575.0 * (t * t * t * t * t * t)) / (40320 * sr * (sn * sn * sn * sn * sn * sn * sn) * (ok * ok * ok * ok * ok * ok * ok * ok));
+ geoCoord.lat = ftphi - (de * de) * t10 + (de * de * de * de) * t11 - (de * de * de * de * de * de) * t12 + (de * de * de * de * de * de * de * de) * t13;
+ t14 = 1.0 / (sn * c * ok);
+ t15 = (1.0 + 2.0 * (t * t) + eta) / (6.0 * (sn * sn * sn) * c * (ok * ok * ok));
+ t16 = 1.0 * (5.0 + 6.0 * eta + 28.0 * (t * t) - 3.0 * (eta * eta) + 8.0 * (t * t) * eta + 24.0 * (t * t * t * t) - 4.0 * (eta * eta * eta) + 4.0 * (t * t) * (eta * eta) + 24.0 * (t * t) * (eta * eta * eta)) / (120.0 * (sn * sn * sn * sn * sn) * c * (ok * ok * ok * ok * ok));
+ t17 = 1.0 * (61.0 + 662.0 * (t * t) + 1320.0 * (t * t * t * t) + 720.0 * (t * t * t * t * t * t)) / (5040.0 * (sn * sn * sn * sn * sn * sn * sn) * c * (ok * ok * ok * ok * ok * ok * ok));
+ double dlam = de * t14 - (de * de * de) * t15 + (de * de * de * de * de) * t16 - (de * de * de * de * de * de * de) * t17;
+ double olam = (utmCoord.xZone * 6 - 183.0) * DEG_2_RAD;
+ geoCoord.lon = olam + dlam;
+ geoCoord.lon *= RAD_2_DEG;
+ geoCoord.lat *= RAD_2_DEG;
+ }
+
+
+ // Współczynnik zniekształcenia skali mapy w południku osiowym dla odwzorowania kartograficznego UTM
+ private static final double ok = 0.9996;
+ private static final double DEG_2_RAD = Math.PI / 180.0;
+ private static final double RAD_2_DEG = 180.0 / Math.PI;
+ /**
+ * double a: dlługość dużej półsi, w metrach dla elipsoidy WGS-84, 6378137.0
+ */
+ private static final double a = 6378137.0;
+
+ private static final double recf = 298.257223563;
+ /**
+ * double f: spłaszczenie elipsoidalne dla elipsoidy WGS-84, 1 / 298.257223563
+ */
+ private static final double f = 1.0 / recf;
+ // private static final double b = a * (recf - 1) / recf;
+ private static final double b = a * (1.0 - f);
+ private static final double eSquared = calculateESquared(a, b);
+ private static final double e2Squared = 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;
+
+ /**
+ * Funkcja do konwersji współrzędnych płaskich X/Y odwzorowania kartograficznego 1992 i 2000 na elipsoidalne lat/lon elipsoide WGS84.
+ *
+ * PUWGCoord.proj: odwzorowanie kartograficzne (proj = 1 odpowiada odwzorowaniu 1992, natomiast każda inna odwzorowaniu 2000)
+ *
+ * @param puwgCoord współrzędne odwzorowania kartograficznego PUWG-1992 lub PUWG-2000 do konwersji [metry]
+ * @param geoCoord współrzędne geograficzne odwzorowania WGS-84 po konwersji [stopnie]
+ */
+ public static void convertPuwgToLatLon(PUWGCoord puwgCoord, GeoCoord geoCoord) {
+ double ok = (puwgCoord.proj != 1) ? 0.999923 : 0.9993;
+ double nfn;
+ double tmd;
+ double ftphi;
+ double eta;
+ double dlam;
+ double olam = 0.0;
+ double strf = 0.0;
+
+ if (puwgCoord.proj == 1) {
+ olam = 19.0 * DEG_2_RAD;
+ strf = 0.0;
+ nfn = -5300000.0;
+ } else {
+ nfn = 0;
+ if (puwgCoord.easting < 6000000.0 && puwgCoord.easting > 5000000.0) {
+ strf = 5000000.0;
+ olam = 15.0 * DEG_2_RAD;
+ }
+ if (puwgCoord.easting < 7000000.0 && puwgCoord.easting > 6000000.0) {
+ strf = 6000000.0;
+ olam = 18.0 * DEG_2_RAD;
+ }
+ if (puwgCoord.easting < 8000000.0 && puwgCoord.easting > 7000000.0) {
+ strf = 7000000.0;
+ olam = 21.0 * DEG_2_RAD;
+ }
+ if (puwgCoord.easting < 9000000.0 && puwgCoord.easting > 8000000.0) {
+ strf = 8000000.0;
+ olam = 24.0 * DEG_2_RAD;
+ }
+ }
+ tmd = (puwgCoord.northing - nfn) / ok;
+ double sr = sphsr(a, eSquared, 0.0);
+ ftphi = tmd / sr;
+ double t10, t11, t12, t13, t14, t15, t16, t17;
+ for (int i = 0; i < 5; i++) {
+ t10 = sphtmd(ap, bp, cp, dp, ep, ftphi);
+ sr = sphsr(a, eSquared, ftphi);
+ ftphi = ftphi + (tmd - t10) / sr;
+ }
+ sr = sphsr(a, eSquared, ftphi);
+ double sn = sphsn(a, eSquared, 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;
+ eta = e2Squared * (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 = puwgCoord.easting - fe - strf;
+ double de_pow_2 = de * de;
+ double de_pow_3 = de_pow_2 * de;
+ double de_pow_4 = de_pow_3 * de;
+ t10 = t / (2.0 * sr * sn * (ok * ok));
+ t11 = 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 * ok * ok * ok));
+ t12 = 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 * ok * ok * ok * ok * ok));
+ t13 = t * (1385.0 + 3633 * t_pow_2 + 4095.0 * t_pow_4 + 1575.0 * t_pow_6) / (40320 * sr * sn_pow_7 * (ok * ok * ok * ok * ok * ok * ok * ok));
+ geoCoord.lat = ftphi - de_pow_2 * t10 + de_pow_4 * t11 - de_pow_3 * de_pow_3 * t12 + de_pow_4 * de_pow_3 * t13;
+ t14 = 1.0 / (sn * c * ok);
+ t15 = (1.0 + 2.0 * t_pow_2 + eta) / (6.0 * sn_pow_3 * c * (ok * ok * ok));
+ t16 = 1.0 * (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 * ok * ok * ok * ok));
+ t17 = 1.0 * (61.0 + 662.0 * t_pow_2 + 1320.0 * t_pow_4 + 720.0 * t_pow_6) / (5040.0 * sn_pow_7 * c * (ok * ok * ok * ok * ok * ok * ok));
+ dlam = de * t14 - de_pow_3 * t15 + de_pow_3 * de_pow_2 * t16 - de_pow_3 * de_pow_4 * t17;
+ geoCoord.lon = olam + dlam;
+ geoCoord.lon *= RAD_2_DEG;
+ geoCoord.lat *= RAD_2_DEG;
+ }
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/DaneWysok.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/DaneWysok.java
new file mode 100644
index 0000000..006e5ab
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/DaneWysok.java
@@ -0,0 +1,21 @@
+package pl.wat.ms4ds.terenfunkcje.konwersja;
+
+import pl.wat.ms4ds.terenfunkcje.GridCoord;
+
+/**
+ *
+ */
+public class DaneWysok {
+
+ GridCoord idKw;
+
+ double suma;
+
+ int licz;
+
+ public DaneWysok(GridCoord idKw, double suma, int licz) {
+ this.idKw = idKw;
+ this.suma = suma;
+ this.licz = licz;
+ }
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EAreaFeature.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EAreaFeature.java
new file mode 100644
index 0000000..df44fc8
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EAreaFeature.java
@@ -0,0 +1,9 @@
+package pl.wat.ms4ds.terenfunkcje.konwersja;
+
+public enum EAreaFeature {
+
+ FOREST,
+ SWAMP,
+ WATER,
+ BUILDINGS
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/ELinearFeature.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/ELinearFeature.java
new file mode 100644
index 0000000..14da0de
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/ELinearFeature.java
@@ -0,0 +1,8 @@
+package pl.wat.ms4ds.terenfunkcje.konwersja;
+
+public enum ELinearFeature {
+
+ ROAD,
+ WATER_WAY,
+ DITCH
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMAmenity.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMAmenity.java
new file mode 100644
index 0000000..51d121b
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMAmenity.java
@@ -0,0 +1,47 @@
+package pl.wat.ms4ds.terenfunkcje.konwersja;
+
+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;
+ }
+ }
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMBridge.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMBridge.java
new file mode 100644
index 0000000..2c8008e
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMBridge.java
@@ -0,0 +1,19 @@
+package pl.wat.ms4ds.terenfunkcje.konwersja;
+
+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;
+ }
+ }
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMBuilding.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMBuilding.java
new file mode 100644
index 0000000..6e2ed96
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMBuilding.java
@@ -0,0 +1,29 @@
+package pl.wat.ms4ds.terenfunkcje.konwersja;
+
+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;
+ }
+ }
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMHighway.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMHighway.java
new file mode 100644
index 0000000..3ee1995
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMHighway.java
@@ -0,0 +1,50 @@
+package pl.wat.ms4ds.terenfunkcje.konwersja;
+
+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;
+ }
+ }
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMLandcover.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMLandcover.java
new file mode 100644
index 0000000..d7a0e54
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMLandcover.java
@@ -0,0 +1,21 @@
+package pl.wat.ms4ds.terenfunkcje.konwersja;
+
+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;
+ }
+ }
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMLanduse.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMLanduse.java
new file mode 100644
index 0000000..4406bc0
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMLanduse.java
@@ -0,0 +1,21 @@
+package pl.wat.ms4ds.terenfunkcje.konwersja;
+
+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;
+ }
+ }
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMNatural.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMNatural.java
new file mode 100644
index 0000000..d4e28f2
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMNatural.java
@@ -0,0 +1,23 @@
+package pl.wat.ms4ds.terenfunkcje.konwersja;
+
+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;
+ }
+ }
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMWater.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMWater.java
new file mode 100644
index 0000000..4086402
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMWater.java
@@ -0,0 +1,29 @@
+package pl.wat.ms4ds.terenfunkcje.konwersja;
+
+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;
+ }
+ }
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMWaterway.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMWaterway.java
new file mode 100644
index 0000000..422290b
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EOSMWaterway.java
@@ -0,0 +1,27 @@
+package pl.wat.ms4ds.terenfunkcje.konwersja;
+
+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;
+ }
+ }
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EsriFileReader.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EsriFileReader.java
new file mode 100644
index 0000000..867f724
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/EsriFileReader.java
@@ -0,0 +1,210 @@
+package pl.wat.ms4ds.terenfunkcje.konwersja;
+
+import org.apache.log4j.Logger;
+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.terenfunkcje.GridCoord;
+import pl.wat.ms4ds.terenfunkcje.MapConsts;
+import pl.wat.ms4ds.terenfunkcje.Teren;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.HashMap;
+
+public class EsriFileReader {
+ private static final Logger LOGGER = Logger.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 relationsMap = new HashMap<>();
+ HashMap 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.X_REF && currNode.lon <= MapConsts.X_REF + MapConsts.DX_REF
+ && currNode.lat >= MapConsts.Y_REF && currNode.lat <= MapConsts.Y_REF + MapConsts.DY_REF) {
+ jest_wezel_z_obszaru = true;
+ }
+ currNode.lon = Math.max(currNode.lon, MapConsts.X_REF);
+ currNode.lon = Math.min(currNode.lon, MapConsts.X_REF + MapConsts.DX_REF);
+ currNode.lon -= 180;
+ currNode.lat = Math.max(currNode.lat, MapConsts.Y_REF);
+ currNode.lat = Math.min(currNode.lat, MapConsts.Y_REF + MapConsts.DY_REF);
+ currNode.lat -= 90;
+
+ currNode.idX = GridCoord.zamienDlugoscGeoNaIdKwadratuX(currNode.lon);
+ currNode.idY = GridCoord.zamienSzerokoscGeoNaIdKwadratuY(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.zapisBuforaMapyDoPliku();
+// 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.
+ * Jeżeli (x1, y1) mniejsze od (x2, y2) to zwraca -1
+ *
Jeżeli (x1, y1) rowne (x2, y2) to zwraca 0
+ *
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;
+ }
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/MapBounds.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/MapBounds.java
new file mode 100644
index 0000000..8681bd4
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/MapBounds.java
@@ -0,0 +1,11 @@
+package pl.wat.ms4ds.terenfunkcje.konwersja;
+
+/**
+ *
+ */
+public class MapBounds {
+ double minLat;
+ double minLon;
+ double maxLat;
+ double maxLon;
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/Node.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/Node.java
new file mode 100644
index 0000000..6b8cdaa
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/Node.java
@@ -0,0 +1,107 @@
+package pl.wat.ms4ds.terenfunkcje.konwersja;
+
+import pl.wat.ms4ds.terenfunkcje.Kwadrat;
+import pl.wat.ms4ds.terenfunkcje.MapConsts;
+import pl.wat.ms4ds.terenfunkcje.Teren;
+
+/**
+ *
+ */
+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.DL_MK) {
+ 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) {
+ Kwadrat kw = Teren.getKwadrat(idX, idY);
+ kw.setStopienZabudowy(1.0f);
+ } else if (buildingsCount > 0) {
+ Kwadrat kw = Teren.getKwadrat(idX, idY);
+ kw.setStopienZabudowy(0.5f);
+ }
+ }
+
+ @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;
+ }
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/OpenStreetMapReader.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/OpenStreetMapReader.java
new file mode 100644
index 0000000..adec1a8
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/OpenStreetMapReader.java
@@ -0,0 +1,979 @@
+package pl.wat.ms4ds.terenfunkcje.konwersja;
+
+import org.apache.log4j.Logger;
+import pl.wat.ms4ds.terenfunkcje.GridCoord;
+import pl.wat.ms4ds.terenfunkcje.Teren;
+
+import java.io.FileInputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import javax.xml.stream.*;
+
+/**
+ *
+ */
+public class OpenStreetMapReader {
+ private static final Logger LOGGER = Logger.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 relationsMap = new HashMap<>(8000);
+ HashMap relationWaysMap = new HashMap<>(50000);
+ HashMap nodesMap = new HashMap<>(5000000);
+ HashMap buildingNodesMap = new HashMap<>(500000);
+ HashMap waysMap = new HashMap<>(800000);
+ String[] goals = {"lasy", "wody", "bagna", "zabudowa", "drogi", "rzeki", "rowy"};
+ ArrayList 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.zapisBuforaMapyDoPliku();
+ 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 nodesMap, HashMap 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 = GridCoord.zamienDlugoscGeoNaIdKwadratuX(currNode.lon);
+ currNode.idY = GridCoord.zamienSzerokoscGeoNaIdKwadratuY(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 nodesMap, HashMap relationWaysMap,
+ HashMap 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 relationsMap, HashMap 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 relationsMap,
+ HashMap waysMap, HashMap 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 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 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 relationsMap,
+ HashMap waysMap, HashMap buildingNodesMap) {
+ int count = 0;
+ int m1 = relationsMap.size() / 100;
+ m1 = (m1 == 0) ? 1 : m1;
+ ArrayList 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 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);
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/PUWGCoord.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/PUWGCoord.java
new file mode 100644
index 0000000..34e2e5d
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/PUWGCoord.java
@@ -0,0 +1,35 @@
+package pl.wat.ms4ds.terenfunkcje.konwersja;
+
+/**
+ * Współrzędne punktu odwzorowania kartograficznego PUWG 1992 lub 2000.
+ *
+ * Wartośći współrzędnych [metry].
+ *
+ */
+public class PUWGCoord {
+ /**
+ * 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;
+ /**
+ * proj = 1 odpowiada odwzorowaniu 1992, natomiast każda inna odwzorowaniu 2000
+ */
+ public int proj;
+
+ public PUWGCoord() {
+ this.easting = 0;
+ this.northing = 0;
+ // PUWG 1992
+ this.proj = 1;
+ }
+
+ public PUWGCoord(double easting, double northing, int proj) {
+ this.easting = easting;
+ this.northing = northing;
+ this.proj = proj;
+ }
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/Relation.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/Relation.java
new file mode 100644
index 0000000..6c9b4c5
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/Relation.java
@@ -0,0 +1,204 @@
+package pl.wat.ms4ds.terenfunkcje.konwersja;
+
+import org.apache.log4j.Logger;
+
+import java.util.ArrayList;
+
+/**
+ * Bazowa klasa dla obiektów OpenStreetMap.
+ */
+public class Relation {
+ private static final Logger logger = Logger.getLogger(Relation.class);
+
+ public String id;
+ /**
+ * Tag oznacza obiekt obszarowy.
+ * k="natural" - v="water" | v="reservoir" | v="wetland" | v="wood"
+ */
+ public EOSMNatural natural;
+
+ /**
+ * Tag ten oznacza rzekę lub ciek wodny opisywany liniowo.
+ *
Wyjątek: waterway=riverbank, który opisuje obszar.
+ *
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.
+ * k="water" - v="lake" | v="reservoir" | v="river" | v="canal" | v="cove" | v="lagoon" | v="pond"
+ */
+ public EOSMWater water;
+
+ /**
+ * Tag oznacza obiekt obszarowy.
+ * k="landuse" - v="forest" | v="residential" | v="commercial"
+ */
+ public EOSMLanduse landuse;
+
+ /**
+ * Tag oznacza obiekt obszarowy.
+ * k="landcover" - v="trees" | v="water" | v="grass"
+ */
+ public EOSMLandcover landcover;
+
+ ArrayList outerWays = new ArrayList();
+ ArrayList innerWays = new ArrayList();
+
+ 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 generatePolygons(ArrayList wayList) {
+ ArrayList polygons = new ArrayList();
+ 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() +
+ '}';
+ }
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/UTMCoord.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/UTMCoord.java
new file mode 100644
index 0000000..54e246c
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/UTMCoord.java
@@ -0,0 +1,34 @@
+package pl.wat.ms4ds.terenfunkcje.konwersja;
+
+/**
+ * Współrzędna w układzie UTM.
+ * Przykład: 17T 630084 4833438,
+ * gdzie: xZone = 17, yZone = T, easting = 630084, northing = 4833438
+ *
+ * xZone - nr strefy UTM wg. podziału południkowego (zwracane numery od 1 do 60, każda strefa ma sześć stopni);
+ *
+ * yZone - nr strefy wg. podziału równoleżnikowego (zwracane wartości: CDEFGHJKLMNPQRSTUVWX).
+ *
+ * easting - odległość w kierunku wschodnim od początku układu współrzędnych w danej strefie UTM [metr].
+ *
+ * northing - odległość w kierunku północnym od początku układu współrzędnych w danej strefie UTM [metr].
+ */
+public class UTMCoord {
+
+ /**
+ * Nr strefy UTM wg. podziału południkowego (zwracane numery od 1 do 60, każda strefa ma sześć stopni).
+ */
+ public int xZone;
+ /**
+ * Nr strefy wg. podziału równoleżnikowego (zwracane wartości: CDEFGHJKLMNPQRSTUVWX).
+ */
+ public char yZone;
+ /**
+ * Odległość w kierunku wschodnim od początku układu współrzędnych w danej strefie UTM [metr].
+ */
+ public double easting;
+ /**
+ * Odległość w kierunku północnym od początku układu współrzędnych w danej strefie UTM [metr].
+ */
+ public double northing;
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/Way.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/Way.java
new file mode 100644
index 0000000..669d48c
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/Way.java
@@ -0,0 +1,603 @@
+package pl.wat.ms4ds.terenfunkcje.konwersja;
+
+import org.apache.log4j.Logger;
+import pl.wat.ms4ds.common.EGeoDirection;
+import pl.wat.ms4ds.terenfunkcje.*;
+
+import java.util.ArrayList;
+
+/**
+ * Bazowa klasa dla obiektów OpenStreetMap.
+ */
+public class Way {
+ private static final Logger logger = Logger.getLogger(Way.class);
+
+ public String id;
+
+ ArrayList nodes = new ArrayList();
+
+ /**
+ * 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.
+ * k="natural" - v="water" | v="reservoir" | v="wetland" | v="wood"
+ */
+ public EOSMNatural natural;
+
+ /**
+ * Tag ten oznacza rzekę lub ciek wodny opisywany liniowo.
+ *
Wyjątek: waterway=riverbank, który opisuje obszar.
+ *
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.
+ * k="water" - v="lake" | v="reservoir" | v="river" | v="canal" | v="cove" | v="lagoon" | v="pond"
+ */
+ public EOSMWater water;
+
+ /**
+ * Tag oznacza obiekt obszarowy.
+ * 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.
+ * 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 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 node_i;
+ Node node_i_next;
+ Node node_i_prev;
+ boolean collinearFound = false;
+ int dlMax = nodes.size();
+ int iStart = 0;
+ if (!isPolygon) {
+ // łamana otwarta
+ dlMax = nodes.size() - 1;
+ iStart = 1;
+ }
+ for (int i = iStart; i < dlMax; i++) {
+ int i_plus_1 = (i + 1) % nodes.size();
+ int i_minus_1 = (i + nodes.size() - 1) % nodes.size();
+ node_i = nodes.get(i);
+ node_i_next = nodes.get(i_plus_1);
+ node_i_prev = nodes.get(i_minus_1);
+ if (GeomUtils.include(node_i_prev.idX, node_i_prev.idY, node_i_next.idX, node_i_next.idY,
+ node_i.idX, node_i.idY)) {
+ // i-ty do usuniecia
+ toDelete[i] = true;
+ collinearFound = true;
+ } else if (GeomUtils.include(node_i.idX, node_i.idY, node_i_next.idX, node_i_next.idY,
+ node_i_prev.idX, node_i_prev.idY)) {
+ // i-1-ty do usuniecia
+ toDelete[i_minus_1] = true;
+ collinearFound = true;
+ } else if (GeomUtils.include(node_i_prev.idX, node_i_prev.idY, node_i.idX, node_i.idY,
+ node_i_next.idX, node_i_next.idY)) {
+ // i+1-ty do usuniecia
+ toDelete[i_plus_1] = true;
+ collinearFound = true;
+ }
+ }
+ if (collinearFound) {
+ ArrayList newList = new ArrayList();
+ for (int i = 0; i < nodes.size(); i++) {
+ node_i = nodes.get(i);
+ if (!toDelete[i]) {
+ newList.add(node_i);
+ }
+ }
+// 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_j;
+ Node node_k;
+ boolean bylSchodek = false;
+ for (int i = 0; i < nodes.size() - 2; i++) {
+ node_i = nodes.get(i);
+ node_j = nodes.get(i + 1);
+ node_k = nodes.get(i + 2);
+ int absX_i_j = Math.abs(node_j.idX - node_i.idX);
+ int absY_i_j = Math.abs(node_j.idY - node_i.idY);
+ int absX_j_k = Math.abs(node_k.idX - node_j.idX);
+ int absY_j_k = Math.abs(node_k.idY - node_j.idY);
+ if (absX_i_j + absY_i_j + absX_j_k + absY_j_k == 2) {
+ // wezly moga tworzyc schodek
+ if (absX_i_j + absX_j_k == 1) {
+ // wezly tworza schodek, zatem srodkowy wezel schodka do usuniecia
+ toDelete[i + 1] = true;
+ bylSchodek = true;
+ // przeskok o usuwany wezel
+ i++;
+ }
+ }
+ }
+ if (bylSchodek) {
+ ArrayList newList = new ArrayList();
+ 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;
+ }
+ GridCoord[] punktyLamanej = new GridCoord[nodes.size()];
+ for (int i = 0; i < nodes.size(); i++) {
+ punktyLamanej[i] = new GridCoord(nodes.get(i).idX, nodes.get(i).idY);
+ }
+ Kwadrat kw0;
+ Kwadrat kw1;
+ GridCoord id0;
+ GridCoord id1;
+ EGeoDirection kier;
+ GridCoord[] kwadraty = GeomUtils.kwadratyLamanej2(punktyLamanej);
+// float dlug = GeomUtils.dlugoscDrogiPoKwadratch(kwadraty);
+ for (int i = 0; i < kwadraty.length - 1; i++) {
+ try {
+ id0 = kwadraty[i];
+ kw0 = Teren.getKwadrat(id0.x, id0.y);
+ id1 = kwadraty[i + 1];
+ kw1 = Teren.getKwadrat(id1.x, id1.y);
+ kier = GeomUtils.kierunekDlaSasiada(id0, id1);
+ switch (type) {
+ case ROAD:
+ kw0.setJestDroga(kier, true);
+ kw1.setJestDroga(kier.oppositeDirect(), true);
+ break;
+ case WATER_WAY:
+ kw0.setJestPrzeszkodaWodna(kier, true);
+ kw1.setJestPrzeszkodaWodna(kier.oppositeDirect(), true);
+ break;
+ case DITCH:
+ kw0.setJestRow(kier, true);
+ kw1.setJestRow(kier.oppositeDirect(), true);
+ break;
+ default:
+ }
+ } catch (Exception e) {
+ logger.warn(e.toString());
+ }
+ }
+ }
+
+ public static void writeAreaFeatureIntoSquares2(EAreaFeature type, boolean clearFeature, GridCoord[] polygon) {
+ if (polygon.length > 20) {
+ // podział wielokata na dwa mniejsze
+ int m = 2;
+ GridCoord 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;
+ GridCoord 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.rowne(polygon[i].x, polygon[i].y) ||
+ pocz.rowne(polygon[i_puls_1].x, polygon[i_puls_1].y) ||
+ kon.rowne(polygon[i].x, polygon[i].y) ||
+ kon.rowne(polygon[i_puls_1].x, polygon[i_puls_1].y);
+ if (!b) {
+ poprawnyPodzial = false;
+ m++;
+ break;
+ }
+ }
+ }
+ }
+ if (poprawnyPodzial) {
+ // punkt podziału wielokąta jest poprawny, zatem dzielę wielokąt na dwa
+ GridCoord[] polygon1 = new GridCoord[m + 1];
+ for (int i = 0; i < polygon1.length; i++) {
+ polygon1[i] = polygon[i];
+ }
+ writeAreaFeatureIntoSquares2(type, clearFeature, polygon1);
+
+ GridCoord[] polygon2 = new GridCoord[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)
+ GridCoord 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 = (polygon[i].x < minX) ? polygon[i].x : minX;
+ minY = (polygon[i].y < minY) ? polygon[i].y : minY;
+ maxX = (polygon[i].x > maxX) ? polygon[i].x : maxX;
+ maxY = (polygon[i].y > maxY) ? polygon[i].y : maxY;
+ }
+ GridCoord idTest = new GridCoord();
+ boolean inside;
+ for (int j = maxY; j >= minY; j--) {
+ for (int i = minX; i <= maxX; i++) {
+ idTest.x = i;
+ idTest.y = j;
+ Kwadrat kw = Teren.getKwadrat(idTest.x, idTest.y);
+ if (kw == Kwadrat.EMPTY_SQUARE) {
+ continue;
+ }
+ inside = GeomUtils.insidePolygon(polygon, idTest);
+ if (inside) {
+ switch (type) {
+ case FOREST:
+ kw.setStopienZalesienia(val);
+ break;
+ case WATER:
+ kw.setStopienZawodnienia(val);
+ break;
+ case SWAMP:
+ kw.setStopienZabagnienia(val);
+ break;
+ case BUILDINGS:
+ kw.setStopienZabudowy(val);
+ break;
+ default:
+ }
+ }
+ }
+ }
+ }
+
+ public static void writeAreaFeatureIntoSquares(EAreaFeature type, boolean clearFeature, GridCoord[] polygon,
+ int minX,int maxX, int minY, int maxY) {
+ float val = (clearFeature) ? 0.0f : 1.0f;
+ GridCoord idTest = new GridCoord();
+ boolean inside;
+ for (int i = minX; i <= maxX; i++) {
+ for (int j = minY; j <= maxY; j++) {
+ idTest.x = i;
+ idTest.y = j;
+ Kwadrat kw = Teren.getKwadrat(idTest.x, idTest.y);
+ if (kw == Kwadrat.EMPTY_SQUARE) {
+ continue;
+ }
+ inside = GeomUtils.insidePolygon(polygon, idTest);
+ if (inside) {
+ switch (type) {
+ case FOREST:
+ kw.setStopienZalesienia(val);
+ break;
+ case WATER:
+ kw.setStopienZawodnienia(val);
+ break;
+ case SWAMP:
+ kw.setStopienZabagnienia(val);
+ break;
+ case BUILDINGS:
+ kw.setStopienZabudowy(val);
+ break;
+ default:
+ }
+ }
+ }
+ }
+ }
+
+ void writeAreaFeatureIntoSquares2(EAreaFeature type, boolean clearFeature) {
+ if (nodes.size() == 0) {
+ return;
+ }
+ Kwadrat kw;
+ float val = (clearFeature) ? 0.0f : 1.0f;
+ if (nodes.size() == 1) {
+ kw = Teren.getKwadrat(nodes.get(0).idX, nodes.get(0).idY);
+ switch (type) {
+ case FOREST:
+ kw.setStopienZalesienia(val);
+ break;
+ case WATER:
+ kw.setStopienZawodnienia(val);
+ break;
+ case SWAMP:
+ kw.setStopienZabagnienia(val);
+ break;
+ case BUILDINGS:
+ kw.setStopienZabudowy(val);
+ break;
+ default:
+ }
+ return;
+ }
+ if (nodes.size() == 2) {
+ GridCoord[] kwadraty = GeomUtils.kwadratyOdcinka(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.getKwadrat(kwadraty[i].x, kwadraty[i].y);
+ switch (type) {
+ case FOREST:
+ kw.setStopienZalesienia(val);
+ break;
+ case WATER:
+ kw.setStopienZawodnienia(val);
+ break;
+ case SWAMP:
+ kw.setStopienZabagnienia(val);
+ break;
+ case BUILDINGS:
+ kw.setStopienZabudowy(val);
+ break;
+ default:
+ }
+ }
+ return;
+ }
+ GridCoord[] wielokat = new GridCoord[nodes.size()];
+ for (int i = 0; i < nodes.size(); i++) {
+ wielokat[i] = new GridCoord(nodes.get(i).idX, nodes.get(i).idY);
+ }
+ writeAreaFeatureIntoSquares2(type, clearFeature, wielokat);
+ }
+
+ void writeAreaFeatureIntoSquares(EAreaFeature type, boolean clearFeature) {
+ if (nodes.size() == 0) {
+ return;
+ }
+ Kwadrat kw;
+ float val = (clearFeature) ? 0.0f : 1.0f;
+ if (nodes.size() == 1) {
+ kw = Teren.getKwadrat(nodes.get(0).idX, nodes.get(0).idY);
+ switch (type) {
+ case FOREST:
+ kw.setStopienZalesienia(val);
+ break;
+ case WATER:
+ kw.setStopienZawodnienia(val);
+ break;
+ case SWAMP:
+ kw.setStopienZabagnienia(val);
+ break;
+ case BUILDINGS:
+ kw.setStopienZabudowy(val);
+ break;
+ default:
+ }
+ return;
+ }
+ if (nodes.size() == 2) {
+ GridCoord[] kwadraty = GeomUtils.kwadratyOdcinka(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.getKwadrat(kwadraty[i].x, kwadraty[i].y);
+ switch (type) {
+ case FOREST:
+ kw.setStopienZalesienia(val);
+ break;
+ case WATER:
+ kw.setStopienZawodnienia(val);
+ break;
+ case SWAMP:
+ kw.setStopienZabagnienia(val);
+ break;
+ case BUILDINGS:
+ kw.setStopienZabudowy(val);
+ break;
+ default:
+ }
+ }
+ return;
+ }
+ GridCoord[] wielokat = new GridCoord[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 GridCoord(nodes.get(i).idX, nodes.get(i).idY);
+ minX = (wielokat[i].x < minX) ? wielokat[i].x : minX;
+ minY = (wielokat[i].y < minY) ? wielokat[i].y : minY;
+ maxX = (wielokat[i].x > maxX) ? wielokat[i].x : maxX;
+ maxY = (wielokat[i].y > maxY) ? 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;
+ }
+ GridCoord idTest = new GridCoord();
+ boolean nalezyDoWielokata;
+// int liczKw = 0;
+// int liczKwObszaru = 0;
+// for (int j = maxY; j >= minY; j--) {
+// for (int i = minX; i <= maxX; i++) {
+ for (int i = minX; i <= maxX; i++) {
+ for (int j = minY; j <= maxY; j++) {
+ idTest.x = i;
+ idTest.y = j;
+// char c = ' ';
+// liczKw++;
+ kw = Teren.getKwadrat(idTest.x, idTest.y);
+ if (kw == Kwadrat.EMPTY_SQUARE) {
+ continue;
+ }
+ nalezyDoWielokata = GeomUtils.insidePolygon(wielokat, idTest);
+ if (nalezyDoWielokata) {
+// c = 'O';
+ switch (type) {
+ case FOREST:
+ kw.setStopienZalesienia(val);
+ break;
+ case WATER:
+ kw.setStopienZawodnienia(val);
+ break;
+ case SWAMP:
+ kw.setStopienZabagnienia(val);
+ break;
+ case BUILDINGS:
+ kw.setStopienZabudowy(val);
+ 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 +
+ '}';
+ }
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/Worker.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/Worker.java
new file mode 100644
index 0000000..580c9fe
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/konwersja/Worker.java
@@ -0,0 +1,54 @@
+package pl.wat.ms4ds.terenfunkcje.konwersja;
+
+import org.apache.log4j.Logger;
+import pl.wat.ms4ds.terenfunkcje.GridCoord;
+
+import java.util.ArrayList;
+
+/**
+ *
+ */
+public class Worker extends Thread {
+
+ private static final Logger logger = Logger.getLogger(Worker.class);
+
+ static ArrayList workers = new ArrayList<>();
+
+ static Integer nr = 0;
+
+ EAreaFeature type;
+ boolean clearFeature;
+ GridCoord[] polygon;
+ int minX;
+ int maxX;
+ int minY;
+ int maxY;
+
+ public Worker(EAreaFeature type, boolean clearFeature, GridCoord[] 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) * (maxY - minY);
+ synchronized (OpenStreetMapReader.synch) {
+ logger.debug(Thread.currentThread().getName() + " >>> polygon.lent= " + polygon.length + ", ileKwTest= " + Integer.toString(ileKwTest));
+ }
+ Way.writeAreaFeatureIntoSquares(type, clearFeature, polygon, minX, maxX, minY, maxY);
+ synchronized (OpenStreetMapReader.synch) {
+ logger.debug(Thread.currentThread().getName() + " <<< polygon.lent= " + polygon.length + ", ileKwTest= " + Integer.toString(ileKwTest));
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/nmt/NMTDataProvider.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/nmt/NMTDataProvider.java
new file mode 100644
index 0000000..46dff36
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/nmt/NMTDataProvider.java
@@ -0,0 +1,215 @@
+package pl.wat.ms4ds.terenfunkcje.nmt;
+
+import org.apache.log4j.Logger;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamReader;
+import java.io.*;
+import java.net.URI;
+import java.net.URL;
+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.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+public class NMTDataProvider {
+ private static final Logger LOGGER = Logger.getLogger(NMTDataProvider.class);
+
+ public static void main(String[] args) throws Exception {
+// File dir = new File(System.getProperty("user.home") + "/nmt/gugik_SkorowidzNMT2018.gml");
+// HashMap 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 files = listFiles("C:/Workspace/nmt/gugik_1m/");
+
+// downloadFileSet(links_fn, start, end, dir);
+
+// ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
+// executor.execute(() -> {
+// try {
+// downloadFileSet(links_fn, 290, 730, dir);
+// } catch (IOException e) {
+// throw new RuntimeException(e);
+// }
+// });
+// executor.execute(() -> {
+// try {
+// downloadFileSet(links_fn, 779, 1230, dir);
+// } catch (IOException e) {
+// throw new RuntimeException(e);
+// }
+// });
+// executor.shutdown();
+// executor.awaitTermination(25, TimeUnit.MINUTES);
+ LOGGER.info("Koniec");
+ }
+
+ private static void saveLinks(String fn, HashMap 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 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);
+ 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 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();
+ }
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/nmt/NMTReader.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/nmt/NMTReader.java
new file mode 100644
index 0000000..77f880f
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/nmt/NMTReader.java
@@ -0,0 +1,58 @@
+package pl.wat.ms4ds.terenfunkcje.nmt;
+
+import java.io.*;
+
+public class NMTReader {
+
+
+ public static void main(String[] args) {
+// File dir = new File(System.getProperty("user.home") + "/nmt/gugik_SkorowidzNMT2018.gml");
+
+ InputStream is = null;
+ try {
+ File file = new File("C:/Workspace/nmt/N-34-139-A-b-2-4.asc");
+ is = new FileInputStream(file);
+ readFromInputStream(is);
+ //...
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ private static void readFromInputStream(InputStream inputStream) throws IOException {
+ try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStream))) {
+ String line= br.readLine();
+ 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 = Double.parseDouble(split[1]);
+ line= br.readLine();
+ split = line.split(" ");
+ double yll = 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]);
+ while ((line = br.readLine()) != null) {
+ split = line.split(" ");
+
+ }
+ }
+ }
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/DbfField.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/DbfField.java
new file mode 100644
index 0000000..f23bc07
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/DbfField.java
@@ -0,0 +1,37 @@
+package pl.wat.ms4ds.terenfunkcje.osm.shapefile;
+
+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;
+ }
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/DbfHeader.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/DbfHeader.java
new file mode 100644
index 0000000..d1b05de
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/DbfHeader.java
@@ -0,0 +1,80 @@
+package pl.wat.ms4ds.terenfunkcje.osm.shapefile;
+
+import java.io.BufferedInputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Shape File Header Reader.
+ * used for *.dbf-files.
+ *
+ * @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");
+ }
+ }
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/DbfRecord.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/DbfRecord.java
new file mode 100644
index 0000000..de2d598
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/DbfRecord.java
@@ -0,0 +1,68 @@
+package pl.wat.ms4ds.terenfunkcje.osm.shapefile;
+
+import java.io.BufferedInputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+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. If the name in OSM contains
+ * obviously wrong data such as “fixme" or “none”, it will be empty.
+ */
+ String name;
+
+
+ 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");
+ }
+ String str = new String(data, StandardCharsets.UTF_8);
+ // Na pozycji 0 jest flag byte, dane startują od pozycji 1.
+ int from = 1;
+ int to = 1 + header.fields[0].size;
+ 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);
+ endPos = fclass.indexOf(' ');
+ fclass = fclass.substring(0, endPos);
+ from = to;
+ to += header.fields[3].size;
+ name = str.substring(from, to);
+ endPos = name.indexOf(' ');
+ name = name.substring(0, endPos);
+ }
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/Main.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/Main.java
new file mode 100644
index 0000000..255636e
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/Main.java
@@ -0,0 +1,24 @@
+package pl.wat.ms4ds.terenfunkcje.osm.shapefile;
+
+
+public class Main {
+
+ public static void main(String[] args) {
+ try {
+ // GET DIRECTORY
+ String curDir = System.getProperty("user.dir");
+ curDir = "";
+ String folder = "C:/Workspace/osm/dolnoslaskie-251217-free.shp/";
+
+ // LOAD SHAPE FILE (.shp, .shx, .dbf)
+ // gis_osm_buildings_a_free_1
+ // gis_osm_water_a_free_1
+ OsmShapeFileReader shapefile = new OsmShapeFileReader(curDir + folder, "gis_osm_buildings_a_free_1");
+ ShpShape shape = shapefile.nextShape();
+ System.out.println("Shape type = " + shape.getShapeType());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/OsmShapeFileReader.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/OsmShapeFileReader.java
new file mode 100644
index 0000000..f6ba74b
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/OsmShapeFileReader.java
@@ -0,0 +1,125 @@
+package pl.wat.ms4ds.terenfunkcje.osm.shapefile;
+
+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).
+ *
+ * All these files must be in the same folder and start with the same name.
+ * example: "my_shapefile.dbf", "my_shapefile.shp", "my_shapefile.shx"
+ *
+ * http://en.wikipedia.org/wiki/Shapefile"
+ *
+ * @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
+
+ /**
+ *
+ * init the ShapeFile, and load the following files:
+ * "path + filename.shx",
+ * "path + filename.dbf",
+ * "path + filename.shp"
+ *
+ *
+ * @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");
+ FileInputStream is = new FileInputStream(shpFile);
+ bisShp = new BufferedInputStream(is);
+ shpHeader = new ShpHeader(bisShp);
+ File dbfFile = new File(dir, filename + ".dbf");
+ bisDbf = new BufferedInputStream(new FileInputStream(dbfFile));
+ dbfHeader = new DbfHeader(bisDbf);
+ }
+
+ public ShpShape nextShape() throws Exception {
+ boolean hasNext = false;
+ try {
+ hasNext = hasNextShape();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ if (!hasNext) {
+ return null;
+ }
+ ShpShape shape = null;
+ DbfRecord info = null;
+ switch (shpHeader.shapeType) {
+// case Point, PointZ, PointM:
+// shape = new ShpPoint(shpHeader.shapeType);
+// shape.read(bisShp);
+// info = new DbfRecord();
+// info.read(bisDbf, dbfHeader);
+// shape.setInfo(info);
+// return shape;
+// case PolyLine, PolyLineZ, PolyLineM:
+// shape = new ShpPolyLine(shpHeader.shapeType);
+// shape.read(bisShp);
+// info = new DbfRecord();
+// info.read(bisDbf, dbfHeader);
+// shape.setInfo(info);
+// return shape;
+// case Polygon, PolygonZ, PolygonM:
+// shape = new ShpPolygon(shpHeader.shapeType);
+// shape.read(bisShp);
+// info = new DbfRecord();
+// info.read(bisDbf, dbfHeader);
+// shape.setInfo(info);
+// return shape;
+// case MultiPoint, MultiPointZ, MultiPointM:
+// shape = new ShpMultiPoint(shpHeader.shapeType);
+// shape.read(bisShp);
+// info = new DbfRecord();
+// info.read(bisDbf, dbfHeader);
+// shape.setInfo(info);
+// return shape;
+ default:
+ return shape;
+ }
+
+ }
+
+ public boolean hasNextShape() throws IOException {
+ return bisShp.available() > 0;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/ShpHeader.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/ShpHeader.java
new file mode 100644
index 0000000..9161b54
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/ShpHeader.java
@@ -0,0 +1,128 @@
+package pl.wat.ms4ds.terenfunkcje.osm.shapefile;
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Shape File Header Reader.
+ * used for *.shp-files and *.shx-files.
+ * contains information about:
+ * ...
+ * Shape-Type
+ * boundingbox
+ * measure-range
+ * ...
+ *
+ * @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 type ShapeType the shapeFile contains.
+ * a shapeFile contains only one type of shape.
+ *
+ * @return ShpShape.Type
+ */
+ 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.
+ * data storage: [2] --> [min, max]
+ *
+ * @return double[]
+ */
+ public double[] getMeasureRange() {
+ return rangeM;
+ }
+
+ /**
+ * get length in bytes of the shapeFile.
+ *
+ * @return length in bytes.
+ */
+ public int getFileLengthBytes() {
+ 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;
+ }
+
+
+ public void print() {
+ }
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/ShpMultiPoint.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/ShpMultiPoint.java
new file mode 100644
index 0000000..41901e4
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/ShpMultiPoint.java
@@ -0,0 +1,70 @@
+package pl.wat.ms4ds.terenfunkcje.osm.shapefile;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Shape: MultiPoint.
+ *
+ * A MultiPoint represents a set of points.
+ * Possible ShapeTypes:
+ * MultiPoint ( 8 ),
+ * MultiPointZ ( 18 ),
+ * MultiPointM ( 28 ),
+ *
+ *
+ * @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 readRecordContent(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.hasZvalues()) {
+ 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.hasMvalues()) {
+ 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
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/ShpPoint.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/ShpPoint.java
new file mode 100644
index 0000000..93e739c
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/ShpPoint.java
@@ -0,0 +1,45 @@
+package pl.wat.ms4ds.terenfunkcje.osm.shapefile;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Shape: Point.
+ *
+ * possible ShapeTypes:
+ * Point ( 1 ),
+ * PointZ ( 11 ),
+ * PointM ( 21 ),
+ *
+ *
+ * @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 readRecordContent(ByteBuffer bb) {
+ x = bb.getDouble(); // x - coordinate
+ y = bb.getDouble(); // y - coordinate
+ // if SHAPE-TYPE: 11
+ if (type.hasZvalues()) {
+ z = bb.getDouble(); // z - coordinate
+ }
+ // if SHAPE-TYPE: 11 | 21
+ if (type.hasMvalues()) {
+ m = bb.getDouble(); // m - value
+ }
+ }
+
+
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/ShpPollyShape.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/ShpPollyShape.java
new file mode 100644
index 0000000..2e083ab
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/ShpPollyShape.java
@@ -0,0 +1,66 @@
+package pl.wat.ms4ds.terenfunkcje.osm.shapefile;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Base class for PollyLine, Pollygon
+ */
+public abstract class ShpPollyShape extends ShpShape {
+ // SHAPE RECORD CONTENT
+ double xMin;
+ double yMin;
+ double zMin;
+ double mMin;
+ double xMax;
+ double yMax;
+ double zMax;
+ double mMax;
+ private int numberOfParts;
+ private int numberOfPoints;
+ private int[] partsPos;
+ double[] pointsX; // [number of points][x,y,z]
+ double[] pointsY;
+ double[] pointsZ;
+ double[] valuesM; // [number of points][m-value]
+
+ public ShpPollyShape(ShpShape.Type shape_type) {
+ super(shape_type);
+ }
+
+ @Override
+ protected void readRecordContent(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.hasZvalues()) {
+ 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.hasMvalues()) {
+ 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
+ }
+ }
+ }
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/ShpPolyLine.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/ShpPolyLine.java
new file mode 100644
index 0000000..7d562f4
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/ShpPolyLine.java
@@ -0,0 +1,28 @@
+package pl.wat.ms4ds.terenfunkcje.osm.shapefile;
+
+import java.nio.ByteBuffer;
+import java.util.Locale;
+
+/**
+ * Shape: PolyLine.
+ *
+ * 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 ),
+ *
+ *
+ * @author jrulka
+ *
+ */
+public class ShpPolyLine extends ShpPollyShape {
+
+ public ShpPolyLine(Type shape_type) {
+ super(shape_type);
+ }
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/ShpPolygon.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/ShpPolygon.java
new file mode 100644
index 0000000..e46d239
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/ShpPolygon.java
@@ -0,0 +1,26 @@
+package pl.wat.ms4ds.terenfunkcje.osm.shapefile;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Shape: Polygon.
+ *
+ * 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 ),
+ *
+ *
+ * @author jrulka
+ *
+ */
+public class ShpPolygon extends ShpPollyShape {
+
+ public ShpPolygon(Type shape_type) {
+ super(shape_type);
+ }
+}
diff --git a/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/ShpShape.java b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/ShpShape.java
new file mode 100644
index 0000000..a2e4441
--- /dev/null
+++ b/src/main/java/pl/wat/ms4ds/terenfunkcje/osm/shapefile/ShpShape.java
@@ -0,0 +1,195 @@
+package pl.wat.ms4ds.terenfunkcje.osm.shapefile;
+
+import java.io.BufferedInputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Base class for Shapes.
+ *
+ * @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).
+ *
+ */
+ 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
+ readRecordHeader(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) {
+ readRecordContent(bb);
+ } else if (shape_type != type) {
+ throw new Exception("(Shape) shape_type = " + shape_type + ", but expected " + type);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ protected void readRecordHeader(ByteBuffer bb) {
+ bb.order(ByteOrder.BIG_ENDIAN);
+ recordNumber = bb.getInt();
+ contentLength = bb.getInt();
+ }
+
+ protected abstract void readRecordContent(ByteBuffer bb);
+
+ void setInfo(DbfRecord info) {
+ this.info = info;
+ }
+
+ /**
+ * get the record number of the shape.
+ *
+ * @return record number
+ */
+ public int getRecordNumber() {
+ return recordNumber;
+ }
+
+ /**
+ * get the Type of the Shape.
+ *
+ * @return ShpShape.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 has_z_values;
+ boolean has_m_values;
+
+ Type(int code, boolean has_z_values, boolean has_m_values) {
+ this.has_z_values = has_z_values;
+ this.has_m_values = has_m_values;
+ this.code = code;
+ }
+
+ public static Type getByCode(int ID) throws Exception {
+ for (Type st : Type.values())
+ if (st.code == ID)
+ return st;
+ throw new Exception("ShapeType: " + ID + " does not exist");
+ }
+
+ public boolean hasZvalues() {
+ return has_z_values;
+ }
+
+ public boolean hasMvalues() {
+ return has_m_values;
+ }
+
+ 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);
+ }
+ }
+
+}
diff --git a/teren.properties b/teren.properties
new file mode 100644
index 0000000..39c22f8
--- /dev/null
+++ b/teren.properties
@@ -0,0 +1,76 @@
+#Polska
+#Wspolrzedne referencyjne i wielkosc obszaru
+x_ref=14
+y_ref=49
+dx_ref=11
+dy_ref=7
+#kwadraty_dir=c:/Workspace/git/teren-funkcje/au2data/new_teren/Polska/kwadraty/
+kwadraty_dir=C:/Workspace/_data/swdt/ms4ds/teren/kwadraty/
+drogi_dir=au2data/new_teren/Polska/drogi/
+
+#Afganistan
+#Wspolrzedne referencyjne i wielkosc obszaru
+#x_ref=60
+#y_ref=29
+#dx_ref=15
+#dy_ref=10
+#kwadraty_dir=/au2data/new_teren/Afganistan/kwadraty/
+#drogi_dir=/au2data/new_teren/Afganistan/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 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
+