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, 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[][] map; // public ArrayList[][] 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[][] 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(); } } // 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 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 BTSlist = new ArrayList(); for (int x = 0; x < btsarray.length; x++) { BTSlist.add(btsarray[x]); } return helper.ListBTS.content(BTSlist); } private ArrayList generateAveragedList( ArrayList List, SingleBTS[] content) { ArrayList output = new ArrayList(); // 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 getBTSList(GPScoordinate gps) { int x = searchBestX(gps.coord2); int y = searchBestY(gps.coord1); return map[x][y]; } public ArrayList 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 result = new LinkedList(); 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(); // } // } // 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 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 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 getSurrounding(int x, int y, int size, SingleBTS extrapolateThis) { int max = (size - 1) / 2; ArrayList list = new ArrayList(); // 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 find(List MRlist, double thresholddBm) { // check if map got averaged if (!isAveraged) { System.out.println("Needs Average first!"); return null; // mabye average the MRlist first? } LinkedList result = new LinkedList(); // Iterator over MRlist Iterator itr = MRlist.iterator(); while (itr.hasNext()) { SingleBTS MR = itr.next(); result.addAll(find(MR, thresholddBm)); } return new ArrayList(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 find(SingleBTS MR, double thresholddBm) { LinkedList result = new LinkedList(); 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(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 list) { // get first element of list. // traverse list and delete every occurence of first element // get next element // copy list to destroy reference ArrayList list2 = (ArrayList) list.clone(); if (list2.isEmpty()) return null; // int count = 0; ArrayList output = new ArrayList(); 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]); } }