summaryrefslogtreecommitdiffstats
path: root/DataStructure/GSMMap.java
diff options
context:
space:
mode:
Diffstat (limited to 'DataStructure/GSMMap.java')
-rw-r--r--DataStructure/GSMMap.java1275
1 files changed, 1275 insertions, 0 deletions
diff --git a/DataStructure/GSMMap.java b/DataStructure/GSMMap.java
new file mode 100644
index 0000000..88f573c
--- /dev/null
+++ b/DataStructure/GSMMap.java
@@ -0,0 +1,1275 @@
+package DataStructure;
+
+import helper.ListBTS;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.geom.Point2D;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Serializable;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+
+import org.jdesktop.swingx.JXMapViewer;
+import org.jdesktop.swingx.mapviewer.GeoPosition;
+import org.jdesktop.swingx.painter.Painter;
+
+import Parse.sqlreader;
+
+public class GSMMap implements Painter<JXMapViewer>, Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 7231890635513775719L;
+ public double minX;
+ public double maxX;
+ public double minY;
+ public double maxY;
+ public double[] Xcoords;
+ public double[] Ycoords;
+ public double accuracy;
+ public ArrayList<SingleBTS>[][] map;
+ // public ArrayList<SingleBTS>[][] buffer;
+ public SingleBTS[] btsnames; // names of BTS from sql databse
+ private SingleBTS[] btsarray; // btsarray from sqlreader.
+ private GPScoordinate[] gpsarray;
+ public long IMSI;
+ private int matrixsize;
+ private boolean isAveraged = false;
+ private SingleBTS[] mapcontent;
+ public int numberOfCoordinates;
+ public PaintEnum whatToPaint = PaintEnum.DL;
+ public int indexToPaint;
+
+ // Constructor
+ public GSMMap(sqlreader SQL, double accuracy) {
+ // search for min and max Y,X Coords
+ this.accuracy = accuracy;
+ numberOfCoordinates = SQL.gpsarray.length;
+ gpsarray = SQL.gpsarray; // measured GPS coordinates
+ btsarray = SQL.btsarray; // corresponding found BTS
+ btsnames = SQL.BtsNames;
+ this.IMSI = SQL.IMSI;
+ minX = MapHelper.getMinX(gpsarray, 0d);
+ maxX = MapHelper.getMaxX(gpsarray, 0d);
+ minY = MapHelper.getMinY(gpsarray, 0d);
+ maxY = MapHelper.getMaxY(gpsarray, 0d);
+ Xcoords = MapHelper.createArray(minX, maxX, accuracy); // 90°
+ Ycoords = MapHelper.createArray(minY, maxY, accuracy); // 180°
+ // create Array with inside ArrayList
+ ArrayList<SingleBTS>[][] map = new ArrayList[Xcoords.length][Ycoords.length];
+ this.map = map;
+ // initializa map
+ for (int x = 0; x < Xcoords.length; x++) {
+ for (int y = 0; y < Ycoords.length; y++) {
+ map[x][y] = new ArrayList<SingleBTS>();
+ }
+ }
+
+ // fill map
+ for (int i = 0; i < gpsarray.length; i++) {
+ add(gpsarray[i], btsarray[i]);
+ }
+
+ }
+
+ public void add(GPScoordinate gps, SingleBTS bts) {
+ int x = searchBestX(gps.coord2);
+ int y = searchBestY(gps.coord1);
+ map[x][y].add(bts);
+
+ }
+
+ public void add(GPScoordinate gps, ArrayList<SingleBTS> list) {
+ if (list == null)
+ return;
+ int x = searchBestX(gps.coord2);
+ int y = searchBestY(gps.coord1);
+ map[x][y].addAll(list);
+ }
+
+ /**
+ * Averages all MR that fall into one tile. Does not depend on usedBTS from
+ * sql
+ */
+ public void average() {
+ for (int x = 0; x < Xcoords.length; x++) {
+ for (int y = 0; y < Ycoords.length; y++) {
+ SingleBTS[] content = MapHelper.content(map[x][y]);
+ if (content != null) {
+ map[x][y] = generateAveragedList(map[x][y], content);
+ }
+ }
+ }
+ // after averaging the distances can be calculated pretty fast
+ calc_distances();
+ isAveraged = true;
+
+ }
+
+ /**
+ * calculates distance for every measurement report in the gsm map. Reports
+ * distance = 0 if Distance can not be computed
+ */
+ public void calc_distances() {
+ for (int x = 0; x < Xcoords.length; x++) {
+ for (int y = 0; y < Ycoords.length; y++) {
+ for (int z = 0; z < map[x][y].size(); z++) {
+ SingleBTS corr = corrBTS(map[x][y].get(z));
+ if (corr == null) {
+ // if Distance could not be calculated, skip
+ map[x][y].get(z).distance = 0.0;
+ } else {
+ // corresponding BTS was found
+ GPScoordinate coord1 = corr.coordinate;
+ GPScoordinate coord2 = getCoord(x, y);
+ map[x][y].get(z).distance = helper.Distance.calc(
+ coord1, coord2);
+ }
+ }
+
+ }
+ }
+ }
+
+ /**
+ * returns corresponding BTS from SQL-arfcn table for this MR
+ *
+ * @param mr
+ * your MR
+ * @return BTS that fits to this MR. Null if not found
+ */
+ private SingleBTS corrBTS(SingleBTS mr) {
+ for (int i = 0; i < btsnames.length; i++) {
+ if (mr.ARFCN == btsnames[i].ARFCN)
+ return btsnames[i];
+ }
+ return null;
+ }
+
+ private SingleBTS corrBTS(int arfcn) {
+ SingleBTS element = new SingleBTS(arfcn, "whatever");
+ return corrBTS(element);
+ }
+
+ public GPScoordinate getCoord(int x, int y) {
+ return new GPScoordinate(null, Ycoords[y], 'N', Xcoords[x], 'E', true);
+ }
+
+ /**
+ * Gets all BTSs that occur in the GSMmap. Note: this may be different from
+ * the BTSarray. There may be BTSs that are not stored in the sql database.
+ * For example: E-Plus BTSs
+ *
+ * @return Array with BTSs that occur in the GSMmap
+ */
+ public SingleBTS[] getUniqueBTSlist() {
+
+ ArrayList<SingleBTS> BTSlist = new ArrayList<SingleBTS>();
+ for (int x = 0; x < btsarray.length; x++) {
+ BTSlist.add(btsarray[x]);
+ }
+ return helper.ListBTS.content(BTSlist);
+
+ }
+
+ private ArrayList<SingleBTS> generateAveragedList(
+ ArrayList<SingleBTS> List, SingleBTS[] content) {
+ ArrayList<SingleBTS> output = new ArrayList<SingleBTS>();
+ // traverse every unique BTS
+ for (SingleBTS singleBTS : content) {
+ // initialize with ARFCN and Name
+ SingleBTS current = new SingleBTS(singleBTS.ARFCN, singleBTS.name);
+ // add everything from list. SingleBTS-Class takes only correct BTSs
+ for (SingleBTS measure : List) {
+ current.addBTSMeasure(measure);
+ }
+ output.add(current);
+ }
+
+ return output;
+ }
+
+ /**
+ * @param coord
+ * Coordinate in DEC
+ * @return Index where this coordinate is located within the GSMmap (x-axis)
+ */
+ public int searchBestX(double coord) {
+ // search for best fit in array
+ int found = (int) Math.round(((coord - minX) / accuracy));
+ if (found > Xcoords.length) {
+ System.out.println("gesucht nach: " + coord);
+ }
+ return found;
+ }
+
+ /**
+ * @param coord
+ * Coordinate in DEC
+ * @return Index where this coordinate is located within the GSMmap (y-axis)
+ */
+ public int searchBestY(double coord) {
+ // search for best fit in array
+ int found = (int) Math.round(((coord - minY) / accuracy));
+ // if (found == 8)
+ // System.out.println("Gesucht nach: " + coord + " Gefunden bei " +
+ // found);
+ return found;
+ }
+
+ public ArrayList<SingleBTS> getBTSList(GPScoordinate gps) {
+ int x = searchBestX(gps.coord2);
+ int y = searchBestY(gps.coord1);
+ return map[x][y];
+ }
+
+ public ArrayList<SingleBTS> getBTSList(double coordX, double coordY) {
+ // you could create a new GPScoordinate and use
+ // getBTSList(GPScoordinate)
+ // but maybe it's slower?
+ int x = searchBestX(coordX);
+ int y = searchBestY(coordY);
+ return map[x][y];
+
+ }
+
+ public SingleBTS getFirstBTS() {
+ return btsarray[0];
+ }
+
+ /**
+ * gets all the BTS that are stored in this map. content is ordered as the
+ * BTS appear in the map (or lets say... not sorted at all)
+ *
+ * @return
+ */
+ public SingleBTS[] content() {
+ if (mapcontent == null || mapcontent.length == 0) {
+ mapcontent = ListBTS.content(Arrays.asList(btsarray));
+ }
+
+ return mapcontent;
+ }
+
+ /**
+ * gets all BTS in this map that are not from the RZ-GSM
+ *
+ * @return
+ */
+ public SingleBTS[] contentForeignBTS() {
+ content(); // fill mapcontent
+ LinkedList<SingleBTS> result = new LinkedList<SingleBTS>();
+ for (int i = 0; i < mapcontent.length; i++) {
+
+ if (!ListBTS.contains(Arrays.asList(btsnames), mapcontent[i])) {
+ // current Element is not a RZ-GSM bts. Store it
+ result.add(mapcontent[i]);
+ }
+ }
+ if (result == null || result.isEmpty()) {
+ return null;
+ } else {
+ return result.toArray(new SingleBTS[1]);
+ }
+
+ }
+
+ /**
+ * Gets the first BTS out of the map that matches the arfcn of the given one
+ *
+ * @param bts
+ * @return
+ */
+ public SingleBTS getFirstBTSmatch(SingleBTS bts) {
+ for (SingleBTS element : btsarray) {
+ if (element.ARFCN == bts.ARFCN)
+ return element;
+ }
+ return null;
+ }
+
+ public boolean contains(SingleBTS bts) {
+ for (SingleBTS element : btsarray) {
+ if (element.ARFCN == bts.ARFCN)
+ return true;
+ }
+ return false;
+ }
+
+ public void gnuPlotSignalStrength(int ARFCN, int phonecount)
+ throws IOException {
+ // for each Tile: check if ARFCN exists. If so, ouput a file
+ // To calculate decimal deg. to meters, see
+ // http://www.sunearthtools.com/dp/tools/conversion.php?lang=eng
+ int placecount = 0;
+ // coordinates of BTS 877
+ // int BTSXCoord = searchBestX(7.834994d);
+ // int BTSYCoord = searchBestY(48.012708d);
+ File output = new File(IMSI + ".dat");
+ FileWriter fw = new FileWriter(output);
+ fw.append("#Uplink, Mobile Phone: " + IMSI);
+ fw.append("\r\n");
+ fw.append("#x y min max variance");
+ fw.append("\r\n");
+ // for every tile in GSMMap
+ for (int x = 0; x < Xcoords.length; x++) {
+ for (int y = 0; y < Ycoords.length; y++) {
+ for (SingleBTS bts : map[x][y]) {
+ // only full BTS are able to be drawn (uplink)
+ if (bts.ARFCN == ARFCN && bts.fullBTS) {
+ placecount++;
+ // double distance = Math.sqrt(Math.pow(x - BTSXCoord,
+ // 2)
+ // + Math.pow(y - BTSYCoord, 2));
+ double distance = helper.Distance.calc(48.012708,
+ 7.834994, Ycoords[y], Xcoords[x]);
+ // to meters (rough guess): one tile is 8m*8m
+ // distance = distance * 8;
+ // output Signalstrength, min, max and variance
+ NumberFormat nf = DecimalFormat.getInstance(Locale.US);
+ nf.setMaximumFractionDigits(15);
+ fw.append(distance + " " + nf.format(bts.getULmW())
+ + " " + nf.format(bts.minULmW()) + " "
+ + nf.format(bts.maxULmW()) + " "
+ + bts.getVarianceULmW());
+ fw.append("\r\n");
+ }
+ }
+ }
+ }
+ fw.close();
+ }
+
+ /**
+ * Outputs all receivable DLs for given phones. Distance to BTS with arfcn
+ * distanceARFCN is calculated
+ *
+ * @param arfcn
+ * @param distanceArfcn
+ * @throws IOException
+ */
+ public void gnuPlotDLAll(int[] arfcn, int distanceArfcn) throws IOException {
+ File output = new File("delta" + IMSI + ".dat");
+ FileWriter fw = new FileWriter(output);
+ fw.append("#DL all BTS\r\n");
+ String BTSs = "";
+ for (int i : arfcn) {
+ BTSs += "arfcn:" + Integer.toString(i) + " ";
+ }
+ fw.append("#Place " + BTSs + " 877UL 880UL \r\n");
+ for (int x = 0; x < Xcoords.length; x++) {
+ for (int y = 0; y < Ycoords.length; y++) {
+ if (map[x][y] == null || map[x][y].isEmpty()) {
+ continue;
+ }
+ SingleBTS reference = corrBTS(distanceArfcn);
+ fw.append(Double.toString(helper.Distance.calc(
+ reference.coordinate, getCoord(x, y))));
+ // TODO: here, distance to specified arfcn
+ fw.append(Integer.toString(x * Xcoords.length + y) + " ");
+ for (int i : arfcn) {
+ SingleBTS current = helper.ListBTS.getARFCN(map[x][y], i);
+
+ if (current != null) {
+ fw.append(Double.toString(current.getDldB()) + " ");
+ } else {
+ fw.append("NaN ");
+ }
+
+ }
+ SingleBTS uplink = helper.ListBTS.getARFCN(map[x][y], 877);
+ if (uplink != null && uplink.getUldB() != 0) {
+ fw.append(uplink.getUldB() + " ");
+ } else {
+ fw.append("NaN ");
+ }
+ uplink = helper.ListBTS.getARFCN(map[x][y], 880);
+ if (uplink != null && uplink.getUldB() != 0) {
+ fw.append(uplink.getUldB() + " ");
+ } else {
+ fw.append("NaN ");
+ }
+ fw.append("\r\n");
+
+ }
+ }
+ fw.close();
+ }
+
+ public void gnuPlotDeltaBTS(int ARFCN1, int ARFCN2) throws IOException {
+ // draw the ratio of ARFCN1/ARFCN2 and output in a GNUPlot readable file
+
+ // create FileWriter
+ File output = new File("delta" + IMSI + ".dat");
+ FileWriter fw = new FileWriter(output);
+ fw.append("# Delta between BTS " + ARFCN1 + " and " + ARFCN2
+ + " in dBm and mW\r\n");
+ fw.append("# Delta(dBm) Delta(mW) Ratio(dBm) Ratio(mW) DL:"
+ + ARFCN1
+ + " DL:"
+ + ARFCN2
+ + " Delta(strict_dBm) Ratio(strict_dBm) Carrier_Ratio(to 101 dB) \r\n");
+ SingleBTS bts1 = null;
+ SingleBTS bts2 = null;
+ for (int x = 0; x < Xcoords.length; x++) {
+ for (int y = 0; y < Ycoords.length; y++) {
+ bts1 = null;
+ bts2 = null;
+ for (SingleBTS bts : map[x][y]) {
+ if (bts.ARFCN == ARFCN1) {
+ bts1 = bts;
+ }
+ if (bts.ARFCN == ARFCN2) {
+ bts2 = bts;
+ }
+ }
+ // check if both BTS were found
+ if (bts1 != null && bts2 != null) {
+ // make the output. Only Downlink possible!
+ fw.append((bts1.getDldB() - bts2.getDldB())
+ + " "
+ + (bts1.getDLmW() - bts2.getDLmW())
+ + " "
+ + (bts1.getDldB() / bts2.getDldB())
+ + " "
+ + (bts1.getDLmW() / bts2.getDLmW())
+ + " "
+ + bts1.getDldB()
+ + " "
+ + bts2.getDldB()
+ + " "
+ + (bts1.getStrictDLdBAverage() - bts2
+ .getStrictDLdBAverage())
+ + " "
+ + (bts1.getStrictDLdBAverage() / bts2
+ .getStrictDLdBAverage())
+ + " "
+ + (10 * Math.log10(bts2.getDLmW() / bts1.getDLmW()))
+ + "\r\n");
+
+ }
+ }
+ }
+ fw.close();
+
+ }
+
+ /**
+ * removes outliers in each MR. Needs average() first. Otherwise each
+ * SingleBTS only holds one MR!
+ */
+ public void removeOutlier() {
+ for (int x = 0; x < Xcoords.length; x++) {
+ for (int y = 0; y < Ycoords.length; y++) {
+ for (int z = 0; z < map[x][y].size(); z++) {
+ map[x][y].get(z).removeOutlier();
+ }
+
+ }
+ }
+
+ }
+
+ public double getDistance(int x1, int x2, int y1, int y2) {
+ return helper.Distance.calc(Ycoords[y1], Xcoords[x1], Ycoords[y2],
+ Xcoords[x2]);
+
+ }
+
+ /**
+ * Extrapolations the map. For every Point a square eith size size*size is
+ * examined. A log function gets derived and the current point is calculated
+ *
+ * @param size
+ * @return not yet implemented
+ */
+ public boolean extrapolate(int size) {
+ matrixsize = size;
+ // System.out
+ // .println("WARNING: not correct implemented. map overrides buffer. Therefor UL-part of existing BTSs in map where only DL is available will not be stored");
+ // this might not be a problem: on places where a DL exists but no UL,
+ // the phone will always connect to the better cell, so a UL will
+ // actually never be received (only partyl correct)
+
+ // create buffer to store extrapolation
+ // buffer = new ArrayList[map.length][map[0].length];//not needed
+ // initialize
+ // for (int map2X = 0; map2X < buffer.length; map2X++) {
+ // for (int map2Y = 0; map2Y < buffer[0].length; map2Y++) {
+ // buffer[map2X][map2Y] = new ArrayList<SingleBTS>();
+ // }
+ // }
+
+ // take one of the BTS from the sql table arfcn
+ // traverse every place of the map
+ // try if extrapolation is needed or possible
+ // boundary of 3
+
+ // do RZ-GSM BTS first
+ for (SingleBTS extrapolateThis : btsnames) {
+ for (int x = size; x < Xcoords.length - size; x++) {
+ for (int y = size; y < Ycoords.length - size; y++) {
+ checkAndDoExtrapolation(x, y, extrapolateThis);
+ }
+ }
+ }
+
+ // do foreign BTS afterwards
+
+ // unset interpolated flag to prepare for new run. This means that
+ // getSurrounding will get the newly interpolated MR in the next run
+ unsetInterpolated();
+
+ for (SingleBTS extrapolateThis : contentForeignBTS()) {
+ for (int x = size; x < Xcoords.length - size; x++) {
+ for (int y = size; y < Ycoords.length - size; y++) {
+ extrapolateForeignDL(x, y, extrapolateThis);
+ }
+ }
+ }
+
+ // now do the extrapolation for foreign BTS. Calculate a delta between
+ // two BTS
+ // extrapolateForeign();
+
+ return false;
+ }
+
+ /*
+ * private void extrapolateForeign() { SingleBTS[] foreign =
+ * contentForeignBTS(); for (SingleBTS extrapolateThis : foreign) { for (int
+ * x = 2; x < Xcoords.length - 2; x++) { for (int y = 2; y < Ycoords.length
+ * - 2; y++) { for (int i = 0; i < directions.values().length; i++) {
+ * extrapolateForeignDL(directions.values()[i], x, y, extrapolateThis); } }
+ * }
+ *
+ * }
+ *
+ * }
+ */
+
+ /**
+ *
+ * @param direction
+ * which direction to extrapolate
+ * @param x
+ * map coordinate
+ * @param y
+ * map coordinate
+ * @param extrapolateThis
+ * BTS to extrapolate
+ */
+ private void extrapolateForeignDL(int x, int y, SingleBTS extrapolateThis) {
+ SingleBTS bts1 = null;
+ SingleBTS bts2 = null;
+ for (int i = 0; i < directions.values().length; i++) {
+ directions direction = directions.values()[i];
+ switch (direction) {
+ case DOWN:
+ bts1 = ListBTS.getARFCN(map[x - 1][y], extrapolateThis);
+ bts2 = ListBTS.getARFCN(map[x - 2][y], extrapolateThis);
+ break;
+ case UP:
+ bts1 = ListBTS.getARFCN(map[x + 1][y], extrapolateThis);
+ bts2 = ListBTS.getARFCN(map[x + 2][y], extrapolateThis);
+ break;
+ case LEFT:
+ bts1 = ListBTS.getARFCN(map[x][y - 1], extrapolateThis);
+ bts2 = ListBTS.getARFCN(map[x][y - 2], extrapolateThis);
+ break;
+ case RIGHT:
+ bts1 = ListBTS.getARFCN(map[x][y + 1], extrapolateThis);
+ bts2 = ListBTS.getARFCN(map[x][y + 2], extrapolateThis);
+ break;
+ case UPLEFT:
+ bts1 = ListBTS.getARFCN(map[x][y + 1], extrapolateThis);
+ bts2 = ListBTS.getARFCN(map[x][y + 2], extrapolateThis);
+ break;
+ default:
+ break;
+ }
+ // do interpolation. Average extrapolated bts between all.
+ insertForeignBTS(x, y, bts1, bts2, extrapolateThis);
+
+ }
+
+ }
+
+ /**
+ * Gets two BTS values, extrapolates from bts1 to bts2 and then guesses
+ * bts3. Bts3 gets updated or inserted into map[x][y].
+ *
+ * @param x
+ * @param y
+ * @param bts1
+ * @param bts2
+ * @param extrapolateThis
+ */
+ private void insertForeignBTS(int x, int y, SingleBTS bts1, SingleBTS bts2,
+ SingleBTS extrapolateThis) {
+ // boolean contains = ListBTS.contains(map[x][y], extrapolateThis);
+ // check if map[x][y]already contains the corresponding bts
+ if (bts1 == null || bts2 == null)
+ return; // nothing one can do
+ SingleBTS update = null;
+ if (ListBTS.contains(map[x][y], extrapolateThis)) {
+ if (!ListBTS.getARFCN(map[x][y], extrapolateThis).isInterpolated()) {
+ return;// is already measured! Do not change!
+ }
+ // map[x][y] contains a corresponding bts that is interpolated.
+ // update it
+ update = ListBTS.removeARFCN(map[x][y], extrapolateThis);
+
+ } else {
+ update = new SingleBTS(extrapolateThis.ARFCN, extrapolateThis.name);
+
+ }
+ update.interpolated.add(true);
+ // TODO: völlig falsch hier!!!
+ double DL = bts1.getDldB() + bts2.getDldB();
+ DL = DL / 2d;
+ update.addDl(DL);
+ // insert into map[x][y]
+ map[x][y].add(update);
+
+ }
+
+ /**
+ * adds a new boolean value (false) to each SingleBTS. A new extrapolation
+ * round starts. This means, that extrapolated BTS from the last run may now
+ * be used for extrapolation
+ */
+ private void unsetInterpolated() {
+ for (int x = 0; x < map.length; x++) {
+ for (int y = 0; y < map[0].length; y++) {
+ for (int z = 0; z < map[x][y].size(); z++) {
+ map[x][y].get(z).interpolated.add(false);
+ }
+ }
+ }
+
+ }
+
+ public boolean hasAMeasurement(int x, int y) {
+ boolean result = !(map[x][y] == null || map[x][y].isEmpty());
+ return result;
+ }
+
+ public boolean[][] getAllocation() {
+ boolean[][] result = new boolean[Xcoords.length][Ycoords.length];
+ for (int x = 0; x < Xcoords.length; x++) {
+ for (int y = 0; y < Ycoords.length; y++) {
+ result[x][y] = hasAMeasurement(x, y);
+ }
+ }
+ return result;
+ }
+
+ public long countTilesWMeasures() {
+ boolean[][] allocation = getAllocation();
+ long count = 0;
+ for (int x = 0; x < Xcoords.length; x++) {
+ for (int y = 0; y < Ycoords.length; y++) {
+ if (allocation[x][y])
+ count++;
+ }
+
+ }
+ return count;
+ }
+
+ /*
+ * private void merge() { for (int x = 0; x < map.length; x++) { for (int y
+ * = 0; y < map[0].length; y++) { if (map[x][y] != null &&
+ * !map[x][y].isEmpty()) { buffer[x][y] = map[x][y]; } } } map = buffer;
+ *
+ * }
+ */
+
+ /**
+ * Checks what kind of extrapolation is needed, if any
+ *
+ * @param x
+ * Coordinate in GSM map
+ * @param y
+ * Coordinate in GSM map
+ * @param extrapolateThis
+ * what BTS should be interpolated
+ */
+ private void checkAndDoExtrapolation(int x, int y, SingleBTS extrapolateThis) {
+ // check current x/y coordinate if extrapolateThis is existing
+ if (helper.ListBTS.contains(map[x][y], extrapolateThis)) {
+ if (helper.ListBTS.containsUL(map[x][y], extrapolateThis)) {
+ return; // nothing to do
+ }
+ // only uplink must be interpolated
+ tryExtrapolateUL(x, y, extrapolateThis);
+ } else {
+ tryExtrapolateDL(x, y, extrapolateThis);
+ // uplink and downlink must be interpolated.
+ // only downlink here. it the next run, the uplink will be
+ // interpolated
+ }
+
+ }
+
+ private boolean tryExtrapolateUL(int x, int y, SingleBTS extrapolateThis) {
+ // check if extrapolateThis is a foreign BTS
+ if (isForeign(extrapolateThis)) {
+ // extrapolateThis is not a RZ-GSM BTS. Uplink not available
+ return false;
+ }
+
+ // TODO: create copy of map. Place Extrapolation inside of this copy.
+ // Merge both at the end
+ // get Distance of this place to coordinates in extrapolateThis
+ double xval = helper.Distance.calc(extrapolateThis.coordinate,
+ getCoord(x, y));
+ ArrayList<SingleBTS> surrounding = getSurrounding(x, y, matrixsize,
+ extrapolateThis);
+
+ // create empty array
+
+ // do extrapolation
+ if (surrounding != null && !surrounding.isEmpty()) {
+ SingleBTS extrapolated = helper.Extrapolate.extrapolateLogUL(
+ surrounding, xval, extrapolateThis, 49);
+ if (extrapolated == null) {
+ return false;
+ } else {
+ // take out the extrapolated BTS from map. Update UL,
+ // reintegrate
+ SingleBTS element = helper.ListBTS.removeARFCN(map[x][y],
+ extrapolateThis);
+ element.addUl(extrapolated.getUldB());
+ element.interpolated.add(true);
+ element.distance = xval;
+ map[x][y].add(element);
+ // buffer[x][y].add(element);
+ return true;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ private boolean tryExtrapolateDL(int x, int y, SingleBTS extrapolateThis) {
+
+ // if (isForeign(extrapolateThis)) {
+ // do interpolation step by step because distances to corresponding
+ // BTS is unknown.
+ // eight directions and some special cases
+ // extrapolateForeignDL(x, y, extrapolateThis);
+ // return true;
+ // }
+
+ // TODO: create copy of map. Place Extrapolation inside of this copy.
+ // Merge both at the end
+ // get x/y Distance to corresponding this BTS
+
+ // extrapolate to value of x:
+ // double xval = helper.Distance.calc(extrapolateThis.coordinate.coord1,
+ // extrapolateThis.coordinate.coord2, Ycoords[y], Xcoords[x]);
+ double xval = helper.Distance.calc(extrapolateThis.coordinate,
+ getCoord(x, y));
+
+ ArrayList<SingleBTS> surrounding = getSurrounding(x, y, matrixsize,
+ extrapolateThis);
+ SingleBTS extrapolated = helper.Extrapolate.extrapolateLogDL(
+ surrounding, xval, extrapolateThis, 44);
+
+ // add extrapolated BTS to GSM map only if not null. Add distance
+ if (extrapolated != null) {
+ extrapolated.distance = xval;
+ extrapolated.interpolated.add(true);
+ map[x][y].add(extrapolated);
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Copies all SingleBTS of given surrounding into one linked list. If a
+ * Measurement was newly interpolated, it will be ignored and not added to
+ * the list
+ *
+ * @param x
+ * GSM map coordinate
+ * @param y
+ * GSm map coordinate
+ * @param size
+ * size of matrix where size specifies length and width. must be
+ * unequal
+ * @param extrapolateThis
+ * indicates which BTS.arfcn should be taken. Only matching
+ * arfcn's are copied to the list
+ * @return linked list with all bts in that area. Null if no matching BTS
+ * where found
+ */
+ private ArrayList<SingleBTS> getSurrounding(int x, int y, int size,
+ SingleBTS extrapolateThis) {
+ int max = (size - 1) / 2;
+ ArrayList<SingleBTS> list = new ArrayList<SingleBTS>();
+ // int max_x = map.length;
+ // int max_y = map[0].length;
+ for (int i = -1 * ((size - 1) / 2); i <= max; i++) {
+ for (int j = -1 * ((size - 1) / 2); j <= max; j++) {
+ // check boundaries
+ if (x + i > 0 && x + i < map.length && y + j > 0
+ && y + j < map[0].length) {
+ for (SingleBTS element : map[x + i][y + j]) {
+ if (element.ARFCN == extrapolateThis.ARFCN
+ && !element.newlyInterpolated()) {
+ // Boundaries okay, arfcn okay, was not interpolated
+ // in the last run
+ list.add(element);
+ }
+ }
+ }
+ }
+ }
+ // remove null elements
+ return helper.ListBTS.removeNullElements(list);
+
+ }
+
+ /**
+ * returns true if the BTS arfcn is not part of the RZ-GSM. Note that no
+ * check is done if arfcn is contained within the map
+ *
+ * @param arfcn
+ * which BTS to check
+ * @return True if arfcn is foreign. That means it is not part of the RZ-GSM
+ */
+ public boolean isForeign(SingleBTS arfcn) {
+ return (!ListBTS.contains(Arrays.asList(btsnames), arfcn));
+ }
+
+ /**
+ *
+ * @param MRlist
+ * Live MR from SQL database or List of Measurements to search
+ * @param thresholddBm
+ * take each MR +/- threshold_dB. Elements that are within
+ * threshold_dB get returned
+ * @return Coordinates that match to ANY of the provided MR, not to all! It
+ * is not the intersection!
+ */
+ public ArrayList<GPScoordinate> find(List<SingleBTS> MRlist,
+ double thresholddBm) {
+ // check if map got averaged
+ if (!isAveraged) {
+ System.out.println("Needs Average first!");
+ return null; // mabye average the MRlist first?
+ }
+
+ LinkedList<GPScoordinate> result = new LinkedList<GPScoordinate>();
+ // Iterator over MRlist
+ Iterator<SingleBTS> itr = MRlist.iterator();
+ while (itr.hasNext()) {
+ SingleBTS MR = itr.next();
+ result.addAll(find(MR, thresholddBm));
+ }
+ return new ArrayList<GPScoordinate>(result);
+
+ }
+
+ /**
+ *
+ * @param MR
+ * One measurement point
+ * @param thresholddBm
+ * search within this threshold_dB for coordinates
+ * (threshold_dB+/-MR)
+ * @return coordinates that match to the MR
+ */
+ public ArrayList<GPScoordinate> find(SingleBTS MR, double thresholddBm) {
+ LinkedList<GPScoordinate> result = new LinkedList<GPScoordinate>();
+ SingleBTS reference;
+ for (int x = 0; x < Xcoords.length; x++) {
+ for (int y = 0; y < Ycoords.length; y++) {
+ if (helper.ListBTS.contains(map[x][y], MR)) {
+ // test DL first
+ reference = helper.ListBTS.getARFCN(map[x][y], MR);
+ if ((reference.getDldB() + thresholddBm > MR.getDldB())
+ && (MR.getDldB() > reference.getDldB()
+ - thresholddBm)) {
+ // the MR fits with this coordinate
+ result.add(getCoord(x, y));
+ }
+ // test UL
+ reference = helper.ListBTS.getARFCN(map[x][y], MR);
+ if ((reference.getUldB() + thresholddBm > MR.getUldB())
+ && (MR.getUldB() > reference.getUldB()
+ - thresholddBm)) {
+ // the MR fits with this coordinate
+ result.add(getCoord(x, y));
+ }
+
+ }
+ }
+ }
+ return new ArrayList<GPScoordinate>(result);
+ }
+
+ public void merge(GSMMap map2) {
+ // TODO: check & possible increase boundaries first!
+ for (int x = 0; x < map2.Xcoords.length; x++) {
+ for (int y = 0; y < map2.Ycoords.length; y++) {
+ add(map2.getCoord(x, y), map2.map[x][y]);
+ average();
+ }
+ }
+ }
+
+ private enum directions {
+ UP, DOWN, LEFT, RIGHT, UPLEFT, UPRIGHT, DOWNRIGHT, DOWNLEFT, LEFTRIGHT, UPDOWN
+ }
+
+ public enum PaintEnum {
+ variance, UL, DL, DLexpected, BERSubUL, BERSubDL, OverallCoverageDL, OverallCoverageBER
+ }
+
+ @Override
+ public void paint(Graphics2D g, JXMapViewer OSmap, int w, int h) {
+ // TODO Auto-generated method stub
+ g = (Graphics2D) g.create();
+ g.setColor(Color.BLACK);
+ g.drawString(whatToPaint.toString(), 50, 30);
+ // convert from viewport to world bitmap
+ Rectangle rect = ((org.jdesktop.swingx.JXMapViewer) OSmap)
+ .getViewportBounds();
+ g.translate(-rect.x, -rect.y);
+
+ // draw each rectangle
+ for (int x = 0; x < Xcoords.length; x++) {
+ for (int y = 0; y < Ycoords.length; y++) {
+ SingleBTS current = ListBTS.getARFCN(map[x][y],
+ content()[indexToPaint]);
+ if (current != null
+ || whatToPaint == PaintEnum.OverallCoverageDL
+ || whatToPaint == PaintEnum.OverallCoverageBER) {
+ // if (hasAMeasurement(x, y)) {
+ // try {
+ // draw it
+ double coordX = Xcoords[x];
+ double coordY = Ycoords[y];
+ // double accuracy = accuracy;
+ Polygon tile = new Polygon();
+
+ GeoPosition pos1 = new GeoPosition(coordY - accuracy / 2,
+ coordX + accuracy / 2);
+ GeoPosition pos2 = new GeoPosition(coordY + accuracy / 2,
+ coordX + accuracy / 2);
+ GeoPosition pos3 = new GeoPosition(coordY + accuracy / 2,
+ coordX - accuracy / 2);
+ GeoPosition pos4 = new GeoPosition(coordY - accuracy / 2,
+ coordX - accuracy / 2);
+ Point2D pt1 = OSmap.getTileFactory().geoToPixel(pos1,
+ OSmap.getZoom());
+ Point2D pt2 = OSmap.getTileFactory().geoToPixel(pos2,
+ OSmap.getZoom());
+ Point2D pt3 = OSmap.getTileFactory().geoToPixel(pos3,
+ OSmap.getZoom());
+ Point2D pt4 = OSmap.getTileFactory().geoToPixel(pos4,
+ OSmap.getZoom());
+
+ // finally, draw it!
+ tile.addPoint((int) pt1.getX(), (int) pt1.getY());
+ tile.addPoint((int) pt2.getX(), (int) pt2.getY());
+ tile.addPoint((int) pt3.getX(), (int) pt3.getY());
+ tile.addPoint((int) pt4.getX(), (int) pt4.getY());
+ // Depending to what is set in whatToPaint
+ Color color = null;
+ if (whatToPaint == PaintEnum.DL) {
+ color = getColordB((int) current.getDldB());
+
+ } else if (whatToPaint == PaintEnum.DLexpected) {
+ // color = getColorStd(current.getVarianceDLdB());
+ color = getColordB((int) current.getStrictDLdBAverage());
+ } else if (whatToPaint == PaintEnum.variance) {
+ color = getColorStd(current.getTrueVarianceDLdB());
+ } else if (whatToPaint == PaintEnum.BERSubUL) {
+ if (current.ulQsub.isEmpty() || current.getULQsub() < 0)
+ continue;
+ color = getColorBER(current.getULQsub());
+ } else if (whatToPaint == PaintEnum.BERSubDL) {
+ if (current.dlQsub.isEmpty() || current.getDLQsub() < 0)
+ continue;
+ color = getColorBER(current.getDLQsub());
+ } else if (whatToPaint == PaintEnum.OverallCoverageDL
+ && hasAMeasurement(x, y)) {
+ SingleBTS bts1 = ListBTS.getARFCN(map[x][y], 880);
+ SingleBTS bts2 = ListBTS.getARFCN(map[x][y], 877);
+ if (bts1 != null && bts2 != null) {
+ // double bts1 = ListBTS.getARFCN(map[x][y],
+ // 880).getStrictDLdBAverage();
+ color = getColordB((int) Math.max(
+ bts1.getStrictDLdBAverage(),
+ bts2.getStrictDLdBAverage()));
+ } else if (bts2 != null) {
+ color = getColordB((int) bts2
+ .getStrictDLdBAverage());
+ } else if (bts1 != null) {
+ color = getColordB((int) bts1
+ .getStrictDLdBAverage());
+ }
+ } else if (whatToPaint == PaintEnum.OverallCoverageBER
+ && hasAMeasurement(x, y)) {
+ SingleBTS bts1 = ListBTS.getARFCN(map[x][y], 880);
+ SingleBTS bts2 = ListBTS.getARFCN(map[x][y], 877);
+ if (bts1 != null && bts2 != null) {
+ // double bts1 = ListBTS.getARFCN(map[x][y],
+ // 880).getStrictDLdBAverage();
+ color = getColorBER((int) Math.max(
+ bts1.getULQsub(), bts2.getULQsub()));
+ } else if (bts2 != null) {
+ color = getColorBER((int) bts2.getULQsub());
+ } else if (bts1 != null) {
+ color = getColorBER((int) bts1.getULQsub());
+ }
+ }
+ if (color != null) {
+ g.setColor(color);
+ g.fill(tile);
+ // g.setColor(Color.black);
+ // g.draw(tile);
+ // g.draw(tile);
+ }
+ try {
+ // Messungen schwarz umranden
+ if (!current.isInterpolated()) {
+ // g.setColor(Color.BLACK);
+ // g.draw(tile);
+ }
+ } catch (NullPointerException e) {
+
+ }
+
+ }
+ }
+ }
+ g.dispose();
+ }
+
+ private Color getColorBER(double dlQ) {
+ // between 0...7
+ int green = 0;
+ int red = 0;
+ if (dlQ < 3.5) {
+ green = 255;
+ red = (int) (255 * (dlQ / 3.5));
+ } else {
+ red = 255;
+ green = 255 - ((int) (255 * ((dlQ - 3.5) / 3.5)));
+ if (green < 0)
+ green = 0;
+ }
+
+ if (green < 0 || red < 0)
+ return null;
+
+ if (green > 255)
+ green = 255;
+ if (red > 255)
+ red = 255;
+
+ return new Color(red, green, 0, 185);
+ }
+
+ private Color getColordB(int strength) {
+
+ int green = 0;
+ int red = 0;
+ // yellow at -75
+ if (strength > -75) {
+ green = 255;
+ red = 256 - Math.abs((256 / 28) * (-75 - strength));
+
+ } else {
+ // transient green from now on
+ red = 255;
+ green = Math.abs((256 / 34) * (-110 - strength));
+ }
+ // int green = 256 - Math.abs((256 / 90) * (-120 - strength));
+ // int red = Math.abs((256 / 90) * (-120 - strength));
+ // int result = red << 24 | green
+ if ((green > 255) || (red > 255))
+ System.out.println("Zu groß bei strength= " + strength + ",Rot: "
+ + red + "Grün: " + green);
+ if (green > 255)
+ green = 255;
+ if (red > 255)
+ red = 255;
+ // return ("7f00" + Integer.toHexString(red) +
+ // Integer.toHexString(green));
+ // return ("ff00" + Integer.toHexString(red) +
+ // Integer.toHexString(green));
+ // return ("ff00" + Integer.toHexString(red) +
+ // Integer.toHexString(green));
+
+ Color result = new Color(red, green, 0, 185);
+
+ // return ("ff00" + Integer.toHexString(green) +
+ // Integer.toHexString(red));
+ return result;
+
+ }
+
+ private Color getColorStd(double var) {
+
+ double std = Math.sqrt(var);
+ // Std between 0...7
+ int green = 0;
+ int red = 0;
+ if (std < 3.5) {
+ green = 255;
+ red = (int) (255 * (std / 3.5));
+ } else {
+ red = 255;
+ green = 255 - ((int) (255 * ((std - 3.5) / 3.5)));
+ if (green < 0)
+ green = 0;
+ }
+ if (green > 255)
+ green = 255;
+ if (red > 255)
+ red = 255;
+
+ return new Color(red, green, 0, 185);
+ }
+
+ @SuppressWarnings("unused")
+ private Color getColorVar(double var) {
+ // let var be between 0 and 40
+ // 0...5: only a shade of green
+ // 5...15: between green and red
+ // 15...20: red
+ double middle = 25;
+
+ int green = 0;
+ int red = 0;
+ if (var < middle) {
+ green = 255;
+ red = (int) (255 * (var / middle));
+ } else {
+ red = 255;
+ green = 255 - ((int) (255 * ((var - middle) / middle)));
+ if (green < 0)
+ green = 0;
+ }
+ if (green > 255)
+ green = 255;
+ if (red > 255)
+ red = 255;
+
+ if (var > 20) {
+ // System.out.println("Brakepoiint");
+ }
+
+ return new Color(red, green, 0, 185);
+ }
+
+}
+
+final class MapHelper {
+ static public double getMaxX(GPScoordinate[] gps, double offset) {
+ double max = -181;
+ for (GPScoordinate current : gps) {
+ if (current.coord2 > max)
+ max = current.coord2;
+ }
+ return max;
+ // return max + offset;
+
+ }
+
+ static public double getMinX(GPScoordinate[] gps, double offset) {
+ double min = 181;
+ for (GPScoordinate current : gps) {
+ if (current.coord2 < min)
+ min = current.coord2;
+ }
+ return min;
+ // return min - offset;
+ }
+
+ static public double getMaxY(GPScoordinate[] gps, double offset) {
+ double max = -181;
+ for (GPScoordinate current : gps) {
+ if (current.coord1 > max)
+ max = current.coord1;
+ }
+ return max;
+ // return max + offset;
+ }
+
+ static public double getMinY(GPScoordinate[] gps, double offset) {
+ double min = 181;
+ for (GPScoordinate current : gps) {
+ if (current.coord1 < min)
+ min = current.coord1;
+ }
+ return min;
+ // return min - offset;
+ }
+
+ static public double[] createArray(double begin, double end, double accuracy) {
+ // add 1 to make sure even the last measurement fits in and doesn't
+ // through index out of bounds!
+ int size = (int) Math.ceil((end - begin) / accuracy) + 1;
+ double[] array = new double[size];
+ for (int i = 0; i < size; i++) {
+ array[i] = i * accuracy + begin;
+ }
+ return array;
+ }
+
+ /**
+ * ListBTS all the unique SingleBTS's that occur in this list
+ *
+ * @param list
+ * ListBTS with SingleBTS's
+ * @return Array with the unique SingleBTS's. That is, every BTS in this
+ * Array occurs also in the list. Null if the list was empty
+ */
+ static SingleBTS[] content(ArrayList<SingleBTS> list) {
+ // get first element of list.
+ // traverse list and delete every occurence of first element
+ // get next element
+ // copy list to destroy reference
+ ArrayList<SingleBTS> list2 = (ArrayList<SingleBTS>) list.clone();
+ if (list2.isEmpty())
+ return null;
+ // int count = 0;
+ ArrayList<SingleBTS> output = new ArrayList<SingleBTS>();
+ while (!list2.isEmpty()) {
+ SingleBTS bts = list2.get(0);
+ list2.remove(0);
+ output.add(bts);
+ // remove the just added bts from the BTS-list
+ for (int i = 0; i < list2.size(); i++) {
+ if (list2.get(i).ARFCN == bts.ARFCN) {
+ list2.remove(i);
+ i--;
+
+ }
+
+ }
+
+ }
+ return output.toArray(new SingleBTS[1]);
+ }
+}