From 08d5f7b0a0b24c042aa5976f66bf3a1b5b754478 Mon Sep 17 00:00:00 2001 From: Richard Zahoransky Date: Mon, 7 Nov 2011 16:29:56 +0100 Subject: Localization Code. How-To will follow... --- .classpath | 10 + .project | 19 + DataStructure/BayesAll.java | 380 +++++ DataStructure/GPScoordinate.java | 88 ++ DataStructure/GSMMap.java | 1275 +++++++++++++++++ DataStructure/GSMMapInterpolatorOld.java | 200 +++ DataStructure/GoogleOut.java | 598 ++++++++ DataStructure/Interpolator.java | 366 +++++ DataStructure/MeasurementReport.java | 60 + DataStructure/MobilePhone.java | 337 +++++ DataStructure/NormDistribution.java | 77 ++ DataStructure/PhoneContainer.java | 106 ++ DataStructure/PossibilityObject.java | 21 + DataStructure/ResultScore.java | 54 + DataStructure/ScoreElement.java | 21 + DataStructure/SingleBTS.java | 775 +++++++++++ DataStructure/Weight.java | 19 + DataStructure/gsmBayes.java | 752 ++++++++++ DataStructure/jdom.jar | Bin 0 -> 152797 bytes DataStructure/ratioElem.java | 114 ++ DoGsmMap.java | 87 ++ GSMMapping.java | 128 ++ Interpolate.java | 43 + MapSearch.java | 123 ++ Parse/CalcVariance.java | 65 + Parse/MapInverse.java | 115 ++ Parse/NMEAParse.java | 224 +++ Parse/SqlPoller.java | 47 + Parse/SqlPollerDate.java | 406 ++++++ Parse/SqlPollerUnThreaded.java | 370 +++++ Parse/sqlreader.java | 483 +++++++ Variance.java | 45 + VoronoiInterpolate.java | 50 + delaunay/ArraySet.java | 104 ++ delaunay/DelaunayAp.java | 429 ++++++ delaunay/Graph.java | 108 ++ delaunay/Pnt.java | 470 +++++++ delaunay/Triangle.java | 152 ++ delaunay/Triangulation.java | 281 ++++ gui/GUI.java | 69 + gui/ListTest.java | 47 + gui/Localization.java | 291 ++++ gui/LocalizationNew.java | 773 +++++++++++ gui/MapShow.java | 38 + gui/MapTest.java | 119 ++ gui/MapViewer.java | 54 + gui/ShowMapStrength.java | 309 +++++ gui/Start.java | 64 + gui/test.java | 72 + helper/Distance.java | 75 + helper/Extrapolate.java | 508 +++++++ helper/FunctionFit.java | 91 ++ helper/LMfunc.java | 37 + helper/ListBTS.java | 300 ++++ helper/ListGPS.java | 191 +++ helper/Polygons.java | 34 + lookup/BTSLut.java | 200 +++ lookup/GSMLut.java | 88 ++ lookup/ILut.java | 18 + lookup/RatioLut.java | 41 + lookup/ResultScore.java | 101 ++ lookup/ScoreElement.java | 44 + mysql-connector-java-5.1.14-bin.jar | Bin 0 -> 775688 bytes parallel-strictdB-BER.obj | Bin 0 -> 50796259 bytes swingx-beaninfo.jar | Bin 0 -> 222643 bytes swingx-ws.jar | Bin 0 -> 328767 bytes swingx.jar | Bin 0 -> 1402344 bytes testing/testsVar.java | 26 + voronoi/Classtest.java | 36 + voronoi/CompGeom.java | 35 + voronoi/CompGeomTest.java | 132 ++ voronoi/ConvexHull2D.java | 233 ++++ voronoi/DelaunayTri.java | 612 ++++++++ voronoi/GeomCanvas.java | 297 ++++ voronoi/cEdge.java | 23 + voronoi/cEdgeList.java | 61 + voronoi/cFace.java | 22 + voronoi/cFaceList.java | 62 + voronoi/cPointd.java | 15 + voronoi/cPointi.java | 107 ++ voronoi/cVertex.java | 51 + voronoi/cVertexList.java | 233 ++++ voronoi/erstesVoronoi.png | Bin 0 -> 120990 bytes voronoi/sweepLineVD.java | 73 + voronoi/voronoi.java | 2228 ++++++++++++++++++++++++++++++ voronoiTest.java | 222 +++ 86 files changed, 17034 insertions(+) create mode 100644 .classpath create mode 100644 .project create mode 100644 DataStructure/BayesAll.java create mode 100644 DataStructure/GPScoordinate.java create mode 100644 DataStructure/GSMMap.java create mode 100644 DataStructure/GSMMapInterpolatorOld.java create mode 100644 DataStructure/GoogleOut.java create mode 100644 DataStructure/Interpolator.java create mode 100644 DataStructure/MeasurementReport.java create mode 100644 DataStructure/MobilePhone.java create mode 100644 DataStructure/NormDistribution.java create mode 100644 DataStructure/PhoneContainer.java create mode 100644 DataStructure/PossibilityObject.java create mode 100644 DataStructure/ResultScore.java create mode 100644 DataStructure/ScoreElement.java create mode 100644 DataStructure/SingleBTS.java create mode 100644 DataStructure/Weight.java create mode 100644 DataStructure/gsmBayes.java create mode 100644 DataStructure/jdom.jar create mode 100644 DataStructure/ratioElem.java create mode 100644 DoGsmMap.java create mode 100644 GSMMapping.java create mode 100644 Interpolate.java create mode 100644 MapSearch.java create mode 100644 Parse/CalcVariance.java create mode 100644 Parse/MapInverse.java create mode 100644 Parse/NMEAParse.java create mode 100644 Parse/SqlPoller.java create mode 100644 Parse/SqlPollerDate.java create mode 100644 Parse/SqlPollerUnThreaded.java create mode 100644 Parse/sqlreader.java create mode 100644 Variance.java create mode 100644 VoronoiInterpolate.java create mode 100644 delaunay/ArraySet.java create mode 100644 delaunay/DelaunayAp.java create mode 100644 delaunay/Graph.java create mode 100644 delaunay/Pnt.java create mode 100644 delaunay/Triangle.java create mode 100644 delaunay/Triangulation.java create mode 100644 gui/GUI.java create mode 100644 gui/ListTest.java create mode 100644 gui/Localization.java create mode 100644 gui/LocalizationNew.java create mode 100644 gui/MapShow.java create mode 100644 gui/MapTest.java create mode 100644 gui/MapViewer.java create mode 100644 gui/ShowMapStrength.java create mode 100644 gui/Start.java create mode 100644 gui/test.java create mode 100644 helper/Distance.java create mode 100644 helper/Extrapolate.java create mode 100644 helper/FunctionFit.java create mode 100644 helper/LMfunc.java create mode 100644 helper/ListBTS.java create mode 100644 helper/ListGPS.java create mode 100644 helper/Polygons.java create mode 100644 lookup/BTSLut.java create mode 100644 lookup/GSMLut.java create mode 100644 lookup/ILut.java create mode 100644 lookup/RatioLut.java create mode 100644 lookup/ResultScore.java create mode 100644 lookup/ScoreElement.java create mode 100644 mysql-connector-java-5.1.14-bin.jar create mode 100644 parallel-strictdB-BER.obj create mode 100644 swingx-beaninfo.jar create mode 100644 swingx-ws.jar create mode 100644 swingx.jar create mode 100644 testing/testsVar.java create mode 100644 voronoi/Classtest.java create mode 100644 voronoi/CompGeom.java create mode 100644 voronoi/CompGeomTest.java create mode 100644 voronoi/ConvexHull2D.java create mode 100644 voronoi/DelaunayTri.java create mode 100644 voronoi/GeomCanvas.java create mode 100644 voronoi/cEdge.java create mode 100644 voronoi/cEdgeList.java create mode 100644 voronoi/cFace.java create mode 100644 voronoi/cFaceList.java create mode 100644 voronoi/cPointd.java create mode 100644 voronoi/cPointi.java create mode 100644 voronoi/cVertex.java create mode 100644 voronoi/cVertexList.java create mode 100644 voronoi/erstesVoronoi.png create mode 100644 voronoi/sweepLineVD.java create mode 100644 voronoi/voronoi.java create mode 100644 voronoiTest.java diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..303ee3b --- /dev/null +++ b/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..b6b206f --- /dev/null +++ b/.project @@ -0,0 +1,19 @@ + + + GSMMapping + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.jdt.core.javanature + org.eclipse.jem.beaninfo.BeanInfoNature + + diff --git a/DataStructure/BayesAll.java b/DataStructure/BayesAll.java new file mode 100644 index 0000000..27ab797 --- /dev/null +++ b/DataStructure/BayesAll.java @@ -0,0 +1,380 @@ +package DataStructure; + +import helper.ListBTS; + +import java.util.ArrayList; +import java.util.Arrays; + +public class BayesAll { + GSMMap map; + // ArrayList MR; + ArrayList[][] RatioMap; + boolean[][] hasElement; + + /** + * @param args + */ + public static void main(String[] args) { + + } + + public BayesAll(Interpolator map) { + this.map = map; + hasElement = map.getAllocation(); + + // Compute ALL Ratios for GSMmap + RatioMap = computeMapRatio(); + + } + + public BayesAll(GSMMap map) { + this.map = map; + hasElement = map.getAllocation(); + RatioMap = computeMapRatio(); + } + + public double[][] locate(ArrayList MR, double confidence) { + + SingleBTS[] content = ListBTS.content(MR); + // check if MR only has one BTS inside! + if (content == null || content.length <= 1) { + // only one or zero BTS. mark all tiles where this BTS is received! + // get BTS + + return markOneBTS(content); + } + + // Compute ALL Ratios out of mobile phone's MR + ArrayList RSSVector = computeAllRatios(MR); + + // Compute scoremap + double[][] scoremap = computeScoreMap(RSSVector); + + if (confidence >= 1) + return scoremap; + else + return toConfidence(scoremap, confidence); + } + + /** + * This returns the distribution if only one BTS is measured + * + * @param singleBTS + * @return + */ + private double[][] markOneBTS(SingleBTS[] singleBTS) { + int count = 0; + double[][] scoremap = new double[map.Xcoords.length][map.Ycoords.length]; + + if (singleBTS == null) { + long numberOfTiles = map.countTilesWMeasures(); + for (int x = 0; x < map.Xcoords.length; x++) { + for (int y = 0; y < map.Ycoords.length; y++) { + if (hasElement[x][y]) { + scoremap[x][y] = 1d / (double) numberOfTiles; + } + } + } + } + + // count tiles where this bts is measured + for (int x = 0; x < map.Xcoords.length; x++) { + for (int y = 0; y < map.Ycoords.length; y++) { + if (ListBTS.contains(map.map[x][y], singleBTS[0])) { + count++; + } + } + } + + // give every tile a equal distributed possibility + for (int x = 0; x < map.Xcoords.length; x++) { + for (int y = 0; y < map.Ycoords.length; y++) { + if (ListBTS.contains(map.map[x][y], singleBTS[0])) { + scoremap[x][y] = 1d / (double) count; + } + } + } + + return scoremap; + } + + private double[][] computeScoreMap(ArrayList RSSVector) { + double[][] score = new double[map.Xcoords.length][map.Ycoords.length]; + // Compute possibility that this RSSVector was measured in RatioMap as + // TODO: Thread!!! + computeTotalProbability totalProbRunnable = new computeTotalProbability( + RSSVector); + Thread totalProbThread = new Thread(totalProbRunnable); + totalProbThread.start(); + // double totalProbability = computeTotalProb(RSSVector); + // now we have P(S) (=totalProb that RSSVector appears in map) + double numberOfTiles = map.countTilesWMeasures(); + // compute Bayes with RSSVector + for (int x = 0; x < RatioMap.length; x++) { + for (int y = 0; y < RatioMap[0].length; y++) { + if (hasElement[x][y]) { + score[x][y] = (ProbabilityForRSSVector(RSSVector, + RatioMap[x][y]) * (1 / numberOfTiles)); + // / totalProbability; + } + } + } + + // division with total Probability + try { + totalProbThread.join(); + double totalProbability = totalProbRunnable.totalProbability; + for (int x = 0; x < RatioMap.length; x++) { + for (int y = 0; y < RatioMap[0].length; y++) { + if (hasElement[x][y]) { + score[x][y] = score[x][y] / totalProbability; + } + } + + } + + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return score; + } + + /** + * Computes Probability that this RSSVector is seen in the Map + * + * @param RSSVector + * @return + */ + @SuppressWarnings("unused") + private double computeTotalProb(ArrayList RSSVector) { + double totalProb = 0; + // go through all valid Elements in RatioMap. Sum up the possibilities + // for each tile + for (int x = 0; x < RatioMap.length; x++) { + for (int y = 0; y < RatioMap[0].length; y++) { + if (hasElement[x][y]) + totalProb += ProbabilityForRSSVector(RSSVector, + RatioMap[x][y]); + } + + /* + * int y = 0; while (y < RatioMap[0].length) { possibilityThread + * threadable1 = new possibilityThread( RSSVector, x, y); Thread + * thread1 = new Thread(threadable1); if (hasElement[x][y]) + * thread1.start(); y++; possibilityThread threadable2 = new + * possibilityThread( RSSVector, x, y); Thread thread2 = new + * Thread(threadable2); if (y < RatioMap[0].length && + * hasElement[x][y]) thread2.start(); y++; try { thread1.join(); + * thread2.join(); } catch (InterruptedException e) { + * e.printStackTrace(); } // Threads fertig. + * + * } + */ + } + + double numberOfTiles = map.countTilesWMeasures(); + totalProb = totalProb / numberOfTiles; + return totalProb; + } + + private double ProbabilityForRSSVector(ArrayList MRphone, + ArrayList MRmap) { + + double probability = 1; + boolean thereWasAHit = false; + for (int i = 0; i < MRphone.size(); i++) { + // when there is no measurement from phone, go to next ratio element + if (MRphone.get(i) != null) { + if (MRmap.get(i) == null) + return 0; + probability *= MRphone.get(i).probability(MRmap.get(i)); + thereWasAHit = true; + } + + } + + if (thereWasAHit) + return probability; + else + return 0; + } + + /** + * Creates Ratios out of map (all possible ratios!) + * + * @return + */ + private ArrayList[][] computeMapRatio() { + ArrayList[][] result = new ArrayList[map.Xcoords.length][map.Ycoords.length]; + + // int size = sumOfRatio(map.content().length - 1); + // result initilisieren und füllen + for (int x = 0; x < map.Xcoords.length; x++) { + for (int y = 0; y < map.Ycoords.length; y++) { + if (hasElement[x][y]) { + // result[x][y] = new ArrayList(size); + + result[x][y] = (computeAllRatios(map.map[x][y])); + } + } + } + + return result; + } + + /** + * Returns all possible Ratios that can be built with GSM-Map's content out + * of MR. Not available Ratios get stored as null + * + * @return + */ + private ArrayList computeAllRatios(ArrayList MR) { + SingleBTS[] content = map.content(); + ArrayList result = new ArrayList( + sumOfRatio(content.length - 1)); + // get ratio between every BTS and the others + for (int i = 0; i < content.length; i++) { + for (int j = i + 1; j < content.length; j++) { + SingleBTS top = ListBTS.getARFCN(MR, content[i]); + SingleBTS bottom = ListBTS.getARFCN(MR, content[j]); + if (top == null || bottom == null) { + result.add(null); + } else { + result.add(new ratioElem(top, bottom)); + } + } + } + + return result; + } + + /** + * Computes all Ratios that can be built out of MR + * + * @param MR + * @return + */ + @SuppressWarnings("unused") + private ArrayList computeRatios(ArrayList MR) { + ArrayList result = new ArrayList( + sumOfRatio(MR.size() - 1)); + for (int i = 0; i < MR.size(); i++) { + for (int j = i + 1; j < MR.size(); j++) { + result.add(new ratioElem(MR.get(i), MR.get(j))); + } + } + return result; + } + + private static int sumOfRatio(int n) { + return n == 0 ? 1 : n + sumOfRatio(n - 1); + } + + public double[][] toConfidence(double[][] scoremap, double confidence) { + if (confidence >= 1) { + return scoremap; + } + + // scoremap to possibility objects (faster...) + PossibilityObject[] possibilities = toPossibility(scoremap); + double sum_confidence = 0; + double[][] result = new double[scoremap.length][scoremap[0].length]; + int boundary = possibilities.length - 1; + while (sum_confidence < confidence) { + // run from highest element to lowest. + // as long as confidence is not reached: store current element in + // result + sum_confidence += possibilities[boundary].possibility; + int x = possibilities[boundary].x; + int y = possibilities[boundary].y; + result[x][y] = possibilities[boundary].possibility; + boundary--; + } + // result = PossObjToScoremap(possibilities, boundary, result); + + /* + * double max = 0; int xmax = 0; int ymax = 0; for (int x = 0; x < + * scoremap.length; x++) { for (int y = 0; y < scoremap[0].length; y++) + * { if (scoremap[x][y] > max) { max = scoremap[x][y]; xmax = x; ymax = + * y; } + * + * } } // max found. + * + * result[xmax][ymax] = scoremap[xmax][ymax]; sum_confidence += + * scoremap[xmax][ymax]; scoremap[xmax][ymax] = 0; } + */ + return result; + + } + + /** + * Makes a scoremap to a SORTED one dimensional PossibilityObject Array. + * Calculates the entropy on the way and prints to Console + * + * @param scoremap + * @return + */ + public PossibilityObject[] toPossibility(double[][] scoremap) { + int gsmmapsize = (int) map.countTilesWMeasures(); + // PossibilityObject[] possibilities = new + // PossibilityObject[gsmmapsize]; + ArrayList result = new ArrayList( + gsmmapsize); + double entropy = 0; + for (int x = 0; x < scoremap.length; x++) { + for (int y = 0; y < scoremap[0].length; y++) { + if (hasElement[x][y] && scoremap[x][y] > 0) { + entropy = entropy + scoremap[x][y] + * ((Math.log(scoremap[x][y])) / Math.log(2)); + + PossibilityObject current = new PossibilityObject(); + current.possibility = scoremap[x][y]; + current.x = x; + current.y = y; + result.add(current); + } + } + + } + + System.out.println("Entropy dieser Karte: " + (entropy * (-1)) + + " max. Entropy: " + (Math.log(gsmmapsize) / Math.log(2))); + PossibilityObject[] possibilities = result + .toArray(new PossibilityObject[1]); + Arrays.sort(possibilities); + return possibilities; + } + + class computeTotalProbability implements Runnable { + private ArrayList RSSVector; + public double totalProbability; + + public computeTotalProbability(ArrayList RSSVector) { + this.RSSVector = RSSVector; + } + + @Override + public void run() { + double totalProb = 0; + // go through all valid Elements in RatioMap. Sum up the + // possibilities + // for each tile + for (int x = 0; x < RatioMap.length; x++) { + for (int y = 0; y < RatioMap[0].length; y++) { + if (hasElement[x][y]) + totalProb += ProbabilityForRSSVector(RSSVector, + RatioMap[x][y]); + } + + } + + double numberOfTiles = map.countTilesWMeasures(); + totalProb = totalProb / numberOfTiles; + totalProbability = totalProb; + } + + } + +} diff --git a/DataStructure/GPScoordinate.java b/DataStructure/GPScoordinate.java new file mode 100644 index 0000000..dee0748 --- /dev/null +++ b/DataStructure/GPScoordinate.java @@ -0,0 +1,88 @@ +/** + * + */ +package DataStructure; + +import java.io.Serializable; +import java.util.Date; + +/** + * @author richy + * + */ +@SuppressWarnings("serial") +public class GPScoordinate implements Comparable, Serializable { + public Date time; + public double coord1; + public char coord1NS; + public double coord2; + public char coord2EW; + public boolean isGood; + public String coord1S; + public String coord2S; + + // Constructor + public GPScoordinate(Date time, double coord1, char coord1NS, + double coord2, char coord2EW, boolean isGood) { + this.time = time; + this.coord1 = coord1; + this.coord1NS = coord1NS; + this.coord2 = coord2; + this.coord2EW = coord2EW; + this.isGood = isGood; + + } + + public boolean equals(GPScoordinate gps2) { + return (coord1 == gps2.coord1 && coord2 == gps2.coord2); + } + + public String toString() { + String time = "noDate"; + if (this.time != null) + time = this.time.toString(); + return (Double.toString(coord1) + coord1NS + ";" + + Double.toString(coord2) + coord2EW + ";" + isGood + ";" + time); + } + + public Double getCoord1AsDezim() { + // int whole = (int) coord1; + // double floor = (coord1 - whole) * 60; + // return (whole + floor); + return coord1; + } + + public Double getCoord2AsDezim() { + // int whole = (int) coord2; + // double floor = (coord2 - whole) * 60; + // return (whole + floor); + return coord2; + } + + public int compareTo(Date timestamp) { + if (this.time == null || timestamp == null) { + throw new NullPointerException("objects is null!"); + } + if (this.time.getTime() > timestamp.getTime()) { + return 1; + } else if (this.time.getTime() < timestamp.getTime()) { + return -1; + } else + return 0; + + } + + public boolean isValid() { + if (time == null || time.getTime() < 10l) { + return false; + } + if (!isGood) { + return false; + } + if (coord1 == 0 || coord2 == 0) { + return false; + } + return true; + } + +} 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, 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]); + } +} diff --git a/DataStructure/GSMMapInterpolatorOld.java b/DataStructure/GSMMapInterpolatorOld.java new file mode 100644 index 0000000..eff8057 --- /dev/null +++ b/DataStructure/GSMMapInterpolatorOld.java @@ -0,0 +1,200 @@ +package DataStructure; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import Parse.sqlreader; + +@SuppressWarnings("serial") +public class GSMMapInterpolatorOld extends GSMMap { + + public GSMMapInterpolatorOld(sqlreader SQL, double accuracy) { + super(SQL, accuracy); + // TODO Auto-generated constructor stub + } + + public void interpolate() { + for (SingleBTS currentBTS : this.btsnames) { + // go through every known BTS + interpolateBTS(currentBTS); + + } + } + + private void interpolateBTS(SingleBTS currentBTS) { + // add security bounds + for (int x = 2; x < this.Xcoords.length - 2; x++) { + for (int y = 2; y < this.Ycoords.length - 2; y++) { + // check if interpolation is needed + if (!InterpolateHelper.listContains(currentBTS, this.map[x][y])) { + // try to interpolate + SingleBTS interpolated = tryInterpolation(currentBTS, x, y); + if (interpolated != null) + // maybe the list is empty. then create list + if (map[x][y] == null) { + ArrayList list = new ArrayList(); + list.add(interpolated); + map[x][y] = list; + } else { + map[x][y].add(interpolated); + } + + } + + } + } + + } + + private SingleBTS tryInterpolation(SingleBTS btsName, int x, int y) { + int interpolated = 0; + // do interpolation for left,right,up,down + SingleBTS left = interpolate1to2(btsName, x - 2, x - 1, y, y); + SingleBTS right = interpolate1to2(btsName, x + 2, x + 1, y, y); + SingleBTS down = interpolate1to2(btsName, x, x, y + 2, y + 1); + SingleBTS up = interpolate1to2(btsName, x, x, y - 2, y - 1); + SingleBTS between = interpolateInBetween(btsName, x, y); + if (left != null) + interpolated++; + if (right != null) + interpolated++; + if (down != null) + interpolated++; + if (up != null) + interpolated++; + if (between != null) + interpolated++; + if (interpolated > 1) { + // interpolation successfull! + SingleBTS element = new SingleBTS(btsName.ARFCN, 0, 0, true, + new Date(), btsName.name); + // prepare element for averaging + element.clear(); + // nothing bad will happen if one of these BTSs are null! + element.addBTSMeasure(left); + element.addBTSMeasure(right); + element.addBTSMeasure(down); + element.addBTSMeasure(up); + element.addBTSMeasure(between); + if (element.getDldB() > -121 && element.getUldB() > -121) + if (element.getDldB() < -29 && element.getUldB() < -29) + return element; + + } + return null; + + } + + private SingleBTS interpolate1to2(SingleBTS btsName, int x1, int x2, + int y1, int y2) { + + SingleBTS first = InterpolateHelper.getFromList(btsName, map[x1][y1]); + SingleBTS second = InterpolateHelper.getFromList(btsName, map[x2][y2]); + // prepare returning BTS + + if (first != null && second != null) { + // interpolation for these two elements possible + double deltaDL = second.getDldB() - first.getDldB(); + double deltaUL = second.getUldB() - first.getUldB(); + // add the value of log10(0.005). one Array cell is 5*5m big! See + // the + // Youngs Model! + + // TODO: careful! double gets castet to int. Do correct + // interpolation here! + + double DL = deltaDL + second.getDldB(); + double UL = deltaUL + second.getUldB(); + SingleBTS element = new SingleBTS(first.ARFCN, (int) UL, (int) DL, + true, new Date(), first.name); + // first.interpolated = true; + return element; + } + + return null; + } + + private SingleBTS interpolateInBetween(SingleBTS btsName, int x, int y) { + // take one from the left, one from the right + // one from the top, one from the bottom + // one from the diagonal and one from the other diagonal + // prepare interpolated element! + SingleBTS element = new SingleBTS(btsName.ARFCN, 0, 0, true, + new Date(), btsName.name); + element.clear(); + + // to check if a correct interpolation was done + boolean[] done = { false, false, false, false }; + + // diagonal leftAndRight + SingleBTS first = InterpolateHelper.getFromList(btsName, + map[x - 1][y + 1]); + SingleBTS third = InterpolateHelper.getFromList(btsName, + map[x + 1][y - 1]); + if (first != null && third != null) { + element.addBTSMeasure(first); + element.addBTSMeasure(third); + done[0] = true; + } + + // diagonal rightAndLeft + first = InterpolateHelper.getFromList(btsName, map[x + 1][y + 1]); + third = InterpolateHelper.getFromList(btsName, map[x - 1][y - 1]); + if (first != null && third != null) { + element.addBTSMeasure(first); + element.addBTSMeasure(third); + done[1] = true; + } + + // leftAndRight + first = InterpolateHelper.getFromList(btsName, map[x - 1][y]); + third = InterpolateHelper.getFromList(btsName, map[x + 1][y]); + if (first != null && third != null) { + element.addBTSMeasure(first); + element.addBTSMeasure(third); + done[2] = true; + } + + // bottomAndTop + first = InterpolateHelper.getFromList(btsName, map[x][y + 1]); + third = InterpolateHelper.getFromList(btsName, map[x][y - 1]); + if (first != null && third != null) { + element.addBTSMeasure(first); + element.addBTSMeasure(third); + done[3] = true; + } + + // return the BTS only if at least one Interpolation worked out + for (int i = 0; i < done.length; i++) { + if (done[i]) + return element; + } + return null; + + } +} + +final class InterpolateHelper { + + public static boolean listContains(SingleBTS bts, List btsList) { + for (SingleBTS listBTS : btsList) { + if (bts.ARFCN == listBTS.ARFCN) + return true; + } + return false; + } + + // get the Element containing the ARFCN of btsName. Returns null, if no + // Element found! + public static SingleBTS getFromList(SingleBTS btsName, + List btslist) { + for (SingleBTS listBTS : btslist) { + if (listBTS.ARFCN == btsName.ARFCN) + return listBTS; + + } + return null; + } + +} diff --git a/DataStructure/GoogleOut.java b/DataStructure/GoogleOut.java new file mode 100644 index 0000000..0d96e33 --- /dev/null +++ b/DataStructure/GoogleOut.java @@ -0,0 +1,598 @@ +package DataStructure; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +public class GoogleOut { + private BufferedWriter br; + private LinkedList MRlog; + // private LinkedList GPSlog; + private double accuracy = 0.00004; + private GSMMap map; + private double[] Xcoords; + private double[] Ycoords; + private String fileName; + + public GoogleOut(GSMMap map, String fileName) { + this.map = map; + this.fileName = fileName; + } + + // Constructor + public void write() throws IOException { + // this.map = map; + Xcoords = map.Xcoords; + Ycoords = map.Ycoords; + br = new BufferedWriter(new FileWriter(new File(fileName))); + writeHeader(); + + // Downlink + // write Folder and Polygons for each BTS in the database + SingleBTS[] btsNames = map.btsnames; // change here to plot e-plus bts + for (SingleBTS singleBTSDL : btsNames) { + if (map.contains(singleBTSDL)) { + // if the GSMmap contains at least one of this BTS, do it + writeFolderDesc(singleBTSDL, false); + writePlacemarks(singleBTSDL, false); + br.write(" \n"); + } + + } + + // Uplink (RZ-GSM) + for (SingleBTS singleBTSDL : btsNames) { + if (map.contains(singleBTSDL)) { + // if the GSMmap contains at least one of this BTS, do it + writeFolderDesc(singleBTSDL, true); + writePlacemarks(singleBTSDL, true); + br.write(" \n"); + } + + } + + // Downlink (foreign BTSs). Actually one could just change BTSnames = + // map.content() in the beginning + SingleBTS[] foreign = map.contentForeignBTS(); + if (foreign != null) { + for (SingleBTS foreignBTS : foreign) { + writeFolderDesc(foreignBTS, false); + writePlacemarks(foreignBTS, false); + br.write(" \n"); + } + } + + br.write(""); + br.write(""); + br.flush(); + br.close(); + } + + /** + * Writes Header for the folder: Foldername, Up/Downlink, LookAt,... + * + * @param btsname + * @param uplink + * @throws IOException + */ + private void writeFolderDesc(SingleBTS btsname, boolean uplink) + throws IOException { + SingleBTS foundBTS = map.getFirstBTSmatch(btsname); + String upDown; + if (uplink) + upDown = "Uplink: "; + else + upDown = "Downlink: "; + + // br.write("1\n"); + br.write(" \n"); + br.write("MR " + upDown + "" + btsname.ARFCN + ": " + + btsname.name + "\n"); + br.write(" 1\n"); + br.write("MR from " + foundBTS.time.toString() + + "\n"); + br.write(" \n"); + br.write("" + (map.maxX + map.minX) / 2 + "\n"); + br.write("" + (map.maxY + map.minY) / 2 + "\n"); + br.write("0\n"); + br.write("0.0\n"); + br.write("0\n"); + br.write("276.0\n"); + br.write("\n"); + + } + + private void writePlacemarks(SingleBTS btsName, boolean uplink) + throws IOException { + // was a BTS written to file? + // Polygon Description for every Measured BTS + for (double gpsX : Xcoords) { + for (double gpsY : Ycoords) { + // because within GSMmap, every cell of the array is + // initialized, no null pointer exception will occur. only a + // empty list will be "thrown" but it doesn't hurt + ArrayList currentBTSList = map + .getBTSList(gpsX, gpsY); + + // traverse the ListBTS to find out if a BTS with the current + // name + // exists on this coordinate. Tell if a BTS was written to file + + writePlacemarkDetails(currentBTSList, btsName, gpsX, gpsY, + uplink); + + } + + } + + // Polygon Coordinates + } + + private void writePlacemarkDetails(List btsList, + SingleBTS btsName, double coordX, double coordY, boolean uplink) + throws IOException { + // if the current field was empty, so is the btsList. But still it is + // initilized, so there is no nullpointer exception! + String name; + for (SingleBTS singleBTS : btsList) { + // maybe its null, then continue with next + if (singleBTS == null) + continue; + + // get correct output String for UL or DL + if (uplink) + name = singleBTS.ULtoString(); + else + name = singleBTS.DLtoString(); + // you can only draw uplink if you've got a FullBTS! + if ((singleBTS.ARFCN == btsName.ARFCN && (!uplink || singleBTS.fullBTS))) { + if (uplink) + name = singleBTS.ULtoString(); + else + name = singleBTS.DLtoString(); + // draw it! + br.write(" \n"); + br.write("1\n"); + br.write("" + name + "\n"); + + writeStyleIdentifier(singleBTS, uplink); + + br.write("\n"); + br.write("1\n"); + br.write("\n"); + br.write("\n"); + br.write("\n"); + + writePolygonCoordinates(coordX, coordY, map.accuracy); + + br.write("\n"); + br.write("\n"); + br.write("\n"); + br.write("\n"); + br.write("\n"); + + // if (singleBTS.name.equals("neuer Name")) { + // System.out.print("hier! " + coordX + "/" + coordY); + // System.out.println(" Xcoord results to array " + // + map.searchBestX(coordX)); + // } + + } + + } + } + + private void writeStyleIdentifier(SingleBTS bts, boolean uplink) + throws IOException { + int btsRXvalue; + if (uplink) + btsRXvalue = (int) bts.getUldB(); + else + btsRXvalue = (int) bts.getDldB(); + + if (bts.isInterpolated()) { + // no FullBTS but interpolated: draw black line("#I") + br.write("#I" + btsRXvalue + "\n"); + } else if (bts.fullBTS) { + // show the nice FullBTS line around + br.write("#F" + btsRXvalue + "\n"); + } else { + // no line + br.write("#" + btsRXvalue + "\n"); + } + + } + + private void writePolygonCoordinates(double coordX, double coordY, + double accuracy) throws IOException { + double accuracyX = accuracy / 2; + double accuracyY = accuracy; + // Point 1 + br.write(coordX - accuracyX + "," + coordY + accuracyY + ",0,\n"); + // Point 2 + br.write(coordX + accuracyX + "," + coordY + accuracyY + ",0,\n"); + // Point3 + br.write(coordX + accuracyX + "," + (coordY - accuracyY) + ",0,\n"); + // Point4 + br.write((coordX - accuracyX) + "," + (coordY - accuracyY) + ",0,\n"); + // End: Point 1 + br.write((coordX - accuracyX) + "," + coordY + accuracyY + ",0\n"); + + } + + public GoogleOut(LinkedList GPSlog, + LinkedList MRlog, String fileName) + throws IOException { + this.MRlog = MRlog; + // this.GPSlog = GPSlog; + + br = new BufferedWriter(new FileWriter(new File(fileName))); + // write header + writeHeader(); + // write viewpoint + br.write("1"); + br.write(" "); + br.write("Measurement Report " + map.IMSI + ""); + br.write(" 1"); + br.write("MR from " + GPSlog.getFirst().time.toString() + + ""); + br.write(" "); + br.write("" + GPSlog.getFirst().coord2 + ""); + br.write("" + GPSlog.getFirst().coord1 + ""); + br.write("0"); + br.write("-34.82469740081282"); + br.write("0"); + br.write("276.7870053764046"); + br.write(""); + + // write content + int i = 0; + int discarded = 0; + Iterator GPSitr = GPSlog.iterator(); + while (GPSitr.hasNext()) { + GPScoordinate GPS = GPSitr.next(); + MeasurementReport MR = MRlog.get(i); + + // do nothing if Time is not valid + if (Math.abs(MR.time.getTime() - GPS.time.getTime()) < 3000) { + + br.write(" \n"); + br.write("1"); + br.write("" + MR.toString() + ""); + // br.write(""); + // br.write("bf00ff00"); + // br.write(""); + + // dl: Downlink - Network to phone + // up: Uplink - Phone to Network (has better perception for some + // reason) + br.write("#" + MRlog.get(i).getFirstBTSdl() + + ""); + + br.write(""); + br.write("1"); + br.write(""); + br.write(""); + br.write(""); + // Point 1 + System.out.println("this should not be started anymore"); + br.write(GPS.coord2 - accuracy + "," + GPS.coord1 + accuracy + + ",0,"); + // Point 2 + br.write(GPS.coord2 + accuracy + "," + GPS.coord1 + accuracy + + ",0,"); + // Point3 + br.write(GPS.coord2 + accuracy + "," + (GPS.coord1 - accuracy) + + ",0,"); + // Point4 + br.write((GPS.coord2 - accuracy) + "," + + (GPS.coord1 - accuracy) + ",0,"); + // End: Point 1 + br.write((GPS.coord2 - accuracy) + "," + GPS.coord1 + accuracy + + ",0"); + + br.write(""); + br.write(""); + br.write(""); + br.write(""); + br.write("\n"); + } else { + discarded++; + + } + + i++; + } + br.write(""); + br.write(""); + br.write(""); + br.flush(); + br.close(); + System.out.println("Discarded Coordinates: " + discarded); + + } + + @SuppressWarnings("unused") + private int getMin() { + Iterator itr = MRlog.iterator(); + MeasurementReport current; + int min = 0; + while (itr.hasNext()) { + current = itr.next(); + if (current.getFirstBTSul() < min) + min = current.getFirstBTSul(); + } + return min; + + } + + @SuppressWarnings("unused") + private int getMax() { + Iterator itr = MRlog.iterator(); + MeasurementReport current; + int max = -999; + while (itr.hasNext()) { + current = itr.next(); + if (current.getFirstBTSul() > max) + max = current.getFirstBTSul(); + } + return max; + } + + @SuppressWarnings("unused") + private int getSteps() { + Iterator itr = MRlog.iterator(); + int i = 0; + while (itr.hasNext()) { + itr.next(); + i++; + } + return i; + } + + @SuppressWarnings("unused") + private String toHex(int i) { + String out = Integer.toHexString(Math.abs(i)); + if (out.length() == 4) + return (out + "000"); + if (out.length() == 5) + return (out + "00"); + if (out.length() == 6) + return (out + "0"); + if (out.length() == 7) + return (out); + return out; + + } + + // strength -30 to -120 + // yellow at -75 + private String getColor(int strength) { + int green = 0; + int red = 0; + // yellow at -75 + if (strength > -75) { + green = 255; + red = 256 - Math.abs((256 / 45) * (-75 - strength)); + + } else { + // transient green from now on + red = 255; + green = Math.abs((256 / 45) * (-120 - 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)); + return ("ff00" + Integer.toHexString(green) + Integer.toHexString(red)); + + } + + private void writeHeader() throws IOException { + br.write("\n"); + br.write("\n"); + br.write(" \n"); + br.write("Measurement Report " + map.IMSI + "\n"); + br.write("1\n"); + + // style: color for signal strength from -30db to -120db + // color red = #FF0000 (16711680) + // color green = #00FF00 (65280) + + // styles for normal BTS + for (int style = -30; style >= -120; style--) { + + // int step = (16711680 - 65280) / getSteps(); + // for (int i = getMin(); i <= getMax(); i++) { + + br.write(" \n"); + } + + // styles for Full BTS: full white ffffff, no transparency:ff + for (int style = -30; style >= -120; style--) { + br.write(" \n"); + } + + // styles for Interpolated BTS: full black 000000, no transparency:ff + for (int style = -30; style >= -120; style--) { + br.write("\n"); + } + + } + + /** + * Writes Probabilitymap to file. + * + * @param scoremap + * @param file + * @throws IOException + */ + public void writeProbability(double[][] scoremap, String file) + throws IOException { + BufferedWriter br = new BufferedWriter(new FileWriter(new File(file))); + writeProbHeader(br); + for (int x = 0; x < map.Xcoords.length; x++) { + for (int y = 0; y < map.Ycoords.length; y++) { + if (scoremap[x][y] > 0) { + writeProbabilityLandmark(x, y, scoremap, br); + } + } + } + br.write(" \n"); + br.write(""); + br.write(""); + br.flush(); + br.close(); + } + + private void writeProbabilityLandmark(int x, int y, double[][] scoremap, + BufferedWriter br) throws IOException { + int score = (int) (scoremap[x][y] * 100); + + br.write(" \n"); + br.write("1\n"); + br.write("" + score + "\n"); + + br.write("#" + score + "\n"); + + br.write("\n"); + br.write("1\n"); + br.write("\n"); + br.write("\n"); + br.write("\n"); + + // draw the square + double accuracyX = map.accuracy; + double accuracyY = map.accuracy; + double coordX = map.Xcoords[x]; + double coordY = map.Ycoords[y]; + br.write(coordX - accuracyX + "," + coordY + accuracyY + ",0,\n"); + // Point 2 + br.write(coordX + accuracyX + "," + coordY + accuracyY + ",0,\n"); + // Point3 + br.write(coordX + accuracyX + "," + (coordY - accuracyY) + ",0,\n"); + // Point4 + br.write((coordX - accuracyX) + "," + (coordY - accuracyY) + ",0,\n"); + // End: Point 1 + br.write((coordX - accuracy) + "," + coordY + accuracy + ",0\n"); + + br.write("\n"); + br.write("\n"); + br.write("\n"); + br.write("\n"); + br.write("\n"); + + } + + private void writeProbHeader(BufferedWriter br) throws IOException { + br.write("\n"); + br.write("\n"); + br.write(" \n"); + br.write(" Probability map \n"); + br.flush(); + br.write("1\n"); + + // style: color for probability from 0% to 100% + // color red = #FF0000 (16711680) + // color green = #00FF00 (65280) + + // styles for probability + for (int style = 0; style <= 100; style++) { + + // int step = (16711680 - 65280) / getSteps(); + // for (int i = getMin(); i <= getMax(); i++) { + + br.write(" \n"); + } + br.write(" \n"); + br.write("Probability"); + br.write(" 1\n"); + br.write("Probability Map\n"); + br.write(" \n"); + br.write("" + (map.maxX + map.minX) / 2 + "\n"); + br.write("" + (map.maxY + map.minY) / 2 + "\n"); + br.write("0\n"); + br.write("0.0\n"); + br.write("0\n"); + br.write("276.0\n"); + br.write("\n"); + + } + + private String getProbabilityColor(int probability) { + + int greenp = (int) (probability * 2.55); + return ("ff00" + Integer.toHexString(greenp) + "00"); + + /* + * // probability is from 0 - 100 int green = 0; int red = 0; // yellow + * at -75 if (probability > 70) { green = 255; red = 256 - Math.abs((256 + * / 30) * (-70 - probability)); + * + * } else { // transient green from now on red = 255; green = + * Math.abs((256 / 70) * (-30 - probability)); } // 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= " + probability + ",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)); + * return ("ff00" + Integer.toHexString(green) + + * Integer.toHexString(red)); + */ + } +} diff --git a/DataStructure/Interpolator.java b/DataStructure/Interpolator.java new file mode 100644 index 0000000..3869255 --- /dev/null +++ b/DataStructure/Interpolator.java @@ -0,0 +1,366 @@ +package DataStructure; + +import helper.ListBTS; + +import java.awt.geom.Path2D; +import java.awt.geom.Point2D; +import java.util.ArrayList; +import java.util.Date; + +import voronoi.voronoi; +import Parse.sqlreader; + +public class Interpolator extends GSMMap { + /** + * + */ + private static final long serialVersionUID = 1388761837460629751L; + public ArrayList[][] buffer; + + public Interpolator(sqlreader SQL, double accuracy) { + super(SQL, accuracy); + // initialize buffer + buffer = new ArrayList[this.Xcoords.length][this.Ycoords.length]; + for (int x = 0; x < Xcoords.length; x++) { + for (int y = 0; y < Ycoords.length; y++) { + buffer[x][y] = new ArrayList(); + } + } + + } + + /** + * Interpolates every Point on the map,every arfcn + */ + public void interpolateVR() { + // get starting time + long start = new Date().getTime(); + + // average first! + // average(); + // removeOutlier(); + SingleBTS[] content = content(); + int success = 0; + int failure = 0; + int number = Xcoords.length * Ycoords.length * content.length; + // traverse each bts + for (int i = 0; i < content.length; i++) { + // for (int i = 2; i < 3; i++) { + // initialize voronoi with current arfcn + voronoi primary = new voronoi(); + primary.sortNode(this, content[i].ARFCN, 1); + primary.generateVoronoi(0, Xcoords.length * 3.5, 0, + Ycoords.length * 3.5); + // now, traverse each point. Check if interpolation is needed! + // loop is a little tricky because of threats! + for (int x = 0; x < Xcoords.length; x++) { + for (int y = 0; y < Ycoords.length; y++) { + // this is a crucial point for parallelism. Change this if + // statement + // if (ListBTS.contains(map[x][y], content[i])) { + // this coordinates already contains this bts + // continue; + // } + // System.out.print("Interpoliere bei:" + x + "," + y + // + ", arfcn " + content[i].ARFCN); + + // make it parallel? + interpolateThread it1 = new interpolateThread(x, y, + content[i], primary); + Thread it1T = new Thread(it1); + try { + if (!ListBTS.contains(map[x][y], content[i])) { + it1T.start(); + // success++; + } + } catch (Exception e) { + failure++; + } + + y++; + + interpolateThread it2 = new interpolateThread(x, y, + content[i], primary); + Thread it2T = new Thread(it2); + try { + if (checkBounds(x, y) + && !ListBTS.contains(map[x][y], content[i])) { + it2T.start(); + // success++; + } + } catch (Exception e) { + failure++; + } + + y++; + + interpolateThread it3 = new interpolateThread(x, y, + content[i], primary); + Thread it3T = new Thread(it3); + try { + if (checkBounds(x, y) + && !ListBTS.contains(map[x][y], content[i])) { + it3T.start(); + // success++; + } + } catch (Exception e) { + failure++; + } + + y++; + interpolateThread it4 = new interpolateThread(x, y, + content[i], primary); + + Thread it4T = new Thread(it4); + try { + if (checkBounds(x, y) + && !ListBTS.contains(map[x][y], content[i])) { + it4T.start(); + // success++; + } + } catch (Exception e) { + failure++; + } + + // y++; + // interpolateThread it5 = new interpolateThread(x, y, + // content[i], primary); + + // Thread it5T = new Thread(it5); + // try { + // if (checkBounds(x, y) + // && !ListBTS.contains(map[x][y], content[i])) { + // it5T.start(); + // success++; + // } + // } catch (Exception e) { + // failure++; + // } + + // success += 5; + success += 4; + if (success % 200 == 0) { + // calc ETA + long difference = new Date().getTime() - start; + int resttime = (int) (difference / success * (number - success)); + resttime = (resttime / 1000) / 60; + System.out.println("Total: " + number + " current: " + + success + " rest: " + resttime + + " min; current ARFCN: " + content[i].ARFCN + + ", Index:" + i + "/" + content.length); + + } + + try { + it1T.join(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + try { + it2T.join(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + try { + it3T.join(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + try { + it4T.join(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + // try { + // it5T.join(); + // } catch (InterruptedException e) { + // TODO Auto-generated catch block + // e.printStackTrace(); + // } + + // interpolateAT(x, y, content[i], primary); + // //singleThread + + // } catch (Exception e) { + // System.out.println("Fehler bei:" + x + "," + y); + // failure++; + // } + + } + } + } + mergebuffer(); + System.out.println("Fertig!"); + } + + private boolean checkBounds(int x, int y) { + return (x < Xcoords.length && y < Ycoords.length); + } + + /** + * Takes map[x][y]. Inserts an interpolated BTS on this point if neccessary + * + * @param x + * @param y + * @param arfcn + * @param primary + * original Voronoi without the current Interpolationpoint + */ + private void interpolateAT(int x, int y, SingleBTS interpolateThis, + voronoi primary) { + if (!ListBTS.contains(map[x][y], interpolateThis)) { + // do it! + + voronoi secondary = new voronoi(); + secondary.sortNode((GSMMap) this, interpolateThis.ARFCN, 1, x, y); + secondary.generateVoronoi(0, 4000, 0, 4000); + + // get area of polygon for current x,y + // double area = secondary.areaOf(x, y); + Path2D region = secondary.getPoly(x, y); + double area = secondary.area(region); + if (region == null) { + return; + } + // get Neighbors of x,y + ArrayList neighbors = secondary.getDirectNeighbors(x, y); + + // calculate intersection of voronoi region for each neighbor + ArrayList weights = new ArrayList(neighbors.size()); + for (int i = 0; i < neighbors.size(); i++) { + int neighX = (int) neighbors.get(i).getX(); + int neighY = (int) neighbors.get(i).getY(); + // double area2 = primary.areaOf(currentx, currenty); + + Path2D underling = primary.getPoly(neighX, neighY); + if (underling == null) { + // one of the neighbors doesn't have a vornoi region. + // this happens at the bounds of the gsm map:a infinit big + // polygon + continue; + // TODO: das continue könnte zu problemen führen, weil dann + // auch kein weights element an dieser Stelle eingefügt wird + // und das Array somit an dieser Stelle auch null ist + // TODO: warum ist temporary manchmal null?!!!!!!! + } + // intersection between both voronoi regions + double intersectA = primary.intersectArea(region, underling); + Weight new_element = new Weight(); + new_element.weight = intersectA / area; + new_element.bts = ListBTS.getARFCN(map[neighX][neighY], + interpolateThis); + weights.add(new_element); + } + + // now, traverse weights, get sum of weights (to check if it equals + // one) + double newDL = 0; + double mode = 0; + double var = 0; + double DlQualsub = 0; + // double DlQualFull = 0; + double UlQualsub = 0; + // double UlQualFull = 0; + double sum_of_weights = 0; + for (int i = 0; i < weights.size(); i++) { + if (weights.get(i) == null) + continue; + sum_of_weights += weights.get(i).weight; + } + + // calculate with weights and normalize + for (int i = 0; i < weights.size(); i++) { + if (weights.get(i) == null) + continue; + // HACK: normalize weights + weights.get(i).weight = weights.get(i).weight / sum_of_weights; + // calulate + newDL = newDL + weights.get(i).weight + * weights.get(i).bts.getDLmW(); + mode = mode + weights.get(i).weight + * weights.get(i).bts.getStrictDLdBAverage(); + var = var + weights.get(i).weight + * weights.get(i).bts.getTrueVarianceDLdB(); + DlQualsub = DlQualsub + weights.get(i).weight + * weights.get(i).bts.getDLQsub(); + // DlQualFull = DlQualFull + weights.get(i).weight + // * weights.get(i).bts.getDLQfull(); + UlQualsub = UlQualsub + weights.get(i).weight + * weights.get(i).bts.getULQsub(); + // UlQualFull = UlQualFull + weights.get(i).weight + // * weights.get(i).bts.getULQfull(); + + // weights.get(i).bts. + } + + // map[x][y] doesn't contain the just interpolated bts + SingleBTS temp = new SingleBTS(interpolateThis.ARFCN, + interpolateThis.name + "I"); + temp.addDl(newDL); + temp.dlQsub.add(DlQualsub); + // temp.dlQfull.add(DlQualFull); + temp.ulQsub.add(UlQualsub); + // temp.ulQfull.add(UlQualFull); + temp.interpolated.add(true); + temp.setVarDLdB(var); + temp.mode = mode; + buffer[x][y].add(temp); + + } + + } + + private void mergebuffer() { + for (int x = 0; x < Xcoords.length; x++) { + for (int y = 0; y < Ycoords.length; y++) { + if (map[x][y].isEmpty()) { + map[x][y] = buffer[x][y]; + } else { + mergeSingleBTS(x, y); + } + } + } + } + + /** + * If map[x][y] contains measurements, check if some BTS are missing and + * merge with buffer + * + * @param x + * @param y + */ + private void mergeSingleBTS(int x, int y) { + for (SingleBTS current : buffer[x][y]) { + if (!ListBTS.contains(map[x][y], current)) { + map[x][y].add(current); + } + } + + } + + class interpolateThread implements Runnable { + public int x; + public int y; + public SingleBTS what; + public voronoi primary; + + @Override + public void run() { + if (x < Xcoords.length && y < Ycoords.length) + interpolateAT(x, y, what, primary); + } + + public interpolateThread(int x, int y, SingleBTS what, voronoi primary) { + this.x = x; + this.y = y; + this.what = what; + this.primary = primary; + } + + } + +} diff --git a/DataStructure/MeasurementReport.java b/DataStructure/MeasurementReport.java new file mode 100644 index 0000000..ee06667 --- /dev/null +++ b/DataStructure/MeasurementReport.java @@ -0,0 +1,60 @@ +package DataStructure; + +import java.util.Date; +import java.util.LinkedList; + +public class MeasurementReport { + private LinkedList MR = new LinkedList(); + public Date time = new Date(); + + // Constructor + public MeasurementReport() { + // MR = new LinkedList(); + } + + // TODO: think of a way to get data out of this structure (eg. as array, + // etc.) + + // add a new BTS to list + public void add(SingleBTS BTS) { + // SingleBTS current; + // int i = 0; + // BTS with same frequency already existing? If so, average + // while ((!MR.isEmpty()) && (current = MR.get(i)) != null) { + // if (current.ARFCN == BTS.ARFCN) { + // System.out.println("DEBUG: Element found. Averaging"); + // current.addBTSMeasure(BTS); + // MR.remove(i); + // MR.add(i, current); + // break; // only one duplicate BTS should exist + // } else { + MR.add(BTS); + // } + // } + } + + public void add(String SqlStatement) { + String[] answers = SqlStatement.split(","); + // WARNING get only first BTS here. Problem: ARFCN is unknown! + SingleBTS BTS = new SingleBTS(123, Integer.parseInt(answers[3]), + Integer.parseInt(answers[13]), false, null, "unknown"); + add(BTS); + + } + + // returns RX-Quality of first BTS in the Measurement + public String toString() { + return time.toString() + ";" + MR.getFirst().toString(); + + } + + public int getFirstBTSul() { + return (int) MR.getFirst().getUldB(); + } + + public int getFirstBTSdl() { + return (int) MR.getFirst().getDldB(); + } +} + +// Stores single BTS information diff --git a/DataStructure/MobilePhone.java b/DataStructure/MobilePhone.java new file mode 100644 index 0000000..2276bb6 --- /dev/null +++ b/DataStructure/MobilePhone.java @@ -0,0 +1,337 @@ +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.util.ArrayList; +import java.util.Date; + +import org.jdesktop.swingx.JXMapViewer; +import org.jdesktop.swingx.mapviewer.GeoPosition; +import org.jdesktop.swingx.painter.Painter; + +public class MobilePhone implements Painter { + public ArrayList MR; + public long IMSI; + public double[][] scoremap; + public GSMMap gsmmap; + public Color color; + public boolean timeSensitiv = false; + public double confidence; + public BayesAll bayes; + public GPScoordinate correctCoordinate; + public String name = ""; + public Date time = new Date(); + + // private int maxProbX; + // private int maxProbY; + + public MobilePhone() { + MR = new ArrayList(); + } + + public MobilePhone(BayesAll bayes) { + MR = new ArrayList(); + this.bayes = bayes; + + } + + private void DrawDetails(Graphics2D g, double highestScore, int tileCount) { + g.setColor(Color.WHITE); + g.fillRect(0, 0, 300, 25); + g.setColor(Color.BLACK); + g.drawString("Score tile: " + highestScore + "\n\r #Tiles: " + + tileCount, 5, 10); + Date time; + if (timeSensitiv) { + time = this.time; + } else { + time = MR.get(0).time; + } + g.drawString(name + " " + time, 5, 20); + + } + + public void average() { + + } + + public String toString() { + return IMSI + " " + MR; + } + + /** + * Returns (and stores in scoremap) the possibility that this Mobile Phone + * falls within the tile. Dimensions and Coordinates of scoremap are that of + * map. Must be run before this Phone gets drawn! + * + * @param map + * @return + */ + public double[][] locate(GSMMap map, boolean dropNaN) { + scoremap = gsmBayes.computeScore(MR, map); + this.gsmmap = map; + + return scoremap; + } + + public double[][] locate(double confidence) { + this.gsmmap = this.bayes.map; + this.confidence = confidence; + timeSensitiv = false; + ArrayList averagedMR = ListBTS.generateAveragedList(MR); + + // remove outlier! + // for (int i = 0; i < averagedMR.size(); i++) { + // averagedMR.get(i).removeOutlier(); + // } + scoremap = bayes.locate(averagedMR, confidence); + if (correctCoordinate != null) { + System.out.println(localizationAccuracy()); + } + return scoremap; + } + + /** + * Returns (and stores) the possibility that this Mobile Phone falls within + * the tile. Possibilities get summed up until they are greater or equal + * confidence. Dimensions and Coordinates of scoremap are that of map + * + * @param map + * @return + */ + public double[][] locate(GSMMap map, double confidence, boolean dropNaN) { + scoremap = gsmBayes.toConfidence(gsmBayes.computeScore(MR, map), + confidence); + gsmmap = map; + this.confidence = confidence; + return scoremap; + } + + public double[][] locateTimeSensitiv(GSMMap map, double confidence, + long time, boolean dropNaN) { + gsmmap = map; + this.confidence = confidence; + ArrayList temporalMR = filterTime(MR, time); + temporalMR = ListBTS.generateAveragedList(temporalMR); + scoremap = gsmBayes.toConfidence( + gsmBayes.computeScore(temporalMR, map), confidence); + return scoremap; + } + + public double[][] locateTimeSensitiv(double confidence, long time) { + this.gsmmap = this.bayes.map; + this.confidence = confidence; + timeSensitiv = true; + this.time = new Date(time); + ArrayList temporalMR = filterTime(MR, time); + temporalMR = ListBTS.generateAveragedList(temporalMR); + scoremap = bayes.locate(temporalMR, confidence); + + // sum up scoremap!!!! + double sum = 0; + for (int x = 0; x < scoremap.length; x++) { + for (int y = 0; y < scoremap[0].length; y++) { + sum += scoremap[x][y]; + } + } + // System.out.println("Summe scoremap: " + sum); + + return scoremap; + + } + + /** + * Returns entries in MR that are +/- 1 second within time + * + * @param MR + * @param time + * @return + */ + private ArrayList filterTime(ArrayList MR, long time) { + ArrayList temporalMR = new ArrayList(20); + for (SingleBTS current : MR) { + if (Math.abs(current.time.getTime() - time) <= 1001) { + temporalMR.add(current); + } + } + return temporalMR; + } + + @Override + public void paint(Graphics2D g, JXMapViewer map, int w, int h) { + // locate(gsmmap); + + g = (Graphics2D) g.create(); + + // convert from viewport to world bitmap + Rectangle rect = ((org.jdesktop.swingx.JXMapViewer) map) + .getViewportBounds(); + g.translate(-rect.x, -rect.y); + // maxProbX = 0; + // maxProbY = 0; + double currentscore = 0; + int tileCounter = 0; + Polygon maxTile = null; + // now, draw + for (int x = 0; x < scoremap.length; x++) { + for (int y = 0; y < scoremap[0].length; y++) { + + if (scoremap[x][y] > 0) { + tileCounter++; + double coordX = gsmmap.Xcoords[x]; + double coordY = gsmmap.Ycoords[y]; + double accuracy = gsmmap.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 = map.getTileFactory().geoToPixel(pos1, + map.getZoom()); + Point2D pt2 = map.getTileFactory().geoToPixel(pos2, + map.getZoom()); + Point2D pt3 = map.getTileFactory().geoToPixel(pos3, + map.getZoom()); + Point2D pt4 = map.getTileFactory().geoToPixel(pos4, + map.getZoom()); + Color c = getColor(scoremap[x][y]); + // g.setColor(new Color(255, 0, 0, 255)); + g.setColor(c); + 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()); + g.fill(tile); + g.draw(tile); + if (scoremap[x][y] >= currentscore) { + // update x, y of biggest score + currentscore = scoremap[x][y]; + // maxProbX = x; + // maxProbY = y; + maxTile = tile; + } + } + } + } + + // g.translate(-rect.x, -rect.y); + try { + g.setColor(Color.red); + g.draw(maxTile); + } catch (NullPointerException e) { + + } + + if (correctCoordinate != null) { + // draw a circle where the correct position of this phone is + double latitude = correctCoordinate.coord1; + double longitude = correctCoordinate.coord2; + GeoPosition correct = new GeoPosition(latitude, longitude); + Point2D circle = map.getTileFactory().geoToPixel(correct, + map.getZoom()); + g.setColor(Color.RED); + g.drawOval((int) circle.getX() - 5, (int) circle.getY() - 5, 10, 10); + } + // translate back to Monitor coordinates + g.translate(rect.x, rect.y); + DrawDetails(g, currentscore, tileCounter); + g.dispose(); + + } + + /** + * After a localization was done, you can output details for this + * localization + * + * @return + */ + public String localizationAccuracy() { + try { + // get maximum possible tile + PossibilityObject[] possibilities = bayes.toPossibility(scoremap); + PossibilityObject mostPossible = possibilities[possibilities.length - 1]; + // x,y for most possible coord + int x = mostPossible.x; + int y = mostPossible.y; + GPScoordinate possibleCoord = new GPScoordinate(new Date(), + gsmmap.Ycoords[y], 'N', gsmmap.Xcoords[x], 'E', true); + + // distance between correct localization and possibleCoord + double distance = helper.Distance.calc(possibleCoord, + correctCoordinate); + // get distance of tile that is maximum away from correct location + double radius = maxError(); + String result = "Distance to correct position: " + distance * 1000 + + "m. Most away tile: " + radius * 1000 + + "m from correct position"; + return result; + + } catch (NullPointerException e) { + // System.out.println("ERROR: cannot aquire most possible location"); + return ""; + } + + } + + private double maxError() { + double maxDistance = 0; + double correctN = correctCoordinate.coord1; + double correctE = correctCoordinate.coord2; + for (int x = 0; x < scoremap.length; x++) { + for (int y = 0; y < scoremap[0].length; y++) { + if (scoremap[x][y] > 0) { + double currentDistance = helper.Distance.calc(correctN, + correctE, gsmmap.Ycoords[y], gsmmap.Xcoords[x]); + maxDistance = Math.max(maxDistance, currentDistance); + } + } + } + return maxDistance; + } + + private Color getColor(double d) { + // d between 0...confidence + // Color between black and green??? + // int green = (int) (d * 255); + // return new Color(0, green, 0, 100); + + // r+b means probability of 1/2!!! + int color = (int) ((d / confidence) * 255); + // lets say half of confidence is already full pink! + color = color * 2; + if (color > 255) + color = 255; + return new Color(color, 0, color, 255); + } + + public long getMinTime() { + long time = MR.get(0).time.getTime(); + for (int i = 1; i < MR.size(); i++) { + if (MR.get(i).time.getTime() < time) { + time = MR.get(i).time.getTime(); + } + } + return time; + } + + public long getMaxTime() { + long time = MR.get(0).time.getTime(); + for (int i = 1; i < MR.size(); i++) { + if (MR.get(i).time.getTime() > time) { + time = MR.get(i).time.getTime(); + } + } + return time; + } + +} diff --git a/DataStructure/NormDistribution.java b/DataStructure/NormDistribution.java new file mode 100644 index 0000000..109d4fa --- /dev/null +++ b/DataStructure/NormDistribution.java @@ -0,0 +1,77 @@ +package DataStructure; + +class NormDistribution { + double variance; + double mean; + static final double sqrtPI = 2.506628274631000502415765284811d; + + public static void main(String args[]) { + NormDistribution one = new NormDistribution(5.12, 10); + NormDistribution two = new NormDistribution(5.12, 10); + NormDistribution three = new NormDistribution(0, 4); + System.out.println(one.intersection(two)); + System.out.println("value at max: " + three.valueAt(2)); + } + + public NormDistribution(double mean, double variance) { + this.mean = mean; + this.variance = variance; + } + + public double valueAt(double x) { + double std = Math.sqrt(variance); + // double sqrtPI = Math.sqrt(2 * Math.PI); + + double exp = Math.exp(((Math.pow((x - mean), 2)) / variance) / (-2)); + double result = (1 / (std * sqrtPI)) * exp; + return result; + } + + /** + * Calculates the intersection area of both Distributions + * + * @param distribution + * @return + */ + public double intersection(NormDistribution distribution) { + + // return one, if both distributions are alike? (speedup) + if (Math.abs(this.mean - distribution.mean) < 0.01 + && Math.abs(this.variance - distribution.variance) < 0.01) { + return 0.998; + } + + // if (variance < 0.1 && distribution.variance < 0.1 + // && Math.abs(mean - distribution.mean) < 0.1) { + // return 1; + // } + + // get plus/minus 3*sigma Intervall (95% of the values) + double begin = -3.5 + * Math.sqrt(Math.min(variance, distribution.variance)) + + Math.min(mean, distribution.mean); + ; + double end = 3.5 * Math.sqrt(Math.max(variance, distribution.variance)) + + Math.max(mean, distribution.mean); + // get stepwidth for integration. + double step = (end - begin) / 42; // Resolution: 42 steps! + // what if rounding errors appear and step == 0? + if (step < 0.0000001) { + return 0; + } + + double area = 0; + end -= step; + + for (double x0 = begin; x0 <= end; x0 += step) { + // get min value + double x1 = x0 + step; + double fx0 = Math.min(valueAt(x0), distribution.valueAt(x0)); + double fx1 = Math.min(valueAt(x1), distribution.valueAt(x1)); + area += fx0 * (x1 - x0) + ((x1 - x0) * (fx1 - fx0)) / 2; + } + + return area; + } + +} \ No newline at end of file diff --git a/DataStructure/PhoneContainer.java b/DataStructure/PhoneContainer.java new file mode 100644 index 0000000..efcc24c --- /dev/null +++ b/DataStructure/PhoneContainer.java @@ -0,0 +1,106 @@ +package DataStructure; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.util.ArrayList; +import java.util.Random; + +import org.jdesktop.swingx.JXMapViewer; +import org.jdesktop.swingx.painter.Painter; + +public class PhoneContainer implements Painter { + + private ArrayList phones = new ArrayList(); + private ArrayList colors = new ArrayList(); + + public PhoneContainer() { + + } + + /** + * Adds the phone to the JXMAP-Painter. Assigns a random Color if phone is + * new. Make sure phone is already initialized. That means, locate method is + * already called. This container takes MobilEPhone Objects and draws them + * all! + * + * @param phone + */ + public void add(MobilePhone phone) { + // look if Phone is already inside + int index = findIMSI(phone); + if (index > -1) { + // phone is there at position index + Color intermediate = phones.get(index).color; + phone.color = intermediate; + phones.set(index, phone); + } else { + + Random r = new Random(); + phone.color = new Color(r.nextInt(256), r.nextInt(256), + r.nextInt(256)); + phones.add(phone); + } + + // oder Farbe durch einen Hash auf die IMSI machen... + + } + + private int findIMSI(MobilePhone phone) { + for (int i = 0; i < phones.size(); i++) { + if (phones.get(i).IMSI == phone.IMSI) { + return i; + } + } + return -1; + } + + /** + * Removes all Phones from Painter list. Colors for each phone (IMSI) is + * remembered + */ + public void removeAll() { + phones.clear(); + } + + @Override + /** + * HACK: Outputs only two phones now! For Journal. Remove test for IMSI afterwards + */ + public void paint(Graphics2D g, JXMapViewer map, int w, int h) { + for (MobilePhone phone : phones) { + if (phone.IMSI == 262230000000003L + || phone.IMSI == 262230000000013L) { + // g.setColor(phone.color); + g.setColor(getColor(phone)); + + phone.paint(g, map, w, h); + } + } + g.dispose(); + + } + + private Color getColor(MobilePhone phone) { + // search if IMSI already in list + for (int i = 0; i < colors.size(); i++) { + if (colors.get(i).IMSI == phone.IMSI) { + return colors.get(i).c; + } + } + Random r = new Random(); + Color result = new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256)); + colors.add(new ImsiColor(phone.IMSI, result)); + return result; + } + +} + +class ImsiColor { + public long IMSI; + public Color c; + + public ImsiColor(long IMSI, Color c) { + this.IMSI = IMSI; + this.c = c; + } +} diff --git a/DataStructure/PossibilityObject.java b/DataStructure/PossibilityObject.java new file mode 100644 index 0000000..9718012 --- /dev/null +++ b/DataStructure/PossibilityObject.java @@ -0,0 +1,21 @@ +package DataStructure; + +class PossibilityObject implements Comparable { + double possibility; + int x; + int y; + + @Override + public int compareTo(PossibilityObject comperator) { + if (this == null || comperator == null) { + throw new NullPointerException( + "one of the Possiblity objects is null!"); + } + if (this.possibility > comperator.possibility) { + return 1; + } else if (this.possibility < comperator.possibility) { + return -1; + } else + return 0; + } +} diff --git a/DataStructure/ResultScore.java b/DataStructure/ResultScore.java new file mode 100644 index 0000000..9d498ec --- /dev/null +++ b/DataStructure/ResultScore.java @@ -0,0 +1,54 @@ +package DataStructure; + +import helper.ListGPS; + +import java.util.ArrayList; +import java.util.LinkedList; + +public class ResultScore { + ArrayList scores = new ArrayList(); + GSMMap map; + + /** + * Gets score for every Coordinate + * + * @param list + */ + public ResultScore(GSMMap map) { + this.map = map; + + } + + public ArrayList find(LinkedList MR, + double thresholdDBm) { + ArrayList places = map.find(MR, thresholdDBm); + GPScoordinate[] content = ListGPS.content(places); + for (GPScoordinate curr_content : content) { + // take every Coordinate once. Build a ScoreElement with it.Traverse + // the whole list + ScoreElement curr_score = new ScoreElement(curr_content); + for (GPScoordinate curr_place : places) { + curr_score.add(curr_place); + } + scores.add(curr_score); + + // traverse every coordinate from gsm.find. check every tile if all + // mesurements match. if not, score gets low + + // then, check BTS relations! + + } + return scores; + } + + private void checkRatio(LinkedList MR) { + // calculate ratios from MR first + // compare with ratios that occur in scores.gps + + } +} + +class ratio { + SingleBTS first; + SingleBTS second; +} diff --git a/DataStructure/ScoreElement.java b/DataStructure/ScoreElement.java new file mode 100644 index 0000000..c5ed85a --- /dev/null +++ b/DataStructure/ScoreElement.java @@ -0,0 +1,21 @@ +package DataStructure; + +class ScoreElement { + public int occurrence; // how often was this coordinate chosen based on + // Signalstrength + public int ratio_hit; // how often was this coordinate chosen based on + // SignalRatio + public GPScoordinate gps; + private double score; + + public ScoreElement(GPScoordinate reference) { + gps = reference; + } + + public void add(GPScoordinate gps) { + if (this.gps.equals(gps)) { + score++; + } + + } +} diff --git a/DataStructure/SingleBTS.java b/DataStructure/SingleBTS.java new file mode 100644 index 0000000..5d7be6a --- /dev/null +++ b/DataStructure/SingleBTS.java @@ -0,0 +1,775 @@ +package DataStructure; + +import java.io.Serializable; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.LinkedList; + +public class SingleBTS implements Comparable, Serializable { + + private static final long serialVersionUID = 1L; + + public int ARFCN; // BTS-Frequency + + public String name; // Name of BTS + public Date time; // used to distinguish usedBTS; + public LinkedList interpolated = new LinkedList(); + // Is this BTS interpolated or measured? + public boolean fullBTS; // Is this a fully Measured BTS? Does it have UL, TA + // and so on... + public int TA; // Timing-Advance + public int BS_POWER; // BaseSation Power + public int MS_TO; // MS_TO + public int MS_PWR; // L1_MS_PWR + // public GPScoordinate coord; // where was the BTS found? + private ArrayList RXul = new ArrayList(); // Strength + // Up-link + private ArrayList RXdl = new ArrayList(); // Strength + // Down-Link + public int reason; // SMS, call, LocationUpdate... + + public double distance; // Distance to BTS in km + + public GPScoordinate coordinate; + private double varDL; // Stores variance if this SingleBTS is + // interpolated + public double mode; // maximum probability density in dBm + + // public double ulQ = -1; + public ArrayList dlQsub = new ArrayList(); + // public ArrayList dlQfull = new ArrayList(); + public ArrayList ulQsub = new ArrayList(); + + // public ArrayList ulQfull = new ArrayList(); + + // Constructor + public SingleBTS(int ARFCN, double RXul, double RXdl, boolean interpolated, + Date time, String name) { + this.ARFCN = ARFCN; + if (RXul != 0) + this.addUl(RXul); + this.addDl(RXdl); + this.interpolated.add(interpolated); + // this.interpolated = interpolated; + this.time = time; + this.name = name; + } + + public SingleBTS(int ARFCN, double RXul, double RXdl, boolean interpolated, + Date time, String name, double varDL) { + this(ARFCN, RXul, RXdl, interpolated, time, name); + this.varDL = varDL; + + } + + /* + * // Constructor without boolean without time public SingleBTS(int ARFCN, + * int RXul, int RXdl, int TA) { this(ARFCN, RXul, RXdl, TA, false, null); } + * + * // Constructor with date public SingleBTS(int ARFCN, int RXul, int RXdl, + * int TA, Date time) { this(ARFCN, RXul, RXdl, TA, false, time); } + */ + + public SingleBTS(int ARFCN, int RXul, int RXdl, boolean interpolated, + Date timestamp, String name, int TA, int BS_POWER, int MS_TO, + int mS_PWR) { + this.ARFCN = ARFCN; + + this.addUl(RXul); + this.addDl(RXdl); + + this.interpolated.add(interpolated); + // this.interpolated = interpolated; + this.time = timestamp; + this.name = name; + this.TA = TA; + this.BS_POWER = BS_POWER; + this.MS_TO = MS_TO; + + } + + // "empty" constructor to do averaging + public SingleBTS(int ARFCN, String name) { + this.ARFCN = ARFCN; + this.name = name; + this.reason = 2; + time = new Date(); + } + + public void addUl(double RXul) { + // a Measurement of 0 will not happen! + if (RXul != 0) { + if (RXul > 0) { + // RXul is in mW + this.RXul.add(RXul); + } else { + // RXul is in dBmw + double value = Math.pow(10, RXul / 10d); + this.RXul.add(value); + } + // it gets automatically a full BTS + fullBTS = true; + } + } + + public double getDLQsub() { + if (dlQsub.size() == 0) { + return -10000; + } + if (dlQsub.size() == 1) { + return dlQsub.get(0); + } + + int result = 0; + for (int i = 0; i < dlQsub.size(); i++) { + result += dlQsub.get(i); + } + return ((double) result / dlQsub.size()); + } + + public double getULQsub() { + if (ulQsub.size() == 0) { + return -10000; + } + if (ulQsub.size() == 1) { + return ulQsub.get(0); + } + + int result = 0; + for (int i = 0; i < ulQsub.size(); i++) { + result += ulQsub.get(i); + } + return ((double) result / ulQsub.size()); + } + + /* + * public double getULQfull() { if (ulQfull.size() == 0) { return -10000; } + * if (ulQfull.size() == 1) { return ulQfull.get(0); } + * + * int result = 0; for (int i = 0; i < ulQfull.size(); i++) { result += + * ulQfull.get(i); } return ((double) result / ulQfull.size()); } + */ + + /* + * public double getDLQfull() { if (dlQfull.size() == 0) { return 9; } if + * (dlQfull.size() == 1) { return dlQfull.get(0); } + * + * int result = 0; for (int i = 0; i < dlQfull.size(); i++) { result += + * dlQfull.get(i); } return ((double) result / dlQfull.size()); } + */ + + public double getUldB() { + if (RXul.isEmpty()) + return Double.NaN; + double sum = 0; + for (Double ul : RXul) { + sum = sum + ul; + } + // average + sum = sum / RXul.size(); + // to dbm + double dbm = 10 * Math.log10(sum); + return (dbm); + } + + public double getULmW() { + if (RXul.isEmpty()) + return 0; + double sum = 0; + for (Double ul : RXul) { + sum = sum + ul; + } + return (sum / RXul.size()); + } + + public double getDLmW() { + if (RXdl.isEmpty()) + return 0; + double sum = 0; + for (Double dl : RXdl) { + sum = sum + dl; + } + return (sum / RXdl.size()); + } + + public void addDl(double RXdl) { + if (RXdl != 0) { + if (RXdl > 0) { + // RXdl is in mW + this.RXdl.add(RXdl); + } else { + // RXul is in dBmW + double value = Math.pow(10, RXdl / 10d); + this.RXdl.add(value); + } + } + } + + public double getDldB() { + if (RXdl.isEmpty()) + return Double.NaN; + double sum = 0; + for (Double dl : RXdl) { + sum = sum + dl; + } + // average + sum = sum / RXdl.size(); + // to dB + double dbm = 10 * Math.log10(sum); + return (dbm); + } + + /** + * Returns average of dB-Values. No prior transform to mW before averaging. + * Seems wrong! + * + * @return + */ + public double getStrictDLdBAverage() { + if (mode == 0) { + double sum = 0; + for (Double x : RXdl) { + sum += 10 * Math.log10(x); + } + sum = sum / getDLcount(); + // mode = sum; + return sum; + } else + return mode; + } + + /** + * Adds measurements from another SingleBTS. Provided BTS is only added if: + * BTS is not null, ARFCN of BTS matches + * + * @param BTS + * The BTS that should be added + */ + public void addBTSMeasure(SingleBTS BTS) { + if (BTS != null && BTS.ARFCN == this.ARFCN) { + addUl(BTS.getUldB()); + addDl(BTS.getDldB()); + // this.dlQsub.addAll(BTS.dlQsub); + // this.dlQfull.addAll(BTS.dlQfull); + this.ulQsub.addAll(BTS.ulQsub); + // this.ulQfull.addAll(BTS.ulQfull); + this.dlQsub.addAll(BTS.dlQsub); + if (BTS.BS_POWER != 0) + this.BS_POWER = BTS.BS_POWER; + if (BTS.MS_PWR != 0) + this.MS_PWR = BTS.MS_PWR; + if (BTS.MS_TO != 0) + this.MS_TO = BTS.MS_TO; + if (BTS.TA != 0) + this.TA = BTS.TA; + if (BTS.time != null) + this.time = BTS.time; + if (!this.fullBTS) + this.fullBTS = BTS.fullBTS; + } + } + + public double getVarianceULmW() { + /* + * Variance: calculate avarage calculate for each measurement x: + * (x-average)² sum up and divide by number of measurements + */ + double average = getULmW(); + double variance = 0; + for (double xi : RXul) { + variance += Math.pow(xi - average, 2); + } + return variance / getULcount(); + + } + + public double getVarianceDLmW() { + + /* + * Variance: calculate avarage calculate for each measurement x: + * (x-average)² sum up and divide by number of measurements + */ + double average = getDLmW(); + double variance = 0; + for (double xi : RXdl) { + variance += Math.pow(xi - average, 2); + } + return variance / getDLcount(); + } + + @SuppressWarnings("unused") + public double getVarianceDLdB() { + // HACK: always return sigma 5 (Variance 25 = 5^2)!!! + if (true) { + // return 8; // std of 4 if no user present + // return 12.5; // std of 5 if a user present + // was 2.5! + // return 16; + return 25; + } + + // if (RXdl.isEmpty()) { + // return 0; + // } + + // if (isInterpolated()) { + // return varDL; + // } + + double variance = 0; + + // TODO: set average to getAverageDLdB(). Then calculate variance! + + // calculate average of dB values (no Tranform to mW and back) + double average = 0; + for (double value : RXdl) { + average += 10 * Math.log10(value); + } + average = average / getDLcount(); + + for (double xi : RXdl) { + variance += Math.pow(10 * Math.log10(xi) - average, 2); + } + variance = variance / getDLcount(); + // double variance = 10 * Math.log10(getVarianceDLmW()); + + if (variance == Double.NaN) { + System.out.println("NaN in Variance"); + } + + return variance; + } + + public double getVarianceULdB() { + if (RXdl.isEmpty()) { + return 0; + } + + double variance = 0; + + // calculate simple average of dB values (no tranform to mW) + double average = 0; + for (double value : RXul) { + average += 10 * Math.log10(value); + } + average = average / getULcount(); + + for (double xi : RXul) { + variance += Math.pow(10 * Math.log10(xi) - average, 2); + } + variance = variance / getULcount(); + // double variance = 10 * Math.log10(getVarianceDLmW()); + return variance; + } + + public double getTrueVarianceDLdB() { + if (RXdl.isEmpty()) { + return 5; + } + + if (isInterpolated()) { + return varDL; + } + + double variance = 0; + + // TODO: set average to getAverageDLdB(). Then calculate variance! + + // calculate average of dB values (no Tranform to mW and back) + double average = 0; + for (double value : RXdl) { + average += 10 * Math.log10(value); + } + average = average / getDLcount(); + + for (double xi : RXdl) { + variance += Math.pow(10 * Math.log10(xi) - average, 2); + } + variance = variance / getDLcount(); + // double variance = 10 * Math.log10(getVarianceDLmW()); + + if (variance == Double.NaN) { + System.out.println("NaN in Variance"); + } + + return variance; + } + + public int getULcount() { + return RXul.size(); + } + + public int getDLcount() { + return RXdl.size(); + } + + public int minDLdB() { + double minmW = minDLmW(); + if (((int) (10 * Math.log10(minmW))) == 33) { + System.out.print("min falsch"); + } + double minDLdB = (10 * Math.log10(minmW)); + if (minDLdB == Double.NEGATIVE_INFINITY) { + return -111; + } + + return (int) minDLdB; + } + + public double minDLmW() { + if (RXdl.isEmpty()) { + return 0; + } + + double min = 2000; + for (Double measure : RXdl) { + if (measure < min) + min = measure; + } + return min; + } + + public int minULdB() { + double minmW = minULmW(); + + double mindB = 10 * Math.log10(minmW); + + if (mindB == Double.NEGATIVE_INFINITY) { + return -111; + } + + return (int) (mindB); + } + + public double minULmW() { + if (RXul.isEmpty()) { + return 0; + } + + double min = 2000; + for (Double measure : RXul) { + if (measure < min) + min = measure; + } + return min; + } + + public int maxDLdB() { + double maxmW = maxDLmW(); + return (int) (10 * Math.log10(maxmW)); + } + + public double maxDLmW() { + double max = -2000; + for (Double measure : RXdl) { + if (measure > max) { + max = measure; + } + } + return max; + } + + public int maxULdB() { + double maxmW = maxULmW(); + return (int) (10 * Math.log10(maxmW)); + } + + public double maxULmW() { + double max = -2000; + for (Double measure : RXul) { + if (measure > max) { + max = measure; + } + } + return max; + } + + // returns "ARFCN;RXul;RXdl;TA" + public String toString() { + if (RXdl.size() == 1 && RXul.size() == 1) { + return (name + ":" + ARFCN + "; UL:" + (int) (getUldB()) + "; DL:" + + (int) (getDldB()) + " Mode:" + getStrictDLdBAverage() + + " " + time.toString()); + } else { + + String dl = getDLString(); + String ul = getULString(); + + return (name + ": " + ARFCN + "; " + ul + " " + dl + " " + time + .toString()); + } + } + + public String ULtoString() { + return getULString() + " " + time.toString(); + } + + public String DLtoString() { + return getDLString() + " Mode: " + getStrictDLdBAverage() + ", " + + time.toString(); + } + + private String getULString() { + NumberFormat nf = NumberFormat.getInstance(); + nf.setMaximumFractionDigits(3); + String ul = "UL(min:" + minULdB() + ",max:" + maxULdB() + ",varDL:" + + nf.format(getVarianceULdB()) + "avg:" + nf.format(getUldB()) + + "),#meas:" + RXul.size(); + return ul; + } + + public String getDLString() { + NumberFormat nf = NumberFormat.getInstance(); + nf.setMaximumFractionDigits(3); + // String variance = Double.toString(getVarianceDLdB()); + // String variancevariable = Double.toString(varDL); + String dl = "DL(min:" + minDLdB() + ",max:" + maxDLdB() + ",varDL:" + + nf.format(getVarianceDLdB()) + "avg:" + nf.format(getDldB()) + + "),#meas:" + RXdl.size(); + return dl; + } + + // make SingleBTS comparable to SingleBTS! + public int compareTo(SingleBTS comperator) { + if (this.time == null || comperator.time == null) { + throw new NullPointerException( + "one of the SingleBTS objects is null!"); + } + if (this.time.getTime() > comperator.time.getTime()) { + return 1; + } else if (this.time.getTime() < comperator.time.getTime()) { + return -1; + } else + return 0; + + } + + public int compareTo(Date timestamp) { + if (this.time == null || timestamp == null) { + throw new NullPointerException("objects is null!"); + } + if (this.time.getTime() > timestamp.getTime()) { + return 1; + } else if (this.time.getTime() < timestamp.getTime()) { + return -1; + } else + return 0; + + } + + public boolean newlyInterpolated() { + if (interpolated == null || interpolated.isEmpty()) + return false; + return interpolated.get(interpolated.size() - 1); + } + + /** + * remove outlier with Grubb's test. see + * http://www.graphpad.com/articles/outlier.htm + */ + public void removeOutlier() { + // if (RXul.size() < 4) + // System.out.println("Too few data points: UL! " + RXul.size()); + // if (RXdl.size() < 4) + // System.out.println("Too few data points: DL! " + RXdl.size()); + boolean outlier = true; + // loop until no more outlier is found + while (outlier) { + outlier = false; + double maxUL = maxULdB(); + double minUL = minULdB(); + double maxDL = maxDLdB(); + double minDL = minDLdB(); + + // calculate Z for each. Use dBm values. They are in normal + // distribution + double maxULZ = Math.abs(getUldB() - maxUL) + / Math.sqrt(getVarianceULdB()); + double minULZ = Math.abs(getUldB() - minUL) + / Math.sqrt(getVarianceULdB()); + double maxDLZ = Math.abs(getStrictDLdBAverage() - maxDL) + / Math.sqrt(getTrueVarianceDLdB()); + double minDLZ = Math.abs(getStrictDLdBAverage() - minDL) + / Math.sqrt(getTrueVarianceDLdB()); + + // check for probability < 95% that it is within the gauss curve + if (maxULZ > getCritZ(getULcount()) && RXul.size() > 2) { + RXul.remove((Object) maxULmW()); + outlier = true; + // start again from the beginning: continue + continue; + // System.out.println("Outlier UL removed: " + maxUL); + } + if (minULZ > getCritZ(getULcount()) && RXul.size() > 2) { + RXul.remove((Object) minULmW()); + outlier = true; + continue; + // System.out.println("Outlier UL removed: " + minUL); + } + if (maxDLZ > getCritZ(getDLcount()) && RXdl.size() > 2) { + RXdl.remove((Object) maxDLmW()); + outlier = true; + continue; + // System.out.println("Outlier DL removed: " + maxDL); + } + if (minDLZ > getCritZ(getDLcount()) && RXdl.size() > 2) { + RXdl.remove((Object) minDLmW()); + outlier = true; + continue; + // System.out.println("Outlier DL removed: " + minDL); + } + + } + + } + + // search for arfcn! + public int compareTo(int arfcn) { + if (this.ARFCN > arfcn) + return 1; + if (this.ARFCN < arfcn) + return -1; + else + return 0; + + } + + // resets UL and DL + public void clear() { + RXdl.clear(); + RXul.clear(); + + } + + public boolean isInterpolated() { + if (interpolated == null || interpolated.isEmpty()) { + return false; + } else { + return interpolated.getLast(); // damit die Log-Interpolation + // wieder + // funktioniert, muss das hier auf + // getFirst() stehen + // return interpolated.getFirst(); + } + } + + // show critical values for Z + private float getCritZ(int N) { + if (N == 3) + return 1.15f; + if (N == 4) + return 1.48f; + if (N == 5) + return 1.71f; + if (N == 6) + return 1.89f; + if (N == 7) + return 2.02f; + if (N == 8) + return 2.13f; + if (N == 9) + return 2.21f; + if (N == 10) + return 2.29f; + if (N == 11) + return 2.34f; + if (N == 12) + return 2.41f; + if (N == 13) + return 2.46f; + if (N == 14) + return 2.51f; + if (N == 15) + return 2.55f; + if (N == 16) + return 2.59f; + if (N == 17) + return 2.62f; + if (N == 18) + return 2.65f; + if (N == 19) + return 2.68f; + if (N == 20) + return 2.73f; + if (N == 21) + return 2.73f; + if (N == 22) + return 2.76f; + if (N == 23) + return 2.78f; + if (N == 24) + return 2.80f; + if (N == 25) + return 2.82f; + if (N == 26) + return 2.84f; + if (N == 27) + return 2.86f; + if (N == 28) + return 2.88f; + if (N == 29) + return 2.89f; + if (N == 30) + return 2.91f; + if (N == 31) + return 2.92f; + if (N == 32) + return 2.94f; + if (N == 33) + return 2.95f; + if (N == 34) + return 2.97f; + if (N == 35) + return 2.98f; + if (N == 36) + return 2.99f; + if (N == 37) + return 3.00f; + if (N == 38) + return 3.01f; + if (N == 39) + return 3.03f; + if (N >= 40 && N < 50) + return 3.04f; + if (N >= 50 && N < 60) + return 3.13f; + if (N >= 60 && N < 70) + return 3.20f; + if (N >= 70 && N < 80) + return 3.26f; + if (N >= 80 && N < 90) + return 3.31f; + if (N >= 90 && N < 100) + return 3.35f; + if (N >= 100 && N < 110) + return 3.38f; + if (N >= 110 && N < 120) + return 3.42f; + if (N >= 120 && N < 130) + return 3.44f; + if (N >= 130 && N < 140) + return 3.47f; + if (N >= 140 && N < 150) + return 3.49f; + if (N >= 150 && N < 160) + return 3.52f; + else + return 3.7f; + } + + /** + * Sets the Variance for DL in mW. Works only if this BTS is interpolated! + * + * @param varDL + */ + public void setVarDLdB(double var) { + if (isInterpolated()) { + this.varDL = var; + } else { + System.out.println("kann Variance nicht setzen!"); + } + + } + +} diff --git a/DataStructure/Weight.java b/DataStructure/Weight.java new file mode 100644 index 0000000..a22ab9f --- /dev/null +++ b/DataStructure/Weight.java @@ -0,0 +1,19 @@ +package DataStructure; + +public class Weight { + int x; + int y; + SingleBTS bts; + double weight; + double area; + + public Weight(int x, int y, double weight) { + this.x = x; + this.y = y; + this.weight = weight; + } + + public Weight() { + + } +} diff --git a/DataStructure/gsmBayes.java b/DataStructure/gsmBayes.java new file mode 100644 index 0000000..2490633 --- /dev/null +++ b/DataStructure/gsmBayes.java @@ -0,0 +1,752 @@ +package DataStructure; + +import helper.ListBTS; + +import java.awt.Point; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Date; +import java.util.List; + +public class gsmBayes { + GSMMap map; + + public static void main(String[] args) throws FileNotFoundException, + IOException, ClassNotFoundException { + + NormDistribution one = new NormDistribution(30, 0.21); + NormDistribution two = new NormDistribution(30, 0.21); + System.out.println(one.intersection(two) + " " + two.intersection(one)); + + // System.out.println(10 * Math.log10(0.0)); + + // Comparator test + // ArrayList testlist = new ArrayList(); + // testlist.add(new SingleBTS(999, "letzte")); + // testlist.add(new SingleBTS(124, "zweite")); + // testlist.add(new SingleBTS(123, "erste")); + // ArrayList testlistcopy = new + // ArrayList(testlist); + // Collections.copy(testlistcopy, testlist); + + // Collections.sort(testlist, new BTSArfcnComparator()); + // testlist.get(0).name = "blabla"; + // System.out.println(testlist); + // System.out.println(testlistcopy); + + // gsmmap object einlesen + ObjectInputStream ois = new ObjectInputStream(new FileInputStream( + "interpolatedGSMMap.obj")); + GSMMap map = (GSMMap) ois.readObject(); + System.out.println("Start"); + // ArrayList MR = getMR106(); + ArrayList MR = subtractBTS(getMensa(), 0); + double[][] scoremap = computeScore(MR, map); + System.out.println("fertig"); + + double maxSingleProbability = 0; + double sumOfProbabilities = 0; + for (int x = 0; x < scoremap.length; x++) { + for (int y = 0; y < scoremap[0].length; y++) { + if (scoremap[x][y] > 0) { + // System.out.println("positive Wahrsch. gefunden! " + // + scoremap[x][y]); + if (scoremap[x][y] > maxSingleProbability) { + maxSingleProbability = scoremap[x][y]; + System.out.println("neues Maximum bei " + x + "/" + y + + " !"); + } + sumOfProbabilities += scoremap[x][y]; + // sind das vll. die falschen Wahrscheinlihckeiten? + // P(RSS|Kachel) = 1 oder + // P(Kachel|RSS) = 1? + } + } + } + System.out.println("Summe: " + sumOfProbabilities + ", maximum: " + + maxSingleProbability); + GoogleOut out = new GoogleOut(map, "bla"); + // out.write(); + + // fill up to confidence level + double[][] confidence = toConfidence(scoremap, 0.75); + + double confidencesum = 0; + for (int x = 0; x < confidence.length; x++) { + for (int y = 0; y < confidence[0].length; y++) { + confidencesum += confidence[x][y]; + } + } + System.out.println("Confidence level bei: " + confidencesum); + + out.writeProbability(confidence, "probabilities.kml"); + + } + + /** + * Returns all tiles until they sum up to confidence. scoremap gets + * destroyed + * + * @param scoremap + * @param d + * @return + */ + public static double[][] toConfidence(double[][] scoremap, double confidence) { + if (confidence == 1 || confidence > 1) { + return scoremap; + } + + // scoremap to possibility objects (faster...) + PossibilityObject[] possibilities = toPossibility(scoremap); + double sum_confidence = 0; + double[][] result = new double[scoremap.length][scoremap[0].length]; + int boundary = possibilities.length - 1; + while (sum_confidence < confidence) { + sum_confidence += possibilities[boundary].possibility; + int x = possibilities[boundary].x; + int y = possibilities[boundary].y; + result[x][y] = possibilities[boundary].possibility; + boundary--; + } + // result = PossObjToScoremap(possibilities, boundary, result); + + /* + * double max = 0; int xmax = 0; int ymax = 0; for (int x = 0; x < + * scoremap.length; x++) { for (int y = 0; y < scoremap[0].length; y++) + * { if (scoremap[x][y] > max) { max = scoremap[x][y]; xmax = x; ymax = + * y; } + * + * } } // max found. + * + * result[xmax][ymax] = scoremap[xmax][ymax]; sum_confidence += + * scoremap[xmax][ymax]; scoremap[xmax][ymax] = 0; } + */ + return result; + + } + + @SuppressWarnings("unused") + private static double[][] PossObjToScoremap( + PossibilityObject[] possibilities, int boundary, double[][] result) { + for (int i = possibilities.length - 1; i <= boundary; i--) { + int x = possibilities[i].x; + int y = possibilities[i].y; + result[x][y] = possibilities[i].possibility; + } + + return result; + } + + @SuppressWarnings("unused") + private static ArrayList gettheater() { + ArrayList MR2 = new ArrayList(); + ArrayList MR = new ArrayList(); + MR.add(new SingleBTS(806, Double.NaN, -101, true, new Date(), "lookup", + 1)); + MR.add(new SingleBTS(817, Double.NaN, -96, true, new Date(), "lookup", + 1)); + MR.add(new SingleBTS(815, Double.NaN, -92, true, new Date(), "lookup", + 12)); + MR.add(new SingleBTS(823, Double.NaN, -97, true, new Date(), "lookup", + 0.25)); + MR.add(new SingleBTS(871, Double.NaN, -90, true, new Date(), "lookup", + 1)); + MR.add(new SingleBTS(877, Double.NaN, -101, true, new Date(), "lookup", + 1)); + + MR2.add(new SingleBTS(806, Double.NaN, -101, true, new Date(), "lookup")); + MR2.add(new SingleBTS(817, Double.NaN, -96, true, new Date(), "lookup")); + MR2.add(new SingleBTS(815, Double.NaN, -92, true, new Date(), "lookup")); + MR2.add(new SingleBTS(823, Double.NaN, -97, true, new Date(), "lookup")); + MR2.add(new SingleBTS(871, Double.NaN, -90, true, new Date(), "lookup")); + MR2.add(new SingleBTS(877, Double.NaN, -101, true, new Date(), "lookup")); + return MR; + } + + @SuppressWarnings("unused") + private static ArrayList getArt() { + ArrayList MR = new ArrayList(); + MR.add(new SingleBTS(806, Double.NaN, -90, true, new Date(), "lookup", + 3.33)); + MR.add(new SingleBTS(817, Double.NaN, -90, true, new Date(), "lookup", + 2.28)); + MR.add(new SingleBTS(815, Double.NaN, -88, true, new Date(), "lookup", + 2.05)); + MR.add(new SingleBTS(823, Double.NaN, -76, true, new Date(), "lookup", + 9)); + MR.add(new SingleBTS(880, Double.NaN, -96, true, new Date(), "lookup", + 4)); + MR.add(new SingleBTS(877, Double.NaN, -65, true, new Date(), "lookup", + 3.77)); + return MR; + } + + @SuppressWarnings("unused") + private static ArrayList getMR101() { + ArrayList MR = new ArrayList(); + MR.add(new SingleBTS(806, Double.NaN, -94, true, new Date(), "lookup")); + MR.add(new SingleBTS(817, Double.NaN, -92, true, new Date(), "lookup")); + MR.add(new SingleBTS(815, Double.NaN, -88, true, new Date(), "lookup")); + MR.add(new SingleBTS(823, Double.NaN, -79, true, new Date(), "lookup")); + MR.add(new SingleBTS(880, Double.NaN, -97, true, new Date(), "lookup")); + MR.add(new SingleBTS(877, Double.NaN, -84, true, new Date(), "lookup")); + return MR; + } + + @SuppressWarnings("unused") + private static ArrayList getMR106() { + ArrayList MR = new ArrayList(); + MR.add(new SingleBTS(806, Double.NaN, -98, true, new Date(), "lookup", + 0.25)); + MR.add(new SingleBTS(817, Double.NaN, -89, true, new Date(), "lookup", + 0.25)); + MR.add(new SingleBTS(815, Double.NaN, -85, true, new Date(), "lookup", + 0.25)); + MR.add(new SingleBTS(823, Double.NaN, -90, true, new Date(), "lookup", + 0)); + MR.add(new SingleBTS(880, Double.NaN, -98, true, new Date(), "lookup", + 0)); + MR.add(new SingleBTS(877, Double.NaN, -102, true, new Date(), "lookup", + 6.25)); + return MR; + } + + @SuppressWarnings("unused") + private static ArrayList get79() { + ArrayList MR = new ArrayList(); + + MR.add(new SingleBTS(806, Double.NaN, -88, true, new Date(), "lookup", + 2.64)); + MR.add(new SingleBTS(817, Double.NaN, -90, true, new Date(), "lookup", + 2.05)); + MR.add(new SingleBTS(815, Double.NaN, -86, true, new Date(), "lookup", + 1.42)); + MR.add(new SingleBTS(823, Double.NaN, -87, true, new Date(), "lookup", + 1.57)); + MR.add(new SingleBTS(871, Double.NaN, -63, true, new Date(), "lookup", + 25.4)); + MR.add(new SingleBTS(880, Double.NaN, -83, true, new Date(), "lookup", + 0.658)); + MR.add(new SingleBTS(877, Double.NaN, -93, true, new Date(), "lookup", + 10)); + + ArrayList MR2 = new ArrayList(); + MR2.add(new SingleBTS(806, Double.NaN, -87, true, new Date(), "lookup", + 2.04)); + MR2.add(new SingleBTS(817, Double.NaN, -91, true, new Date(), "lookup", + 2.25)); + MR2.add(new SingleBTS(815, Double.NaN, -88, true, new Date(), "lookup", + 1.32)); + MR2.add(new SingleBTS(823, Double.NaN, -85, true, new Date(), "lookup", + 1.47)); + MR2.add(new SingleBTS(871, Double.NaN, -62, true, new Date(), "lookup", + 20.4)); + MR2.add(new SingleBTS(880, Double.NaN, -81, true, new Date(), "lookup", + 10.658)); + MR2.add(new SingleBTS(877, Double.NaN, -97, true, new Date(), "lookup", + 10)); + + /* + * MR.add(new SingleBTS(806, Double.NaN, -88, true, new Date(), + * "lookup")); MR.add(new SingleBTS(817, Double.NaN, -90, true, new + * Date(), "lookup")); MR.add(new SingleBTS(815, Double.NaN, -86, true, + * new Date(), "lookup")); MR.add(new SingleBTS(823, Double.NaN, -87, + * true, new Date(), "lookup")); MR.add(new SingleBTS(871, Double.NaN, + * -63, true, new Date(), "lookup")); MR.add(new SingleBTS(880, + * Double.NaN, -83, true, new Date(), "lookup")); MR.add(new + * SingleBTS(877, Double.NaN, -93, true, new Date(), "lookup")); + */ + System.out.println("slightly altered"); + return MR; + } + + @SuppressWarnings("unused") + private static ArrayList getBermuda() { + ArrayList MR = new ArrayList(); + + MR.add(new SingleBTS(806, Double.NaN, -93, true, new Date(), "lookup", + 3.4)); + MR.add(new SingleBTS(817, Double.NaN, -88, true, new Date(), "lookup", + 5.65)); + MR.add(new SingleBTS(815, Double.NaN, -85, true, new Date(), "lookup", + 5.1)); + MR.add(new SingleBTS(823, Double.NaN, -47, true, new Date(), "lookup", + 12.36)); + MR.add(new SingleBTS(880, Double.NaN, -92, true, new Date(), "lookup", + 10.6)); + MR.add(new SingleBTS(877, Double.NaN, -68, true, new Date(), "lookup", + 9.1)); + return MR; + } + + private static ArrayList getMensa() { + ArrayList MR = new ArrayList(); + MR.add(new SingleBTS(806, Double.NaN, -95, true, new Date(), "lookup")); + MR.add(new SingleBTS(817, Double.NaN, -91, true, new Date(), "lookup")); + MR.add(new SingleBTS(815, Double.NaN, -86, true, new Date(), "lookup")); + MR.add(new SingleBTS(823, Double.NaN, -86, true, new Date(), "lookup")); + MR.add(new SingleBTS(871, Double.NaN, -75, true, new Date(), "lookup")); + MR.add(new SingleBTS(880, Double.NaN, -74, true, new Date(), "lookup")); + MR.add(new SingleBTS(877, Double.NaN, -87, true, new Date(), "lookup")); + return MR; + } + + private static ArrayList subtractBTS(ArrayList MR, + double value) { + ArrayList result = new ArrayList(); + for (int i = 0; i < MR.size(); i++) { + int arfcn = MR.get(i).ARFCN; + double RXul = MR.get(i).getUldB(); + double RXdl = MR.get(i).getDldB(); + double var = MR.get(i).getVarianceDLdB(); + SingleBTS element = new SingleBTS(arfcn, RXul, RXdl, true, + new Date(), "lookup", var); + result.add(element); + } + return result; + } + + public gsmBayes(GSMMap map) { + this.map = map; + // generate difference between multiple BTSs. + // For example: arfcn 877 - arfcn 880, 877-823,... + // get OpenBSC arfcn's to calculate ratios + + // go over all tiles and calculate the probability that this RSS-vector + // falls within this tile. Use the gaussian assumption here! + // than, return all tiles until they sum up to confidence + + } + + /** + * Makes a scoremap to a SORTED one dimensional PossibilityObject Array. + * Calculates the entropy on the way and prints to Console + * + * @param scoremap + * @return + */ + private static PossibilityObject[] toPossibility(double[][] scoremap) { + int gsmmapsize = (scoremap.length + 1) * (scoremap[0].length + 1); + // PossibilityObject[] possibilities = new + // PossibilityObject[gsmmapsize]; + ArrayList result = new ArrayList( + gsmmapsize); + double entropy = 0; + for (int x = 0; x < scoremap.length; x++) { + for (int y = 0; y < scoremap[0].length; y++) { + if (scoremap[x][y] != 0) { + entropy = entropy + scoremap[x][y] + * (Math.log(scoremap[x][y])); + } + PossibilityObject current = new PossibilityObject(); + current.possibility = scoremap[x][y]; + current.x = x; + current.y = y; + result.add(current); + } + + } + + System.out.println("Entropy dieser Wahrscheibnlichkeitskarte: " + + (entropy * (-1))); + PossibilityObject[] possibilities = result + .toArray(new PossibilityObject[1]); + Arrays.sort(possibilities); + return possibilities; + } + + /** + * Returns all possible tiles that fall within the confidence. Output is the + * tile coordinate within the gsm map. DO NOT USE IN THE MOMENT!!!!! + * + * @param MR + * The measurement from the phone that you want to locate + * @return + */ + @SuppressWarnings("unused") + static private Point[] search(List MR, GSMMap map, + double confidence) { + double[][] possibility = new double[map.Xcoords.length][map.Ycoords.length]; + double rssProbability = 0; + rssProbability = getProbOfMR(map); + + for (int x = 0; x < map.Xcoords.length; x++) { + for (int y = 0; y < map.Ycoords.length; y++) { + possibility[x][y] = getPossibility(map.map[x][y], MR, + rssProbability); + } + } + return null; + } + + /** + * Computes just raw score (not probability) for each tile with given MR + * + * @param MR + * @param map + * @return + */ + static public double[][] computeScore(List MR, GSMMap map) { + + // get Vector how to sort!!! Important so that subtraction with NaN + // doesnÄt destroy too much Information! + SingleBTS[] sortVector = getSortVector(MR, map.content()); + // sortVector = MR.toArray(new SingleBTS[0]); + ArrayList sortedMR = substituteMR(MR, sortVector); + // get ratio map + ratioElem[][][] ratiomap = getRatio(map, sortVector); + + // get RatioVector for MR: + // make a (shallow) copy of MR to work with + // ArrayList sortedMR = new ArrayList(MR); + // take the measured MR. Make it to a complete Measurement vector. + // SingleBTS[] content = map.content(); + // Arrays.sort(content, new BTSArfcnComparator()); + // sortedMR = substituteMR(sortedMR, content); + // now MR is a complete Vector + // sort MR: ascending arfcn. Its the same order as in ratiomap + // Collections.sort(sortedMR, new BTSArfcnComparator()); + + // get Ratio out of sortedMR (MeasurementReportRatio) + ratioElem[] MRRatio = new ratioElem[sortedMR.size() - 1]; + for (int i = 0; i < sortedMR.size() - 1; i++) { + MRRatio[i] = new ratioElem(sortedMR.get(i), sortedMR.get(i + 1)); + } + + // now we can do the Bayes stuff with sortedMR and ratioElem + // first get probability that sortedMR appears in ratiomap + double[][] probabilitymap = doBayes(MRRatio, ratiomap); + + return probabilitymap; + } + + private static SingleBTS[] getSortVector(List mR, + SingleBTS[] content) { + ArrayList result = new ArrayList(content.length); + ArrayList NaNs = new ArrayList(content.length); + for (int i = 0; i < content.length; i++) { + SingleBTS element = ListBTS.getARFCN(mR, content[i]); + if (element != null) { + result.add(element); + } else { + NaNs.add(new SingleBTS(content[i].ARFCN, Double.NaN, + Double.NaN, true, new Date(), content[i].name)); + } + } + + result.addAll(NaNs); + + return result.toArray(new SingleBTS[content.length]); + } + + private static double[][] doBayes(ratioElem[] MRRatio, + ratioElem[][][] ratiomap) { + + double[][] score = new double[ratiomap.length][ratiomap[0].length]; + double totalProb = 0; + for (int x = 0; x < ratiomap.length; x++) { + for (int y = 0; y < ratiomap[0].length; y++) { + // if (x == 48 && y == 14) { + // System.out.println("halt!"); + // } + totalProb += getProbOfSingleHit(ratiomap[x][y], MRRatio); + } + } + double numberTiles = (ratiomap.length * ratiomap[0].length); + totalProb = totalProb / numberTiles; + + // now we have P(S):totalProb + + for (int x = 0; x < ratiomap.length; x++) { + for (int y = 0; y < ratiomap[0].length; y++) { + score[x][y] = (getProbOfSingleHit(MRRatio, ratiomap[x][y]) * (1 / numberTiles)) + / totalProb; + } + } + + return score; + } + + private static double getProbOfSingleHit(ratioElem[] MapRatio, + ratioElem[] MRRatio) { + double probability = 1; + // for now: MR is without variance! and only Downlink! + for (int i = 0; i < MapRatio.length; i++) { + probability *= MapRatio[i].probability(MRRatio[i]); + } + + if (probability > 0) { + // System.out.println("Probability größer 0! gut! Debug"); + } + if (Double.isNaN(probability)) { + System.out.println("Probability = NaN"); + } + + return probability; + } + + /** + * Sort content before use! Takes a list of measurements (MR) and checks if + * it contains all the elements given in content. If not, this element gets + * added with NaN value. MR itself is not altered. Elements are ordered + * accordingly to content. If content was ordered to e.g. arfcn, so the + * result. At the end, all Ratios with NaN get pushed + * + * @param mR + * @param content + * @return + */ + private static ArrayList substituteMR(List mR, + SingleBTS[] content) { + // TODO Auto-generated method stub + ArrayList result = new ArrayList(content.length); + // ArrayList NaNs = new ArrayList(content.length); + SingleBTS element; + for (int i = 0; i < content.length; i++) { + if ((element = helper.ListBTS.getARFCN(mR, content[i])) != null) { + // result.add(element); + } else { + // BTS not there. Put in Double.NaN instead! + element = new SingleBTS(content[i].ARFCN, Double.NaN, + Double.NaN, true, new Date(), content[i].name); + // element = new SingleBTS(content[i].ARFCN, -999, -999, true, + // new Date(), content[i].name); + // NaNs.add(element); + + } + // Collections.sort(NaNs, new BTSArfcnComparator()); + result.add(element); + // result.addAll(NaNs); + } + + // now, sort NaN + + return result; + } + + /** + * Returns all Ratios out of MapElement that can be build using the + * measurements from MR. Non existing elements are substituted with NaN. + * + * @param MR + * that is to be located + * @return + */ + private static ratioElem[][][] getRatio(GSMMap map, SingleBTS[] sortVector) { + + // sort the map content. This makes sure that RSSVector is sorted + // accordingly + SingleBTS[] content = sortVector; + // Arrays.sort(content, new BTSArfcnComparator()); + + // create ratioMap + ratioElem[][][] ratiomap = new ratioElem[map.Xcoords.length][map.Ycoords.length][content.length - 1]; + + // built ratio for every cell in map + for (int x = 0; x < map.Xcoords.length; x++) { + for (int y = 0; y < map.Ycoords.length; y++) { + // substitute map at position [x][y] to get full Vector + // ArrayList RSSVector = new ArrayList( + // map.map[x][y]); + ArrayList RSSVector = substituteMR(map.map[x][y], + sortVector); + + // debug: only if RSSVector has some stuff inside + // if (!RSSVector.isEmpty() && RSSVector.get(0).getDldB() < 0) { + // System.out.println("etwas da!"); + // } + + // get full vector + // RSSVector = substituteMR(RSSVector, content); + // sort the vector. Not needed. already sorted + // Collections.sort(RSSVector, new BTSArfcnComparator()); + // built ratios + for (int i = 0; i < content.length - 1; i++) { + ratiomap[x][y][i] = new ratioElem(RSSVector.get(i), + RSSVector.get(i + 1)); + } + } + } + + // TODO Auto-generated method stub + return ratiomap; + } + + /** + * Returns the probability that this measurement is received within map + * + * @param map + * @return + */ + private static double getProbOfMR(GSMMap map) { + // TODO Auto-generated method stub + return 0; + } + + /** + * Calculates the possibility that MR was received on this tile's + * RSS-Vector. + * + * @param rssVector + * @param MR + * @param PRssV + * Probability that MR is received + * @return + */ + private static double getPossibility(ArrayList rssVector, + List MR, double PRssV) { + // get all ratios out of MR. Compare with rssVector + + // TODO Auto-generated method stub + return 0; + } +} + +/* + * class ratioBTS { SingleBTS own; SingleBTS second; + * + * public ratioBTS(SingleBTS ownBTS, SingleBTS second) { this.own = ownBTS; + * this.second = second; } + * + * public double getRatioDL() { return own.getDldB() - second.getDldB(); } + * + * public double getRatioUL() { if (own.fullBTS && second.fullBTS) { return + * own.getUldB() - second.getUldB(); } return Double.NaN; } } + */ + +/** + * Comperator that computes the ARFCN of this bts + * + * @author richy + * + */ +class BTSArfcnComparator implements Comparator { + + public int compare(SingleBTS bts1, SingleBTS bts2) { + + if (((SingleBTS) bts1).ARFCN > ((SingleBTS) bts2).ARFCN) { + return 1; + } else if (((SingleBTS) bts1).ARFCN < ((SingleBTS) bts2).ARFCN) { + return -1; + } else + return 0; + + } +} + +/** + * Everything in dBm! + * + * @author richy + * + */ +class ratioElem2 { + SingleBTS top; + SingleBTS bottom; + double ratioDL; + double ratioUL; + double varDL; + double varUL; + + public ratioElem2(SingleBTS top, SingleBTS bottom) { + this.top = top; + this.bottom = bottom; + + // double topUL = top.getDldB(); + // double bottomUL = bottom.getDldB(); + + ratioDL = top.getDldB() - bottom.getDldB(); + ratioUL = top.getUldB() - bottom.getUldB(); + // varDL = Math.sqrt(Math.pow(top.getVarianceDLdB(), 2)); + // - Math.pow(bottom.getVarianceDLdB(), 2)); + // varUL = Math.sqrt(Math.pow(top.getVarianceULdB(), 2) + // - Math.pow(bottom.getVarianceULdB(), 2)); + varDL = top.getVarianceDLdB() + bottom.getVarianceDLdB(); + varUL = top.getVarianceULdB() + bottom.getVarianceULdB(); + // if (varDL != 0 && varDL != Double.NaN) { + // System.out.println("var ungleich 0"); + // } + } + + public String toString() { + return "RatioDL: " + ratioDL + ", varDl: " + varDL; + } + + public double probability(ratioElem vector) { + + if (top.ARFCN != vector.top.ARFCN + || bottom.ARFCN != vector.bottom.ARFCN) { + System.out.println("Sortierung falsch!"); + } + + if (Double.isNaN(vector.ratioDL) || Double.isNaN(this.ratioDL)) { + if (Double.isNaN(vector.ratioDL) && Double.isNaN(this.ratioDL)) { + // ratio between both bts cannot been built. This means top or + // bottom bts is not received. let's say a cell phone has a poor + // antenna, than this would not neccesarily mean that the + // probability of beeing there is one. It can although be used + // to + // boost the probability + return 1; + } else + return 0; + } + + if (vector.varDL == 0 && this.varDL == 0) { + if (Math.abs(vector.ratioDL - this.ratioDL) <= 1) { + return 1; + } else { + return 0; + } + } + + /* + * if (this.ratioDL == Double.NaN && vector.ratioDL == Double.NaN) { + * return 1; } else if (this.ratioDL != Double.NaN && vector.ratioDL == + * Double.NaN) { return Double.MIN_VALUE; } else if (this.ratioDL == + * Double.NaN && vector.ratioDL != Double.NaN) { return + * Double.MIN_VALUE; } else if (this.ratioDL == 0 && vector.ratioDL == + * 0) { return 1; } else if (this.ratioDL == 0 && vector.ratioDL == + * Double.NaN) { return 1; } else if (this.ratioDL == Double.NaN && + * vector.ratioDL == 0) { return 1; } + * + * else + */if (vector.varDL == 0 && this.varDL != 0) { + // compute just value at given point. No integration! + double std = Math.sqrt(varDL); + double x = vector.ratioDL; + double u = this.ratioDL; + double sqrtPI = Math.sqrt(2 * Math.PI); + double exp = Math.exp(-0.5 * Math.pow((x - u) / std, 2)); + double result = (1 / (std * sqrtPI)) * exp; + if (Double.isNaN(result)) + return 0; + return result; + } else if (this.varDL == 0 && vector.varDL != 0) { + // compute just value at given point. No integration! + double std = Math.sqrt(vector.varDL); + double x = ratioDL; + double u = vector.ratioDL; + double sqrtPI = Math.sqrt(2 * Math.PI); + double exp = Math.exp(-0.5 * Math.pow((x - u) / std, 2)); + double result = (1 / (std * sqrtPI)) * exp; + if (Double.isNaN(result)) + return 0; + return result; + } else { + // integration! + // System.out.println("Integration now implemented!"); + return new NormDistribution(ratioDL, varDL) + .intersection(new NormDistribution(vector.ratioDL, + vector.varDL)); + + } + + } + +} diff --git a/DataStructure/jdom.jar b/DataStructure/jdom.jar new file mode 100644 index 0000000..65a1b3f Binary files /dev/null and b/DataStructure/jdom.jar differ diff --git a/DataStructure/ratioElem.java b/DataStructure/ratioElem.java new file mode 100644 index 0000000..365f2f8 --- /dev/null +++ b/DataStructure/ratioElem.java @@ -0,0 +1,114 @@ +package DataStructure; + +class ratioElem { + SingleBTS top; + SingleBTS bottom; + double ratioDL; + double ratioUL; + double varDL; + double varUL; + + public ratioElem(SingleBTS top, SingleBTS bottom) { + // if (top==null||bottom==null){ + // return null; + // } + + this.top = top; + this.bottom = bottom; + + // double topUL = top.getDldB(); + // double bottomUL = bottom.getDldB(); + + // ratioDL = top.getDldB() - bottom.getDldB(); + ratioDL = top.getStrictDLdBAverage() - bottom.getStrictDLdBAverage(); + ratioUL = top.getUldB() - bottom.getUldB(); + // varDL = Math.sqrt(Math.pow(top.getVarianceDLdB(), 2)); + // - Math.pow(bottom.getVarianceDLdB(), 2)); + // varUL = Math.sqrt(Math.pow(top.getVarianceULdB(), 2) + // - Math.pow(bottom.getVarianceULdB(), 2)); + varDL = top.getVarianceDLdB() + bottom.getVarianceDLdB(); + varUL = top.getVarianceULdB() + bottom.getVarianceULdB(); + // if (varDL != 0 && varDL != Double.NaN) { + // System.out.println("var ungleich 0"); + // } + } + + public String toString() { + return "RatioDL: " + ratioDL + ", varDl: " + varDL + " (" + top.ARFCN + + "-" + bottom.ARFCN + ")"; + } + + public double probability(ratioElem vector) { + + if (top.ARFCN != vector.top.ARFCN + || bottom.ARFCN != vector.bottom.ARFCN) { + System.out.println("Sortierung falsch!"); + } + + if (Double.isNaN(vector.ratioDL) || Double.isNaN(this.ratioDL)) { + System.out.println("das sollte nicht passieren"); + if (Double.isNaN(vector.ratioDL) && Double.isNaN(this.ratioDL)) { + // ratio between both bts cannot been built. This means top or + // bottom bts is not received. let's say a cell phone has a poor + // antenna, than this would not neccesarily mean that the + // probability of beeing there is one. It can although be used + // to + // boost the probability + return 1; + } else + return 0; + } + + if (vector.varDL == 0 && this.varDL == 0) { + if (Math.abs(vector.ratioDL - this.ratioDL) <= 1) { + return 1; + } else { + return 0; + } + } + + /* + * if (this.ratioDL == Double.NaN && vector.ratioDL == Double.NaN) { + * return 1; } else if (this.ratioDL != Double.NaN && vector.ratioDL == + * Double.NaN) { return Double.MIN_VALUE; } else if (this.ratioDL == + * Double.NaN && vector.ratioDL != Double.NaN) { return + * Double.MIN_VALUE; } else if (this.ratioDL == 0 && vector.ratioDL == + * 0) { return 1; } else if (this.ratioDL == 0 && vector.ratioDL == + * Double.NaN) { return 1; } else if (this.ratioDL == Double.NaN && + * vector.ratioDL == 0) { return 1; } + * + * else + */if (vector.varDL == 0 && this.varDL != 0) { + // compute just value at given point. No integration! + double std = Math.sqrt(varDL); + double x = vector.ratioDL; + double u = this.ratioDL; + double sqrtPI = Math.sqrt(2 * Math.PI); + double exp = Math.exp(-0.5 * Math.pow((x - u) / std, 2)); + double result = (1 / (std * sqrtPI)) * exp; + if (Double.isNaN(result)) + return 0; + return result; + } else if (this.varDL == 0 && vector.varDL != 0) { + // compute just value at given point. No integration! + double std = Math.sqrt(vector.varDL); + double x = ratioDL; + double u = vector.ratioDL; + double sqrtPI = Math.sqrt(2 * Math.PI); + double exp = Math.exp(-0.5 * Math.pow((x - u) / std, 2)); + double result = (1 / (std * sqrtPI)) * exp; + if (Double.isNaN(result)) + return 0; + return result; + } else { + // integration! + // System.out.println("Integration now implemented!"); + return new NormDistribution(ratioDL, varDL) + .intersection(new NormDistribution(vector.ratioDL, + vector.varDL)); + + } + + } + +} diff --git a/DoGsmMap.java b/DoGsmMap.java new file mode 100644 index 0000000..dad59fb --- /dev/null +++ b/DoGsmMap.java @@ -0,0 +1,87 @@ +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.sql.SQLException; + +import DataStructure.GSMMap; +import DataStructure.GoogleOut; +import DataStructure.Interpolator; +import Parse.NMEAParse; +import Parse.sqlreader; + +public class DoGsmMap { + + /** + * @param args + * @throws SQLException + * @throws ClassNotFoundException + * @throws IOException + */ + public static void main(String[] args) throws ClassNotFoundException, + SQLException, IOException { + + // richy + NMEAParse nmeaR = new NMEAParse("Messungen/richy.log"); + long IMSI = 262026003662195l; + sqlreader sqlR = new sqlreader(nmeaR, IMSI, 2000); + sqlR.merge(new sqlreader(new NMEAParse("Messungen/richy2.log"), IMSI, + 2000)); + // sqlR.merge(new sqlreader(new NMEAParse("Messungen/richy3.log"), IMSI, + // 2000)); + sqlR.merge(new sqlreader(new NMEAParse("Messungen/richy4.log"), IMSI, + 2000)); + sqlR.merge(new sqlreader(new NMEAParse("Messungen/richy5.log"), IMSI, + 2000)); + + // intermezzo + GSMMap bla = new GSMMap(new sqlreader(new NMEAParse( + "Messungen/richy5.log"), IMSI, 3000), 0.00008); + bla.average(); + bla.removeOutlier(); + GoogleOut blaout = new GoogleOut(bla, "richy-gestern.kml"); + blaout.write(); + + GSMMap map_richy = new GSMMap(sqlR, 0.00004); + map_richy.average(); + map_richy.removeOutlier(); + GoogleOut out = new GoogleOut(map_richy, "richy.kml"); + out.write(); + + // kerstin + NMEAParse nmeaK = new NMEAParse("Messungen/kerstin.log"); + // long IMSIK = 262230000000004l; + long IMSIK = 262032733192317l; + sqlreader sqlK = new sqlreader(nmeaK, IMSIK, 2000); + GSMMap map_kerstin = new GSMMap(sqlK, 0.00004); + map_kerstin.average(); + map_kerstin.removeOutlier(); + GoogleOut outK = new GoogleOut(map_kerstin, "kerstin.kml"); + outK.write(); + + // merge. Ab hier gesammt + sqlR.merge(sqlK); + GSMMap richyUndKerstin = new GSMMap(sqlR, 0.00004); + richyUndKerstin.average(); + richyUndKerstin.removeOutlier(); + GoogleOut richyUndKerstinOut = new GoogleOut(richyUndKerstin, + "RichyUndKerstin.kml"); + richyUndKerstinOut.write(); + Interpolator RuKI = new Interpolator(sqlR, 0.00008); + // Interpolator RuKI = new Interpolator(sqlR, 0.00032); + RuKI.average(); + RuKI.removeOutlier(); + RuKI.interpolateVR(); + GoogleOut interpolationOut = new GoogleOut(RuKI, + "parallel-strictDB.kml"); + interpolationOut.write(); + // gsmmap speichern + FileOutputStream fos = new FileOutputStream( + "D:/parallel-strictdB-BER.obj"); + ObjectOutputStream oos = new ObjectOutputStream(fos); + System.gc(); + oos.writeObject(RuKI); + System.out.println("gespeichert"); + + } + +} diff --git a/GSMMapping.java b/GSMMapping.java new file mode 100644 index 0000000..d644b2e --- /dev/null +++ b/GSMMapping.java @@ -0,0 +1,128 @@ +import java.io.IOException; +import java.sql.SQLException; +import java.text.ParseException; + +import DataStructure.GSMMap; +import DataStructure.GoogleOut; +import Parse.NMEAParse; +import Parse.sqlreader; + +public class GSMMapping { + // private double[] CoordsNS; + // private double[] CoordsEW; + // private double[][] bla; + + // Constructor + public GSMMapping() { + // TODO Auto-generated constructor stub + } + + /** + * @param args + * @throws ClassNotFoundException + * @throws SQLException + * @throws IOException + * @throws ParseException + */ + public static void main(String[] args) throws SQLException, + ClassNotFoundException, IOException, ParseException { + String file = null; + file = "varianz3-4.log"; + // ask for file + // BufferedReader in = new BufferedReader(new + // InputStreamReader(System.in)); + System.out.println("GPS-File?"); + // long IMSI = 262230000000010l; + /* + * if (file == null) { try { file = in.readLine(); } catch (Exception e) + * { System.out.println("Cannot read input"); System.exit(-1); } } + */ + + // parse NMEA log + NMEAParse gpslog = new NMEAParse(file); + + // testing: + sqlreader testing = new sqlreader(gpslog, 262230000000010L, 3000l); + GSMMap testingmap = new GSMMap(testing, 0.00004); + GoogleOut testingoogle = new GoogleOut(testingmap, "testing.kml"); + testingoogle.write(); + + // search in SQL + + long[] IMSIs = { 262012430041708L, 262026003662195L, 262026550055616L, + 262073958646614L, 262123456789177L, 262230000000010L }; + // sqlreader sql = new sqlreader(gpslog, IMSI, 3000l); + int count = 0; + for (long l : IMSIs) { + sqlreader current = new sqlreader(new NMEAParse(file), l, 3000l); + try { + GSMMap map = new GSMMap(current, 0.00008); + System.out.println("Average"); + map.average(); + System.out.println("Outlier"); + map.removeOutlier(); + System.out.println("Gnuplot Signal"); + map.gnuPlotSignalStrength(877, count); + System.out.println("Gnuplot Delta"); + map.gnuPlotDeltaBTS(877, 880); + GoogleOut google = new GoogleOut(map, "varianz/GSM-" + l + + "-varianz.kml"); + google.write(); + count++; + } catch (Exception e) { + + } + } + + // do the Google Magic WITHOUT INTERPOLATION! + // GSMMapInterpolatorOld testmap = new GSMMapInterpolatorOld(sql, + // 0.00004);// + // 0.00004d + // testmap.average(); + + // GoogleOut testfile = new GoogleOut(testmap, "varianz/GSM-" + IMSI + // + "-varianz.kml"); + + /* + * get Variance! + * + * Timestamp start = new Timestamp(new SimpleDateFormat( + * "yyyy-MM-dd HH:mm:ss.S").parse("2011-04-05 14:22:45.0") .getTime()); + * Timestamp end = new Timestamp(new SimpleDateFormat( + * "yyyy-MM-dd HH:mm:ss.S").parse("2011-04-05 14:22:54.0") .getTime()); + * CalcVariance.Calc(sql, start, end, 877, 6); + */ + + // do GoogleOut WITH interpolation! + + // GoogleOut testfile2 = new GoogleOut(testmap, "GSMMap.kml"); + + // save GSM Map + // File outfile = new File("GSMout.obj"); + // try { + // ObjectOutputStream oos = new ObjectOutputStream( + // new FileOutputStream(outfile)); + // oos.writeObject(testmap); + + // } catch (FileNotFoundException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } catch (IOException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } + + // try to load + /* + * try { ObjectInputStream ois = new ObjectInputStream(new + * FileInputStream( outfile)); GSMMapInterpolatorOld openedGSMmap = + * (GSMMapInterpolatorOld) ois .readObject(); // GoogleOut + * openedGSMmapout = new GoogleOut(openedGSMmap, // "readout.kml"); + * + * } catch (FileNotFoundException e) { // TODO Auto-generated catch + * block e.printStackTrace(); } catch (IOException e) { // TODO + * Auto-generated catch block e.printStackTrace(); } + */ + + } +} \ No newline at end of file diff --git a/Interpolate.java b/Interpolate.java new file mode 100644 index 0000000..a5f4975 --- /dev/null +++ b/Interpolate.java @@ -0,0 +1,43 @@ +import java.io.IOException; +import java.sql.SQLException; + +import DataStructure.GSMMap; +import DataStructure.GoogleOut; +import Parse.NMEAParse; +import Parse.sqlreader; + +public class Interpolate { + + /** + * @param args + */ + public static void main(String[] args) { + try { + sqlreader sql = new sqlreader(new NMEAParse("nachGPN.log"), + 262026003662195l, 3000l); + GSMMap map = new GSMMap(sql, 0.00004); + map.average(); + map.removeOutlier(); + GoogleOut average = new GoogleOut(map, "average-all.kml"); + average.write(); + int size = 3; + for (int i = 0; i < 15; i++) { + map.extrapolate(size); + } + + GoogleOut google = new GoogleOut(map, "tiles-average-all.kml"); + google.write(); + } catch (ClassNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + +} diff --git a/MapSearch.java b/MapSearch.java new file mode 100644 index 0000000..29eef01 --- /dev/null +++ b/MapSearch.java @@ -0,0 +1,123 @@ +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.LinkedList; + +import lookup.ResultScore; +import lookup.ScoreElement; +import DataStructure.GSMMap; +import DataStructure.SingleBTS; +import Parse.NMEAParse; +import Parse.sqlreader; + +public class MapSearch { + + /** + * @param args + * @throws SQLException + * @throws ClassNotFoundException + */ + public static void main(String[] args) throws ClassNotFoundException, + SQLException { + NMEAParse nmea = new NMEAParse("campus7 - E-Plus.log"); + sqlreader sql = new sqlreader(nmea, 262026003662195l, 3000l); + GSMMap map = new GSMMap(sql, 0.00004); + map.average(); + for (int times = 0; times < 9; times++) { + map.extrapolate(3); + } + + ResultScore score = new ResultScore(map); + LinkedList MR = getMR_greenhouse(); + Date start = new Date(); + ArrayList hits = score.find(MR, 15); + Date stop = new Date(); + Collections.sort(hits); + for (int i = 0; i < hits.size(); i++) { + System.out.println(hits.get(i)); + } + for (int j = hits.size() - 1; j >= 0; j--) { + // System.out.println(hits.get(j)); + } + System.out.println("Time for search in ms: " + + (stop.getTime() - start.getTime())); + + } + + public static LinkedList getMR_greenhouse() { + LinkedList testlist = new LinkedList(); + SingleBTS bts1 = new SingleBTS(880, -62, -77, false, new Date(), + "Tf. Geb. 78"); + testlist.add(bts1); + bts1 = new SingleBTS(880, -63, -77, false, new Date(), "Tf. Geb. 78"); + testlist.add(bts1); + bts1 = new SingleBTS(880, -67, -77, false, new Date(), "Tf. Geb. 78"); + testlist.add(bts1); + bts1 = new SingleBTS(880, -69, -74, false, new Date(), "Tf. Geb. 78"); + testlist.add(bts1); + + SingleBTS bts2 = new SingleBTS(877, 0, -79, false, new Date(), + "Tf. Geb. 101"); + testlist.add(bts2); + bts2 = new SingleBTS(877, 0, -82, false, new Date(), "Tf. Geb. 101"); + testlist.add(bts2); + bts2 = new SingleBTS(877, 0, -82, false, new Date(), "Tf. Geb. 101"); + testlist.add(bts2); + bts2 = new SingleBTS(877, 0, -82, false, new Date(), "Tf. Geb. 101"); + testlist.add(bts2); + return testlist; + + } + + public static LinkedList getMR_Mensa() { + LinkedList testlist = new LinkedList(); + SingleBTS bts1 = new SingleBTS(880, 0, -80, false, new Date(), + "Tf. Geb. 78"); + testlist.add(bts1); + bts1 = new SingleBTS(880, 0, -82, false, new Date(), "Tf. Geb. 78"); + testlist.add(bts1); + bts1 = new SingleBTS(880, 0, -77, false, new Date(), "Tf. Geb. 78"); + testlist.add(bts1); + bts1 = new SingleBTS(880, 0, -78, false, new Date(), "Tf. Geb. 78"); + testlist.add(bts1); + + SingleBTS bts2 = new SingleBTS(877, -66, -77, false, new Date(), + "Tf. Geb. 101"); + testlist.add(bts2); + bts2 = new SingleBTS(877, -69, -76, false, new Date(), "Tf. Geb. 101"); + testlist.add(bts2); + bts2 = new SingleBTS(877, -74, -77, false, new Date(), "Tf. Geb. 101"); + testlist.add(bts2); + bts2 = new SingleBTS(877, -76, -81, false, new Date(), "Tf. Geb. 101"); + testlist.add(bts2); + return testlist; + + } + + public static LinkedList getMR_Door51() { + LinkedList testlist = new LinkedList(); + SingleBTS bts1 = new SingleBTS(880, 0, -107, false, new Date(), + "Tf. Geb. 78"); + testlist.add(bts1); + bts1 = new SingleBTS(880, 0, -108, false, new Date(), "Tf. Geb. 78"); + testlist.add(bts1); + bts1 = new SingleBTS(880, 0, -108, false, new Date(), "Tf. Geb. 78"); + testlist.add(bts1); + bts1 = new SingleBTS(880, 0, -110, false, new Date(), "Tf. Geb. 78"); + testlist.add(bts1); + + SingleBTS bts2 = new SingleBTS(877, -47, -49, false, new Date(), + "Tf. Geb. 101"); + testlist.add(bts2); + bts2 = new SingleBTS(877, -47, -48, false, new Date(), "Tf. Geb. 101"); + testlist.add(bts2); + bts2 = new SingleBTS(877, -47, -48, false, new Date(), "Tf. Geb. 101"); + testlist.add(bts2); + bts2 = new SingleBTS(877, -47, -48, false, new Date(), "Tf. Geb. 101"); + testlist.add(bts2); + return testlist; + + } + +} diff --git a/Parse/CalcVariance.java b/Parse/CalcVariance.java new file mode 100644 index 0000000..1aaccc9 --- /dev/null +++ b/Parse/CalcVariance.java @@ -0,0 +1,65 @@ +// OLD! no longer used! 06.06.2011 + +package Parse; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Timestamp; + +import DataStructure.SingleBTS; + +public class CalcVariance { + static SingleBTS[] btsarray; + + public static void Calc(sqlreader sql, Timestamp start, Timestamp end, + int ARFCN, int place) throws ClassNotFoundException, SQLException, + IOException { + btsarray = sql.btsarray; + + // create output File + File outputUL = new File("varianz/Ort " + place + " UL-" + sql.IMSI + + ".txt"); + File outputDL = new File("varianz/Ort " + place + " DL-" + sql.IMSI + + ".txt"); + FileWriter streamUL = new FileWriter(outputUL); + FileWriter streamDL = new FileWriter(outputDL); + BufferedWriter UL = new BufferedWriter(streamUL); + BufferedWriter DL = new BufferedWriter(streamDL); + + for (SingleBTS current : btsarray) { + if (current.time.getTime() >= start.getTime() + && current.time.getTime() <= end.getTime() + && current.ARFCN == ARFCN) { + if (current.getUldB() != 0) + UL.write((int) current.getUldB() + ";"); + if (current.getDldB() != 0) + DL.write((int) current.getDldB() + ";"); + + } + } + UL.close(); + DL.close(); + streamUL.close(); + streamDL.close(); + + Class.forName("com.mysql.jdbc.Driver"); + // open connection + Connection cn = DriverManager.getConnection( + "jdbc:mysql://132.230.4.13:3306/logging", "richard", + "uh237Aug.ad7"); + cn.setReadOnly(true); + System.out.println("Connected to SQL"); + // prepare a statement to the connection cn + // Statement st_MR = cn.createStatement(); + + // Timestamp start = new Timestamp(2011, 04, 05, 13, 42, 28, 0); + // Timestamp end = new Timestamp(2011, 04, 05, 13, 42, 28, 0); + + } + +} diff --git a/Parse/MapInverse.java b/Parse/MapInverse.java new file mode 100644 index 0000000..aa462e4 --- /dev/null +++ b/Parse/MapInverse.java @@ -0,0 +1,115 @@ +package Parse; + +import java.util.ArrayList; + +import DataStructure.GPScoordinate; +import DataStructure.GSMMap; +import DataStructure.SingleBTS; + +//do stuff without inverse Map. Just filter out the BTSs that might match + +public class MapInverse { + private ArrayList[] receive; + + public MapInverse(GSMMap map) { + // traverse every receive strength + // receive array (-47 ... -115) mit allen gefundenen Werten (68 + // Elemente) + // coordinates ListBTS + // Funktion, um Verhältnisse zu prüfen (z.B. BTS877 zu 880, etc.) + + // initialize receive + + // SingleBTS[] mapcontent = map.getUniqueBTSlist(); + // receive = new ArrayList[68]; + for (int i = 0; i < receive.length; i++) { + receive[i] = new ArrayList(); + } + + // traverse GSMmap, fill received + + // ArrayList receive = new ArrayList(); + + // or maybe: have only two Objekts: one with Strength and one with + // Ratio. Ask Both and compare the result + + } + +} + +/** + * Stores information about signalstrength and ratios and coordinates where this + * occured. + * + * @author richy + * + */ +class BtsLut implements iLut { + public int ARFCN; + double[] strength = new double[68]; + ArrayList DL = new ArrayList(); + ArrayList UL = new ArrayList(); + + /** + * Define for which ARFCN this GSMLut is for. It will then only take + * measurements for this specific ARFCN + * + * @param ARFCN + * Set ARFCN + */ + public BtsLut(SingleBTS ARFCN) { + this.ARFCN = ARFCN.ARFCN; + + // create dBm Array + for (int i = 0; i < 69; i++) { + strength[i] = -115 + i; + } + } + + public BtsLut(int ARFCN) { + this(new SingleBTS(ARFCN, "arfcn set")); + } + + public void addMR(SingleBTS MR, GPScoordinate gps) { + // do DL first + // int hit = Arrays.binarySearch(strength, + // (int) (Math.round(MR.getDldB()))); + // hit is the index where this Coordinate should be added to + + } + + @Override + public GPScoordinate getCoord(SingleBTS measuremet) { + // TODO Auto-generated method stub + return null; + } + +} + +class RatioLut extends BtsLut implements iLut { + + public RatioLut(int ARFCN) { + super(ARFCN); + // TODO Auto-generated constructor stub + } + + @Override + public GPScoordinate getCoord(SingleBTS measuremet) { + // TODO Auto-generated method stub + return null; + } + +} + +/** + * Stores information about signalstrength and ratios and coordinates where this + * occured. Null when no information is present + * + * @author richy + * + */ + +interface iLut { + GPScoordinate getCoord(SingleBTS measuremet); + +} diff --git a/Parse/NMEAParse.java b/Parse/NMEAParse.java new file mode 100644 index 0000000..0f88cd3 --- /dev/null +++ b/Parse/NMEAParse.java @@ -0,0 +1,224 @@ +package Parse; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.TimeZone; + +import DataStructure.GPScoordinate; + +// Parse GPS textual file +public class NMEAParse { + private BufferedReader br; + private FileReader fr; + // private DateFormat time = new SimpleDateFormat("HHmmss.SSS"); + private DateFormat date = new SimpleDateFormat("HHmmssddMMyy"); + private DateFormat dateWithMillis = new SimpleDateFormat("HHmmss.SSSddMMyy"); + private boolean QualityGood; + private LinkedList GPSData = new LinkedList(); + private int valid; + + // Constructor + public NMEAParse(String fileName) { + + // Try open file read-only + try { + this.fr = new FileReader(fileName); + this.br = new BufferedReader(this.fr); + } catch (IOException e) { + System.out.println("Cannot open file"); + e.printStackTrace(); + System.exit(-1); + } + try { + Parse(); + } catch (NumberFormatException e) { + System.out.println("Cannot parse time"); + e.printStackTrace(); + } catch (IOException e) { + System.out.println("Cannot read file"); + e.printStackTrace(); + } + + } + + private int getTimeDiff(Date UTCtime) { + + TimeZone tz = TimeZone.getDefault(); + return tz.getOffset(UTCtime.getTime()); + + } + + private void Parse() throws NumberFormatException, IOException { + Date time = new Date(); + String content; + // TimeZone tz = TimeZone.getDefault(); + int utcDifference = 0; + boolean timeSet = false; + + while ((content = br.readLine()) != null) { + + // check if something is wrong, for example more than one & is + // inside + if (StringIsWrong(content)) { + continue; + } + + // parse current Date + if (content.contains("GPRMC")) { + String[] Array = content.split(","); + try { + // DateFormat time = DateFormat.getTimeInstance(); + String timeString = Array[1].concat(Array[9]); + if (timeString.contains(".")) { + time = dateWithMillis.parse(timeString); + } else { + time = this.date.parse(Array[1].concat(Array[9])); + } + + // time.parse(Array[1].concat(Array[9]); + // to current TimeZone + // if TimeZone not yet checked, do it + if (!timeSet) { + utcDifference = getTimeDiff(time); + // System.out.println("Found time difference: " + // + utcDifference / (60 * 60 * 1000)); + // timeSet = true; //time is set + } + time.setTime(time.getTime() + utcDifference); + } catch (ParseException e) { + // System.out.println("Cannot read time or date"); + time = new Date(); + // e.printStackTrace(); + // continue; + } + // TODO: compare to current time. Add Time-Zone offset + } + + // parse coordinates + if (content.contains("$GPGGA")) { + String[] Array = content.split(","); + + // Parse coordinate 1 in DEZ (GoogleEarth style coordinate) + // see http://www.kowoma.de/gps/zusatzerklaerungen/NMEA.htm + double coordNS = Double.parseDouble(Array[2].substring(0, 2)) + + Double.parseDouble(Array[2].substring(2, + Array[2].length())) / 60; + char NS = Array[3].charAt(0); + if (NS == 'S') + coordNS = coordNS * (-1); + + // Parse coordinate 2 in DEZ (GoogleEarth style coordinate) + double coordEW = Double.parseDouble(Array[4].substring(0, 3)) + + Double.parseDouble(Array[4].substring(3, + Array[4].length())) / 60; + + char EW = Array[5].charAt(0); + if (EW == 'W') + coordEW = coordEW * (-1); + + // check quality + // String quality = "bad"; + QualityGood = false; + if (Integer.parseInt(Array[6]) == 1) { + // quality = "GPS"; + QualityGood = true; + } + if (Integer.parseInt(Array[6]) == 2) { + // quality = "DGPS"; + QualityGood = true; + } + // String justSeconds = "HH:mm:ss"; + // String secondsAndMilliSeconds = "HH:mm:ss.SSS"; + // return (new SimpleDateFormat(justSeconds).format(time) + ";" + // + coordNS + ";" + NS + ";" + coordEW + ";" + EW + ";" + + // quality); + GPScoordinate currentGPS = new GPScoordinate(time, coordNS, NS, + coordEW, EW, QualityGood); + // currentGPS.coord1S = coordNSString; + // currentGPS.coord2S = coordEWString; + + // check if currentGPS is valid + if (currentGPS.isValid()) { + GPSData.add(currentGPS); + valid++; + } + } + } + System.out.println("Valid NMEA-Lines: " + valid); + } + + /** + * Returns true if something in this NMEA line is wrong + * + * @param content + * @return + */ + private boolean StringIsWrong(String content) { + // check if more than one $ is inside + if (content.lastIndexOf('$') > 1) { + return true; + } + return false; + } + + public LinkedList getGPSList() { + // remove first coordinate. Date might be set wrong; + GPSData.remove(); + return GPSData; + } + + public double getMinX() { + Iterator itr = GPSData.iterator(); + GPScoordinate current; + double min = 181; + while (itr.hasNext()) { + current = itr.next(); + if (current.coord2 < min) + min = current.coord2; + } + return min; + } + + public double getMaxX() { + Iterator itr = GPSData.iterator(); + GPScoordinate current; + double max = -181; + while (itr.hasNext()) { + current = itr.next(); + if (current.coord2 > max) + max = current.coord2; + } + return max; + } + + public double getMinY() { + Iterator itr = GPSData.iterator(); + GPScoordinate current; + double min = 181; + while (itr.hasNext()) { + current = itr.next(); + if (current.coord1 < min) + min = current.coord1; + } + return min; + } + + public double getMaxY() { + Iterator itr = GPSData.iterator(); + GPScoordinate current; + double max = -181; + while (itr.hasNext()) { + current = itr.next(); + if (current.coord1 > max) + max = current.coord1; + } + return max; + } +} diff --git a/Parse/SqlPoller.java b/Parse/SqlPoller.java new file mode 100644 index 0000000..2d528dd --- /dev/null +++ b/Parse/SqlPoller.java @@ -0,0 +1,47 @@ +package Parse; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.concurrent.Callable; + +import DataStructure.MobilePhone; + +public class SqlPoller implements Callable> { + static long last_id; + static Connection cn; + + /** + * @param args + */ + public static void main(String[] args) { + // TODO Auto-generated method stub + + } + + public SqlPoller() { + try { + if (cn == null || cn.isClosed()) { + Class.forName("com.mysql.jdbc.Driver"); + cn = DriverManager.getConnection( + "jdbc:mysql://132.230.4.13:3306/logging", "richard", + "uh237Aug.ad7"); + } + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ClassNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Override + public ArrayList call() throws Exception { + // make a statement + + // TODO Auto-generated method stub + return null; + } +} diff --git a/Parse/SqlPollerDate.java b/Parse/SqlPollerDate.java new file mode 100644 index 0000000..e71e66b --- /dev/null +++ b/Parse/SqlPollerDate.java @@ -0,0 +1,406 @@ +package Parse; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; + +import DataStructure.GPScoordinate; +import DataStructure.MobilePhone; +import DataStructure.SingleBTS; + +public class SqlPollerDate { + public Connection cn; + public Connection cnForName; + + /** + * @param args + * @throws SQLException + * @throws ClassNotFoundException + */ + public static void main(String[] args) throws ClassNotFoundException, + SQLException { + SqlPollerDate sql = new SqlPollerDate(); + MobilePhone phone = sql.getActionRefID(146024l); + phone.toString(); + + } + + public SqlPollerDate() throws ClassNotFoundException, SQLException { + + cn = getConnection(); + cnForName = getNameConnection(); + + } + + private Connection getNameConnection() { + // catch Exceptions as Name lookup is not needed for operation + try { + Class.forName("com.mysql.jdbc.Driver"); + } catch (ClassNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + try { + Connection cn = DriverManager.getConnection( + "jdbc:mysql://132.230.4.13:3306/hlr", "richard", + "uh237Aug.ad7"); + cn.setReadOnly(true); + return cn; + } catch (SQLException e) { + return null; + } + + } + + public SqlPollerDate(SqlPollerUnThreaded sql) { + cn = sql.cn; + } + + /** + * Returns last occured MRs of phone with given IMSI. + * + * @param IMSI + * @return + * @throws SQLException + */ + public MobilePhone getLastMRs(long IMSI) throws SQLException { + // TODO + MobilePhone result = new MobilePhone(); + result.IMSI = IMSI; + result.MR = getIMSIMRs(IMSI); + result.name = getName(IMSI); + + return result; + } + + private ArrayList getIMSIMRs(long IMSI) throws SQLException { + String query = imsiQuery(IMSI); + ResultSet rs = cn.createStatement().executeQuery(query); + // get current assigned BTS-arfcn + int usedBTS = getUsedBTSIMSI(IMSI); + ArrayList result = new ArrayList(); + while (rs.next()) { + // parse first BTS + SingleBTS assigned = new SingleBTS(usedBTS, "lastUsed"); + assigned.addDl(rs.getInt("RXL_FULL_dl")); + Date timestamp = rs.getTimestamp("cur_timestamp"); + assigned.time = timestamp; + result.add(assigned); + // now, add neighbor BTSs + int neigh = rs.getInt("NUM_NEIGH"); + if (neigh != 7) { + for (int i = 0; i < neigh; i++) { + int ARFCN = rs.getInt("ARFCN_" + i); + int rxdl = rs.getInt("rxlev_" + i); + // int reason = rs.getInt("actionID"); + SingleBTS neighbor = new SingleBTS(ARFCN, 0, rxdl, false, + timestamp, "Lookup Record"); + // neighbor.reason = reason; + result.add(neighbor); + } + } + } + return result; + } + + private int getUsedBTSIMSI(long iMSI) throws SQLException { + String query = "SELECT arfcn FROM arfcn " + + "JOIN usedBTS ON usedBTS.bts = " + + "arfcn.bts JOIN action ON imsi = " + iMSI + + " AND usedBTS.actionRefID = action.ID " + + "ORDER BY usedBTS.cur_timestamp DESC LIMIT 0,1"; + ResultSet rs = cn.createStatement().executeQuery(query); + rs.first(); + int arfcn = rs.getInt("arfcn"); + // return new SingleBTS(arfcn, "last Used BTS"); + return arfcn; + } + + private String imsiQuery(long iMSI) { + // TODO Auto-generated method stub + return "SELECT MR.cur_timestamp, RXL_FULL_dl, RXL_SUB_dl, " + + "RXQ_FULL_dl, RXQ_SUB_dl, NUM_NEIGH, " + + "IDX_0, ARFCN_0, BSIC_0, rxlev_0, IDX_1, " + + "ARFCN_1, BSIC_1, rxlev_1, IDX_2, ARFCN_2, " + + "BSIC_2, rxlev_2, IDX_3, ARFCN_3, BSIC_3, " + + "rxlev_3, IDX_4, ARFCN_4, BSIC_4, rxlev_4, " + + "IDX_5, ARFCN_5, BSIC_5, rxlev_5 " + + "FROM measurementResults MR JOIN action ON " + "IMSI = " + + iMSI + " AND MR.actionRefID = action.ID " + + "ORDER BY MR.id DESC LIMIT 0,6"; + + } + + public MobilePhone getActionRefID(long actionRefID) throws SQLException { + + // get MRs + ArrayList MRs = getActionRefMRs(actionRefID); + + // get IMSI of actionRefID + long IMSI = getIMSI(actionRefID); + MobilePhone phone = new MobilePhone(); + phone.IMSI = IMSI; + // phone.MR = filterMRTime(MRs, 9000l); + // phone.MR = getMiddle(MRs); + phone.MR = MRs; + // phone.MR = ListBTS.generateAveragedList(phone.MR); + + System.out.println("ActionRefID " + actionRefID + " fertig"); + + // get Coordinates of that phone if possible + phone.correctCoordinate = getCoord(actionRefID); + phone.name = getName(IMSI); + + return phone; + } + + private String getName(long iMSI) { + try { + Statement st = cnForName.createStatement(); + ResultSet rs = st + .executeQuery("SELECT surname, User.name FROM Subscriber" + + " JOIN UserWatch ON imsi = '" + iMSI + + "' AND Subscriber.id = subscriber_id " + + "JOIN User ON user_id = User.id"); + rs.first(); + return rs.getString("surname") + " " + rs.getString("name"); + } catch (SQLException e) { + // e.printStackTrace(); + } catch (NullPointerException e) { + + } + return null; + } + + /** + * Searches the logging table coordinates for the correct coordinate for + * this measure + * + * @param actionRefID + * @return + * @throws SQLException + */ + public GPScoordinate getCoord(long actionRefID) { + String query = "SELECT * FROM coordinates WHERE ActionID = " + + actionRefID; + try { + ResultSet rs = cn.createStatement().executeQuery(query); + while (rs.next()) { + GPScoordinate coordinate = new GPScoordinate(new Date(), + rs.getDouble("CoordNS"), 'N', rs.getDouble("CoordEW"), + 'E', true); + return coordinate; + } + } catch (SQLException e) { + + } + return null; + } + + /** + * Returns all BTS that are l seconds before last Measurement + * + * @param mRs + * @param l + * @return + */ + @SuppressWarnings("unused") + private ArrayList filterMRTime(ArrayList mRs, long l) { + // get max time + long time = getMaxTime(mRs); + + // make new list. copy every entry that is l milliseconds before time + ArrayList newMR = new ArrayList(); + for (int i = 0; i < mRs.size(); i++) { + if ((time - mRs.get(i).time.getTime()) <= l) { + newMR.add(mRs.get(i)); + } + } + return newMR; + } + + /** + * Returns Middle +/- 1/2 second! + * + * @param MR + * @return + */ + @SuppressWarnings("unused") + private ArrayList getMiddle(ArrayList MR) { + ArrayList result = new ArrayList(); + long time = (getMinTime(MR) + getMaxTime(MR)) / 2; + for (SingleBTS current : MR) { + if (Math.abs(current.time.getTime() - time) <= 1000) { + result.add(current); + } + } + return result; + } + + private long getMinTime(ArrayList MR) { + long time = MR.get(0).time.getTime(); + for (int i = 1; i < MR.size(); i++) { + if (MR.get(i).time.getTime() < time) { + time = MR.get(i).time.getTime(); + } + } + return time; + } + + private long getMaxTime(ArrayList MR) { + long time = MR.get(0).time.getTime(); + for (int i = 1; i < MR.size(); i++) { + if (MR.get(i).time.getTime() > time) { + time = MR.get(i).time.getTime(); + } + } + return time; + } + + /** + * Returns IMSI from given ActionRefID + * + * @param actionRefID + * @return + * @throws SQLException + */ + private long getIMSI(long actionRefID) throws SQLException { + String query = "Select IMSI from action WHERE ID = " + actionRefID; + ResultSet rs = cn.createStatement().executeQuery(query); + rs.first(); + + return rs.getLong("IMSI"); + } + + /** + * Gets all MR with given actionRefID + * + * @param actionRefID + * @param usedBTS + * @return + * @throws SQLException + */ + private ArrayList getActionRefMRs(long actionRefID) + throws SQLException { + SingleBTS[] usedBTS = getUsedBTS(actionRefID); + String query = "SELECT * FROM measurementResults MR " + + "WHERE actionRefID = " + actionRefID; + Statement st = cn.createStatement(); + ResultSet rs = st.executeQuery(query); + + ArrayList result = new ArrayList(); + + while (rs.next()) { + // add current assigned BTS + Date timestamp = rs.getTimestamp("cur_timestamp"); + // get name of the assigned BTS + SingleBTS search = searchForUsedBTS(usedBTS, timestamp); + // transfer name to current + SingleBTS current = new SingleBTS(search.ARFCN, search.name); + current.clear(); + // fill current with its receive level + int RXdl = rs.getInt("RXL_FULL_dl"); + current.addDl(RXdl); + current.time = timestamp; + result.add(current); + + // now: neighbors! + result.addAll(readNeighborList(rs, timestamp)); + } + + return result; + } + + /** + * Parses all BTSs from neighbor list fo given ResultSet. Assigned date + * provided in timestamp + * + * @param rs + * @param timestamp + * @return + * @throws SQLException + */ + private ArrayList readNeighborList(ResultSet rs, Date timestamp) + throws SQLException { + int numOfNeigh = rs.getInt("NUM_NEIGH"); + if (numOfNeigh == 7 || numOfNeigh == 0) { + return new ArrayList(); + } + ArrayList result = new ArrayList(); + for (int i = 0; i < numOfNeigh; i++) { + int ARFCN = rs.getInt("ARFCN_" + i); + int RXdl = rs.getInt("rxlev_" + i); + SingleBTS neighbor = new SingleBTS(ARFCN, "neighbor"); + neighbor.clear(); + neighbor.addDl(RXdl); + neighbor.time = timestamp; + result.add(neighbor); + + } + return result; + } + + /** + * Returns index of currently used BTS + * + * @param btsnames + * @param timestamp + * @return + */ + private SingleBTS searchForUsedBTS(SingleBTS[] btsnames, Date timestamp) { + if (btsnames == null || btsnames.length == 0 || timestamp == null) { + return null; + } + // System.out.print("searchInBetween called..."); + SingleBTS searchelement = new SingleBTS(0, 0, 0, false, timestamp, + "name"); + int between = Arrays.binarySearch(btsnames, searchelement); + if (between < 0) { + between = Math.abs(between); + between = between - 2; + } + // if between < 0 it means that the call would be invalid because there + // is no usedBTS assignable. A call was before a BTS got assigned + // through OpenBSC. Check if there is a x second margin! + + // System.out.println("ended!"); + + return btsnames[between]; + } + + private SingleBTS[] getUsedBTS(long actionRefID) throws SQLException { + String query = "select bts.cur_timestamp, " + "bts.bts, " + + "arfcn.arfcn, " + "arfcn.location " + "from usedBTS bts " + + "join action on bts.actionRefID = " + actionRefID + " " + + "AND bts.actionRefID = action.ID " + + "JOIN arfcn ON bts.bts = arfcn.bts " + "ORDER BY bts.ID"; + Statement st = cn.createStatement(); + ResultSet rs = st.executeQuery(query); + ArrayList usedBTS = new ArrayList(); + while (rs.next()) { + int ARFCN = rs.getInt("arfcn.arfcn"); + String name = rs.getString("arfcn.location"); + Date time = rs.getTimestamp("bts.cur_timestamp"); + SingleBTS current = new SingleBTS(ARFCN, name); + current.time = time; + usedBTS.add(current); + } + return usedBTS.toArray(new SingleBTS[1]); + } + + private Connection getConnection() throws ClassNotFoundException, + SQLException { + Class.forName("com.mysql.jdbc.Driver"); + cn = DriverManager.getConnection( + "jdbc:mysql://132.230.4.13:3306/logging", "richard", + "uh237Aug.ad7"); + cn.setReadOnly(true); + return cn; + } + +} diff --git a/Parse/SqlPollerUnThreaded.java b/Parse/SqlPollerUnThreaded.java new file mode 100644 index 0000000..e5136c6 --- /dev/null +++ b/Parse/SqlPollerUnThreaded.java @@ -0,0 +1,370 @@ +package Parse; + +import helper.ListBTS; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; + +import DataStructure.MobilePhone; +import DataStructure.SingleBTS; + +/** + * Man könnte auch das Datum des aktuellsten Eintrags nehmen und x Sekunden + * davon abziehen! Methoden: gefundene IMSI ausgeben. Zeitspanne angeben, in der + * man suchen will. Mitteln immer über eine (x) Sekunde? + * + * @author richy + * + */ +public class SqlPollerUnThreaded { + /** + * + */ + private static final long serialVersionUID = 1L; + public Connection cn; + public long last_id; + public long last_ActionRef; + public ArrayList results = new ArrayList(); + public int polltime = 3000; + public ArrayList phones; + private Long[] IMSIs; + + // private boolean interrupt = false; + + /** + * @param args + * @throws InterruptedException + */ + public static void main(String[] args) throws InterruptedException { + + ArrayList blalist = new ArrayList(); + blalist.add(1l); + blalist.add(1l); + blalist.add(1l); + blalist.add(3l); + blalist.add(4l); + ArrayList result = new ArrayList(new HashSet(blalist)); + System.out.println(result); + SqlPollerUnThreaded bla = new SqlPollerUnThreaded(); + System.out.println("Init... Wait"); + Thread.sleep(1300); + bla.getMRs(); + Thread.sleep(1300); + bla.getMRs(); + System.out.println("Done"); + + } + + /** + * Between creation and use of SqlPoller, some time must pass so that the + * SQL table can grow! + */ + public SqlPollerUnThreaded() { + + // mit LIMIT(0,30) die aktuellesten n Einträge anzeigen? + // Oder auf cur_timestamp achten? Z.B.: die letzten drei Sekunden? + initSQL(); + + } + + // public void Interrupt() { + // interrupt = true; + // } + + // public boolean isInterrupted() { + // return interrupt; + // } + + public ArrayList getMRs() { + // formerly known as run() + if (cn == null || last_id < 0) { + initSQL(); + } + + // TODO Get Elements here and store it in a public variable + + try { + Statement st = cn.createStatement(); + st.setQueryTimeout(polltime); // ------------------- + ResultSet rsMR = getAllMR(); + ArrayList rsBTS = getUsedBTS(rsMR); + ArrayList phones = mergeMrBts(rsMR, rsBTS); + phones = mergePhones(phones, IMSIs); + this.phones = phones; + System.out.println(phones); + } catch (SQLException e) { + // TODO Auto-generated catch block + System.out.println("Cannot get a Statement from SQL in SqlPoller"); + e.printStackTrace(); + } + /* + * try { Thread.sleep(polltime); } catch (InterruptedException e) { + * System.out.println("sqlPoller closed"); // e.printStackTrace(); try { + * System.out.println("Closing Connection to SQL Server..."); + * cn.close(); System.out.println("Closed successfully"); } catch + * (SQLException e1) { System.out.println(""); // e1.printStackTrace(); + * } } + */ + + // at the end, get new last_id: prepare for next run + try { + last_id = getLastID(); + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return phones; + } + + /** + * Traverses IMSIs and takes all phones from phones that match each IMSI. + * All MRs are joined and averaged + * + * @param phones + * @param IMSIs + * @return + */ + private ArrayList mergePhones(ArrayList phones, + Long[] IMSIs) { + ArrayList result = new ArrayList(); + for (long imsi : IMSIs) { + MobilePhone current = new MobilePhone(); + current.IMSI = imsi; + for (int i = 0; i < phones.size(); i++) { + if (phones.get(i).IMSI == imsi) { + current.MR.addAll(phones.get(i).MR); + phones.remove(i); + i--; + } + } + result.add(current); + + } + result = averagePhones(result); + return result; + } + + private ArrayList averagePhones(ArrayList phones) { + ArrayList result = new ArrayList(); + for (int i = 0; i < phones.size(); i++) { + MobilePhone current = new MobilePhone(); + current.IMSI = phones.get(i).IMSI; + SingleBTS[] content = ListBTS.content(phones.get(i).MR); + current.MR = ListBTS + .generateAveragedList(phones.get(i).MR, content); + result.add(current); + } + return result; + } + + private ArrayList mergeMrBts(ResultSet rsMR, + ArrayList rsBTS) throws SQLException { + ArrayList phones = new ArrayList(); + rsMR.beforeFirst(); + while (rsMR.next()) { + MobilePhone current = new MobilePhone(); + current.IMSI = rsMR.getLong("IMSI"); + int neigh = rsMR.getInt("NUM_NEIGH"); + if (neigh != 7) { + for (int i = 0; i < neigh; i++) { + int ARFCN = rsMR.getInt("ARFCN_" + i); + int rxdl = rsMR.getInt("rxlev_" + i); + int reason = rsMR.getInt("actionID"); + SingleBTS new_elem = new SingleBTS(ARFCN, 0, rxdl, false, + new Date(), "Lookup Record"); + new_elem.reason = reason; + current.MR.add(new_elem); + } + } + // now, search currently connected BTS for this phone's IMSI + int ARFCN = getARFCNforIMSI(current.IMSI, rsBTS); + int reason = rsMR.getInt("actionID"); + int rxul = rsMR.getInt("RXL_SUB_ul"); + int rxdl = rsMR.getInt("RXL_SUB_dl"); + SingleBTS new_elem = new SingleBTS(ARFCN, rxul, rxdl, false, + new Date(), "Lookup Record"); + new_elem.reason = reason; + current.MR.add(new_elem); + phones.add(current); + + } + + // put phones together + return phones; + } + + private int getARFCNforIMSI(long IMSI, ArrayList rsBTS) + throws SQLException { + for (ResultSet rs : rsBTS) { + rs.beforeFirst(); + while (rs.next()) { + if (rs.getLong("IMSI") == IMSI) { + return rs.getInt("arfcn"); + } + } + } + return 0; + } + + /** + * Matches entries from rs with usedBTS table + * + * @param rs + * @throws SQLException + */ + private ArrayList getUsedBTS(ResultSet rs) throws SQLException { + // get lowest actionRefID + long actionRefID = getLowestRefID(rs); + rs.beforeFirst(); + Long[] IMSIs = getDistinctIMSIs(rs); + this.IMSIs = IMSIs; + // now, get the usedBTS part for each IMSI that is found in rs + ArrayList result = new ArrayList(); + for (long IMSI : IMSIs) { + Statement st = cn.createStatement(); + ResultSet rs2 = st.executeQuery(usedBTSQuery(IMSI, actionRefID)); + result.add(rs2); + + // merge this stuff + } + return result; + + } + + private String usedBTSQuery(long IMSI, long RefID) { + String query = "SELECT * FROM usedBTS" + + " JOIN action ON usedBTS.actionRefID >= " + RefID + + " AND action.IMSI=" + IMSI + + " AND usedBTS.actionRefID = action.id" + + " JOIN arfcn ON arfcn.bts = usedBTS.bts" + + " ORDER BY usedBTS.cur_timestamp desc"; + System.out.println("Query for usedBTS: " + query); + return query; + } + + /** + * Traverses ResultSet from getAllMR(). Outputs all IMSIs that are inside + * this Set + * + * @param rs + * @return + * @throws SQLException + */ + private Long[] getDistinctIMSIs(ResultSet rs) throws SQLException { + // make ArrayList with all IMSIs inside + Collection IMSIs = new ArrayList(); + rs.beforeFirst(); + while (rs.next()) { + IMSIs.add(rs.getLong("IMSI")); + } + // make Hashset + ArrayList result = new ArrayList(new HashSet(IMSIs)); + return result.toArray(new Long[1]); + + } + + /** + * Takes a ResultSet with MRs. Gets the lowest actionRefID + * + * @param rs + * @return + * @throws SQLException + */ + private long getLowestRefID(ResultSet rs) throws SQLException { + long actionRefID = Long.MAX_VALUE; + rs.beforeFirst(); + while (rs.next()) { + if (actionRefID > rs.getLong("MR.actionRefID")) { + actionRefID = rs.getLong("actionRefID"); + } + } + return actionRefID; + } + + private void initSQL() { + try { + Class.forName("com.mysql.jdbc.Driver"); + cn = DriverManager.getConnection( + "jdbc:mysql://132.230.4.13:3306/logging", "richard", + "uh237Aug.ad7"); + cn.setReadOnly(true); + // Connection is ready + // get current ID + // Statement getCurrID = cn.createStatement(); + last_id = getLastID(); + } catch (ClassNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + /** + * Gets a resultset that contains all MeasurementReports since last_id. + * MIN(actionRefID is at the end of this ResultSet) + * + * @return + * @throws SQLException + * when last_id <= 0 or Connection is broken + */ + private ResultSet getAllMR() throws SQLException { + // e.g. last id = 1702898 + if (last_id <= 0) { + throw new SQLException( + "seems it is not inilialized. Last_id points to 0"); + } + String query = "SELECT * FROM measurementResults MR " + + "JOIN action ON " + "MR.id >= " + last_id + " AND " + + "MR.actionRefID = action.ID " + // + "ORDER BY MR.cur_timestamp DESC"; + + "ORDER BY MR.actionRefID"; + System.out.println("Query for all MR is: " + query); + Statement st = cn.createStatement(); + ResultSet result = st.executeQuery(query); + result.first(); + // last_ActionRef = result.getLong("ActionRefID"); + result.beforeFirst(); + return result; + + /* + * SELECT MR.id, MR.cur_timestamp, action.IMSI, MR.RXL_FULL_ul, + * MR.RXL_FULL_dl, BS_POWER, MS_TO, L1_MS_PWR, L1_TA,NUM_NEIGH, IDX_0, + * ARFCN_0,BSIC_0, rxlev_0, IDX_1, ARFCN_1,BSIC_1, rxlev_1, IDX_2, + * ARFCN_2,BSIC_2, rxlev_2, IDX_3, ARFCN_3,BSIC_3, rxlev_3, IDX_4, + * ARFCN_4,BSIC_4, rxlev_4, IDX_5, ARFCN_5,BSIC_5, rxlev_5, actionID + * FROM measurementResults MR JOIN action ON MR.id >= last_id AND + * MR.actionRefID = action.ID; + */ + + } + + private int getLastID() throws SQLException { + String query = "SELECT MAX( id ) FROM measurementResults "; + Statement st = cn.createStatement(); + ResultSet result = st.executeQuery(query); + if (result.first()) { + return result.getInt(1); + } else { + return -1; + } + } + + public void close() { + try { + cn.close(); + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + +} diff --git a/Parse/sqlreader.java b/Parse/sqlreader.java new file mode 100644 index 0000000..8268810 --- /dev/null +++ b/Parse/sqlreader.java @@ -0,0 +1,483 @@ +package Parse; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.LinkedList; + +import DataStructure.GPScoordinate; +import DataStructure.SingleBTS; + +public class sqlreader { + private LinkedList gpslist; + public SingleBTS[] btsarray; + public GPScoordinate[] gpsarray; + private ResultSet MR_rs; + private ResultSet usedBTS_rs; + private Statement st; + private Date start; + private Date end; + public long IMSI; + public SingleBTS[] BtsNames; + + /** + * Builds a list of MR and Coordinates. Entry x of the first list reflects + * element x of the second list + * + * @param nmea + * NMEAParse Object + * @param IMSI + * which phone + * @param matchtime + * Time in milliseconds a coordinate may be away from a + * measurement result + * @throws ClassNotFoundException + * when no sql driver is found + * @throws SQLException + * when no connection to databse is possible + */ + // Constructor + public sqlreader(NMEAParse nmea, long IMSI, long matchtime) + throws ClassNotFoundException, SQLException { + this.IMSI = IMSI; + gpslist = nmea.getGPSList(); + // if a call was done before a gps fix, it would crash while searching + // for the usedBTS. So, minus 1 minute or so + this.start = new Date(gpslist.getFirst().time.getTime() - 60000); + this.end = new Date(gpslist.getLast().time.getTime() + 60000); + + openSQL(); + // ask sql for all known BTS in database (table arfcn) + BtsNames = getBTSnames(); + // get (starting)timestamps when BTS got used (during a call). Nothing + // else + SingleBTS[] usedBTStimestamps = getBTSlist(); + // get all Measurement Reports + SingleBTS[] BTSarray = parseMR(usedBTStimestamps, BtsNames); + System.out.println("Valid SQL-Entries: " + BTSarray.length); + searchCorrespondingCoords(gpslist, BTSarray, matchtime); + + // now, get corresponding gps-coordinates + + // Date[] mrDate = openSQL(gpslist.getFirst().time, + // gpslist.getLast().time, IMSI); + // match usedBTS to MRlist (max. valid arfcn = 1023) + // SingleBTS[] usedBTS = getBTSlist(); + } + + // fills the MR_rs ResultSet + public void openSQL() throws ClassNotFoundException, SQLException { + // select driver + Class.forName("com.mysql.jdbc.Driver"); + // open connection + Connection cn = DriverManager.getConnection( + "jdbc:mysql://132.230.4.13:3306/logging", "richard", + "uh237Aug.ad7"); + cn.setReadOnly(true); + System.out.println("Connected to SQL"); + st = cn.createStatement(); + // query Timeout + st.setQueryTimeout(20);// --------------------------- + + } + + // queries the Database and fills MR_rs + private void fillMR_rs() throws SQLException { + // System.out.println("fillMR_rs called"); + String query = queryMR(); + try { + MR_rs = st.executeQuery(query); + } catch (SQLException e) { + System.out + .println("Timeout. SQL query hasn't finished within time"); + e.printStackTrace(); + } + + } + + /** + * reads the MR from SQL database. Also takes Information from + * btsTimestamps(usedBTS table) and the btsNames(arfcn table) to get the + * name and arfcn of each SingleBTS + * + * @param btsTimestamp + * Array: SQL table usedBTS + * @param btsNames + * Array: SQL table arfcn. Information about location and name + */ + private SingleBTS[] parseMR(SingleBTS[] btsTimestamp, SingleBTS[] btsNames) + throws SQLException { + // System.out.println("parseMR called with btsTimestamp of size " + // + btsTimestamp.length + " and btsNames of size " + // + btsNames.length); + + // fill SQL buffer first -> query + fillMR_rs(); + MR_rs.beforeFirst(); + + // prepare variables + SingleBTS current; + LinkedList btslist = new LinkedList(); + // traverse sql output + int result = 0; + while (MR_rs.next()) { + // System.out.println("getting SQL row number " + result); + result++; + // search for timestamp when this MR was created + Date timestamp = MR_rs.getTimestamp("cur_timestamp"); + + // to which BTS was the phone connected when this MR got created + int hit = searchForUsedBTS(btsTimestamp, timestamp); + if (hit < 0) { + System.out.println("corresponding BTS not found for " + IMSI + + " !"); + hit = 0; + } + // parse SQL input for FullBTS + int ARFCN = btsTimestamp[hit].ARFCN; + int RXul = MR_rs.getInt("RXL_FULL_ul"); + int RXdl = MR_rs.getInt("RXL_FULL_dl"); + boolean interpolated = false; + String name = btsTimestamp[hit].name; + int TA = MR_rs.getInt("L1_TA"); + int BS_POWER = MR_rs.getInt("BS_POWER"); + int MS_TO = MR_rs.getInt("MS_TO"); + int MS_PWR = MR_rs.getInt("L1_MS_PWR"); + int reason = MR_rs.getInt("actionID"); + int rxQualsubDL = MR_rs.getInt("RXQ_FULL_dl"); + // int rxQualfullDL = MR_rs.getInt("RXQ_SUB_dl"); + int rxQualsubUL = MR_rs.getInt("RXQ_SUB_ul"); + // int rxQualfullUL = MR_rs.getInt("RXQ_FULL_ul"); + // only add if source was a phone call! + if (reason == 2) { + // store the FullBTS details + current = new SingleBTS(ARFCN, RXul, RXdl, interpolated, + timestamp, name, TA, BS_POWER, MS_TO, MS_PWR); + current.fullBTS = true; + current.reason = reason; + // current.dlQfull.add((double) rxQualfullDL); + // current.dlQsub.add((double) rxQualsubDL); + // current.ulQfull.add((double) rxQualfullUL); + current.ulQsub.add((double) rxQualsubUL); + current.dlQsub.add((double) rxQualsubDL); + btslist.add(current); + + // parse other BTS from the measurement report + // parse SQL input for SingleBTS. Number of neighbors: neigh + int neigh = MR_rs.getInt("NUM_NEIGH"); + if (neigh == 7) { + neigh = 0; + // no more BTS available. Actually, the MR is not valid! + // Maybe + // check for this before adding the FullBTS? + } else { + for (int i = 0; i < neigh; i++) { + RXdl = MR_rs.getInt("rxlev_" + i); + // throw out BTS that are in neighbor list but not + // received + if (RXdl > -116) { + ARFCN = MR_rs.getInt("ARFCN_" + i); + // get The Name (String) of this ARFCN + name = searchBTSName(btsNames, ARFCN); + current = new SingleBTS(ARFCN, 0, RXdl, false, + timestamp, name); + current.reason = reason; + btslist.add(current); + } + + } + } + } + + } + SingleBTS[] btsarray = new SingleBTS[btslist.size()]; + btsarray = btslist.toArray(btsarray); + return btsarray; + + } + + /** + * Gets the table usedBTS. It contains Timestamps when which BTS got used. + * This is needed to when a MS was connected to which BTS + * + * @return Array of SingleBTS with Timestamp. Timestamp indicates since when + * this BTS was used by the MS + * @throws SQLException + * when SQL connection is unavailable or some problem occurs + */ + private SingleBTS[] getBTSlist() throws SQLException { + // System.out.println("getBtslist called"); + // LinkedList list = new LinkedList(); + usedBTS_rs = st.executeQuery(queryusedBTS()); + int y = getRowCount(usedBTS_rs); + int n = 0; + SingleBTS[] BTSarray = new SingleBTS[y]; + // array mit usedBTS erstellen + while (usedBTS_rs.next()) { + String name = usedBTS_rs.getString("location"); + Date time = usedBTS_rs.getTimestamp("cur_timestamp"); + int arfcn = usedBTS_rs.getInt("arfcn"); + // use SingleBTS to represent usedBTS + BTSarray[n] = new SingleBTS(arfcn, 0, 0, false, time, name); + n++; + } + return BTSarray; + // für jeden MR einen Binary Search machen. Das Ergebnis ist die + // benutzte Zelle (weil binary search den insert point findet) + + } + + // queries for all measurementResults for given IMSI and time + private String queryMR() { + String beginning = dateToString(start); + String ending = dateToString(end); + String query = "SELECT MR.cur_timestamp, MR.RXL_FULL_ul, MR.RXL_FULL_dl, BS_POWER, " + + "MS_TO, L1_MS_PWR, L1_TA,NUM_NEIGH," + + "IDX_0, ARFCN_0,BSIC_0, rxlev_0," + + "IDX_1, ARFCN_1,BSIC_1, rxlev_1," + + "IDX_2, ARFCN_2,BSIC_2, rxlev_2," + + "IDX_3, ARFCN_3,BSIC_3, rxlev_3," + + "IDX_4, ARFCN_4,BSIC_4, rxlev_4," + + "IDX_5, ARFCN_5,BSIC_5, rxlev_5," + + "actionID, RXQ_FULL_dl, RXQ_SUB_dl, RXQ_FULL_ul, RXQ_SUB_ul " + + "FROM measurementResults MR " + + "JOIN action ON MR.cur_timestamp BETWEEN " + + "\"" + + beginning + + "\"" + + " AND " + + "\"" + + ending + + "\"" + + " AND action.IMSI = " + + IMSI + " AND MR.actionRefID = action.ID"; + System.out.println("Query for MR is: " + query); + return query; + } + + // queries usedBTS + private String queryusedBTS() { + String beginning = dateToString(start); + String ending = dateToString(end); + String query = "select bts.cur_timestamp, " + "bts.bts, " + + "arfcn.arfcn, " + "arfcn.location " + "from usedBTS bts " + + "join action on " + "imsi = " + IMSI + " and " + + "bts.cur_timestamp BETWEEN \"" + beginning + "\"" + "AND " + + "\"" + ending + "\" " + "AND bts.actionRefID = action.ID " + + "JOIN arfcn ON bts.bts = arfcn.bts " + "ORDER BY bts.ID"; + System.out.println("BTSQuery is: " + query); + return query; + } + + // returns date string in mySQL-fashion + public static String dateToString(Date time) { + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S").format(time); + // 2011-01-13 19:51:55.0 + } + + // parses mySQL date to java date + public static Date stringToDate(String s) { + try { + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S").parse(s); + } catch (ParseException e) { + System.out.println("Cannot parse SQL timestamp"); + e.printStackTrace(); + System.exit(-1); + return null; + } + } + + // finds usedBTS index for a measured BTS + // btsnames: SQL table "usedBTS" + private int searchForUsedBTS(SingleBTS[] btsnames, Date timestamp) { + + // System.out.print("searchInBetween called..."); + SingleBTS searchelement = new SingleBTS(0, 0, 0, false, timestamp, + "name"); + int between = Arrays.binarySearch(btsnames, searchelement); + if (between < 0) { + between = Math.abs(between); + between = between - 2; + } + // if between < 0 it means that the call would be invalid because there + // is no usedBTS assignable. A call was before a BTS got assigned + // through OpenBSC. Check if there is a x second margin! + + // System.out.println("ended!"); + + return between; + } + + // not as speedy as it could be + /** + * gets name of bts for given arfcn. If name is not found this might + * indicate that the logging databse is out of date or this is a foreign + * BTS, for example from E-Plus + */ + private String searchBTSName(SingleBTS[] btsnames, int arfcn) { + // System.out.println("searchBTSName called"); + for (int i = 0; i < btsnames.length; i++) { + if (btsnames[i].ARFCN == arfcn) + return btsnames[i].name; + } + // System.out.println("arfcn Database is out of Date!"); + return "unknown - possible foreign BTS"; + + } + + // would be faster with a "sweep" approach! For example: get bts counter. + // start searching from specific point + + private void searchCorrespondingCoords(LinkedList gpslist, + SingleBTS[] btsarray, long matchtime) { + // create gpsarray out of gpslist to search efficiently + GPScoordinate[] gpsarray = new GPScoordinate[1]; + gpsarray = gpslist.toArray(gpsarray); + // create BTS list + LinkedList btslist = new LinkedList(); + // recycle gpslist. Clear it + gpslist.clear(); + boolean insert = false; + GPScoordinate bestfit = new GPScoordinate(null, 0, 'N', 0, 'W', false); + int discarded = 0; + // traverse every bts, find best gps coordinate + for (SingleBTS singleBTS : btsarray) { + // check for FullBTS. After a FullBTS, other BTS follow from the + // Neighbor list! + if (singleBTS.fullBTS) { + bestfit = getBestCoord(gpsarray, singleBTS); + // check for matchtime + if (Math.abs(bestfit.time.getTime() - singleBTS.time.getTime()) < matchtime) { + insert = true; + } else + insert = false; + } + if (insert) { + // if insert is true, bestfit is securely initlialized! + + gpslist.add(bestfit); + btslist.add(singleBTS); + + } else + // do not insert any following SingleBTS. GPS coordinat and BTS + // time are too far away! + discarded++; + + } + System.out.println("Measurements without GPS point: " + discarded); + // save lists to arrays + this.btsarray = btslist.toArray(new SingleBTS[0]); + this.gpsarray = gpslist.toArray(new GPScoordinate[0]); + if (this.btsarray.length != this.gpsarray.length) + System.out.println("Array sizes not correct: btsarray" + + btsarray.length + "Elements, gpsarray: " + + gpsarray.length + " Elements"); + + } + + private GPScoordinate getBestCoord(GPScoordinate[] gpsarray, + SingleBTS singleBTS) { + int hit = Arrays.binarySearch(gpsarray, singleBTS.time); + // search for best fit! + if (hit < 0) { + hit++; + hit = Math.abs(hit); + } + // if hit is at start of the array, there's nothing more to do + if (hit == 0) { + return gpsarray[hit]; + } + // hit is the last element. Take it + else if (hit == gpsarray.length) { + return gpsarray[hit - 1]; + } + // hit is in between the array bounds. Check hit and hit-1 for best fit + else { + long left = gpsarray[hit - 1].time.getTime(); + long right = gpsarray[hit].time.getTime(); + long element = singleBTS.time.getTime(); + if (Math.abs(left - element) < Math.abs(right - element)) { + return gpsarray[hit - 1]; + } else + return gpsarray[hit]; + + } + + } + + private int getRowCount(ResultSet rs) throws SQLException { + rs.last(); + int i = rs.getRow(); + rs.beforeFirst(); + return i; + + } + + /** + * + * @return Names and Coordinates of BTS stored in the sql database + * @throws SQLException + */ + private SingleBTS[] getBTSnames() throws SQLException { + // System.out.println("getBTSNames called"); + ResultSet btsNames = st.executeQuery("Select * from arfcn"); + LinkedList btslist = new LinkedList(); + SingleBTS currentBTS = null; + while (btsNames.next()) { + int ARFCN = btsNames.getInt("arfcn"); + String name = btsNames.getString("location"); + currentBTS = new SingleBTS(ARFCN, 0, 0, false, null, name); + // btslist.add(new SingleBTS(ARFCN, 0, 0, false, null, name)); + double coord1 = btsNames.getDouble("CoordNS"); + double coord2 = btsNames.getDouble("CoordEW"); + currentBTS.coordinate = new GPScoordinate(null, coord1, 'N', + coord2, 'E', true); + btslist.add(currentBTS); + } + // random part, just to initiate a SingleBTS array + SingleBTS[] instancearray = new SingleBTS[1]; + instancearray[0] = new SingleBTS(123, 0, 0, false, null, "unknown"); + return btslist.toArray(instancearray); + + } + + /** + * Adds sql entries from another sqlreader to this one. BTS names stored in + * SQLreader must be the same! + * + * @param item + */ + public void merge(sqlreader item) { + // only merge arrays! + int totalsizeGPS = item.gpsarray.length + this.gpsarray.length + 10; + int totalsizeBTS = item.btsarray.length + this.btsarray.length + 10; + ArrayList tempGPS = new ArrayList( + totalsizeGPS); + for (int i = 0; i < gpsarray.length; i++) { + tempGPS.add(gpsarray[i]); + } + for (int i = 0; i < item.gpsarray.length; i++) { + tempGPS.add(item.gpsarray[i]); + } + + ArrayList tempBTS = new ArrayList(totalsizeBTS); + for (int i = 0; i < btsarray.length; i++) { + tempBTS.add(btsarray[i]); + } + for (int i = 0; i < item.btsarray.length; i++) { + tempBTS.add(item.btsarray[i]); + } + + // back to array again + gpsarray = tempGPS.toArray(gpsarray); + btsarray = tempBTS.toArray(btsarray); + IMSI = 0; + } +} diff --git a/Variance.java b/Variance.java new file mode 100644 index 0000000..5c916e6 --- /dev/null +++ b/Variance.java @@ -0,0 +1,45 @@ +import java.sql.SQLException; + +import DataStructure.GSMMap; +import DataStructure.GoogleOut; +import Parse.NMEAParse; +import Parse.sqlreader; + +public class Variance { + + /** + * @param args + * @throws SQLException + * @throws ClassNotFoundException + */ + public static void main(String[] args) throws ClassNotFoundException, + SQLException { + String file = "varianz3-4.log"; + // NMEAParse gpslog = new NMEAParse(file); + long[] IMSIs = { 262123456789177L, 262026550055616L, 262026003662195L, + 262012430041708L, 262073958646614L, 262230000000010L }; + int count = 0; + for (long l : IMSIs) { + sqlreader current = new sqlreader(new NMEAParse(file), l, 3000l); + try { + GSMMap map = new GSMMap(current, 0.00020); + System.out.println("Average"); + map.average(); + System.out.println("Outlier"); + map.removeOutlier(); + System.out.println("Gnuplot Signal"); + int[] arfcn = { 806, 815, 817, 823, 877, 880 }; + map.gnuPlotDLAll(arfcn, 877); + // System.out.println("Gnuplot Delta"); + // map.gnuPlotDeltaBTS(877, 880); + GoogleOut google = new GoogleOut(map, "varianz/GSM-" + l + + "-varianz.kml"); + google.write(); + count++; + } catch (Exception e) { + System.out.println("IMSI " + l + "not available"); + } + } + + } +} diff --git a/VoronoiInterpolate.java b/VoronoiInterpolate.java new file mode 100644 index 0000000..fbb8ab8 --- /dev/null +++ b/VoronoiInterpolate.java @@ -0,0 +1,50 @@ +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.sql.SQLException; + +import DataStructure.GoogleOut; +import DataStructure.Interpolator; +import Parse.NMEAParse; +import Parse.sqlreader; + +public class VoronoiInterpolate { + + /** + * @param args + */ + public static void main(String[] args) { + try { + sqlreader sql = new sqlreader(new NMEAParse("vorabbaubooster.log"), + 262026003662195l, 3000l); + Interpolator map = new Interpolator(sql, 0.00004); + map.average(); + map.removeOutlier(); + GoogleOut average = new GoogleOut(map, "average-all.kml"); + average.write(); + // int size = 3; + map.interpolateVR(); + // breakpoint bei arfcn 880, x=60, y=13!!!!! + GoogleOut google = new GoogleOut(map, "voronoi-interpolation.kml"); + google.write(); + + // gsmmap speichern + FileOutputStream fos = new FileOutputStream( + "interpolatedGSMMap.obj"); + ObjectOutputStream oos = new ObjectOutputStream(fos); + oos.writeObject(map); + + } catch (ClassNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + +} diff --git a/delaunay/ArraySet.java b/delaunay/ArraySet.java new file mode 100644 index 0000000..b3fe357 --- /dev/null +++ b/delaunay/ArraySet.java @@ -0,0 +1,104 @@ +package delaunay; + +/* + * Copyright (c) 2007 by L. Paul Chew. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; + +/** + * An ArrayList implementation of Set. An ArraySet is good for small sets; it + * has less overhead than a HashSet or a TreeSet. + * + * @author Paul Chew + * + * Created December 2007. For use with Voronoi/Delaunay applet. + * + */ +public class ArraySet extends AbstractSet { + + private ArrayList items; // Items of the set + + /** + * Create an empty set (default initial capacity is 3). + */ + public ArraySet () { + this(3); + } + + /** + * Create an empty set with the specified initial capacity. + * @param initialCapacity the initial capacity + */ + public ArraySet (int initialCapacity) { + items = new ArrayList(initialCapacity); + } + + /** + * Create a set containing the items of the collection. Any duplicate + * items are discarded. + * @param collection the source for the items of the small set + */ + public ArraySet (Collection collection) { + items = new ArrayList(collection.size()); + for (E item: collection) + if (!items.contains(item)) items.add(item); + } + + /** + * Get the item at the specified index. + * @param index where the item is located in the ListSet + * @return the item at the specified index + * @throws IndexOutOfBoundsException if the index is out of bounds + */ + public E get (int index) throws IndexOutOfBoundsException { + return items.get(index); + } + + /** + * True iff any member of the collection is also in the ArraySet. + * @param collection the Collection to check + * @return true iff any member of collection appears in this ArraySet + */ + public boolean containsAny (Collection collection) { + for (Object item: collection) + if (this.contains(item)) return true; + return false; + } + + @Override + public boolean add(E item) { + if (items.contains(item)) return false; + return items.add(item); + } + + @Override + public Iterator iterator() { + return items.iterator(); + } + + @Override + public int size() { + return items.size(); + } + +} diff --git a/delaunay/DelaunayAp.java b/delaunay/DelaunayAp.java new file mode 100644 index 0000000..43fbecc --- /dev/null +++ b/delaunay/DelaunayAp.java @@ -0,0 +1,429 @@ +package delaunay; + +/* + * Copyright (c) 2005, 2007 by L. Paul Chew. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Label; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import javax.swing.AbstractButton; +import javax.swing.ButtonGroup; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.SwingUtilities; + +/** + * The Delauany applet. + * + * Creates and displays a Delaunay Triangulation (DT) or a Voronoi Diagram + * (VoD). Has a main program so it is an application as well as an applet. + * + * @author Paul Chew + * + * Created July 2005. Derived from an earlier, messier version. + * + * Modified December 2007. Updated some of the Triangulation methods. Added the + * "Colorful" checkbox. Reorganized the interface between DelaunayAp and + * DelaunayPanel. Added code to find a Voronoi cell. + * + */ +@SuppressWarnings("serial") +public class DelaunayAp extends javax.swing.JApplet + implements Runnable, ActionListener, MouseListener { + + private boolean debug = false; // Used for debugging + private Component currentSwitch = null; // Entry-switch that mouse is in + + private static String windowTitle = "Voronoi/Delaunay Window"; + private JRadioButton voronoiButton = new JRadioButton("Voronoi Diagram"); + private JRadioButton delaunayButton = + new JRadioButton("Delaunay Triangulation"); + private JButton clearButton = new JButton("Clear"); + private JCheckBox colorfulBox = new JCheckBox("More Colorful"); + private DelaunayPanel delaunayPanel = new DelaunayPanel(this); + private JLabel circleSwitch = new JLabel("Show Empty Circles"); + private JLabel delaunaySwitch = new JLabel("Show Delaunay Edges"); + private JLabel voronoiSwitch = new JLabel("Show Voronoi Edges"); + + /** + * Main program (used when run as application instead of applet). + */ + public static void main (String[] args) { + DelaunayAp applet = new DelaunayAp(); // Create applet + applet.init(); // Applet initialization + JFrame dWindow = new JFrame(); // Create window + dWindow.setSize(700, 500); // Set window size + dWindow.setTitle(windowTitle); // Set window title + dWindow.setLayout(new BorderLayout()); // Specify layout manager + dWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + // Specify closing behavior + dWindow.add(applet, "Center"); // Place applet into window + dWindow.setVisible(true); // Show the window + } + + /** + * Initialize the applet. + * As recommended, the actual use of Swing components takes place in the + * event-dispatching thread. + */ + public void init () { + try {SwingUtilities.invokeAndWait(this);} + catch (Exception e) {System.err.println("Initialization failure");} + } + + /** + * Set up the applet's GUI. + * As recommended, the init method executes this in the event-dispatching + * thread. + */ + public void run () { + setLayout(new BorderLayout()); + + // Add the button controls + ButtonGroup group = new ButtonGroup(); + group.add(voronoiButton); + group.add(delaunayButton); + JPanel buttonPanel = new JPanel(); + buttonPanel.add(voronoiButton); + buttonPanel.add(delaunayButton); + buttonPanel.add(clearButton); + buttonPanel.add(new JLabel(" ")); // Spacing + buttonPanel.add(colorfulBox); + this.add(buttonPanel, "North"); + + // Add the mouse-entry switches + JPanel switchPanel = new JPanel(); + switchPanel.add(circleSwitch); + switchPanel.add(new Label(" ")); // Spacing + switchPanel.add(delaunaySwitch); + switchPanel.add(new Label(" ")); // Spacing + switchPanel.add(voronoiSwitch); + this.add(switchPanel, "South"); + + // Build the delaunay panel + delaunayPanel.setBackground(Color.gray); + this.add(delaunayPanel, "Center"); + + // Register the listeners + voronoiButton.addActionListener(this); + delaunayButton.addActionListener(this); + clearButton.addActionListener(this); + colorfulBox.addActionListener(this); + delaunayPanel.addMouseListener(this); + circleSwitch.addMouseListener(this); + delaunaySwitch.addMouseListener(this); + voronoiSwitch.addMouseListener(this); + + // Initialize the radio buttons + voronoiButton.doClick(); + } + + /** + * A button has been pressed; redraw the picture. + */ + public void actionPerformed(ActionEvent e) { + if (debug) + System.out.println(((AbstractButton)e.getSource()).getText()); + if (e.getSource() == clearButton) delaunayPanel.clear(); + delaunayPanel.repaint(); + } + + /** + * If entering a mouse-entry switch then redraw the picture. + */ + public void mouseEntered(MouseEvent e) { + currentSwitch = e.getComponent(); + if (currentSwitch instanceof JLabel) delaunayPanel.repaint(); + else currentSwitch = null; + } + + /** + * If exiting a mouse-entry switch then redraw the picture. + */ + public void mouseExited(MouseEvent e) { + currentSwitch = null; + if (e.getComponent() instanceof JLabel) delaunayPanel.repaint(); + } + + /** + * If mouse has been pressed inside the delaunayPanel then add a new site. + */ + public void mousePressed(MouseEvent e) { + if (e.getSource() != delaunayPanel) return; + Pnt point = new Pnt(e.getX(), e.getY()); + if (debug ) System.out.println("Click " + point); + delaunayPanel.addSite(point); + delaunayPanel.repaint(); + } + + /** + * Not used, but needed for MouseListener. + */ + public void mouseReleased(MouseEvent e) {} + public void mouseClicked(MouseEvent e) {} + + /** + * @return true iff the "colorful" box is selected + */ + public boolean isColorful() { + return colorfulBox.isSelected(); + } + + /** + * @return true iff doing Voronoi diagram. + */ + public boolean isVoronoi() { + return voronoiButton.isSelected(); + } + + /** + * @return true iff within circle switch + */ + public boolean showingCircles() { + return currentSwitch == circleSwitch; + } + + /** + * @return true iff within delaunay switch + */ + public boolean showingDelaunay() { + return currentSwitch == delaunaySwitch; + } + + /** + * @return true iff within voronoi switch + */ + public boolean showingVoronoi() { + return currentSwitch == voronoiSwitch; + } + +} + +/** + * Graphics Panel for DelaunayAp. + */ +@SuppressWarnings("serial") +class DelaunayPanel extends JPanel { + + public static Color voronoiColor = Color.magenta; + public static Color delaunayColor = Color.green; + public static int pointRadius = 3; + + private DelaunayAp controller; // Controller for DT + private Triangulation dt; // Delaunay triangulation + private Map colorTable; // Remembers colors for display + private Triangle initialTriangle; // Initial triangle + private static int initialSize = 10000; // Size of initial triangle + private Graphics g; // Stored graphics context + private Random random = new Random(); // Source of random numbers + + /** + * Create and initialize the DT. + */ + public DelaunayPanel (DelaunayAp controller) { + this.controller = controller; + initialTriangle = new Triangle( + new Pnt(-initialSize, -initialSize), + new Pnt( initialSize, -initialSize), + new Pnt( 0, initialSize)); + dt = new Triangulation(initialTriangle); + colorTable = new HashMap(); + } + + /** + * Add a new site to the DT. + * @param point the site to add + */ + public void addSite(Pnt point) { + dt.delaunayPlace(point); + } + + /** + * Re-initialize the DT. + */ + public void clear() { + dt = new Triangulation(initialTriangle); + } + + /** + * Get the color for the spcified item; generate a new color if necessary. + * @param item we want the color for this item + * @return item's color + */ + private Color getColor (Object item) { + if (colorTable.containsKey(item)) return colorTable.get(item); + Color color = new Color(Color.HSBtoRGB(random.nextFloat(), 1.0f, 1.0f)); + colorTable.put(item, color); + return color; + } + + /* Basic Drawing Methods */ + + /** + * Draw a point. + * @param point the Pnt to draw + */ + public void draw (Pnt point) { + int r = pointRadius; + int x = (int) point.coord(0); + int y = (int) point.coord(1); + g.fillOval(x-r, y-r, r+r, r+r); + } + + /** + * Draw a circle. + * @param center the center of the circle + * @param radius the circle's radius + * @param fillColor null implies no fill + */ + public void draw (Pnt center, double radius, Color fillColor) { + int x = (int) center.coord(0); + int y = (int) center.coord(1); + int r = (int) radius; + if (fillColor != null) { + Color temp = g.getColor(); + g.setColor(fillColor); + g.fillOval(x-r, y-r, r+r, r+r); + g.setColor(temp); + } + g.drawOval(x-r, y-r, r+r, r+r); + } + + /** + * Draw a polygon. + * @param polygon an array of polygon vertices + * @param fillColor null implies no fill + */ + public void draw (Pnt[] polygon, Color fillColor) { + int[] x = new int[polygon.length]; + int[] y = new int[polygon.length]; + for (int i = 0; i < polygon.length; i++) { + x[i] = (int) polygon[i].coord(0); + y[i] = (int) polygon[i].coord(1); + } + if (fillColor != null) { + Color temp = g.getColor(); + g.setColor(fillColor); + g.fillPolygon(x, y, polygon.length); + g.setColor(temp); + } + g.drawPolygon(x, y, polygon.length); + } + + /* Higher Level Drawing Methods */ + + /** + * Handles painting entire contents of DelaunayPanel. + * Called automatically; requested via call to repaint(). + * @param g the Graphics context + */ + public void paintComponent (Graphics g) { + super.paintComponent(g); + this.g = g; + + // Flood the drawing area with a "background" color + Color temp = g.getColor(); + if (!controller.isVoronoi()) g.setColor(delaunayColor); + else if (dt.contains(initialTriangle)) g.setColor(this.getBackground()); + else g.setColor(voronoiColor); + g.fillRect(0, 0, this.getWidth(), this.getHeight()); + g.setColor(temp); + + // If no colors then we can clear the color table + if (!controller.isColorful()) colorTable.clear(); + + // Draw the appropriate picture + if (controller.isVoronoi()) + drawAllVoronoi(controller.isColorful(), true); + else drawAllDelaunay(controller.isColorful()); + + // Draw any extra info due to the mouse-entry switches + temp = g.getColor(); + g.setColor(Color.white); + if (controller.showingCircles()) drawAllCircles(); + if (controller.showingDelaunay()) drawAllDelaunay(false); + if (controller.showingVoronoi()) drawAllVoronoi(false, false); + g.setColor(temp); + } + + /** + * Draw all the Delaunay triangles. + * @param withFill true iff drawing Delaunay triangles with fill colors + */ + public void drawAllDelaunay (boolean withFill) { + for (Triangle triangle : dt) { + Pnt[] vertices = triangle.toArray(new Pnt[0]); + draw(vertices, withFill? getColor(triangle) : null); + } + } + + /** + * Draw all the Voronoi cells. + * @param withFill true iff drawing Voronoi cells with fill colors + * @param withSites true iff drawing the site for each Voronoi cell + */ + public void drawAllVoronoi (boolean withFill, boolean withSites) { + // Keep track of sites done; no drawing for initial triangles sites + HashSet done = new HashSet(initialTriangle); + for (Triangle triangle : dt) + for (Pnt site: triangle) { + if (done.contains(site)) continue; + done.add(site); + List list = dt.surroundingTriangles(site, triangle); + Pnt[] vertices = new Pnt[list.size()]; + int i = 0; + for (Triangle tri: list) + vertices[i++] = tri.getCircumcenter(); + draw(vertices, withFill? getColor(site) : null); + if (withSites) draw(site); + } + } + + /** + * Draw all the empty circles (one for each triangle) of the DT. + */ + public void drawAllCircles () { + // Loop through all triangles of the DT + for (Triangle triangle: dt) { + // Skip circles involving the initial-triangle vertices + if (triangle.containsAny(initialTriangle)) continue; + Pnt c = triangle.getCircumcenter(); + double radius = c.subtract(triangle.get(0)).magnitude(); + draw(c, radius, null); + } + } + +} diff --git a/delaunay/Graph.java b/delaunay/Graph.java new file mode 100644 index 0000000..c56df74 --- /dev/null +++ b/delaunay/Graph.java @@ -0,0 +1,108 @@ +package delaunay; + +/* + * Copyright (c) 2007 by L. Paul Chew. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * Straightforward undirected graph implementation. + * Nodes are generic type N. + * + * @author Paul Chew + * + * Created November, December 2007. For use in Delaunay/Voronoi code. + * + */ +public class Graph { + + private Map> theNeighbors = // Node -> adjacent nodes + new HashMap>(); + private Set theNodeSet = // Set view of all nodes + Collections.unmodifiableSet(theNeighbors.keySet()); + + /** + * Add a node. If node is already in graph then no change. + * @param node the node to add + */ + public void add (N node) { + if (theNeighbors.containsKey(node)) return; + theNeighbors.put(node, new ArraySet()); + } + + /** + * Add a link. If the link is already in graph then no change. + * @param nodeA one end of the link + * @param nodeB the other end of the link + * @throws NullPointerException if either endpoint is not in graph + */ + public void add (N nodeA, N nodeB) throws NullPointerException { + theNeighbors.get(nodeA).add(nodeB); + theNeighbors.get(nodeB).add(nodeA); + } + + /** + * Remove node and any links that use node. If node not in graph, nothing + * happens. + * @param node the node to remove. + */ + public void remove (N node) { + if (!theNeighbors.containsKey(node)) return; + for (N neighbor: theNeighbors.get(node)) + theNeighbors.get(neighbor).remove(node); // Remove "to" links + theNeighbors.get(node).clear(); // Remove "from" links + theNeighbors.remove(node); // Remove the node + } + + /** + * Remove the specified link. If link not in graph, nothing happens. + * @param nodeA one end of the link + * @param nodeB the other end of the link + * @throws NullPointerException if either endpoint is not in graph + */ + public void remove (N nodeA, N nodeB) throws NullPointerException { + theNeighbors.get(nodeA).remove(nodeB); + theNeighbors.get(nodeB).remove(nodeA); + } + + /** + * Report all the neighbors of node. + * @param node the node + * @return the neighbors of node + * @throws NullPointerException if node does not appear in graph + */ + public Set neighbors (N node) throws NullPointerException { + return Collections.unmodifiableSet(theNeighbors.get(node)); + } + + /** + * Returns an unmodifiable Set view of the nodes contained in this graph. + * The set is backed by the graph, so changes to the graph are reflected in + * the set. + * @return a Set view of the graph's node set + */ + public Set nodeSet () { + return theNodeSet; + } + +} diff --git a/delaunay/Pnt.java b/delaunay/Pnt.java new file mode 100644 index 0000000..d9db79f --- /dev/null +++ b/delaunay/Pnt.java @@ -0,0 +1,470 @@ +package delaunay; + +/* + * Copyright (c) 2005, 2007 by L. Paul Chew. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * Points in Euclidean space, implemented as double[]. + * + * Includes simple geometric operations. + * Uses matrices; a matrix is represented as an array of Pnts. + * Uses simplices; a simplex is represented as an array of Pnts. + * + * @author Paul Chew + * + * Created July 2005. Derived from an earlier, messier version. + * + * Modified Novemeber 2007. Minor clean up. + */ +public class Pnt { + + private double[] coordinates; // The point's coordinates + + /** + * Constructor. + * @param coords the coordinates + */ + public Pnt (double... coords) { + // Copying is done here to ensure that Pnt's coords cannot be altered. + // This is necessary because the double... notation actually creates a + // constructor with double[] as its argument. + coordinates = new double[coords.length]; + System.arraycopy(coords, 0, coordinates, 0, coords.length); + } + + @Override + public String toString () { + if (coordinates.length == 0) return "Pnt()"; + String result = "Pnt(" + coordinates[0]; + for (int i = 1; i < coordinates.length; i++) + result = result + "," + coordinates[i]; + result = result + ")"; + return result; + } + + @Override + public boolean equals (Object other) { + if (!(other instanceof Pnt)) return false; + Pnt p = (Pnt) other; + if (this.coordinates.length != p.coordinates.length) return false; + for (int i = 0; i < this.coordinates.length; i++) + if (this.coordinates[i] != p.coordinates[i]) return false; + return true; + } + + @Override + public int hashCode () { + int hash = 0; + for (double c: this.coordinates) { + long bits = Double.doubleToLongBits(c); + hash = (31*hash) ^ (int)(bits ^ (bits >> 32)); + } + return hash; + } + + /* Pnts as vectors */ + + /** + * @return the specified coordinate of this Pnt + * @throws ArrayIndexOutOfBoundsException for bad coordinate + */ + public double coord (int i) { + return this.coordinates[i]; + } + + /** + * @return this Pnt's dimension. + */ + public int dimension () { + return coordinates.length; + } + + /** + * Check that dimensions match. + * @param p the Pnt to check (against this Pnt) + * @return the dimension of the Pnts + * @throws IllegalArgumentException if dimension fail to match + */ + public int dimCheck (Pnt p) { + int len = this.coordinates.length; + if (len != p.coordinates.length) + throw new IllegalArgumentException("Dimension mismatch"); + return len; + } + + /** + * Create a new Pnt by adding additional coordinates to this Pnt. + * @param coords the new coordinates (added on the right end) + * @return a new Pnt with the additional coordinates + */ + public Pnt extend (double... coords) { + double[] result = new double[coordinates.length + coords.length]; + System.arraycopy(coordinates, 0, result, 0, coordinates.length); + System.arraycopy(coords, 0, result, coordinates.length, coords.length); + return new Pnt(result); + } + + /** + * Dot product. + * @param p the other Pnt + * @return dot product of this Pnt and p + */ + public double dot (Pnt p) { + int len = dimCheck(p); + double sum = 0; + for (int i = 0; i < len; i++) + sum += this.coordinates[i] * p.coordinates[i]; + return sum; + } + + /** + * Magnitude (as a vector). + * @return the Euclidean length of this vector + */ + public double magnitude () { + return Math.sqrt(this.dot(this)); + } + + /** + * Subtract. + * @param p the other Pnt + * @return a new Pnt = this - p + */ + public Pnt subtract (Pnt p) { + int len = dimCheck(p); + double[] coords = new double[len]; + for (int i = 0; i < len; i++) + coords[i] = this.coordinates[i] - p.coordinates[i]; + return new Pnt(coords); + } + + /** + * Add. + * @param p the other Pnt + * @return a new Pnt = this + p + */ + public Pnt add (Pnt p) { + int len = dimCheck(p); + double[] coords = new double[len]; + for (int i = 0; i < len; i++) + coords[i] = this.coordinates[i] + p.coordinates[i]; + return new Pnt(coords); + } + + /** + * Angle (in radians) between two Pnts (treated as vectors). + * @param p the other Pnt + * @return the angle (in radians) between the two Pnts + */ + public double angle (Pnt p) { + return Math.acos(this.dot(p) / (this.magnitude() * p.magnitude())); + } + + /** + * Perpendicular bisector of two Pnts. + * Works in any dimension. The coefficients are returned as a Pnt of one + * higher dimension (e.g., (A,B,C,D) for an equation of the form + * Ax + By + Cz + D = 0). + * @param point the other point + * @return the coefficients of the perpendicular bisector + */ + public Pnt bisector (Pnt point) { + dimCheck(point); + Pnt diff = this.subtract(point); + Pnt sum = this.add(point); + double dot = diff.dot(sum); + return diff.extend(-dot / 2); + } + + /* Pnts as matrices */ + + /** + * Create a String for a matrix. + * @param matrix the matrix (an array of Pnts) + * @return a String represenation of the matrix + */ + public static String toString (Pnt[] matrix) { + StringBuilder buf = new StringBuilder("{"); + for (Pnt row: matrix) buf.append(" " + row); + buf.append(" }"); + return buf.toString(); + } + + /** + * Compute the determinant of a matrix (array of Pnts). + * This is not an efficient implementation, but should be adequate + * for low dimension. + * @param matrix the matrix as an array of Pnts + * @return the determinnant of the input matrix + * @throws IllegalArgumentException if dimensions are wrong + */ + public static double determinant (Pnt[] matrix) { + if (matrix.length != matrix[0].dimension()) + throw new IllegalArgumentException("Matrix is not square"); + boolean[] columns = new boolean[matrix.length]; + for (int i = 0; i < matrix.length; i++) columns[i] = true; + try {return determinant(matrix, 0, columns);} + catch (ArrayIndexOutOfBoundsException e) { + throw new IllegalArgumentException("Matrix is wrong shape"); + } + } + + /** + * Compute the determinant of a submatrix specified by starting row + * and by "active" columns. + * @param matrix the matrix as an array of Pnts + * @param row the starting row + * @param columns a boolean array indicating the "active" columns + * @return the determinant of the specified submatrix + * @throws ArrayIndexOutOfBoundsException if dimensions are wrong + */ + private static double determinant(Pnt[] matrix, int row, boolean[] columns){ + if (row == matrix.length) return 1; + double sum = 0; + int sign = 1; + for (int col = 0; col < columns.length; col++) { + if (!columns[col]) continue; + columns[col] = false; + sum += sign * matrix[row].coordinates[col] * + determinant(matrix, row+1, columns); + columns[col] = true; + sign = -sign; + } + return sum; + } + + /** + * Compute generalized cross-product of the rows of a matrix. + * The result is a Pnt perpendicular (as a vector) to each row of + * the matrix. This is not an efficient implementation, but should + * be adequate for low dimension. + * @param matrix the matrix of Pnts (one less row than the Pnt dimension) + * @return a Pnt perpendicular to each row Pnt + * @throws IllegalArgumentException if matrix is wrong shape + */ + public static Pnt cross (Pnt[] matrix) { + int len = matrix.length + 1; + if (len != matrix[0].dimension()) + throw new IllegalArgumentException("Dimension mismatch"); + boolean[] columns = new boolean[len]; + for (int i = 0; i < len; i++) columns[i] = true; + double[] result = new double[len]; + int sign = 1; + try { + for (int i = 0; i < len; i++) { + columns[i] = false; + result[i] = sign * determinant(matrix, 0, columns); + columns[i] = true; + sign = -sign; + } + } catch (ArrayIndexOutOfBoundsException e) { + throw new IllegalArgumentException("Matrix is wrong shape"); + } + return new Pnt(result); + } + + /* Pnts as simplices */ + + /** + * Determine the signed content (i.e., area or volume, etc.) of a simplex. + * @param simplex the simplex (as an array of Pnts) + * @return the signed content of the simplex + */ + public static double content (Pnt[] simplex) { + Pnt[] matrix = new Pnt[simplex.length]; + for (int i = 0; i < matrix.length; i++) + matrix[i] = simplex[i].extend(1); + int fact = 1; + for (int i = 1; i < matrix.length; i++) fact = fact*i; + return determinant(matrix) / fact; + } + + /** + * Relation between this Pnt and a simplex (represented as an array of + * Pnts). Result is an array of signs, one for each vertex of the simplex, + * indicating the relation between the vertex, the vertex's opposite facet, + * and this Pnt. + * + *
+     *   -1 means Pnt is on same side of facet
+     *    0 means Pnt is on the facet
+     *   +1 means Pnt is on opposite side of facet
+     * 
+ * + * @param simplex an array of Pnts representing a simplex + * @return an array of signs showing relation between this Pnt and simplex + * @throws IllegalArgumentExcpetion if the simplex is degenerate + */ + public int[] relation (Pnt[] simplex) { + /* In 2D, we compute the cross of this matrix: + * 1 1 1 1 + * p0 a0 b0 c0 + * p1 a1 b1 c1 + * where (a, b, c) is the simplex and p is this Pnt. The result is a + * vector in which the first coordinate is the signed area (all signed + * areas are off by the same constant factor) of the simplex and the + * remaining coordinates are the *negated* signed areas for the + * simplices in which p is substituted for each of the vertices. + * Analogous results occur in higher dimensions. + */ + int dim = simplex.length - 1; + if (this.dimension() != dim) + throw new IllegalArgumentException("Dimension mismatch"); + + /* Create and load the matrix */ + Pnt[] matrix = new Pnt[dim+1]; + /* First row */ + double[] coords = new double[dim+2]; + for (int j = 0; j < coords.length; j++) coords[j] = 1; + matrix[0] = new Pnt(coords); + /* Other rows */ + for (int i = 0; i < dim; i++) { + coords[0] = this.coordinates[i]; + for (int j = 0; j < simplex.length; j++) + coords[j+1] = simplex[j].coordinates[i]; + matrix[i+1] = new Pnt(coords); + } + + /* Compute and analyze the vector of areas/volumes/contents */ + Pnt vector = cross(matrix); + double content = vector.coordinates[0]; + int[] result = new int[dim+1]; + for (int i = 0; i < result.length; i++) { + double value = vector.coordinates[i+1]; + if (Math.abs(value) <= 1.0e-6 * Math.abs(content)) result[i] = 0; + else if (value < 0) result[i] = -1; + else result[i] = 1; + } + if (content < 0) { + for (int i = 0; i < result.length; i++) + result[i] = -result[i]; + } + if (content == 0) { + for (int i = 0; i < result.length; i++) + result[i] = Math.abs(result[i]); + } + return result; + } + + /** + * Test if this Pnt is outside of simplex. + * @param simplex the simplex (an array of Pnts) + * @return simplex Pnt that "witnesses" outsideness (or null if not outside) + */ + public Pnt isOutside (Pnt[] simplex) { + int[] result = this.relation(simplex); + for (int i = 0; i < result.length; i++) { + if (result[i] > 0) return simplex[i]; + } + return null; + } + + /** + * Test if this Pnt is on a simplex. + * @param simplex the simplex (an array of Pnts) + * @return the simplex Pnt that "witnesses" on-ness (or null if not on) + */ + public Pnt isOn (Pnt[] simplex) { + int[] result = this.relation(simplex); + Pnt witness = null; + for (int i = 0; i < result.length; i++) { + if (result[i] == 0) witness = simplex[i]; + else if (result[i] > 0) return null; + } + return witness; + } + + /** + * Test if this Pnt is inside a simplex. + * @param simplex the simplex (an arary of Pnts) + * @return true iff this Pnt is inside simplex. + */ + public boolean isInside (Pnt[] simplex) { + int[] result = this.relation(simplex); + for (int r: result) if (r >= 0) return false; + return true; + } + + /** + * Test relation between this Pnt and circumcircle of a simplex. + * @param simplex the simplex (as an array of Pnts) + * @return -1, 0, or +1 for inside, on, or outside of circumcircle + */ + public int vsCircumcircle (Pnt[] simplex) { + Pnt[] matrix = new Pnt[simplex.length + 1]; + for (int i = 0; i < simplex.length; i++) + matrix[i] = simplex[i].extend(1, simplex[i].dot(simplex[i])); + matrix[simplex.length] = this.extend(1, this.dot(this)); + double d = determinant(matrix); + int result = (d < 0)? -1 : ((d > 0)? +1 : 0); + if (content(simplex) < 0) result = - result; + return result; + } + + /** + * Circumcenter of a simplex. + * @param simplex the simplex (as an array of Pnts) + * @return the circumcenter (a Pnt) of simplex + */ + public static Pnt circumcenter (Pnt[] simplex) { + int dim = simplex[0].dimension(); + if (simplex.length - 1 != dim) + throw new IllegalArgumentException("Dimension mismatch"); + Pnt[] matrix = new Pnt[dim]; + for (int i = 0; i < dim; i++) + matrix[i] = simplex[i].bisector(simplex[i+1]); + Pnt hCenter = cross(matrix); // Center in homogeneous coordinates + double last = hCenter.coordinates[dim]; + double[] result = new double[dim]; + for (int i = 0; i < dim; i++) result[i] = hCenter.coordinates[i] / last; + return new Pnt(result); + } + + /** + * Main program (used for testing). + */ + public static void main (String[] args) { + Pnt p = new Pnt(1, 2, 3); + System.out.println("Pnt created: " + p); + Pnt[] matrix1 = {new Pnt(1,2), new Pnt(3,4)}; + Pnt[] matrix2 = {new Pnt(7,0,5), new Pnt(2,4,6), new Pnt(3,8,1)}; + System.out.print("Results should be -2 and -288: "); + System.out.println(determinant(matrix1) + " " + determinant(matrix2)); + Pnt p1 = new Pnt(1,1); Pnt p2 = new Pnt(-1,1); + System.out.println("Angle between " + p1 + " and " + + p2 + ": " + p1.angle(p2)); + System.out.println(p1 + " subtract " + p2 + ": " + p1.subtract(p2)); + Pnt v0 = new Pnt(0,0), v1 = new Pnt(1,1), v2 = new Pnt(2,2); + Pnt[] vs = {v0, new Pnt(0,1), new Pnt(1,0)}; + Pnt vp = new Pnt(.1, .1); + System.out.println(vp + " isInside " + toString(vs) + + ": " + vp.isInside(vs)); + System.out.println(v1 + " isInside " + toString(vs) + + ": " + v1.isInside(vs)); + System.out.println(vp + " vsCircumcircle " + toString(vs) + ": " + + vp.vsCircumcircle(vs)); + System.out.println(v1 + " vsCircumcircle " + toString(vs) + ": " + + v1.vsCircumcircle(vs)); + System.out.println(v2 + " vsCircumcircle " + toString(vs) + ": " + + v2.vsCircumcircle(vs)); + System.out.println("Circumcenter of " + toString(vs) + " is " + + circumcenter(vs)); + } +} \ No newline at end of file diff --git a/delaunay/Triangle.java b/delaunay/Triangle.java new file mode 100644 index 0000000..8b88a50 --- /dev/null +++ b/delaunay/Triangle.java @@ -0,0 +1,152 @@ +package delaunay; + +/* + * Copyright (c) 2007 by L. Paul Chew. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * A Triangle is an immutable Set of exactly three Pnts. + * + * All Set operations are available. Individual vertices can be accessed via + * iterator() and also via triangle.get(index). + * + * Note that, even if two triangles have the same vertex set, they are + * *different* triangles. Methods equals() and hashCode() are consistent with + * this rule. + * + * @author Paul Chew + * + * Created December 2007. Replaced general simplices with geometric triangle. + * + */ +class Triangle extends ArraySet { + + private int idNumber; // The id number + private Pnt circumcenter = null; // The triangle's circumcenter + + private static int idGenerator = 0; // Used to create id numbers + public static boolean moreInfo = false; // True iff more info in toString + + /** + * @param vertices the vertices of the Triangle. + * @throws IllegalArgumentException if there are not three distinct vertices + */ + public Triangle (Pnt... vertices) { + this(Arrays.asList(vertices)); + } + + /** + * @param collection a Collection holding the Simplex vertices + * @throws IllegalArgumentException if there are not three distinct vertices + */ + public Triangle (Collection collection) { + super(collection); + idNumber = idGenerator++; + if (this.size() != 3) + throw new IllegalArgumentException("Triangle must have 3 vertices"); + } + + @Override + public String toString () { + if (!moreInfo) return "Triangle" + idNumber; + return "Triangle" + idNumber + super.toString(); + } + + /** + * Get arbitrary vertex of this triangle, but not any of the bad vertices. + * @param badVertices one or more bad vertices + * @return a vertex of this triangle, but not one of the bad vertices + * @throws NoSuchElementException if no vertex found + */ + public Pnt getVertexButNot (Pnt... badVertices) { + Collection bad = Arrays.asList(badVertices); + for (Pnt v: this) if (!bad.contains(v)) return v; + throw new NoSuchElementException("No vertex found"); + } + + /** + * True iff triangles are neighbors. Two triangles are neighbors if they + * share a facet. + * @param triangle the other Triangle + * @return true iff this Triangle is a neighbor of triangle + */ + public boolean isNeighbor (Triangle triangle) { + int count = 0; + for (Pnt vertex: this) + if (!triangle.contains(vertex)) count++; + return count == 1; + } + + /** + * Report the facet opposite vertex. + * @param vertex a vertex of this Triangle + * @return the facet opposite vertex + * @throws IllegalArgumentException if the vertex is not in triangle + */ + public ArraySet facetOpposite (Pnt vertex) { + ArraySet facet = new ArraySet(this); + if (!facet.remove(vertex)) + throw new IllegalArgumentException("Vertex not in triangle"); + return facet; + } + + /** + * @return the triangle's circumcenter + */ + public Pnt getCircumcenter () { + if (circumcenter == null) + circumcenter = Pnt.circumcenter(this.toArray(new Pnt[0])); + return circumcenter; + } + + /* The following two methods ensure that a Triangle is immutable */ + + @Override + public boolean add (Pnt vertex) { + throw new UnsupportedOperationException(); + } + + @Override + public Iterator iterator () { + return new Iterator() { + private Iterator it = Triangle.super.iterator(); + public boolean hasNext() {return it.hasNext();} + public Pnt next() {return it.next();} + public void remove() {throw new UnsupportedOperationException();} + }; + } + + /* The following two methods ensure that all triangles are different. */ + + @Override + public int hashCode () { + return (int)(idNumber^(idNumber>>>32)); + } + + @Override + public boolean equals (Object o) { + return (this == o); + } + +} \ No newline at end of file diff --git a/delaunay/Triangulation.java b/delaunay/Triangulation.java new file mode 100644 index 0000000..209e9e7 --- /dev/null +++ b/delaunay/Triangulation.java @@ -0,0 +1,281 @@ +package delaunay; + +/* + * Copyright (c) 2005, 2007 by L. Paul Chew. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.Set; + +/** + * A 2D Delaunay Triangulation (DT) with incremental site insertion. + * + * This is not the fastest way to build a DT, but it's a reasonable way to build + * a DT incrementally and it makes a nice interactive display. There are several + * O(n log n) methods, but they require that the sites are all known initially. + * + * A Triangulation is a Set of Triangles. A Triangulation is unmodifiable as a + * Set; the only way to change it is to add sites (via delaunayPlace). + * + * @author Paul Chew + * + * Created July 2005. Derived from an earlier, messier version. + * + * Modified November 2007. Rewrote to use AbstractSet as parent class and to use + * the Graph class internally. Tried to make the DT algorithm clearer by + * explicitly creating a cavity. Added code needed to find a Voronoi cell. + * + */ +public class Triangulation extends AbstractSet { + + private Triangle mostRecent = null; // Most recently "active" triangle + private Graph triGraph; // Holds triangles for navigation + + /** + * All sites must fall within the initial triangle. + * @param triangle the initial triangle + */ + public Triangulation (Triangle triangle) { + triGraph = new Graph(); + triGraph.add(triangle); + mostRecent = triangle; + } + + /* The following two methods are required by AbstractSet */ + + @Override + public Iterator iterator () { + return triGraph.nodeSet().iterator(); + } + + @Override + public int size () { + return triGraph.nodeSet().size(); + } + + @Override + public String toString () { + return "Triangulation with " + size() + " triangles"; + } + + /** + * True iff triangle is a member of this triangulation. + * This method isn't required by AbstractSet, but it improves efficiency. + * @param triangle the object to check for membership + */ + public boolean contains (Object triangle) { + return triGraph.nodeSet().contains(triangle); + } + + /** + * Report neighbor opposite the given vertex of triangle. + * @param site a vertex of triangle + * @param triangle we want the neighbor of this triangle + * @return the neighbor opposite site in triangle; null if none + * @throws IllegalArgumentException if site is not in this triangle + */ + public Triangle neighborOpposite (Pnt site, Triangle triangle) { + if (!triangle.contains(site)) + throw new IllegalArgumentException("Bad vertex; not in triangle"); + for (Triangle neighbor: triGraph.neighbors(triangle)) { + if (!neighbor.contains(site)) return neighbor; + } + return null; + } + + /** + * Return the set of triangles adjacent to triangle. + * @param triangle the triangle to check + * @return the neighbors of triangle + */ + public Set neighbors(Triangle triangle) { + return triGraph.neighbors(triangle); + } + + /** + * Report triangles surrounding site in order (cw or ccw). + * @param site we want the surrounding triangles for this site + * @param triangle a "starting" triangle that has site as a vertex + * @return all triangles surrounding site in order (cw or ccw) + * @throws IllegalArgumentException if site is not in triangle + */ + public List surroundingTriangles (Pnt site, Triangle triangle) { + if (!triangle.contains(site)) + throw new IllegalArgumentException("Site not in triangle"); + List list = new ArrayList(); + Triangle start = triangle; + Pnt guide = triangle.getVertexButNot(site); // Affects cw or ccw + while (true) { + list.add(triangle); + Triangle previous = triangle; + triangle = this.neighborOpposite(guide, triangle); // Next triangle + guide = previous.getVertexButNot(site, guide); // Update guide + if (triangle == start) break; + } + return list; + } + + /** + * Locate the triangle with point inside it or on its boundary. + * @param point the point to locate + * @return the triangle that holds point; null if no such triangle + */ + public Triangle locate (Pnt point) { + Triangle triangle = mostRecent; + if (!this.contains(triangle)) triangle = null; + + // Try a directed walk (this works fine in 2D, but can fail in 3D) + Set visited = new HashSet(); + while (triangle != null) { + if (visited.contains(triangle)) { // This should never happen + System.out.println("Warning: Caught in a locate loop"); + break; + } + visited.add(triangle); + // Corner opposite point + Pnt corner = point.isOutside(triangle.toArray(new Pnt[0])); + if (corner == null) return triangle; + triangle = this.neighborOpposite(corner, triangle); + } + // No luck; try brute force + System.out.println("Warning: Checking all triangles for " + point); + for (Triangle tri: this) { + if (point.isOutside(tri.toArray(new Pnt[0])) == null) return tri; + } + // No such triangle + System.out.println("Warning: No triangle holds " + point); + return null; + } + + /** + * Place a new site into the DT. + * Nothing happens if the site matches an existing DT vertex. + * @param site the new Pnt + * @throws IllegalArgumentException if site does not lie in any triangle + */ + public void delaunayPlace (Pnt site) { + // Uses straightforward scheme rather than best asymptotic time + + // Locate containing triangle + Triangle triangle = locate(site); + // Give up if no containing triangle or if site is already in DT + if (triangle == null) + throw new IllegalArgumentException("No containing triangle"); + if (triangle.contains(site)) return; + + // Determine the cavity and update the triangulation + Set cavity = getCavity(site, triangle); + mostRecent = update(site, cavity); + } + + /** + * Determine the cavity caused by site. + * @param site the site causing the cavity + * @param triangle the triangle containing site + * @return set of all triangles that have site in their circumcircle + */ + private Set getCavity (Pnt site, Triangle triangle) { + Set encroached = new HashSet(); + Queue toBeChecked = new LinkedList(); + Set marked = new HashSet(); + toBeChecked.add(triangle); + marked.add(triangle); + while (!toBeChecked.isEmpty()) { + triangle = toBeChecked.remove(); + if (site.vsCircumcircle(triangle.toArray(new Pnt[0])) == 1) + continue; // Site outside triangle => triangle not in cavity + encroached.add(triangle); + // Check the neighbors + for (Triangle neighbor: triGraph.neighbors(triangle)){ + if (marked.contains(neighbor)) continue; + marked.add(neighbor); + toBeChecked.add(neighbor); + } + } + return encroached; + } + + /** + * Update the triangulation by removing the cavity triangles and then + * filling the cavity with new triangles. + * @param site the site that created the cavity + * @param cavity the triangles with site in their circumcircle + * @return one of the new triangles + */ + private Triangle update (Pnt site, Set cavity) { + Set> boundary = new HashSet>(); + Set theTriangles = new HashSet(); + + // Find boundary facets and adjacent triangles + for (Triangle triangle: cavity) { + theTriangles.addAll(neighbors(triangle)); + for (Pnt vertex: triangle) { + Set facet = triangle.facetOpposite(vertex); + if (boundary.contains(facet)) boundary.remove(facet); + else boundary.add(facet); + } + } + theTriangles.removeAll(cavity); // Adj triangles only + + // Remove the cavity triangles from the triangulation + for (Triangle triangle: cavity) triGraph.remove(triangle); + + // Build each new triangle and add it to the triangulation + Set newTriangles = new HashSet(); + for (Set vertices: boundary) { + vertices.add(site); + Triangle tri = new Triangle(vertices); + triGraph.add(tri); + newTriangles.add(tri); + } + + // Update the graph links for each new triangle + theTriangles.addAll(newTriangles); // Adj triangle + new triangles + for (Triangle triangle: newTriangles) + for (Triangle other: theTriangles) + if (triangle.isNeighbor(other)) + triGraph.add(triangle, other); + + // Return one of the new triangles + return newTriangles.iterator().next(); + } + + /** + * Main program; used for testing. + */ + public static void main (String[] args) { + Triangle tri = + new Triangle(new Pnt(-10,10), new Pnt(10,10), new Pnt(0,-10)); + System.out.println("Triangle created: " + tri); + Triangulation dt = new Triangulation(tri); + System.out.println("DelaunayTriangulation created: " + dt); + dt.delaunayPlace(new Pnt(0,0)); + dt.delaunayPlace(new Pnt(1,0)); + dt.delaunayPlace(new Pnt(0,1)); + System.out.println("After adding 3 points, we have a " + dt); + Triangle.moreInfo = true; + System.out.println("Triangles: " + dt.triGraph.nodeSet()); + } +} \ No newline at end of file diff --git a/gui/GUI.java b/gui/GUI.java new file mode 100644 index 0000000..03e8b3a --- /dev/null +++ b/gui/GUI.java @@ -0,0 +1,69 @@ +package gui; + +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; + +import javax.swing.JFrame; + +public class GUI { + + /** + * @param args + */ + public static void main(String[] args) { + JFrame map = new JFrame("Map"); + map.setSize(600, 450); + // JFrame control = new JFrame("Control"); + map.setVisible(true); + map.addWindowListener(new WindowsCloser()); + + } + +} + +class WindowsCloser implements WindowListener { + + @Override + public void windowActivated(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowClosed(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowClosing(WindowEvent e) { + // TODO Auto-generated method stub + System.exit(0); + + } + + @Override + public void windowDeactivated(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowDeiconified(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowIconified(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowOpened(WindowEvent e) { + // TODO Auto-generated method stub + + } + +} diff --git a/gui/ListTest.java b/gui/ListTest.java new file mode 100644 index 0000000..951fb71 --- /dev/null +++ b/gui/ListTest.java @@ -0,0 +1,47 @@ +package gui; + +import java.util.Date; + +import javax.swing.DefaultListModel; +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JScrollPane; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +public class ListTest { + + /** + * @param args + */ + public static void main(String[] args) { + JFrame test = new JFrame(); + test.setSize(300, 50); + + DefaultListModel listModel = new DefaultListModel(); + listModel.addElement("bla"); + listModel.addElement(new Date()); + JList list = new JList(listModel); + test.add(list); + test.setVisible(true); + listModel.addElement("neues Element"); + listModel.addElement("neues Element"); + JScrollPane listScroller = new JScrollPane(list); + list.setSelectionMode(0); + test.add(listScroller); + + list.addListSelectionListener(new ListSelectionListener() { + + @Override + public void valueChanged(ListSelectionEvent e) { + // TODO Auto-generated method stub + if (!e.getValueIsAdjusting()) { + System.out.println(((JList) e.getSource()) + .getSelectedIndex()); + } + + } + }); + + } +} diff --git a/gui/Localization.java b/gui/Localization.java new file mode 100644 index 0000000..8024c9e --- /dev/null +++ b/gui/Localization.java @@ -0,0 +1,291 @@ +package gui; + +import helper.ListBTS; + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Graphics2D; +import java.awt.TextField; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Date; + +import javax.swing.JCheckBox; +import javax.swing.JFrame; + +import org.jdesktop.swingx.JXMapKit; +import org.jdesktop.swingx.JXMapKit.DefaultProviders; +import org.jdesktop.swingx.JXMapViewer; +import org.jdesktop.swingx.mapviewer.DefaultTileFactory; +import org.jdesktop.swingx.mapviewer.GeoPosition; +import org.jdesktop.swingx.mapviewer.TileFactoryInfo; +import org.jdesktop.swingx.painter.CompoundPainter; +import org.jdesktop.swingx.painter.Painter; + +import DataStructure.BayesAll; +import DataStructure.Interpolator; +import DataStructure.MobilePhone; +import DataStructure.PhoneContainer; +import DataStructure.SingleBTS; +import Parse.SqlPollerDate; +import Parse.SqlPollerUnThreaded; + +public class Localization { + static Interpolator map; + + private static ArrayList filterMR(ArrayList MR, + JCheckBox[] btsFilter) { + SingleBTS[] content = map.content(); + ArrayList result = new ArrayList(); + for (int i = 0; i < content.length; i++) { + if (btsFilter[i].isSelected()) { + // add this BTS + ArrayList elementsToAdd = ListBTS.getAllARFCN(MR, + content[i].ARFCN); + if (elementsToAdd != null) + result.addAll(elementsToAdd); + } + } + return result; + } + + /** + * @param args + */ + @SuppressWarnings("unused") + public static void main(String[] args) { + JFrame frame = new JFrame(); + JFrame control = new JFrame(); + control.setSize(400, 300); + JFrame filter = new JFrame("filter BTS"); + filter.setSize(200, 600); + + frame.setSize(400, 400); + JXMapKit mapViewer = new JXMapKit(); + // JXMapViewer + // Painter + // mapViewer.setDefaultProvider(DefaultProviders.OpenStreetMaps); + mapViewer.setDefaultProvider(DefaultProviders.Custom); + + TileFactoryInfo ownTileFactory = new TileFactoryInfo(0, 18, 18, 256, + false, false, "http://c.tile.openstreetmap.org", "/", "/", "/") { + public String getTileUrl(int x, int y, int zoom) { + return this.baseURL + "/" + (18 - zoom) + "/" + x + "/" + y + + ".png"; + } + }; + mapViewer.setTileFactory(new DefaultTileFactory(ownTileFactory)); + + mapViewer.setDataProviderCreditShown(true); + frame.add(mapViewer); + System.out.println("da"); + + SqlPollerUnThreaded sql = new SqlPollerUnThreaded(); + SqlPollerDate sqlDate; + sqlDate = new SqlPollerDate(sql); + TextField actionRefID = new TextField(); + TextField confidenceField = new TextField(); + control.add(actionRefID, BorderLayout.CENTER); + JCheckBox useActionRef = new JCheckBox("use RefID"); + control.add(useActionRef, BorderLayout.SOUTH); + confidenceField.setText("0.75"); + actionRefID.setText("146373"); + control.add(confidenceField, BorderLayout.NORTH); + control.setVisible(true); + Button next = new Button("next"); + control.add(next, BorderLayout.EAST); + frame.setVisible(true); + mapViewer.setZoom(18); + try { + + map = readGSM("D:/parallel-strictdB-BER.obj"); + // map = readGSM("parallel-strictdB.obj"); + // map = readGSM("RichyUndKerstinInterpoliert.obj"); + // map = readGSM("parallel.obj"); + mapViewer.setAddressLocation(new GeoPosition( + (map.minY + map.maxY) / 2, (map.minX + map.maxX) / 2)); + mapViewer.setAddressLocationShown(true); + mapViewer.setZoom(1); + mapViewer.setCenterPosition(new GeoPosition( + (map.minY + map.maxY) / 2, (map.minX + map.maxX) / 2)); + + // mapViewer.setTileFactory(new DefaultTileFactory(new + // ownTileFactory(minimumZoomLevel, maximumZoomLevel, totalMapZoom, + // tileSize, xr2l, yt2b, baseURL, xparam, yparam, zparam))) + // mapViewer.getMainMap(). + + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ClassNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + SingleBTS[] content = map.content(); + JCheckBox[] btsFilter = new JCheckBox[content.length]; + int y = 30; + filter.setLayout(null); + for (int i = 0; i < content.length; i++) { + btsFilter[i] = new JCheckBox(Integer.toString(content[i].ARFCN), + true); + btsFilter[i].setLocation(30, y); + btsFilter[i].setSize(70, 25); + y += 30; + filter.add(btsFilter[i]); + } + filter.validate(); + filter.setVisible(true); + + PhoneContainer container = new PhoneContainer(); + CompoundPainter cp = new CompoundPainter(); + BayesAll bayes = new BayesAll(map); + + // hack: make while (true) again! + // long lastRefID = 0; + + while (true) { + + if (useActionRef.isSelected()) { + + try { + double confidence = Double.parseDouble(confidenceField + .getText()); + long refID = Long.parseLong(actionRefID.getText()); + + ArrayList report = sqlDate.getActionRefID(refID).MR; + + // MobilePhone phone = sqlDate.getActionRefID(refID); + MobilePhone phone = new MobilePhone(); + phone.bayes = bayes; + phone.MR = filterMR(report, btsFilter); + phone.correctCoordinate = sqlDate.getCoord(refID); + long time = phone.getMinTime(); + // long timeMax = phone.getMaxTime(); + confidence = Double.parseDouble(confidenceField.getText()); + phone.locate(confidence); + // phone.locateTimeSensitiv(confidence, (time + timeMax) / + // 2); + // phone.locateTimeSensitiv(confidence, timeMax - 3000); + // Zeitschleife + System.out.println(phone.localizationAccuracy()); + + while (time <= phone.getMaxTime()) { + // go out of while loop + if (true) + break; + phone.MR = filterMR(report, btsFilter); + // phone.MR = ListBTS.generateAveragedList(phone.MR); + + System.out.println("Zeit: " + new Date(time) + "(" + + time + ")"); + confidence = Double.parseDouble(confidenceField + .getText()); + // phone.locateTimeSensitiv(map, confidence, time); + phone.locateTimeSensitiv(confidence, time); + System.out.println(phone.localizationAccuracy()); + mapViewer.getMainMap().setOverlayPainter(phone); + time += 3000; + } + System.out.println("Ende Zeitschleife... Neuanfang"); + + // phone.locate(map, confidence, false); + System.out.println("confidence: " + confidence); + mapViewer.getMainMap().setOverlayPainter(phone); + } catch (NumberFormatException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (Exception e) { + System.out.println("irgednwas anderes hat nicht geklappt"); + e.printStackTrace(); + } + } else { + container.removeAll(); + ArrayList phones = sql.getMRs(); + // MobilePhone hackPhone = new MobilePhone(); + + // insert MR reports from phone! + + for (MobilePhone phone : phones) { + phone.locate(map, 0.75, false); + container.add(phone); + } + + // make mappainter overlay + + cp.setCacheable(false); + + mapViewer.getMainMap().setOverlayPainter(container); + } + try { + Thread.sleep(100); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + } + + static private Interpolator readGSM(String filename) + throws FileNotFoundException, IOException, ClassNotFoundException { + + ObjectInputStream ois = new ObjectInputStream(new FileInputStream( + filename)); + Interpolator map = (Interpolator) ois.readObject(); + System.out.println("GSMMap eingelesen"); + return map; + } + +} + +class locationPainter implements Painter { + private ArrayList phones = new ArrayList(); + + // private Interpolator map; + + public locationPainter(ArrayList phones, Interpolator map) { + this.phones = phones; + // this.map = map; + for (int i = 0; i < phones.size(); i++) { + phones.get(i).locate(map, false); + } + + } + + @Override + public void paint(Graphics2D g, JXMapViewer map, int w, int h) { + + for (int i = 0; i < phones.size(); i++) { + + } + + } + +} + +class ownTileFactory extends TileFactoryInfo { + + public ownTileFactory(int minimumZoomLevel, int maximumZoomLevel, + int totalMapZoom, int tileSize, boolean xr2l, boolean yt2b, + String baseURL, String xparam, String yparam, String zparam) { + super(0, 18, 18, 256, true, true, "http://b.tile.openstreetmap.org", + xparam, yparam, zparam); + maximumZoomLevel = 18; + minimumZoomLevel = 0; + totalMapZoom = 18; + + // TODO Auto-generated constructor stub + } + +} diff --git a/gui/LocalizationNew.java b/gui/LocalizationNew.java new file mode 100644 index 0000000..911dc9e --- /dev/null +++ b/gui/LocalizationNew.java @@ -0,0 +1,773 @@ +package gui; + +import helper.ListBTS; + +import java.awt.BorderLayout; +import java.awt.TextField; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Date; + +import javax.swing.DefaultListModel; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JScrollPane; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.jdesktop.swingx.JXMapKit; +import org.jdesktop.swingx.JXMapKit.DefaultProviders; +import org.jdesktop.swingx.JXMapViewer; +import org.jdesktop.swingx.mapviewer.DefaultTileFactory; +import org.jdesktop.swingx.mapviewer.GeoPosition; +import org.jdesktop.swingx.mapviewer.TileFactoryInfo; +import org.jdesktop.swingx.painter.Painter; + +import DataStructure.BayesAll; +import DataStructure.GSMMap; +import DataStructure.Interpolator; +import DataStructure.MobilePhone; +import DataStructure.SingleBTS; +import Parse.SqlPollerDate; + +public class LocalizationNew { + + /** + * @param args + */ + public static void main(String[] args) { + UserInterface.showFrames(); + UserInterface.setLive(false); + UserInterface.setIMSIorRef(153227); + try { + SqlPollerDate sql = new SqlPollerDate(); + BayesAll bayes = new BayesAll(UserInterface.getGsmMap()); + MobilePhone phone = new MobilePhone(bayes); + + while (true) { + try { + if (!UserInterface.getLive() + && UserInterface.getIMSI() != 0) { + phone = getPhoneRefID(UserInterface.getIMSI(), bayes, + sql); + + if (!UserInterface.getStep()) { + // Locate based on average of all MRs + phone.locate(UserInterface.getConfidence()); + UserInterface.setMapPainter(phone); + } else { + long time = phone.getMinTime(); + long maxtime = phone.getMaxTime(); + while (time < maxtime && UserInterface.getStep()) { + phone.locateTimeSensitiv( + UserInterface.getConfidence(), time); + time += 2000; + UserInterface.setMapPainter(phone); + } + } + + } else if (UserInterface.getLive() + && UserInterface.getIMSI() != 0) { + phone = getPhoneLastSeen(UserInterface.getIMSI(), + bayes, sql); + phone.locate(UserInterface.getConfidence()); + UserInterface.setMapPainter(phone); + } + System.gc(); + Thread.sleep(500); + } catch (Exception e) { + System.out.println("Error. Cannot Localize."); + // e.printStackTrace(); + } + } + + } catch (ClassNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + System.out.println("No Internet Connection?"); + } + + } + + private static MobilePhone getPhoneLastSeen(long imsi, BayesAll bayes, + SqlPollerDate sql) throws SQLException { + // TODO Auto-generated method stub + MobilePhone phone = new MobilePhone(); + phone = sql.getLastMRs(imsi); + phone.bayes = bayes; + if (UserInterface.getFilter()) + BTSFilter.filterMR(phone); + return phone; + } + + private static MobilePhone getPhoneRefID(long IMSI, BayesAll bayes, + SqlPollerDate sql) throws SQLException { + MobilePhone phone = sql.getActionRefID(UserInterface.getIMSI()); + phone.bayes = bayes; + if (UserInterface.getFilter()) + BTSFilter.filterMR(phone); + return phone; + } +} + +/** + * Creates user Interface for Localization + * + * @author richy + * + */ +class UserInterface { + private static TextField input; + private static JCheckBox live; + private static JCheckBox history; + private static TextField confidence; + private static JXMapKit mapViewer; + private static GSMMap map; + private static JCheckBox filter; + + /** + * Show UserInterface + */ + public static void showFrames() { + JFrame map = new JFrame(); + map.addWindowListener(new quit()); + map.setSize(600, 450); + mapViewer = getMapViewer(); + map.add(mapViewer); + map.setVisible(true); + JFrame control = new JFrame(); + control.addWindowListener(new quit()); + control.setSize(400, 300); + control.setLayout(null); + // JCheckBox imsiOrActionRef = new JCheckBox("IMSI"); + input = new TextField("187970"); + input.setLocation(20, 20); + input.setSize(200, 20); + final JLabel imsiLabel = new JLabel("IMSI"); + imsiLabel.setSize(200, 20); + imsiLabel.setLocation(20, 0); + + live = new JCheckBox("Last known position"); + live.setSelected(true); + live.setLocation(20, 40); + live.setSize(200, 20); + live.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + + if (live.isSelected()) { + imsiLabel.setText("IMSI"); + // System.out.println("Enabled"); + } else { + imsiLabel.setText("ActionRefID"); + // System.out.println("Disabled"); + } + } + }); + JLabel confidenceLabel = new JLabel("Confidence"); + confidenceLabel.setLocation(230, 0); + confidenceLabel.setSize(100, 20); + + confidence = new TextField("0.75"); + confidence.setLocation(230, 20); + confidence.setSize(60, 20); + + history = new JCheckBox("Step by Step"); + history.setLocation(20, 60); + history.setSize(200, 20); + + filter = new JCheckBox("filter BTS"); + filter.setLocation(20, 80); + filter.setSize(200, 20); + filter.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if (filter.isSelected()) { + BTSFilter.showFilter(getGsmMap()); + } else { + BTSFilter.hideFilter(); + } + + } + }); + + JButton getFromName = new JButton("Get IMSI"); + getFromName.setLocation(20, 120); + getFromName.setSize(80, 20); + getFromName.addActionListener(new ImsiFromName()); + + JButton getActions = new JButton("Get Actions"); + getActions.setLocation(120, 120); + getActions.setSize(120, 20); + getActions.addActionListener(new ActionFromIMSI()); + + control.add(input); + control.add(imsiLabel); + control.add(live); + control.add(confidenceLabel); + control.add(confidence); + control.add(history); + control.add(getFromName); + control.add(getActions); + control.add(filter); + control.setVisible(true); + } + + private static JXMapKit getMapViewer() { + JXMapKit mapViewer = new JXMapKit(); + // JXMapViewer + // Painter + // mapViewer.setDefaultProvider(DefaultProviders.OpenStreetMaps); + mapViewer.setDefaultProvider(DefaultProviders.Custom); + + TileFactoryInfo ownTileFactory = new TileFactoryInfo(0, 18, 18, 256, + false, false, "http://c.tile.openstreetmap.org", "/", "/", "/") { + public String getTileUrl(int x, int y, int zoom) { + return this.baseURL + "/" + (18 - zoom) + "/" + x + "/" + y + + ".png"; + } + }; + mapViewer.setTileFactory(new DefaultTileFactory(ownTileFactory)); + + mapViewer.setDataProviderCreditShown(true); + + try { + map = readGSM("parallel-strictdB-BER.obj"); + mapViewer.setAddressLocation(new GeoPosition( + (map.minY + map.maxY) / 2, (map.minX + map.maxX) / 2)); + mapViewer.setAddressLocationShown(true); + mapViewer.setZoom(1); + mapViewer.setCenterPosition(new GeoPosition( + (map.minY + map.maxY) / 2, (map.minX + map.maxX) / 2)); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + System.out.println("GSM-map not readable"); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + System.out.println("GSM-map not readable"); + } catch (ClassNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return mapViewer; + } + + public static void setMapPainter(Painter painter) { + mapViewer.getMainMap().setOverlayPainter(painter); + } + + public static GSMMap getGsmMap() { + return map; + } + + static private Interpolator readGSM(String filename) + throws FileNotFoundException, IOException, ClassNotFoundException { + System.out.println("trying to read GSM-map..."); + ObjectInputStream ois = new ObjectInputStream(new FileInputStream( + filename)); + Interpolator map = (Interpolator) ois.readObject(); + System.out.println("GSMMap read successful"); + return map; + } + + public static long getIMSI() { + try { + return Long.parseLong(input.getText().trim()); + } catch (Exception e) { + return 0; + } + } + + public static void setIMSIorRef(long IMSI) { + try { + input.setText(Long.toString(IMSI)); + } catch (NullPointerException e) { + setIMSIorRef(0); + } + } + + public static void setLive(boolean value) { + live.setSelected(value); + } + + public static boolean getLive() { + return live.isSelected(); + } + + public static boolean getStep() { + return history.isSelected(); + } + + public static boolean getFilter() { + return filter.isSelected(); + } + + public static void setFilter(boolean value) { + filter.setSelected(value); + } + + public static double getConfidence() { + try { + return Double.parseDouble(confidence.getText().trim()); + } catch (NumberFormatException e) { + return 0.75; + } + } +} + +class ImsiFromName implements ActionListener { + // private name; + // JFrame result; + DefaultListModel listModel; + long[] IMSIs; + + private void createFrame() { + final JFrame result = new JFrame("Search for IMSIs from Name"); + result.setSize(400, 400); + JButton search = new JButton("search"); + + JButton ok = new JButton("OK"); + + final TextField name = new TextField(); + listModel = new DefaultListModel(); + final JList list = new JList(listModel); + list.setSelectionMode(0); + JScrollPane listScroller = new JScrollPane(list); + result.add(listScroller, BorderLayout.CENTER); + result.add(name, BorderLayout.NORTH); + result.add(ok, BorderLayout.SOUTH); + result.add(search, BorderLayout.EAST); + result.addWindowListener(new close()); + result.setVisible(true); + + search.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + try { + IMSIs = searchForIMSI(name.getText().trim()); + } catch (ClassNotFoundException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } catch (SQLException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + } + }); + + ok.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + // get choosen index within list + int i = list.getSelectedIndex(); + try { + UserInterface.setIMSIorRef(IMSIs[i]); + UserInterface.setLive(true); + } catch (ArrayIndexOutOfBoundsException e1) { + + } finally { + // result.dispose(); + } + + } + }); + + } + + @Override + public void actionPerformed(ActionEvent e) { + createFrame(); + + // result.dispose(); + + } + + private long[] searchForIMSI(String name) throws ClassNotFoundException, + SQLException { + // clear the list-window + listModel.clear(); + + // get IMSIs for given name + name = name.trim(); + Connection cn = getConnection(); + // Connection is ready + // get IMSIs now... + Statement st = cn.createStatement(); + st.setQueryTimeout(3); + ResultSet rs = st.executeQuery(query(name)); + // IMSIs are now stored in rs. + ArrayList IMSIs = new ArrayList(); + while (rs.next()) { + // add to result + IMSIs.add(rs.getLong("imsi")); + // add to list + listModel.addElement(rs.getLong("imsi") + " (" + + rs.getString("extension") + ")"); + } + long[] result = new long[IMSIs.size()]; + for (int i = 0; i < result.length; i++) { + result[i] = IMSIs.get(i); + } + rs.close(); + st.close(); + cn.close(); + return result; + } + + private Connection getConnection() throws ClassNotFoundException, + SQLException { + Class.forName("com.mysql.jdbc.Driver"); + Connection cn = DriverManager + .getConnection("jdbc:mysql://132.230.4.13:3306/hlr", "richard", + "uh237Aug.ad7"); + cn.setReadOnly(true); + return cn; + } + + private String query(String name) { + + String query = "select imsi, extension from User JOIN UserWatch ON" + + " surname = '" + name + "' AND user_id = User.id " + + "JOIN Subscriber ON Subscriber.id = subscriber_id"; + + return query; + } + +} + +class ActionFromIMSI implements ActionListener { + DefaultListModel listModel; + long[] Actions; + + private void createFrame() { + final JFrame result = new JFrame("Search for Actions from IMSI"); + result.setSize(400, 400); + JButton search = new JButton("search"); + + JButton ok = new JButton("OK"); + + final TextField imsi = new TextField(Long.toString(UserInterface + .getIMSI())); + listModel = new DefaultListModel(); + final JList list = new JList(listModel); + list.setSelectionMode(0); + JScrollPane listScroller = new JScrollPane(list); + result.add(listScroller, BorderLayout.CENTER); + result.add(imsi, BorderLayout.NORTH); + result.add(ok, BorderLayout.SOUTH); + result.add(search, BorderLayout.EAST); + result.addWindowListener(new close()); + result.setVisible(true); + + search.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + try { + Actions = searchForAction(imsi.getText().trim()); + + } catch (ClassNotFoundException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } catch (SQLException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + } + + private long[] searchForAction(String imsi) + throws ClassNotFoundException, SQLException { + imsi = imsi.trim(); + Connection cn = getConnection(); + Statement st = cn.createStatement(); + st.setQueryTimeout(3); + ResultSet rs = st.executeQuery(query(imsi)); + ArrayList IDs = new ArrayList(500); + listModel.clear(); + while (rs.next()) { + Date time = rs.getTimestamp("cur_timestamp"); + String reason = rs.getString("name"); + String actionID = rs.getString("id"); + actionID current = new actionID(time, reason, actionID); + listModel.addElement(current); + IDs.add(Long.parseLong(actionID)); + } + + long[] result = new long[IDs.size()]; + for (int i = 0; i < result.length; i++) { + result[i] = IDs.get(i); + } + rs.close(); + st.close(); + cn.close(); + return result; + } + }); + + ok.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + // get choosen index within list + int i = list.getSelectedIndex(); + try { + UserInterface.setIMSIorRef(Actions[i]); + UserInterface.setLive(false); + } catch (ArrayIndexOutOfBoundsException e1) { + + } finally { + // result.dispose(); + } + + } + }); + + } + + @Override + public void actionPerformed(ActionEvent arg0) { + createFrame(); + } + + private Connection getConnection() throws ClassNotFoundException, + SQLException { + Class.forName("com.mysql.jdbc.Driver"); + Connection cn = DriverManager.getConnection( + "jdbc:mysql://132.230.4.13:3306/logging", "richard", + "uh237Aug.ad7"); + cn.setReadOnly(true); + return cn; + } + + private String query(String imsi) { + + String query = "Select action.cur_timestamp, action.id, " + + "Name from action JOIN actionIdentifier ON " + + "actionID = actionIdentifier.id WHERE " + "IMSI = '" + imsi + + "' ORDER BY action.id desc LIMIT 0,500"; + + return query; + } +} + +class close implements WindowListener { + + @Override + public void windowOpened(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowIconified(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowDeiconified(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowDeactivated(WindowEvent e) { + // ((JFrame) e.getSource()).dispose(); + + } + + @Override + public void windowClosing(WindowEvent e) { + ((JFrame) e.getSource()).dispose(); + } + + @Override + public void windowClosed(WindowEvent e) { + // TODO Auto-generated method stub + // result.dispose(); + } + + @Override + public void windowActivated(WindowEvent e) { + // TODO Auto-generated method stub + + } + +} + +class quit implements WindowListener { + + @Override + public void windowActivated(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowClosed(WindowEvent e) { + System.exit(0); + + } + + @Override + public void windowClosing(WindowEvent e) { + System.exit(0); + + } + + @Override + public void windowDeactivated(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowDeiconified(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowIconified(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowOpened(WindowEvent e) { + // TODO Auto-generated method stub + + } + +} + +class actionID { + Date time; + String reason; + String actionID; + + public actionID(Date time, String reason, String actionID) { + this.time = time; + this.reason = reason; + this.actionID = actionID; + } + + public String toString() { + return actionID + ": " + time + " (" + reason + ")"; + } +} + +class BTSFilter { + private static JCheckBox[] btsFilter; + private static JFrame filter; + private static GSMMap map; + + static void showFilter(GSMMap GSMmap) { + map = GSMmap; + filter = new JFrame("filter BTS"); + filter.addWindowListener(new WindowListener() { + + @Override + public void windowOpened(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowIconified(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowDeiconified(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowDeactivated(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowClosing(WindowEvent e) { + UserInterface.setFilter(false); + + } + + @Override + public void windowClosed(WindowEvent e) { + UserInterface.setFilter(false); + + } + + @Override + public void windowActivated(WindowEvent e) { + // TODO Auto-generated method stub + + } + }); + filter.setSize(70, 250); + SingleBTS[] content = map.content(); + btsFilter = new JCheckBox[content.length]; + int y = 5; + filter.setLayout(null); + for (int i = 0; i < content.length; i++) { + btsFilter[i] = new JCheckBox(Integer.toString(content[i].ARFCN), + true); + btsFilter[i].setLocation(10, y); + btsFilter[i].setSize(70, 25); + y += 20; + filter.add(btsFilter[i]); + } + filter.validate(); + filter.setVisible(true); + } + + static void hideFilter() { + filter.setVisible(false); + } + + static void filterMR(MobilePhone phone) { + SingleBTS[] content = map.content(); + ArrayList result = new ArrayList(); + for (int i = 0; i < content.length; i++) { + if (btsFilter[i].isSelected()) { + // add this BTS + ArrayList elementsToAdd = ListBTS.getAllARFCN( + phone.MR, content[i].ARFCN); + if (elementsToAdd != null) + result.addAll(elementsToAdd); + } + } + phone.MR = result; + } +} \ No newline at end of file diff --git a/gui/MapShow.java b/gui/MapShow.java new file mode 100644 index 0000000..8e47897 --- /dev/null +++ b/gui/MapShow.java @@ -0,0 +1,38 @@ +package gui; + +@SuppressWarnings("serial") +public class MapShow extends javax.swing.JFrame { + + private org.jdesktop.swingx.JXMapKit jXMapKit1; + + /** + * @param args + */ + public static void main(String[] args) { + // TODO Auto-generated method stub + java.awt.EventQueue.invokeLater(new Runnable() { + + @Override + public void run() { + new MapShow().setVisible(true); + + } + }); + + } + + public MapShow() { + initComponents(); + } + + private void initComponents() { + jXMapKit1 = new org.jdesktop.swingx.JXMapKit(); + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + jXMapKit1 + .setDefaultProvider(org.jdesktop.swingx.JXMapKit.DefaultProviders.OpenStreetMaps); + getContentPane().add(jXMapKit1); + pack(); + + } + +} diff --git a/gui/MapTest.java b/gui/MapTest.java new file mode 100644 index 0000000..97d457d --- /dev/null +++ b/gui/MapTest.java @@ -0,0 +1,119 @@ +package gui; + +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.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.JFrame; + +import org.jdesktop.swingx.JXMapKit; +import org.jdesktop.swingx.JXMapKit.DefaultProviders; +import org.jdesktop.swingx.JXMapViewer; +import org.jdesktop.swingx.mapviewer.GeoPosition; +import org.jdesktop.swingx.painter.Painter; + +import DataStructure.GSMMap; +import DataStructure.SingleBTS; + +public class MapTest { + public static void createGui() throws FileNotFoundException, IOException, + ClassNotFoundException { + JFrame frame = new JFrame(); + frame.setVisible(true); + frame.setSize(400, 400); + JXMapKit mapViewer = new JXMapKit(); + // JXMapViewer + // Painter + mapViewer.setDefaultProvider(DefaultProviders.OpenStreetMaps); + mapViewer.setDataProviderCreditShown(true); + frame.add(mapViewer); + System.out.println("da"); + + ObjectInputStream ois = new ObjectInputStream(new FileInputStream( + "interpolatedGSMMap.obj")); + GSMMap map = (GSMMap) ois.readObject(); + SingleBTS[] content = map.content(); + final ArrayList btss = new ArrayList(); + for (int x = 0; x < map.Xcoords.length; x++) { + for (int y = 0; y < map.Ycoords.length; y++) { + SingleBTS current = ListBTS.getARFCN(map.map[x][y], content[0]); + if (current != null) { + btss.add(new GeoPosition(map.Ycoords[y], map.Xcoords[x])); + } + } + } + + Painter polygonOverlay = new Painter() { + + public void paint(Graphics2D g, JXMapViewer map, int w, int h) { + g = (Graphics2D) g.create(); + // convert from viewport to world bitmap + Rectangle rect = map.getViewportBounds(); + g.translate(-rect.x, -rect.y); + + // create a polygon + Polygon poly = new Polygon(); + for (GeoPosition gp : btss) { + // convert geo to world bitmap pixel + Point2D pt = map.getTileFactory().geoToPixel(gp, + map.getZoom()); + poly.addPoint((int) pt.getX(), (int) pt.getY()); + } + + // do the drawing + g.setColor(new Color(255, 0, 0, 100)); + g.fill(poly); + g.setColor(Color.RED); + g.draw(poly); + + g.dispose(); + } + + }; + mapViewer.getMainMap().setOverlayPainter(polygonOverlay); + + } + + public static void main(String[] args) throws FileNotFoundException, + IOException, ClassNotFoundException { + createGui(); + + final List region = new ArrayList(); + region.add(new GeoPosition(38.266, 12.4)); + region.add(new GeoPosition(38.283, 15.65)); + region.add(new GeoPosition(36.583, 15.166)); + region.add(new GeoPosition(37.616, 12.25)); + /* + * Painter polygonOverlay = new Painter() { + * + * public void paint(Graphics2D g, JXMapViewer map, int w, int h) { g = + * (Graphics2D) g.create(); // convert from viewport to world bitmap + * Rectangle rect = map.getViewportBounds(); g.translate(-rect.x, + * -rect.y); + * + * // create a polygon Polygon poly = new Polygon(); for (GeoPosition gp + * : region) { // convert geo to world bitmap pixel Point2D pt = + * map.getTileFactory().geoToPixel(gp, map.getZoom()); + * poly.addPoint((int) pt.getX(), (int) pt.getY()); } + * + * // do the drawing g.setColor(new Color(255, 0, 0, 100)); + * g.fill(poly); g.setColor(Color.RED); g.draw(poly); + * + * g.dispose(); } + * + * }; + */ + + } + +} \ No newline at end of file diff --git a/gui/MapViewer.java b/gui/MapViewer.java new file mode 100644 index 0000000..3292fdf --- /dev/null +++ b/gui/MapViewer.java @@ -0,0 +1,54 @@ +package gui; + +@SuppressWarnings("serial") +public class MapViewer extends javax.swing.JFrame { + + private org.jdesktop.swingx.JXMapKit jXMapKit1; + + /** + * @param args + */ + public static void main(String[] args) { + // TODO Auto-generated method stub + java.awt.EventQueue.invokeLater(new Runnable() { + + @Override + public void run() { + new MapViewer().setVisible(true); + + } + }); + + } + + public MapViewer() { + initComponents(); + } + + private void initComponents() { + // TileFactoryInfo test = new TileFactoryInfo(1, 14, 3, 50, true, true, + // "http://tile.openstreetmap.org/", "x", "y", "zoom"); + /* + * TileFactoryInfo info = new TileFactoryInfo(0, // min level 8, // max + * allowed level 9, // max level 256, // tile size true, true, // x/y + * orientation is normal "http://wesmilepretty.com/gmap2/", // base url + * "x", "y", "z" // url args for x, y and z ) { public String + * getTileUrl(int x, int y, int zoom) { // int wow_zoom = 9 - zoom; + * String url = this.baseURL; // if (y >= Math.pow(2, wow_zoom - 1)) { + * // url = "http://int2e.com/gmapoutland2/"; // } return url + "zoom" + + * zoom + "maps/" + x + "_" + y + "_" + zoom + ".jpg"; } }; + */ + + jXMapKit1 = new org.jdesktop.swingx.JXMapKit(); + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + jXMapKit1 + .setDefaultProvider(org.jdesktop.swingx.JXMapKit.DefaultProviders.OpenStreetMaps); + // jXMapKit1.setDefaultProvider(test); + // jXMapKit1.setTileFactory(new TileFactory(info)); + + getContentPane().add(jXMapKit1); + pack(); + + } + +} diff --git a/gui/ShowMapStrength.java b/gui/ShowMapStrength.java new file mode 100644 index 0000000..a74e064 --- /dev/null +++ b/gui/ShowMapStrength.java @@ -0,0 +1,309 @@ +package gui; + +import helper.ListBTS; + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Label; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.awt.geom.Point2D; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.ObjectInputStream; + +import javax.swing.JFrame; + +import org.jdesktop.swingx.JXMapKit; +import org.jdesktop.swingx.JXMapKit.DefaultProviders; +import org.jdesktop.swingx.JXMapViewer; +import org.jdesktop.swingx.mapviewer.DefaultTileFactory; +import org.jdesktop.swingx.mapviewer.GeoPosition; +import org.jdesktop.swingx.mapviewer.TileFactoryInfo; +import org.jdesktop.swingx.painter.Painter; + +import DataStructure.GSMMap; +import DataStructure.GSMMap.PaintEnum; +import DataStructure.Interpolator; +import DataStructure.SingleBTS; + +public class ShowMapStrength { + // private static blub overlay; + private static int index = 0; + private GSMMap.PaintEnum whatToPaint = GSMMap.PaintEnum.DL; + static int paintindex = 0; + + /** + * @param args + * @throws IOException + * @throws FileNotFoundException + * @throws ClassNotFoundException + */ + public static void main(String[] args) throws FileNotFoundException, + IOException, ClassNotFoundException { + JFrame frame = new JFrame(); + // JFrame control = new JFrame(); + frame.addWindowListener(new closeWindow()); + + frame.setSize(400, 400); + final JXMapKit mapViewer = new JXMapKit(); + // JXMapViewer + // Painter + mapViewer.setDefaultProvider(DefaultProviders.OpenStreetMaps); + mapViewer.setDataProviderCreditShown(true); + frame.add(mapViewer, BorderLayout.CENTER); + Button knopf1 = new Button("change ARFCN"); + Button knopf2 = new Button("Map -"); + Button knopf3 = new Button("Map +"); + frame.add(knopf1, BorderLayout.SOUTH); + frame.add(knopf2, BorderLayout.WEST); + frame.add(knopf3, BorderLayout.EAST); + final Label label1 = new Label(); + frame.add(label1, BorderLayout.NORTH); + + frame.setVisible(true); + System.out.println("da"); + // ObjectInputStream ois = new ObjectInputStream(new FileInputStream( + // "parallel.obj")); + ObjectInputStream ois = new ObjectInputStream(new FileInputStream( + "parallel-strictdB-BER.obj")); + // ObjectInputStream ois = new ObjectInputStream(new FileInputStream( + // "D:/parallel-strictdB-BER.obj")); + final Interpolator map = (Interpolator) ois.readObject(); + + System.out.println("GSMMap eingelesen"); + + mapViewer.setAddressLocation(new GeoPosition((map.minY + map.maxY) / 2, + (map.minX + map.maxX) / 2)); + mapViewer.setZoom(1); + mapViewer.setAddressLocationShown(true); + + mapViewer.setDefaultProvider(DefaultProviders.Custom); + + TileFactoryInfo ownTileFactory = new TileFactoryInfo(0, 18, 18, 256, + false, false, "http://b.tile.openstreetmap.org", "/", "/", "/") { + public String getTileUrl(int x, int y, int zoom) { + return this.baseURL + "/" + (18 - zoom) + "/" + x + "/" + y + + ".png"; + } + }; + mapViewer.setTileFactory(new DefaultTileFactory(ownTileFactory)); + + mapViewer.setAddressLocation(new GeoPosition((map.minY + map.maxY) / 3, + (map.minX + map.maxX) / 3)); + mapViewer.setAddressLocationShown(true); + mapViewer.setZoom(1); + mapViewer.setCenterPosition(new GeoPosition((map.minY + map.maxY) / 2, + (map.minX + map.maxX) / 2)); + + // overlay = new blub(map, map.content()[index]); + map.whatToPaint = GSMMap.PaintEnum.DL; + map.indexToPaint = 0; + + mapViewer.getMainMap().setOverlayPainter(map); + + knopf1.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + index++; + if (index > map.content().length - 1) { + index = 0; + } + map.indexToPaint = index; + mapViewer.getMainMap().setOverlayPainter(map); + // overlay = new blub(map, map.content()[index]); + // mapViewer.getMainMap().setOverlayPainter( + // (org.jdesktop.swingx.painter.Painter) overlay); + label1.setText("ARFCN:" + map.content()[index].ARFCN); + // label1.setAlignment(2); + + } + }); + + knopf2.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + // map.whatToPaint = GSMMap.PaintEnum.DL; + paintindex++; + if (paintindex > PaintEnum.values().length - 1) { + paintindex = 0; + } + map.whatToPaint = PaintEnum.values()[paintindex]; + mapViewer.getMainMap().setOverlayPainter(map); + } + }); + knopf3.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + // map.whatToPaint = GSMMap.PaintEnum.variance; + // mapViewer.getMainMap().setOverlayPainter(map); + paintindex--; + if (paintindex < 0) { + paintindex = PaintEnum.values().length - 1; + } + map.whatToPaint = PaintEnum.values()[paintindex]; + mapViewer.getMainMap().setOverlayPainter(map); + + } + }); + + } +} + +class blub implements Painter { + private GSMMap gsmmap; + private SingleBTS what; + + public blub(GSMMap map, SingleBTS what) { + this.gsmmap = map; + this.what = what; + } + + public void paint(Graphics2D g, JXMapViewer map, int w, int h) { + g = (Graphics2D) g.create(); + // convert from viewport to world bitmap + Rectangle rect = ((org.jdesktop.swingx.JXMapViewer) map) + .getViewportBounds(); + g.translate(-rect.x, -rect.y); + + // draw each rectangle + for (int x = 0; x < gsmmap.Xcoords.length; x++) { + for (int y = 0; y < gsmmap.Ycoords.length; y++) { + SingleBTS current = ListBTS.getARFCN(gsmmap.map[x][y], what); + if (current != null) { + // draw it + double coordX = gsmmap.Xcoords[x]; + double coordY = gsmmap.Ycoords[y]; + double accuracy = gsmmap.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, + coordX - accuracy); + Point2D pt1 = map.getTileFactory().geoToPixel(pos1, + map.getZoom()); + Point2D pt2 = map.getTileFactory().geoToPixel(pos2, + map.getZoom()); + Point2D pt3 = map.getTileFactory().geoToPixel(pos3, + map.getZoom()); + Point2D pt4 = map.getTileFactory().geoToPixel(pos4, + map.getZoom()); + + // finally, draw it! + Color color = getColor((int) current.getDldB()); + g.setColor(color); + 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()); + g.fill(tile); + g.draw(tile); + + } + } + } + g.dispose(); + } + + private Color getColor(int strength) { + int green = 0; + int red = 0; + // yellow at -75 + if (strength > -75) { + green = 255; + red = 256 - Math.abs((256 / 45) * (-75 - strength)); + + } else { + // transient green from now on + red = 255; + green = Math.abs((256 / 45) * (-120 - 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, 100); + + // return ("ff00" + Integer.toHexString(green) + + // Integer.toHexString(red)); + return result; + + } + +} + +class closeWindow implements WindowListener { + + @Override + public void windowActivated(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowClosed(WindowEvent e) { + // TODO Auto-generated method stub + ((JFrame) e.getSource()).dispose(); + } + + @Override + public void windowClosing(WindowEvent e) { + // TODO Auto-generated method stub + ((JFrame) e.getSource()).dispose(); + System.exit(0); + + } + + @Override + public void windowDeactivated(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowDeiconified(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowIconified(WindowEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void windowOpened(WindowEvent e) { + // TODO Auto-generated method stub + + } + +} diff --git a/gui/Start.java b/gui/Start.java new file mode 100644 index 0000000..aaf05ba --- /dev/null +++ b/gui/Start.java @@ -0,0 +1,64 @@ +package gui; + +import java.awt.BorderLayout; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; + +public class Start extends JFrame { + + private static final long serialVersionUID = 1L; + private JPanel jContentPane = null; + private JButton jButton = null; + + /** + * This is the default constructor + */ + public Start() { + super(); + initialize(); + } + + /** + * This method initializes this + * + * @return void + */ + private void initialize() { + this.setSize(664, 283); + this.setContentPane(getJContentPane()); + this.setTitle("GSM"); + } + + /** + * This method initializes jContentPane + * + * @return javax.swing.JPanel + */ + private JPanel getJContentPane() { + if (jContentPane == null) { + BorderLayout borderLayout = new BorderLayout(); + borderLayout.setHgap(12); + borderLayout.setVgap(5); + jContentPane = new JPanel(); + jContentPane.setLayout(borderLayout); + jContentPane.add(getJButton(), BorderLayout.SOUTH); + } + return jContentPane; + } + + /** + * This method initializes jButton + * + * @return javax.swing.JButton + */ + private JButton getJButton() { + if (jButton == null) { + jButton = new JButton(); + jButton.setText("test"); + } + return jButton; + } + +} // @jve:decl-index=0:visual-constraint="10,10" diff --git a/gui/test.java b/gui/test.java new file mode 100644 index 0000000..a2ce839 --- /dev/null +++ b/gui/test.java @@ -0,0 +1,72 @@ +package gui; + +import java.awt.Button; +import java.awt.Frame; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; + +public class test { + + /** + * @param args + */ + public static void main(String[] args) { + Frame f = new Frame(); + f.setSize(600, 400); + Button test = new Button("ein Test"); + // f.setLayout(new FlowLayout()); + f.setLayout(null); + test.setLocation(10, 10); + test.setSize(25, 25); + f.add(test); + Button test2 = new Button("ein zweiter Test"); + test2.setLocation(50, 100); + test2.setSize(25, 30); + f.add(test2); + f.validate(); + f.setVisible(true); + f.addWindowListener(new WindowListener() { + + @Override + public void windowOpened(WindowEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void windowIconified(WindowEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void windowDeiconified(WindowEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void windowDeactivated(WindowEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void windowClosing(WindowEvent arg0) { + System.exit(0); + } + + @Override + public void windowClosed(WindowEvent arg0) { + System.exit(0); + + } + + @Override + public void windowActivated(WindowEvent arg0) { + // TODO Auto-generated method stub + + } + }); + } +} diff --git a/helper/Distance.java b/helper/Distance.java new file mode 100644 index 0000000..680998b --- /dev/null +++ b/helper/Distance.java @@ -0,0 +1,75 @@ +package helper; + +import DataStructure.GPScoordinate; + +/** + * @author richy + */ +public class Distance { + + public static void main(String[] args) { + GPScoordinate coord1 = new GPScoordinate(null, 52.517, 'N', 13.4, 'E', + true); + GPScoordinate coord2 = new GPScoordinate(null, 35.7, 'N', 139.767, 'E', + true); + System.out.println(calc(coord1, coord2)); + + System.out.println(calc(52.517, 13.4, 35.7, 139.767)); + } + + /** + * Returns distance in kilometers. see + * http://de.wikipedia.org/wiki/Orthodrome + * + * @param coord1 + * GPScoordinate Point 1 + * @param coord2 + * GPScoordinate Point 2 + * @return distance in Kilometer + */ + static public double calc(GPScoordinate coord1, GPScoordinate coord2) { + double a = DEGtoRAD(coord1.coord1); + double b = DEGtoRAD(coord1.coord2); + double c = DEGtoRAD(coord2.coord1); + double d = DEGtoRAD(coord2.coord2); + + double angle = Math.acos(Math.sin(a) * Math.sin(c) + Math.cos(a) + * Math.cos(c) * Math.cos(d - b)); + double distance = angle * 6370; + return distance; + } + + /** + * Returns distance in kilometers + * + * @param coordN1 + * DEC (decimal) value coordinate point 1 N/S (y-axis) + * @param coordE1 + * DEC (decimal) value coordinate point 1 E/W (x-axis) + * @param coordN2 + * DEC (decimal) value coordinate point 2 N/S (y-axis) + * @param coordE2 + * DEC (decimal) value coordinate point 2 E/W (x-axis) + * @return + */ + + static public double calc(double coordN1, double coordE1, double coordN2, + double coordE2) { + GPScoordinate coord1 = new GPScoordinate(null, coordN1, 'N', coordE1, + 'E', true); + GPScoordinate coord2 = new GPScoordinate(null, coordN2, 'N', coordE2, + 'E', true); + return calc(coord1, coord2); + } + + static private double DEGtoRAD(double deg) { + // see wiki http://de.wikipedia.org/wiki/Radiant_%28Einheit%29 + return deg * 0.017453293d; + } + + @SuppressWarnings("unused") + static private double RADtoDEG(double rad) { + // see wiki http://de.wikipedia.org/wiki/Radiant_%28Einheit%29 + return rad * 57.29577951d; + } +} diff --git a/helper/Extrapolate.java b/helper/Extrapolate.java new file mode 100644 index 0000000..40b238b --- /dev/null +++ b/helper/Extrapolate.java @@ -0,0 +1,508 @@ +package helper; + +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import DataStructure.SingleBTS; + +public class Extrapolate { + private static final int SP = 4; + + public static void main(String[] args) { + // String[] args2 = { "15.1", "167.16", "15.2", "167.27", "15.3", + // "167.39", "14", "165.85", "15.2", "167.5" }; + String[] args2 = { "2", "5.4", "3", "6" }; + args = args2; + System.out + .println("Approximationsfunktionen zur Inter- und Extrapolation\n" + + "Kommentare siehe:\n" + + "http://www.torsten-horn.de/techdocs/java-approximationsfunktionen.htm"); + + if (args == null || args.length < 2 || args.length % 2 != 0) { + System.out + .println("\nBitte eine Menge an x-/y-Wertepaaren angeben " + + "(Werte durch Leerzeichen getrennt)."); + return; + } + + double[] xyArr = convertStringArrToDoubleArr(args); + ArrayList result = new ArrayList(); + + // Verschiedene Regressionen: + result.add(calculateLinearRegression(xyArr)); + result.add(calculatePowerRegression(xyArr)); + result.add(calculatelog10arithmicRegression(xyArr)); + result.add(calculateExponentialRegression(xyArr)); + result.add(calculateOneMinusExponentialRegression(xyArr)); + + boolean atLeastOne = false; + for (Iterator itr = result.iterator(); itr.hasNext();) { + RegressionResult res = itr.next(); + atLeastOne |= res != null; + if (res != null) + System.out.println("\n" + + linksbuendigerString(res.titel + ":", " ") + + linksbuendigerString(res.formel, + " ") + + " (Bestimmtheitsmass = " + res.rr + ")"); + } + + if (atLeastOne) { + System.out.print("\nx y "); + for (Iterator itr = result.iterator(); itr + .hasNext();) { + RegressionResult res = itr.next(); + if (res != null) + System.out.print(linksbuendigerString(res.titel, + " ")); + } + System.out.println(); + for (int i = 0; i < args.length && i < 20; i += 2) { + System.out.print(linksbuendigerString("x=" + args[i] + ",", + " ") + + linksbuendigerString(" y=" + args[i + 1] + ":", + " ")); + for (Iterator itr = result.iterator(); itr + .hasNext();) { + RegressionResult res = itr.next(); + if (res != null) + System.out + .print(linksbuendigerString( + " " + + roundSignificant( + res.approxFunction + .execute( + res.a, + res.b, + xyArr[i]), + SP), " ")); + } + System.out.println(); + } + if (args.length > 20) { + System.out.println("..."); + } + } + } + + public static SingleBTS extrapolateLogDL(List list, double x, + SingleBTS extrapolateThis, int sendingStrength) { + if (list == null || list.isEmpty()) { + return null; + } + double[] array = BTStoArrayDL(list, extrapolateThis, sendingStrength); + // log10: + RegressionResult result = calculatelog10arithmicRegression(array); + // linear: + // RegressionResult result = calculateLinearRegression(array); + double DL = result.approxFunction.execute(result.a, result.b, x); + + // add Signal Strenght back again + DL = DL + sendingStrength; + // if (DL < -115 || DL > -47 || Double.isNaN(DL)) + // return null; + if (Double.isNaN(DL)) + return null; + if (DL < -115) + DL = -115; + if (DL > -47) + DL = -47; + SingleBTS interpolated = new SingleBTS(extrapolateThis.ARFCN, 0, DL, + true, new Date(), extrapolateThis.name); + return interpolated; + + } + + /** + * + * @param list + * @param x + * @param extrapolateThis + * @param sendingStrength + * is SignalStrength from the cell phone: About 1 W and 2 dBi + * @return + */ + public static SingleBTS extrapolateLogUL(List list, double x, + SingleBTS extrapolateThis, int sendingStrength) { + if (list == null || list.isEmpty()) { + return null; + } + double[] array = BTStoArrayUL(list, extrapolateThis, sendingStrength); + if (array == null) { + return null; + } + // log10: + RegressionResult result = calculatelog10arithmicRegression(array); + // linear: + // RegressionResult result = calculateLinearRegression(array); + + if (result == null) { + return null; + } + double UL = result.approxFunction.execute(result.a, result.b, x); + // add the sendingStrength back on + UL = UL + sendingStrength; + if (Double.isNaN(UL)) + return null; + if (UL < -115) + UL = -115; + if (UL > -47) + UL = -47; + SingleBTS interpolated = new SingleBTS(extrapolateThis.ARFCN, UL, 0, + true, new Date(), extrapolateThis.name); + interpolated.fullBTS = true; + // interpolated.interpolated = true; + return interpolated; + + } + + /** + * + * @param list + * @param extrapolateThis + * @param sendingStrength + * is the Signalstrength in dB that the BTS sends (Antenna Gain + + * Amplifier + Power) + * @return + */ + private static double[] BTStoArrayDL(List list, + SingleBTS extrapolateThis, int sendingStrength) { + ArrayList array = new ArrayList(); + + // double[] array = new double[list.size() * 2]; + + for (int i = 0; i < list.size(); i++) { + SingleBTS currentElement = list.get(i); + if (currentElement != null + && currentElement.ARFCN == extrapolateThis.ARFCN) { + array.add(currentElement.distance); + array.add(currentElement.getDldB() - sendingStrength); + } + } + + double[] doublearray = new double[array.size()]; + + for (int i = 0; i < doublearray.length; i++) { + doublearray[i] = array.get(i); + } + return doublearray; + } + + private static double[] BTStoArrayUL(List list, + SingleBTS extrapolateThis, int sendingStrength) { + ArrayList array = new ArrayList(); + + for (int i = 0; i < list.size(); i++) { + SingleBTS currentElement = list.get(i); + if (currentElement != null + && currentElement.ARFCN == extrapolateThis.ARFCN) { + array.add(currentElement.distance); + array.add(currentElement.getUldB() - sendingStrength); + } + } + + double[] doublearray = new double[array.size()]; + for (int i = 0; i < doublearray.length; i++) { + doublearray[i] = array.get(i); + } + return doublearray; + } + + // Lineare Regression + // y = a + b * x + static RegressionResult calculateLinearRegression(double[] xyArr) { + if (xyArr == null || xyArr.length < 2 || xyArr.length % 2 != 0) + return null; + + int n = xyArr.length / 2; + double xs = 0; + double ys = 0; + double xqs = 0; + double yqs = 0; + double xys = 0; + + for (int i = 0; i < xyArr.length; i += 2) { + xs += xyArr[i]; + ys += xyArr[i + 1]; + xqs += xyArr[i] * xyArr[i]; + yqs += xyArr[i + 1] * xyArr[i + 1]; + xys += xyArr[i] * xyArr[i + 1]; + } + + RegressionResult abr = new RegressionResult(); + double xm = xs / n; + double ym = ys / n; + double xv = xqs / n - (xm * xm); + double yv = yqs / n - (ym * ym); + double kv = xys / n - (xm * ym); + abr.rr = Math.min((kv * kv) / (xv * yv), 1); + abr.b = kv / xv; + abr.a = ym - abr.b * xm; + abr.titel = "Lin"; + abr.formel = "y = " + roundSignificant(abr.a, SP) + " + " + + roundSignificant(abr.b, SP) + " * x"; + abr.approxFunction = new ApproxFunction() { + public double execute(double a, double b, double x) { + return a + b * x; + } + }; + + return abr; + } + + // Potenzielle Regression + // y = a * x^b + // Regression ueber: ln(y) = ln(a) + b * ln(x) + static RegressionResult calculatePowerRegression(double[] xyArr) { + if (xyArr == null || xyArr.length < 2 || xyArr.length % 2 != 0) + return null; + + double[] xyArrConv = new double[xyArr.length]; + + for (int i = 0; i < xyArr.length; i += 2) { + if (xyArr[i] <= 0 || xyArr[i + 1] <= 0) + return null; + xyArrConv[i] = Math.log10(xyArr[i]); + xyArrConv[i + 1] = Math.log10(xyArr[i + 1]); + } + + RegressionResult abr = calculateLinearRegression(xyArrConv); + if (abr == null) + return null; + abr.a = Math.exp(abr.a); + abr.titel = "Pow"; + abr.formel = "y = " + roundSignificant(abr.a, SP) + " * x ^ " + + roundSignificant(abr.b, SP); + abr.approxFunction = new ApproxFunction() { + public double execute(double a, double b, double x) { + return a * Math.pow(x, b); + } + }; + + return abr; + } + + // log10arithmische Regression + // y = a + b * ln(x) + public static RegressionResult calculatelog10arithmicRegression( + double[] xyArr) { + if (xyArr == null || xyArr.length < 2 || xyArr.length % 2 != 0) + return null; + + double[] xyArrConv = new double[xyArr.length]; + + for (int i = 0; i < xyArr.length; i += 2) { + if (xyArr[i] <= 0) + return null; + xyArrConv[i] = Math.log10(xyArr[i]); + xyArrConv[i + 1] = xyArr[i + 1]; + } + + RegressionResult abr = calculateLinearRegression(xyArrConv); + if (abr == null) + return null; + abr.titel = "log10"; + abr.formel = "y = " + roundSignificant(abr.a, SP) + " + " + + roundSignificant(abr.b, SP) + " * ln(x)"; + abr.approxFunction = new ApproxFunction() { + public double execute(double a, double b, double x) { + return a + b * Math.log10(x); + } + }; + + return abr; + } + + // Exponentielle Regression + // y = a * e^(b * x) + // Regression ueber: ln(y) = ln(a) + b * x + static RegressionResult calculateExponentialRegression(double[] xyArr) { + if (xyArr == null || xyArr.length < 2 || xyArr.length % 2 != 0) + return null; + + double[] xyArrConv = new double[xyArr.length]; + + for (int i = 0; i < xyArr.length; i += 2) { + if (xyArr[i + 1] <= 0) + return null; + xyArrConv[i] = xyArr[i]; + xyArrConv[i + 1] = Math.log10(xyArr[i + 1]); + } + + RegressionResult abr = calculateLinearRegression(xyArrConv); + if (abr == null) + return null; + abr.a = Math.exp(abr.a); + abr.titel = "Exp"; + abr.formel = "y = " + roundSignificant(abr.a, SP) + " * e ^ (" + + roundSignificant(abr.b, SP) + " * x)"; + abr.approxFunction = new ApproxFunction() { + public double execute(double a, double b, double x) { + return a * Math.exp(b * x); + } + }; + + return abr; + } + + // Gespiegelte und verschobene exponentielle Regression + // y = a * ( 1 - e^(-b * x) ) + // Approximationsfunktion beginnt bei 0 und strebt gegen den Grenzwert + // "limit". + // Falls "limit" nicht bekannt ist: Iterativ naehern. + static RegressionResult calculateOneMinusExponentialRegression( + double[] xyArr, double limit) { + double[] xyArrTest = new double[xyArr.length]; + + for (int i = 0; i < xyArr.length; i += 2) { + xyArrTest[i] = -xyArr[i]; + xyArrTest[i + 1] = limit - xyArr[i + 1]; + } + + RegressionResult abr = calculateExponentialRegression(xyArrTest); + if (abr == null) + return null; + abr.a = limit; + return abr; + } + + // Gespiegelte und verschobene exponentielle Regression + // y = a * ( 1 - e^(-b * x) ) + // Approximationsfunktion beginnt bei 0 und strebt gegen den Grenzwert + // "limit". + static RegressionResult calculateOneMinusExponentialRegression( + double[] xyArr) { + final double INCR_FACTOR = 1.001; + double yMax = 0; + if (xyArr == null || xyArr.length < 2 || xyArr.length % 2 != 0) + return null; + + for (int i = 1; i < xyArr.length; i += 2) + yMax = Math.max(yMax, xyArr[i]); + + double lim = searchMaximumFromFunctionFromX(yMax, INCR_FACTOR, xyArr, + new FunctionFromX() { + public double execute(double x, Object helpObject) { + RegressionResult abr = calculateOneMinusExponentialRegression( + (double[]) helpObject, x); + if (abr == null) + return 0; + return abr.rr; + } + }); + + RegressionResult abr = calculateOneMinusExponentialRegression(xyArr, + lim); + + if (abr == null) + return null; + abr.titel = "1_E"; + abr.formel = "y = " + roundSignificant(abr.a, SP) + " * ( 1 - e ^ (-" + + roundSignificant(abr.b, SP) + " * x) )"; + abr.approxFunction = new ApproxFunction() { + public double execute(double a, double b, double x) { + return a * (1 - Math.exp(-b * x)); + } + }; + + return abr; + } + + // Suche den x-Wert fuer den die "FunctionFromX" ein Maximum hat + static double searchMaximumFromFunctionFromX(double xStart, + double incrFactor, Object helpObject, FunctionFromX functionFromX) { + double x1, x2, xTest; + double y1, y2, yTest; + + x1 = x2 = xTest = xStart; + y1 = y2 = yTest = functionFromX.execute(xTest, helpObject); + + for (int i = 0; i < 1000000; i++) { + xTest *= incrFactor; + yTest = functionFromX.execute(xTest, helpObject); + if (yTest < y1) { + x1 = xTest; + y1 = yTest; + break; + } + x2 = x1; + x1 = xTest; + y2 = y1; + y1 = yTest; + } + + for (int i = 0; i < 1000000; i++) { + xTest = (x1 + x2) / 2; + yTest = functionFromX.execute(xTest, helpObject); + if (y2 >= y1) { + x1 = xTest; + y1 = yTest; + } else { + x2 = xTest; + y2 = yTest; + } + if (i > 10 && Math.abs(y2 - y1) < 1.0E-12) { + break; + } + } + + return xTest; + } + + private static double[] convertStringArrToDoubleArr(String[] strArr) { + if (strArr == null || strArr.length <= 0) + return null; + + double[] dblArr = new double[strArr.length]; + + for (int i = 0; i < strArr.length; i++) { + strArr[i] = strArr[i].replace(',', '.'); + dblArr[i] = Double.parseDouble(strArr[i]); + } + + return dblArr; + } + + private static double roundSignificant(double d, int significantPrecision) { + if (d == 0 || significantPrecision < 1 || significantPrecision > 14) + return d; + double mul10 = 1; + double minVal = Math.pow(10, significantPrecision - 1); + while (Math.abs(d) < minVal) { + mul10 *= 10; + d *= 10; + } + return Math.round(d) / mul10; + } + + private static String linksbuendigerString(String s, + String fillStrWithWantLen) { + if (s != null) { + int len = s.length(); + if (len < fillStrWithWantLen.length()) { + return (s + fillStrWithWantLen).substring(0, + fillStrWithWantLen.length()); + } + } + return s; + } + + static class RegressionResult { + double a; + double b; + double rr; + String titel; + String formel; + ApproxFunction approxFunction; + } + + interface ApproxFunction { + double execute(double a, double b, double x); + } + + interface FunctionFromX { + double execute(double x, Object helpObject); + } +} \ No newline at end of file diff --git a/helper/FunctionFit.java b/helper/FunctionFit.java new file mode 100644 index 0000000..4fcf88e --- /dev/null +++ b/helper/FunctionFit.java @@ -0,0 +1,91 @@ +package helper; + +import DataStructure.GSMMap; +import DataStructure.SingleBTS; + +/** + * Fits GSM receive strength to youngs model at 1.8GHz + * + * @author richy + * + */ +public class FunctionFit { + final static double log1800 = (float) Math.log10(1800); + + /** + * @param type + * 0-2 for open, suburban, city. If type is not in range 0...2, + * zero is returned + * @return Hata Model Parameter K for 1800MHz (precomputed) + */ + @SuppressWarnings("unused") + private static double C(int type) { + // Parameter at the end of extendet Hata Model + switch (type) { + case 0: + return 31.924; + case 1: + return 11.9386; + default: + return 0; + } + } + + /** + * Returns value a(h) of the Hata Model. Use this when calculating DL + * (Signal from BTS to MS) + * + * @param suburban + * false, if surrounding is open or with medium buildings. True + * if buildings > 15m exits + * @param ms_height + * height of mobile station antenna (typically around 1.6m) + * @return value for a(h2), partly pre computed + */ + private static double a_DL(boolean suburban, double ms_height) { + if (suburban) { + return ((1.1 * log1800 - 0.7) * ms_height - (1.56 * log1800 - 0.8)); + } else { + return 3.2 * Math.pow(Math.log10(11.75 * ms_height), 2) - 4.97; + } + + } + + /** + * Returns value a(h) of the Hata Model. Use this when calculating UL + * (Signal from MS to BTS) + * + * @param suburban + * false, if surrounding is open or with medium buildings. True + * if buildings > 15m exits + * @param ms_height + * height of mobile station antenna (typically around 1.6m) + * @return value for a(h2), partly pre computed + */ + private static double a_UL(boolean suburban, double bts_height) { + return a_DL(suburban, bts_height); + } + + public static double do_fit(boolean DL, double receive1, double receive2, + double receive3) { + + return 0.0; + } + + public static boolean try_extrapolation(GSMMap map, SingleBTS arfcn, int x, + int y) { + if (ListBTS.contains(map.map[x][y], arfcn)) { + // check if uplink can be extrapolated + if (ListBTS.containsUL(map.map[x][y], arfcn)) { + // nothing todo. map[x][y] contains DL and UL + } else { + // upload is missing. Try Interpolation here. BTS element + // already exists + } + + } else { + // try Interpolation SingleBTS object does not exist + } + return false; + } +} diff --git a/helper/LMfunc.java b/helper/LMfunc.java new file mode 100644 index 0000000..dc16381 --- /dev/null +++ b/helper/LMfunc.java @@ -0,0 +1,37 @@ +// LMfunc.java + +package helper; + +/** + * Caller implement this interface to specify the function to be minimized and + * its gradient. + * + * Optionally return an initial guess and some test data, though the LM.java + * only uses this in its optional main() test program. Return null if these are + * not needed. + */ +public interface LMfunc { + + /** + * x is a single point, but domain may be mulidimensional + */ + double val(double[] x, double[] a); + + /** + * return the kth component of the gradient df(x,a)/da_k + */ + double grad(double[] x, double[] a, int ak); + + /** + * return initial guess at a[] + */ + double[] initial(); + + /** + * return an array[4] of x,a,y,s for a test case; a is the desired final + * answer. + */ + Object[] testdata(); + +} // LMfunc + diff --git a/helper/ListBTS.java b/helper/ListBTS.java new file mode 100644 index 0000000..dac45b0 --- /dev/null +++ b/helper/ListBTS.java @@ -0,0 +1,300 @@ +package helper; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; + +import DataStructure.SingleBTS; + +public class ListBTS { + + /** + * + * @param list + * Where to search + * @param arfcn + * which BTS to search + * @return false if BTS not found or list or arfcn is null or empty. True if + * BTS is found + */ + public static boolean contains(List list, SingleBTS arfcn) { + return contains(list, arfcn.ARFCN); + } + + public static boolean contains(List list, int arfcn) { + if (list == null || list.isEmpty()) { + return false; + } + if (list instanceof LinkedList) { + ListIterator itr = list.listIterator(); + while (itr.hasNext()) { + SingleBTS element = itr.next(); + if (element.ARFCN == arfcn) + return true; + } + } else { + for (int i = list.size() - 1; i >= 0; i--) { + if (list.get(i).ARFCN == arfcn) { + return true; + } + } + } + + return false; + } + + public static boolean containsUL(List list, SingleBTS arfcn) { + for (SingleBTS current : list) { + if (current.ARFCN == arfcn.ARFCN && current.fullBTS) + return true; + } + return false; + } + + public static int countDL(LinkedList list, SingleBTS arfcn) { + int count = 0; + for (SingleBTS current : list) { + if (current != null && current.ARFCN == arfcn.ARFCN) + count++; + } + return count; + } + + public static int countUL(LinkedList list, SingleBTS arfcn) { + int count = 0; + for (SingleBTS current : list) { + if (current != null && current.fullBTS + && current.ARFCN == arfcn.ARFCN) + count++; + } + return count; + } + + /** + * Searches the list for the _first_ BTS with same arfcn. Removes it from + * that list and returns the element + * + * @param list + * from which to search + * @param arfcn + * MR with ARFCN you search for + * @return Element from list that got deleted. Null if element is not + * present in list + */ + public static SingleBTS removeARFCN(List list, SingleBTS arfcn) { + return removeARFCN(list, arfcn.ARFCN); + } + + public static SingleBTS removeARFCN(List list, int arfcn) { + ListIterator itr = list.listIterator(); + while (itr.hasNext()) { + SingleBTS element = itr.next(); + if (element.ARFCN == arfcn) { + itr.remove(); + return element; + } + } + return null; + } + + /** + * Gets the first occurence of the specified arfcn from the list. Element + * stays in list + * + * @param list + * the list from where to extract the BTS + * @param arfcn + * arfcn to extract + * @return first SingleBTS that matches from the list. Null if Element is + * not present + */ + public static SingleBTS getARFCN(List list, SingleBTS arfcn) { + if (list == null || arfcn == null) { + return null; + } + for (int i = 0; i < list.size(); i++) { + if (list.get(i).ARFCN == arfcn.ARFCN) { + return list.get(i); + } + } + return null; + } + + public static ArrayList getAllARFCN(ArrayList list, + int arfcn) { + if (list == null || list.isEmpty()) { + return null; + } + boolean aHitWasFound = false; + ArrayList result = new ArrayList(); + for (int i = 0; i < list.size(); i++) { + if (list.get(i).ARFCN == arfcn) { + result.add(list.get(i)); + aHitWasFound = true; + } + } + if (aHitWasFound) + return result; + else + return null; + } + + /** + * Gets the first occurence of the specified arfcn from the list. Element + * stays in list + * + * @param list + * the list from where to extract the BTS + * @param arfcn + * arfcn to extract + * @return first SingleBTS that matches from the list. Null if Element is + * not present + */ + public static SingleBTS getARFCN(List list, int arfcn) { + for (int i = 0; i < list.size(); i++) { + if (list.get(i).ARFCN == arfcn) { + return list.get(i); + } + } + return null; + } + + /** + * Takes a list. Returns a copy of that list without null-elements + * + * @param list + * ListBTS where all elements with null will be filtered out + * @return a copy of this list without null-elements. Null if the whole list + * is null + */ + public static ArrayList removeNullElements(List list) { + if (list == null) + return null; + ArrayList list2 = new ArrayList(); + boolean element_present = false; + for (SingleBTS element : list) { + if (element != null) { + element_present = true; + list2.add(element); + } + } + if (element_present) + return list2; + else + return null; + } + + /** + * 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 + */ + public static SingleBTS[] content(List list) { + // get first element of list. + // traverse list and delete every occurence of first element + // get next element + // copy list to destroy reference + LinkedList list2 = new LinkedList(list); + if (list2.isEmpty()) + return null; + // int count = 0; + LinkedList output = new LinkedList(); + while (!list2.isEmpty()) { + SingleBTS bts = list2.getFirst(); + list2.removeFirst(); + output.add(bts); + // remove the just added bts from the BTS-list + // speedup with listiterator + /* + * for (int i = 0; i < list2.size(); i++) { if (list2.get(i).ARFCN + * == bts.ARFCN) { list2.remove(i); i--; } + */ + ListIterator itr = list2.listIterator(); + SingleBTS testelement; + while (itr.hasNext()) { + testelement = itr.next(); + if (testelement.ARFCN == bts.ARFCN) { + // same element found. Delete it + itr.remove(); + // if we are on the first element, itr.previous will throw + // an exception. Just ignore it and go on + try { + itr.previous(); + } catch (Exception e) { + + } + } + + } + + } + return output.toArray(new SingleBTS[1]); + } + + /** + * Takes two lists. Merges missing parameters. Interpolated BTS will be + * overwritten by real measurements. NOT IMPLEMENTED!!!! + * + * @param list1 + * @param list2 + * @return + */ + public static LinkedList addMissing(LinkedList list1, + LinkedList list2) { + // LinkedList result = new LinkedList(); + if ((list1 == null && list2 != null)) { + return list2; + } + if (list1 != null && list2 == null) { + return list1; + } + if (list1.isEmpty() && !list2.isEmpty()) { + return list2; + } + if (!list1.isEmpty() && list2.isEmpty()) { + return list1; + } + + // for (SingleBTS element1 : list1) { + // for (SingleBTS element2 : list2) { + // TODO: Code here! + // } + // } + return null; + } + + /** + * Takes all BTS with same arfcn and adds the Measurements together + * + * @param List + * @param content + * @return + */ + public static 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; + } + + public static ArrayList generateAveragedList( + ArrayList List) { + SingleBTS[] content = content(List); + return generateAveragedList(List, content); + } + +} diff --git a/helper/ListGPS.java b/helper/ListGPS.java new file mode 100644 index 0000000..79b383a --- /dev/null +++ b/helper/ListGPS.java @@ -0,0 +1,191 @@ +package helper; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import DataStructure.GPScoordinate; + +public class ListGPS { + + /** + * Get the intersection between both lists. That is, if one coordinate is in + * both lists. add this coordinate to the returning set. + * + * @param list1 + * @param list2 + * @param threshold_dB + * when both coordinates are less than threshold_dB meters away, + * they count as identical. Threshold may be 0. Then only + * identical coordinates get used + * @return + */ + public static LinkedList intersect( + LinkedList list1, LinkedList list2, + int threshold) { + LinkedList result = new LinkedList(); + if (list1 == null || list2 == null) + return result; + if (threshold == 0) { + for (GPScoordinate element1 : list1) { + if ((contains(list2, element1)) && !contains(result, element1)) { + result.add(element1); + } + } + return result; + } else { + for (GPScoordinate element1 : list1) { + result.addAll(getSimilarValues(list2, element1, threshold)); + + } + // remove null elements + result = removeNullElements(result); + // remove duplicate entries + GPScoordinate[] resultarray = content(result); + // clear result to reuse it + result = new LinkedList(); + if (resultarray == null) + return null; + for (int i = 0; i < resultarray.length; i++) { + result.add(resultarray[i]); + } + return result; + } + } + + /** + * + * @param list + * where to search + * @param point + * get elements near to that point + * @param threshold_dB + * how far in meters may elements be away from the point + * @return LinkedList of elements near point. Every element is only added + * once + */ + public static LinkedList getSimilarValues( + LinkedList list, GPScoordinate point, int threshold) { + if (list == null || list.isEmpty() || point == null) + return new LinkedList(); + LinkedList result = new LinkedList(); + for (GPScoordinate element : list) { + if (Distance.calc(point, element) * 1000 < threshold + && !contains(result, element)) { + result.add(element); + + } + } + + return null; + + } + + public static LinkedList intersect( + LinkedList> nestedlist) { + LinkedList result = new LinkedList(); + if (nestedlist.isEmpty()) + return null; + if (nestedlist.size() == 1) + return nestedlist.getFirst(); + // nestedlist has at least 2 elements. do intersect with both. Store in + // list. remove null elements first + nestedlist.add(removeNullElements(nestedlist.removeLast())); + nestedlist.addFirst(removeNullElements(nestedlist.removeFirst())); + result.addAll(intersect(nestedlist.removeFirst(), + nestedlist.removeLast(), 0)); + // now do intersect with the rest. This could get a speedup by using + // pairwise intersection. would be O(log n) then. + while (!nestedlist.isEmpty()) { + nestedlist.addFirst(removeNullElements(nestedlist.removeFirst())); + result = intersect(result, nestedlist.removeFirst(), 0); + } + return result; + } + + public static GPScoordinate[] content(List list) { + // get clone. Not just reference/pointer + if (list == null || list.isEmpty()) + return null; + ArrayList list2 = new ArrayList(list); + // int count = 0; + LinkedList output = new LinkedList(); + while (!list2.isEmpty()) { + GPScoordinate gps = list2.get(0); + list2.remove(0); + output.add(gps); + // remove the just added bts from the GPS-list + for (int i = 0; i < list2.size(); i++) { + if (list2.get(i).equals(gps)) { + // remove every element in the list that is the same as the + // first + list2.remove(i); // WARNING: this is slow! Do it with list + // and iterator + i--; + } + + } + + } + return output.toArray(new GPScoordinate[1]); + + } + + /** + * true if list contains element (that is, coord1 and coord2 are identical) + * + * @param list + * @param element + * @return + */ + public static boolean contains(LinkedList list, + GPScoordinate element) { + if (element == null || list == null || list.isEmpty()) + return false; + for (GPScoordinate current : list) { + if (current.equals(element)) + return true; + } + return false; + } + + /** + * Takes a list. Returns a copy of that list without null-elements + * + * @param list + * ListBTS where all elements with null will be filtered out + * @return a copy of this list without null-elements. Null if the whole list + * is null + */ + public static LinkedList removeNullElements( + LinkedList list) { + if (list == null) + return null; + LinkedList list2 = new LinkedList(); + boolean element_present = false; + for (GPScoordinate element : list) { + if (element != null) { + element_present = true; + list2.add(element); + } + } + if (element_present) + return list2; + else + return null; + } + + public static LinkedList> removeAllNullElements( + LinkedList> nestedlist) { + LinkedList> result = new LinkedList>(); + java.util.Iterator> itr = result.iterator(); + while (itr.hasNext()) { + LinkedList intermediate = itr.next(); + intermediate = removeNullElements(intermediate); + if (intermediate != null && !intermediate.isEmpty()) + result.add(intermediate); + } + return result; + } + +} diff --git a/helper/Polygons.java b/helper/Polygons.java new file mode 100644 index 0000000..9d3c6ad --- /dev/null +++ b/helper/Polygons.java @@ -0,0 +1,34 @@ +package helper; + +import java.awt.Polygon; + +public class Polygons { + public static double area(Polygon poly) { + double area = 0; + // make list out of polygon. see + // http://anklick-bar.de/matheprojekt/kurbel-gauss.pdf + Point[] list = new Point[poly.npoints + 2]; + + for (int i = 0; i < poly.npoints; i++) { + list[i] = new Point(poly.xpoints[i], poly.ypoints[i]); + } + list[poly.npoints] = new Point(poly.xpoints[0], poly.ypoints[0]); + list[poly.npoints + 1] = new Point(poly.xpoints[1], poly.ypoints[1]); + for (int i = 1; i <= poly.npoints; i++) { + // area of polygon is left to the line + area = area + (list[i + 1].y - list[i - 1].y) * list[i].x; + } + return area * (-1); + + } +} + +class Point { + int x; + int y; + + public Point(int x, int y) { + this.x = x; + this.y = y; + } +} diff --git a/lookup/BTSLut.java b/lookup/BTSLut.java new file mode 100644 index 0000000..6abfcb8 --- /dev/null +++ b/lookup/BTSLut.java @@ -0,0 +1,200 @@ +package lookup; + +import helper.ListGPS; + +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; + +import DataStructure.GPScoordinate; +import DataStructure.GSMMap; +import DataStructure.SingleBTS; + +/** + * No longer used! + * + * @author richy + * + */ +public class BTSLut implements ILut { + private LinkedList[] possible_coords_DL = new LinkedList[69]; + private LinkedList[] possible_coords_UL = new LinkedList[69]; + public int bts; // which bts does this Object store + public int threshold_dB; + public int threshold_m; + + /** + * create empty LUT + * + * @param ARFCN + * set BTS-ARFCN this object will take measurements and requests + */ + public BTSLut(int ARFCN, int threshold_dB, int threshold_m) { + this.bts = ARFCN; + this.threshold_dB = threshold_dB; + this.threshold_m = threshold_m; + // initialize strength array: -47 ... -115 + for (int i = 0; i < 69; i++) { + possible_coords_DL[i] = new LinkedList(); + possible_coords_UL[i] = new LinkedList(); + } + + } + + public BTSLut(int ARFCN, GSMMap map, int threshold, int threshold_m) { + this.bts = ARFCN; + this.threshold_dB = threshold; + this.threshold_m = threshold_m; + for (int i = 0; i < 69; i++) { + possible_coords_DL[i] = new LinkedList(); + possible_coords_UL[i] = new LinkedList(); + } + // fill the LUT + for (int x = 0; x < map.Xcoords.length; x++) { + for (int y = 0; y < map.Ycoords.length; y++) { + fill(map.getCoord(x, y), map.map[x][y]); + } + } + + } + + @Override + public LinkedList get(SingleBTS MR) { + // hier muss noch das threshold_dB berücksichtigt werden! + if (MR == null) + return null; + LinkedList result = new LinkedList(); + for (int i = threshold_dB * (-1); i <= threshold_dB; i++) { + try { + if (MR.fullBTS && MR.getDLcount() > 0) { + // get coords for DL and UL and do a intersection + // fix: do no intersection + LinkedList listUL = new LinkedList(); + LinkedList listDL = new LinkedList(); + listUL = possible_coords_UL[getIndex(MR.getUldB() + + threshold_dB)]; + listDL = possible_coords_DL[getIndex(MR.getDldB() + + threshold_dB)]; + listUL = ListGPS.removeNullElements(listUL); + listDL = ListGPS.removeNullElements(listDL); + // result.addAll(helper.ListGPS.intersect(listDL, + // listUL,threshold_m)); + result.addAll(listUL); + result.addAll(listDL); + } else { + result.addAll(possible_coords_DL[(getIndex(MR.getDldB() + + threshold_dB))]); + } + } catch (Exception e) { + // only index out of bound... ignore + + } + } + return result; + + } + + /** + * Takes list. Returns the lookup. Result is the intersection between all + * SingleBTSs in MR. That is, only Coordinates that are in common are + * returned + */ + + @SuppressWarnings("unused") + public LinkedList get(List MR) { + // create result list for each function call + LinkedList list = new LinkedList(); + // create a nested-linked-list in order to compute the intersection + LinkedList> nestedlist = new LinkedList>(); + + // one list for all + LinkedList resultset = new LinkedList(); + + ListIterator itr = MR.listIterator(); + while (itr.hasNext()) { + SingleBTS current = itr.next(); + resultset.addAll(get(current)); + } + if (true) + return resultset; + + for (SingleBTS current : MR) { + // clear list + list = new LinkedList(); + // save results in that list. do that list into the list-list + list.addAll(get(current)); + list = ListGPS.removeNullElements(list); + if (list != null && !list.isEmpty()) + nestedlist.addLast(list); + } + + // ------- + // from here on only calculating intersect + // ------- + + // reuse list. take it to store final result + nestedlist = ListGPS.removeAllNullElements(nestedlist); + if (list != null) + list.clear(); + if (nestedlist == null || nestedlist.isEmpty()) + return null; + if (nestedlist.size() == 1) + return nestedlist.getFirst(); + // nestedlist has at least 2 elements. do intersect with both. Store in + // list. + list.addAll(ListGPS.intersect(nestedlist.removeFirst(), + nestedlist.removeLast(), threshold_m)); + // now do intersect with the rest. This could get a speedup by using + // pairwise intersection. would be O(log n) then. + while (!nestedlist.isEmpty()) { + list = ListGPS.intersect(list, nestedlist.removeFirst(), + threshold_m); + } + // TODO: only null elements are here! + return list; + + } + + /** + * Returns index where the strength (dBm) is stored in the array + * + * @param strength + * . Gets rounded + * @return + */ + private int getIndex(double strength) { + int rounded = (int) Math.round(strength); + // this could be done with math.abs + if (strength < 0) { + return -47 - rounded; + } else { + return rounded - 47; + } + + } + + @Override + public void fill(GPScoordinate where, SingleBTS what) { + if (what == null || what.ARFCN != bts) + return; + int hit = 0; + if (what.getDldB() != 0) { + hit = getIndex(what.getDldB()); + possible_coords_DL[hit].add(where); + } + if (what.getUldB() != 0) { + hit = getIndex(what.getUldB()); + possible_coords_UL[hit].add(where); + } + + } + + public void fill(GPScoordinate where, List what) { + if (what == null) + return; + for (SingleBTS current : what) { + fill(where, current); + } + } + +} diff --git a/lookup/GSMLut.java b/lookup/GSMLut.java new file mode 100644 index 0000000..7b87001 --- /dev/null +++ b/lookup/GSMLut.java @@ -0,0 +1,88 @@ +package lookup; + +import helper.ListGPS; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; + +import DataStructure.GPScoordinate; +import DataStructure.GSMMap; +import DataStructure.SingleBTS; + +/** + * Throw in one or more MR (BTS-list). Get Score Element with possible + * Coordinates. This GSMLut uses ScoreElements to represent coordinates and + * their possibility. NOT USED!!!! + * + * @author richy + * + */ +public class GSMLut { + // private GSMMap map; + private SingleBTS[] content; + private ArrayList lookups = new ArrayList(); + + /** + * Create inverse of map + * + * @param map + * GSMmap to use + */ + public GSMLut(GSMMap map) { + // this.map = map; + content = map.getUniqueBTSlist(); // check if content also contains + // E-Plus arfcn! + for (SingleBTS current : content) { + // create a LUT for every BTS + lookups.add(new BTSLut(current.ARFCN, map, 20, 20)); + // traverse the whole GSMmap, add values to BTSLut + } + + } + + public LinkedList find(List MR) { + // traverse lookups. Build result array + // LinkedList> set = new + // LinkedList>(); + LinkedList set = new LinkedList(); + for (ILut lut : lookups) { + set.addAll(lut.get(MR)); + // set.add(lut.get(MR)); + } + // no intersect + // return ListGPS.intersect(set); + return set; + } + + /** + * Returns Score Elements. No intersect is done. Only common Coordinates are + * counted. This should be a better way to start! + * + * @param MR + * @return + */ + public LinkedList findWithScore(List MR) { + LinkedList resultset = find(MR); + // get unique coords + GPScoordinate[] unique = ListGPS.content(resultset); + ArrayList scores = new ArrayList( + unique.length); + for (GPScoordinate coord : unique) { + scores.add(new ScoreElement(coord)); + } + // score elements are initialized. traverse the whole result set now + ListIterator itr = resultset.listIterator(); + for (int i = 0; i < scores.size(); i++) { + while (itr.hasNext()) { + + } + // reset itr + } + + return null; + + } + +} diff --git a/lookup/ILut.java b/lookup/ILut.java new file mode 100644 index 0000000..854f5e3 --- /dev/null +++ b/lookup/ILut.java @@ -0,0 +1,18 @@ +package lookup; + +import java.util.LinkedList; +import java.util.List; + +import DataStructure.GPScoordinate; +import DataStructure.SingleBTS; + +interface ILut { + int bts = 0; + + public LinkedList get(SingleBTS MR); + + public void fill(GPScoordinate where, SingleBTS what); + + public LinkedList get(List MR); + +} diff --git a/lookup/RatioLut.java b/lookup/RatioLut.java new file mode 100644 index 0000000..9ead05e --- /dev/null +++ b/lookup/RatioLut.java @@ -0,0 +1,41 @@ +package lookup; + +import java.util.LinkedList; +import java.util.List; + +import DataStructure.GPScoordinate; +import DataStructure.SingleBTS; + +/** + * there should be as many RatioLuts as there are entries in arfcn table. For + * every OpenBSC BTS one! + * + * @author richy + * + */ +public class RatioLut implements ILut { + public int bts; // to where are the ratios calculated + + public RatioLut(int ARFCN) { + this.bts = ARFCN; + } + + @Override + public LinkedList get(SingleBTS MR) { + // TODO Auto-generated method stub + return null; + } + + @Override + public void fill(GPScoordinate where, SingleBTS what) { + // TODO Auto-generated method stub + + } + + @Override + public LinkedList get(List MR) { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/lookup/ResultScore.java b/lookup/ResultScore.java new file mode 100644 index 0000000..2044fda --- /dev/null +++ b/lookup/ResultScore.java @@ -0,0 +1,101 @@ +//OUTDATED: no longer used: 06.06.2011 + +package lookup; + +import helper.ListBTS; +import helper.ListGPS; + +import java.util.ArrayList; +import java.util.List; + +import DataStructure.GPScoordinate; +import DataStructure.GSMMap; +import DataStructure.SingleBTS; + +public class ResultScore { + ArrayList scores = new ArrayList(); + GSMMap map; + + /** + * Gets score for every Coordinate + * + * @param list + */ + public ResultScore(GSMMap map) { + this.map = map; + + } + + public ArrayList find(List MR, double thresholdDBm) { + // looks like threshold_dB has to be as high as 25dBm + ArrayList places = map.find(MR, thresholdDBm); + GPScoordinate[] content = ListGPS.content(places); + for (GPScoordinate curr_content : content) { + // take every Coordinate once. Build a ScoreElement with it.Traverse + // all found places + ScoreElement curr_score = new ScoreElement(curr_content); + for (GPScoordinate curr_place : places) { + // count how often this place got marked + curr_score.inc_occurence(curr_place); + } + scores.add(curr_score); + + // traverse every coordinate from gsm.find. check every tile if all + // mesurements match. if not, score gets low + + // then, check BTS relations! + + } + + // check scores. compare it with map + + // HACK: hardcoded ratio between 877 and 880 + for (int i = 0; i < scores.size(); i++) { + ScoreElement score_at_i = scores.get(i); + scores.set(i, ratioboost(score_at_i, MR)); + + } + + return scores; + } + + private ScoreElement ratioboost(ScoreElement place, List MR) { + // MR are the measured values during a call + // ArrayList list = map.getBTSList(place.gps); + // compare list with MR. Ratio between 877 and 880 + + while (ListBTS.contains(MR, 880) && ListBTS.contains(MR, 877)) { + SingleBTS r880 = ListBTS.removeARFCN(MR, 880); + SingleBTS r877 = ListBTS.removeARFCN(MR, 877); + if (r880.getDldB() > -46 || r877.getDldB() > -46) { + continue; + } + double ratio_MR = r880.getDldB() - r877.getDldB(); + // compare ratio with gsmmap. Get a number between 100 and 0 % + // double ratioscore = 0; // zero means absolutly no match + ArrayList maplist = map.getBTSList(place.gps); + // check if map has both BTS at this place + if (ListBTS.contains(maplist, 880) + && ListBTS.contains(maplist, 877)) { + double ratio_map = ListBTS.getARFCN(maplist, 880).getDldB() + - ListBTS.getARFCN(maplist, 877).getDldB(); + // calculate distance in % + if (ratio_MR >= ratio_map) { + place.occurrence += (ratio_map / ratio_MR * 100); + } else if (ratio_MR < ratio_map) { + place.occurrence += (ratio_MR / ratio_map * 100); + } + + } + + } + + return place; + } + +} + +class ratio { + SingleBTS first; + SingleBTS second; +} diff --git a/lookup/ScoreElement.java b/lookup/ScoreElement.java new file mode 100644 index 0000000..cd7dc09 --- /dev/null +++ b/lookup/ScoreElement.java @@ -0,0 +1,44 @@ +package lookup; + +import DataStructure.GPScoordinate; + +/** + * Saves a GPS coordinate from the Lookup. Also stores how often that coordinate + * was chosen or hit. + * + * @author richy + * + */ +public class ScoreElement implements Comparable { + public int occurrence; // how often was this coordinate chosen based on + // Signalstrength + public int ratio_hit; // how often was this coordinate chosen based on + // SignalRatio + public GPScoordinate gps; + private double score; // 0-1 + + public ScoreElement(GPScoordinate reference) { + gps = reference; + } + + public void inc_occurence(GPScoordinate gps) { + if (this.gps.equals(gps)) { + occurrence++; + } + + } + + public String toString() { + return ("Hits:" + occurrence + " Coord:" + gps.coord1 + "," + gps.coord2); + } + + public int compareTo(ScoreElement e) { + if (occurrence < e.occurrence) + return -1; + else if (occurrence > e.occurrence) + return 1; + else + return 0; + + } +} diff --git a/mysql-connector-java-5.1.14-bin.jar b/mysql-connector-java-5.1.14-bin.jar new file mode 100644 index 0000000..7ba8ee8 Binary files /dev/null and b/mysql-connector-java-5.1.14-bin.jar differ diff --git a/parallel-strictdB-BER.obj b/parallel-strictdB-BER.obj new file mode 100644 index 0000000..c10896a Binary files /dev/null and b/parallel-strictdB-BER.obj differ diff --git a/swingx-beaninfo.jar b/swingx-beaninfo.jar new file mode 100644 index 0000000..639814a Binary files /dev/null and b/swingx-beaninfo.jar differ diff --git a/swingx-ws.jar b/swingx-ws.jar new file mode 100644 index 0000000..aace70e Binary files /dev/null and b/swingx-ws.jar differ diff --git a/swingx.jar b/swingx.jar new file mode 100644 index 0000000..e656fcf Binary files /dev/null and b/swingx.jar differ diff --git a/testing/testsVar.java b/testing/testsVar.java new file mode 100644 index 0000000..32695d3 --- /dev/null +++ b/testing/testsVar.java @@ -0,0 +1,26 @@ +package testing; + +import DataStructure.SingleBTS; + +public class testsVar { + + /** + * @param args + */ + public static void main(String[] args) { + SingleBTS bts1 = new SingleBTS(123, "test"); + bts1.addDl(-75); + bts1.addDl(-78); + bts1.addDl(-73); + bts1.addDl(-80); + System.out.println("Varianz in mW:" + bts1.getVarianceDLmW()); + System.out.println("Varianz in dB:" + bts1.getVarianceDLdB()); + System.out.print("umrechnen:"); + double umrechnung = 0;// 10 * Math.log10(bts1.getVarianceDLmW()); + double var = bts1.getVarianceDLmW(); + umrechnung = Math.log(var / Math.pow(bts1.getDLmW(), 2) + 1); + System.out.println(umrechnung); + + } + +} diff --git a/voronoi/Classtest.java b/voronoi/Classtest.java new file mode 100644 index 0000000..9f13fde --- /dev/null +++ b/voronoi/Classtest.java @@ -0,0 +1,36 @@ +package voronoi; +class Parent { + public Parent() { + + } +} + +class Child extends Parent { + public Child() { + super(); + } +} + +public class Classtest { + public static void main(String[] a) { + Parent[] test = new Parent[3]; + test[0] = new Parent(); + test[1] = new Parent(); + test[2] = new Child(); + + int count = 0; + for (Parent parent : test) { + System.out.print("Index " + count + " is of type: "); + if (parent instanceof Child) { + System.out.println("Children"); + } + if (parent instanceof Parent) { + System.out.println("Parent"); + } + + count++; + + } + + } +} diff --git a/voronoi/CompGeom.java b/voronoi/CompGeom.java new file mode 100644 index 0000000..93dcafa --- /dev/null +++ b/voronoi/CompGeom.java @@ -0,0 +1,35 @@ +package voronoi; +import java.applet.Applet; +import java.awt.Button; +import java.awt.Color; +import java.awt.Event; +import java.awt.FlowLayout; + +public class CompGeom extends Applet { + private static final long serialVersionUID = 1L; + + private Button start; + + private CompGeomTest test; + + private int w, h; + + public void init() { + start = new Button("Voronoi/Delaunay Applet..."); + w = 900; + h = 550; + setLayout(new FlowLayout(FlowLayout.CENTER)); + setBackground(Color.lightGray); + add(start); + } + + public boolean action(Event e, Object o) { + if (e.target == start) { + test = new CompGeomTest(this); + test.setSize(w, h); + test.setResizable(false); + test.setVisible(true); + } + return true; + } +} diff --git a/voronoi/CompGeomTest.java b/voronoi/CompGeomTest.java new file mode 100644 index 0000000..ebad8a9 --- /dev/null +++ b/voronoi/CompGeomTest.java @@ -0,0 +1,132 @@ +package voronoi; +import java.applet.Applet; +import java.awt.AWTEvent; +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Checkbox; +import java.awt.Color; +import java.awt.Event; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Panel; + +public class CompGeomTest extends Frame { + private static final long serialVersionUID = 1L; + + private Button clear, close, simde, simvo; + private Checkbox hull, deltri, voronoi; + + private Panel subp1, subp022, subp2, subp3, p,canvasp; + private GeomCanvas c; + + private int cw, ch; // width and height for info frame and canvas + + private Font f; + + public CompGeomTest(Applet a) { + super("COSC 6114 Computational Geometry - Zhenyu Pan"); + setBackground(Color.lightGray); + + // cw = Integer.parseInt(a.getParameter("canvas width")); + cw = 750; + // ch = Integer.parseInt(a.getParameter("canvas height")); + ch = 550; + + clear = new Button("Clear Screen"); + close = new Button("Close Window"); + simde = new Button("Simulation Delaunay"); + simvo = new Button("Simulation Voronoi"); + hull = new Checkbox("Show Convex Hull"); + deltri = new Checkbox("Show Delaunay"); + voronoi = new Checkbox("Show Voronoi"); + + subp1 = new Panel(); + subp1.setLayout(new BorderLayout()); + subp1.add("Center",clear); + subp1.add("South",close); + + subp022 = new Panel(); + subp022.setLayout(new BorderLayout()); + subp022.add("Center",simde); + subp022.add("South",simvo); + + subp3 = new Panel(); + subp3.setLayout(new BorderLayout()); + subp3.add("North",hull); + subp3.add("Center",deltri); + subp3.add("South",voronoi); + + subp2 = new Panel(); + subp2.setLayout(new BorderLayout()); + subp2.add("North", subp1); + subp2.add("Center", subp022); + subp2.add("South", subp3); + + p = new Panel(); + p.setBackground(Color.lightGray); + p.setLayout(new BorderLayout()); + p.add("North", subp2); + + c = new GeomCanvas(cw, ch, this); + c.SetRegime("point"); + + canvasp = new Panel(); + canvasp.setLayout(new BorderLayout()); + canvasp.add("Center", c); + + setLayout(new BorderLayout()); + add("Center", canvasp); + add("East", p); + + } + + public boolean action(Event e, Object o) { + if (e.target instanceof Checkbox) { + Checkbox checkbox = (Checkbox) e.target; + if (e.target == hull) + c.ToCH(checkbox.getState()); + + if (e.target == deltri) { + c.ToDelTri(checkbox.getState()); + } + if (e.target == voronoi){ + c.ToVoronoi(checkbox.getState()); + } + } // end of instanceof Checkbox + + if (e.target instanceof Button) { + if (e.target == clear) { + c.ToBeCleared();// boolean variable + c.CoorClear(); + c.SetPaint(); + } + if (e.target == close) { + setVisible(false); + c.CoorClear(); + c.animator=null; + } + if (e.target == simde) { + c.SimDe();// boolean variabble + } + + if (e.target == simvo) { + c.SimVo(); + } + } + return true; + } + + public void processevent(AWTEvent e) { + if (e.getID() == Event.WINDOW_DESTROY) { + setVisible(false); + dispose(); + return; + } + super.processEvent(e); + } + + public void resetBLabel(Button bprev) { + bprev.setFont(f); + } + +} diff --git a/voronoi/ConvexHull2D.java b/voronoi/ConvexHull2D.java new file mode 100644 index 0000000..05cc07d --- /dev/null +++ b/voronoi/ConvexHull2D.java @@ -0,0 +1,233 @@ +package voronoi; +import java.awt.Graphics; + +class ConvexHull2D { + + private cVertexList list, top; + + private int ndelete = 0; + + private int i = 0; + + public ConvexHull2D(cVertexList list) { + if (list == null) + return; + if (list.head == null) + return; + this.list = new cVertexList(); + cVertex v1 = new cVertex(list.head.v.x, list.head.v.y); + v1.vnum = list.head.vnum; + v1.mark = list.head.mark; + + while (i < list.n) { + cVertex v3 = new cVertex(list.GetElement(i).v.x, + list.GetElement(i).v.y); + v3.mark = list.GetElement(i).mark; + v3.vnum = list.GetElement(i).vnum; + + Push(v3, this.list); + i++; + } + } + + public void ClearHull() { + top = new cVertexList(); + + } + + public void RunHull() { + + // initialization: + cVertex v = list.head; + for (i = 0; i < list.n; i++) { + v.vnum = i; + v = v.next; + } + // + FindLowest(); + qsort(list); + if (ndelete > 0) + Squash(); + top = Graham(); + // top.PrintVertices(); + } + + private cVertexList Graham() { + cVertexList top; + int i; + top = new cVertexList(); + cVertex v1 = new cVertex(list.head.v.x, list.head.v.y); + v1.vnum = list.head.vnum; + v1.mark = list.head.mark; + + cVertex v2 = new cVertex(list.head.next.v.x, list.head.next.v.y); + v2.vnum = list.head.next.vnum; + v2.mark = list.head.next.mark; + + Push(v1, top); + Push(v2, top); + + // Bottom two elements will never be removed. + i = 2; + + while (i < list.n) { + cVertex v3 = new cVertex(list.GetElement(i).v.x, + list.GetElement(i).v.y); + v3.mark = list.GetElement(i).mark; + v3.vnum = list.GetElement(i).vnum; + + if (v1.v.Left(top.head.prev.v, top.head.prev.prev.v, v3.v)) { + Push(v3, top); + i++; + } else { + if (top.n > 2) { + Pop(top); + } + } + + } + + return top; + + } + + private void Squash() { + cVertex v = new cVertex(); + v = list.head; + for (i = 0; i < list.n; i++) { + if (v.mark) + list.Delete(v); + v = v.next; + } + } + + private void Sort(cVertexList a, int lo0, int hi0) { + if (lo0 >= hi0) { + return; + } + cVertex mid = new cVertex(); + mid = a.GetElement(hi0); + int lo = lo0; + int hi = hi0 - 1; + while (lo <= hi) { + while (lo <= hi + && ((Compare(a.GetElement(lo), mid) == 1) || (Compare(a + .GetElement(lo), mid) == 0))) { + lo++; + } + + while (lo <= hi + && ((Compare(a.GetElement(hi), mid) == -1) || (Compare(a + .GetElement(hi), mid) == 0))) { + hi--; + } + + if (lo < hi) { + Swap(a.GetElement(lo), a.GetElement(hi)); + } + + } + Swap(a.GetElement(lo), a.GetElement(hi0)); + Sort(a, lo0, lo - 1); + Sort(a, lo + 1, hi0); + } + + private void qsort(cVertexList a) { + Sort(a, 1, a.n - 1); + } + + private int Compare(cVertex tpi, cVertex tpj) { + int a; // area + int x, y; // projections of ri & rj in 1st quadrant + cVertex pi, pj; + pi = tpi; + pj = tpj; + cVertex myhead = new cVertex(); + myhead = list.head; + a = myhead.v.AreaSign(myhead.v, pi.v, pj.v); + if (a > 0) + return -1; + else if (a < 0) + return 1; + else { // Collinear with list.head + x = Math.abs(pi.v.x - list.head.v.x) + - Math.abs(pj.v.x - list.head.v.x); + y = Math.abs(pi.v.y - list.head.v.y) + - Math.abs(pj.v.y - list.head.v.y); + ndelete++; + + if ((x < 0) || (y < 0)) { + pi.mark = true; + return -1; + } else if ((x > 0) || (y > 0)) { + pj.mark = true; + return 1; + } else { // points are coincident + + if (pi.vnum > pj.vnum) + pj.mark = true; + else + pi.mark = true; + return 0; + + } + } + } + + private void FindLowest() { + int i; + cVertex v1 = list.head.next; + + for (i = 1; i < list.n; i++) { + if ((list.head.v.y < v1.v.y) + || ((v1.v.y == list.head.v.y) && (v1.v.x > list.head.v.x))) { + Swap(list.head, v1); + } + v1 = v1.next; + + } + } + + private void Swap(cVertex first, cVertex second) { + cVertex temp = new cVertex(); + + temp = new cVertex(first.v.x, first.v.y); + temp.vnum = first.vnum; + temp.mark = first.mark; + + list.ResetVertex(first, second.v.x, second.v.y, second.vnum, + second.mark); + list.ResetVertex(second, temp.v.x, temp.v.y, temp.vnum, temp.mark); + + } + + private void Push(cVertex p, cVertexList top) { + // simulating a stack behavior for cVertexList list + top.InsertBeforeHead(p); + } + + private void Pop(cVertexList top) { + top.Delete(top.head.prev); + } + + public void DrawHull(Graphics gContext, int w, int h) { + + if (top.n == 0 || top.head == null) + System.out.println("No drawing is possible."); + else { + cVertex v1 = top.head; + + if (top.n > 2) { + do { + gContext.drawLine(v1.v.x, v1.v.y, v1.next.v.x, v1.next.v.y); + v1 = v1.next; + } while (v1 != top.head); + + } + + } + if (list.head != null) + list.DrawPoints(gContext, w, h); + } + +} diff --git a/voronoi/DelaunayTri.java b/voronoi/DelaunayTri.java new file mode 100644 index 0000000..cc30f47 --- /dev/null +++ b/voronoi/DelaunayTri.java @@ -0,0 +1,612 @@ +package voronoi; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Graphics; + +public class DelaunayTri { + + private static final boolean ONHULL = true; + + private static final boolean REMOVED = true; + + private static final boolean VISIBLE = true; + + private static final boolean PROCESSED = true; + + private static final int SAFE = 1000000; + + boolean toDraw; + + // for simulation + boolean DeSim; + + Graphics g; + + Canvas c; + + int w; + + int h; + + private cVertexList list; + + private cEdgeList elist; + + private cFaceList flist; + + DelaunayTri(cVertexList list) { + this.list = list; + elist = new cEdgeList(); + flist = new cFaceList(); + toDraw = DeSim = false; + g = null; + c = null; + w = 0; + h = 0; + } + + public void DeSim(boolean desim, Graphics Deg, int Dew, int Deh, Canvas Can) { + DeSim = desim; + c = Can; + g = Deg; + w = Dew; + h = Deh; + } + + public void Start(cVertexList listOld) { + this.list = new cVertexList(); + listOld.ListCopy(this.list); + ReadVertices(); + if (DoubleTriangle()) { + toDraw = true; + ConstructHull(); + LowerFaces(); + } + } + + public void ClearDelaunay() { + elist.ClearEdgeList(); + flist.ClearFaceList(); + toDraw = false; + } + + public void ReadVertices() { + int vnum = 0; + cVertex v = list.head; + do { + v.ResetVertex3D(); + v.vnum = vnum++; + if ((Math.abs(v.v.x) > SAFE) || (Math.abs(v.v.y) > SAFE) + || (Math.abs(v.v.z) > SAFE)) { + System.out + .println("Coordinate of vertex below might be too large..."); + } + v = v.next; + } while (v != list.head); + } + + private void LowerFaces() { + cFace f = flist.head; + int Flower = 0; + + do { + if (Normz(f) < 0) { + Flower++; + f.lower = true; + } else { + if (DeSim) { + g.setColor(Color.lightGray); + DrawDelaunayTri(g, w, h); + c.repaint(); + } + f.lower = false; + if (DeSim) { + g.setColor(Color.blue); + DrawDelaunayTri(g, w, h); + c.repaint(); + try { + Thread.sleep(1000); + } catch (InterruptedException ee) { + ; + } + } + } + f = f.next; + } while (f != flist.head); + } + + private boolean DoubleTriangle() { + cVertex v0, v1, v2, v3; + cFace f0, f1 = null; + int vol; + + v0 = list.head; + while (Collinear(v0, v0.next, v0.next.next)) + if ((v0 = v0.next) == list.head) { + System.out + .println("DoubleTriangle: All points are Collinear!"); + return false; + } + v1 = v0.next; + v2 = v1.next; + + v0.mark = PROCESSED; + v1.mark = PROCESSED; + v2.mark = PROCESSED; + + f0 = MakeFace(v0, v1, v2, f1); + f1 = MakeFace(v2, v1, v0, f0); + + f0.edge[0].adjface[1] = f1; + f0.edge[1].adjface[1] = f1; + f0.edge[2].adjface[1] = f1; + f1.edge[0].adjface[1] = f0; + f1.edge[1].adjface[1] = f0; + f1.edge[2].adjface[1] = f0; + + v3 = v2.next; + vol = VolumeSign(f0, v3); + while (vol == 0) { + if ((v3 = v3.next) == v0) { + System.out.println("DoubleTriangle: All points are coplanar!"); + return false; + } + vol = VolumeSign(f0, v3); + } + + list.head = v3; + return true; + } + + private void ConstructHull() { + cVertex v, vnext; + + v = list.head; + do { + vnext = v.next; + if (!v.mark) { + v.mark = PROCESSED; + if (DeSim) { + g.setColor(Color.lightGray); + DrawRest(g, w, h); + c.repaint(); + } + AddOne(v); + if (DeSim) { + g.setColor(Color.blue); + DrawRest(g, w, h); + c.repaint(); + try { + Thread.sleep(1000); + } catch (InterruptedException ee) { + ; + } + } + if (DeSim) { + g.setColor(Color.lightGray); + DrawRest(g, w, h); + c.repaint(); + } + CleanUp(); + if (DeSim) { + g.setColor(Color.blue); + DrawRest(g, w, h); + c.repaint(); + try { + Thread.sleep(1000); + } catch (InterruptedException ee) { + ; + } + } + } + v = vnext; + } while (v != list.head); + } + + private boolean AddOne(cVertex p) { + cFace f; + cEdge e; + int vol; + boolean vis = false; + + f = flist.head; + do { + vol = VolumeSign(f, p); + if (vol < 0) { + f.visible = VISIBLE; + vis = true; + } + f = f.next; + } while (f != flist.head); + + if (!vis) { + p.onhull = !ONHULL; + return false; + } + + e = elist.head; + do { + cEdge temp; + temp = e.next; + if (e.adjface[0].visible && e.adjface[1].visible) { + e.delete = REMOVED; + } else if (e.adjface[0].visible || e.adjface[1].visible) { + e.newface = MakeConeFace(e, p); + } + e = temp; + } while (e != elist.head); + return true; + } + + private int VolumeSign(cFace f, cVertex p) { + double vol; + double ax, ay, az, bx, by, bz, cx, cy, cz, dx, dy, dz; + double bxdx, bydy, bzdz, cxdx, cydy, czdz; + + ax = f.vertex[0].v.x; + ay = f.vertex[0].v.y; + az = f.vertex[0].v.z; + bx = f.vertex[1].v.x; + by = f.vertex[1].v.y; + bz = f.vertex[1].v.z; + cx = f.vertex[2].v.x; + cy = f.vertex[2].v.y; + cz = f.vertex[2].v.z; + dx = p.v.x; + dy = p.v.y; + dz = p.v.z; + + bxdx = bx - dx; + bydy = by - dy; + bzdz = bz - dz; + cxdx = cx - dx; + cydy = cy - dy; + czdz = cz - dz; + vol = (az - dz) * (bxdx * cydy - bydy * cxdx) + (ay - dy) + * (bzdz * cxdx - bxdx * czdz) + (ax - dx) + * (bydy * czdz - bzdz * cydy); + + if (vol > 0.5) + return 1; + else if (vol < -0.5) + return -1; + else + return 0; + } + + private cFace MakeConeFace(cEdge e, cVertex p) { + cEdge new_edge[] = new cEdge[2]; + cFace new_face; + int i, j; + + for (i = 0; i < 2; ++i) { + new_edge[i] = e.endpts[i].duplicate; + if (new_edge[i] == null) { + new_edge[i] = elist.MakeNullEdge(); + new_edge[i].endpts[0] = e.endpts[i]; + new_edge[i].endpts[1] = p; + e.endpts[i].duplicate = new_edge[i]; + } + } + + new_face = flist.MakeNullFace(); + new_face.edge[0] = e; + new_face.edge[1] = new_edge[0]; + new_face.edge[2] = new_edge[1]; + MakeCcw(new_face, e, p); + + for (i = 0; i < 2; ++i) + for (j = 0; j < 2; ++j) + if (new_edge[i].adjface[j] == null) { + new_edge[i].adjface[j] = new_face; + break; + } + + return new_face; + } + + private void MakeCcw(cFace f, cEdge e, cVertex p) { + cFace fv; + int i; + cEdge s = new cEdge(); + + if (e.adjface[0].visible) + fv = e.adjface[0]; + else + fv = e.adjface[1]; + + for (i = 0; fv.vertex[i] != e.endpts[0]; ++i) + ; + if (fv.vertex[(i + 1) % 3] != e.endpts[1]) { + f.vertex[0] = e.endpts[1]; + f.vertex[1] = e.endpts[0]; + } else { + f.vertex[0] = e.endpts[0]; + f.vertex[1] = e.endpts[1]; + Swap(s, f.edge[1], f.edge[2]); + } + + f.vertex[2] = p; + } + + private cFace MakeFace(cVertex v0, cVertex v1, cVertex v2, cFace fold) { + cFace f; + cEdge e0, e1, e2; + + if (fold == null) { + e0 = elist.MakeNullEdge(); + e1 = elist.MakeNullEdge(); + e2 = elist.MakeNullEdge(); + } else { + e0 = fold.edge[2]; + e1 = fold.edge[1]; + e2 = fold.edge[0]; + } + e0.endpts[0] = v0; + e0.endpts[1] = v1; + e1.endpts[0] = v1; + e1.endpts[1] = v2; + e2.endpts[0] = v2; + e2.endpts[1] = v0; + + f = flist.MakeNullFace(); + f.edge[0] = e0; + f.edge[1] = e1; + f.edge[2] = e2; + f.vertex[0] = v0; + f.vertex[1] = v1; + f.vertex[2] = v2; + + e0.adjface[0] = e1.adjface[0] = e2.adjface[0] = f; + + return f; + } + + private void CleanUp() { + CleanEdges(); + CleanFaces(); + CleanVertices(); + } + + private void CleanEdges() { + cEdge e; + cEdge t; + + e = elist.head; + do { + if (e.newface != null) { + if (e.adjface[0].visible) + e.adjface[0] = e.newface; + else + e.adjface[1] = e.newface; + e.newface = null; + } + e = e.next; + } while (e != elist.head); + + while (elist.head != null && elist.head.delete) { + e = elist.head; + elist.Delete(e); + } + e = elist.head.next; + do { + if (e.delete) { + t = e; + e = e.next; + elist.Delete(t); + + } else + e = e.next; + } while (e != elist.head); + } + + private void CleanFaces() { + cFace f; + cFace t; + + while (flist.head != null && flist.head.visible) { + f = flist.head; + flist.Delete(f); + } + f = flist.head.next; + do { + if (f.visible) { + t = f; + f = f.next; + flist.Delete(t); + } else + f = f.next; + } while (f != flist.head); + } + + private void CleanVertices() { + cEdge e; + cVertex v, t; + + e = elist.head; + do { + e.endpts[0].onhull = e.endpts[1].onhull = ONHULL; + e = e.next; + } while (e != elist.head); + + while (list.head != null && list.head.mark && !list.head.onhull) { + v = list.head; + list.Delete(v); + } + v = list.head.next; + do { + if (v.mark && !v.onhull) { + t = v; + v = v.next; + list.Delete(t); + } else + v = v.next; + } while (v != list.head); + + v = list.head; + do { + v.duplicate = null; + v.onhull = !ONHULL; + v = v.next; + } while (v != list.head); + } + + private boolean Collinear(cVertex a, cVertex b, cVertex c) { + return (c.v.z - a.v.z) * (b.v.y - a.v.y) - (b.v.z - a.v.z) + * (c.v.y - a.v.y) == 0 + && (b.v.z - a.v.z) * (c.v.x - a.v.x) - (b.v.x - a.v.x) + * (c.v.z - a.v.z) == 0 + && (b.v.x - a.v.x) * (c.v.y - a.v.y) - (b.v.y - a.v.y) + * (c.v.x - a.v.x) == 0; + } + + private int Normz(cFace f) { + cVertex a, b, c; + + a = f.vertex[0]; + b = f.vertex[1]; + c = f.vertex[2]; + + return (b.v.x - a.v.x) * (c.v.y - a.v.y) - (b.v.y - a.v.y) + * (c.v.x - a.v.x); + } + + private void Swap(cEdge t, cEdge x, cEdge y) { + t = x; + x = y; + y = t; + } + + public void DrawDelaunayTri(Graphics g, int w, int h) { + cVertex v; + cFace f; + int V = 0, F = 0; + + v = list.head; + do { + if (v.mark) + V++; + v = v.next; + } while (v != list.head); + + f = flist.head; + do { + ++F; + f = f.next; + } while (f != flist.head); + do { + if (f.lower) { + if (flist.n >= 2) { + g.drawLine(f.vertex[0].v.x, f.vertex[0].v.y, + f.vertex[1].v.x, f.vertex[1].v.y); + g.drawLine(f.vertex[1].v.x, f.vertex[1].v.y, + f.vertex[2].v.x, f.vertex[2].v.y); + g.drawLine(f.vertex[2].v.x, f.vertex[2].v.y, + f.vertex[0].v.x, f.vertex[0].v.y); + } + } + f = f.next; + } while (f != flist.head); + do { + g.setColor(Color.black); + g.fillOval(v.v.x - (int) (w / 2), v.v.y - (int) (h / 2), w, h); + v = v.next; + } while (v != list.head); + + } + + void out_triple(Graphics g, cVertex s1, cVertex s2, cVertex s3) { + + double P1X = s1.v.x; + double P1Y = s1.v.y; + double P2X = s2.v.x; + double P2Y = s2.v.y; + double P3X = s3.v.x; + double P3Y = s3.v.y; + + double l1a = P2X - P1X; + double l1b = P2Y - P1Y; + double l1c = (P1Y * P1Y - P2Y * P2Y + P1X * P1X - P2X * P2X) * 0.5000; + double l2a = P2X - P3X; + double l2b = P2Y - P3Y; + double l2c = (P3Y * P3Y - P2Y * P2Y + P3X * P3X - P2X * P2X) * 0.5000; + + if (l1a * l2b == l1b * l2a) + return; + double x = (l1c * l2b - l1b * l2c) / (l1b * l2a - l1a * l2b); + double y = (l1a * l2c - l1c * l2a) / (l1b * l2a - l1a * l2b); + + double d = Math.sqrt(Math.pow(s1.v.x - x, 2) + + Math.pow(s1.v.y - y, 2)); + + g.setColor(Color.blue); + g.fillOval((int) P1X - (int) (w / 2), (int) P1Y - (int) (h / 2), w, + h); + g.fillOval((int) P2X - (int) (w / 2), (int) P2Y - (int) (h / 2), w, + h); + g.fillOval((int) P3X - (int) (w / 2), (int) P3Y - (int) (h / 2), w, + h); + g.setColor(Color.red); + g.drawOval((int) (x - d), (int) (y - d), (int) (2 * d), + (int) (2 * d)); + } + + public void DrawCircle(Graphics g, int w, int h) { + cVertex v; + cFace f; + int V = 0, F = 0; + + v = list.head; + do { + if (v.mark) + V++; + v = v.next; + } while (v != list.head); + + f = flist.head; + do { + if(f.lower) + out_triple( g, f.vertex[0],f.vertex[1],f.vertex[2]); + ++F; + f = f.next; + } while (f != flist.head); + } + + + public void DrawRest(Graphics g, int w, int h) { + cVertex v; + cFace f; + int V = 0, F = 0; + + v = list.head; + do { + if (v.mark) + V++; + v = v.next; + } while (v != list.head); + + f = flist.head; + do { + ++F; + f = f.next; + } while (f != flist.head); + do { + if (flist.n >= 2) { + g.drawLine(f.vertex[0].v.x, f.vertex[0].v.y, f.vertex[1].v.x, + f.vertex[1].v.y); + g.drawLine(f.vertex[1].v.x, f.vertex[1].v.y, f.vertex[2].v.x, + f.vertex[2].v.y); + g.drawLine(f.vertex[2].v.x, f.vertex[2].v.y, f.vertex[0].v.x, + f.vertex[0].v.y); + } + f = f.next; + } while (f != flist.head); + + do { + g.setColor(Color.black); + g.fillOval(v.v.x - (int) (w / 2), v.v.y - (int) (h / 2), w, h); + v = v.next; + } while (v != list.head); + } + +} diff --git a/voronoi/GeomCanvas.java b/voronoi/GeomCanvas.java new file mode 100644 index 0000000..33dc431 --- /dev/null +++ b/voronoi/GeomCanvas.java @@ -0,0 +1,297 @@ +package voronoi; +import java.awt.AWTEvent; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.event.MouseEvent; + + +public class GeomCanvas extends Canvas implements Runnable { + + private static final long serialVersionUID = 1L; + + static final int VSIZE = 6; + + private cVertexList list; + + private DelaunayTri delTri; + + private ConvexHull2D myCH; + + private voronoi myVor; + + private boolean toClear, simde, simvo, toPaint, toDelTri, toCH, toVoronoi; + + private cVertex movingV; + + private Graphics gContext; // variables for double buffering + + private Image buffer; + + private int CanW, CanH; // width and height of the drawing canvas + + private int w = VSIZE, h = VSIZE; // w. and h. of vertices + + Thread animator; + + GeomCanvas(int cw, int ch, CompGeomTest frame) { + setSize(cw, ch); + CanW = cw; + CanH = ch; + setBackground(Color.lightGray); + toClear = simde = simvo = false; + toPaint = toDelTri = toCH = false; + list = new cVertexList(); + myCH = new ConvexHull2D(list); + delTri = new DelaunayTri(list); + myVor = new voronoi(); + enableEvents(AWTEvent.MOUSE_EVENT_MASK); + enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK); + start(); + } + + public void SetRegime(String state) { + } + + public void ToBeCleared() { + toClear = true; + repaint(); + } + + public void ToDelTri(boolean iftrue) { + toPaint = true; + toDelTri = iftrue; + repaint(); + } + + public void ToVoronoi(boolean iftrue) { + toPaint = true; + toVoronoi = iftrue; + repaint(); + } + + public void ToCH(boolean iftrue) { + toPaint = true; + toCH = iftrue; + repaint(); + } + + public void CoorClear() { + list.ClearVertexList(); + myCH.ClearHull(); + delTri.ClearDelaunay(); + simde = false; + simvo = false; + toPaint = false; + repaint(); + } + + public void SimDe() { + simde = true; + toPaint = true; + repaint(); + } + + public void SimVo() { + simvo = true; + toPaint = true; + repaint(); + } + + public int GetCount() { + return list.n; + } + + public void paint(Graphics g) { + if (toClear) { + g.setColor(Color.lightGray); + g.fillRect(0, 0, CanW, CanH); + CoorClear(); + toClear = false; + } + + if (toPaint) { + if (list == null) + return; + if (list.head == null) + return; + if (simde) { + g.drawImage(buffer, 0, 0, this); + return; + } + if(simvo){ + g.drawImage(buffer, 0, 0, this); + return; + } + buffer = createImage(CanW, CanH); + gContext = buffer.getGraphics(); + + if (toDelTri) { + delTri.Start(list); + if (delTri.toDraw) { + gContext.setColor(Color.blue); + delTri.DrawDelaunayTri(gContext, w, h); + } + } + if (toVoronoi) { + myVor = new voronoi(); + gContext.setColor(Color.red); + myVor.Sort(list); + myVor.DrawVor(gContext); + } + if (toCH) { + myCH = new ConvexHull2D(list); + myCH.RunHull(); + gContext.setColor(Color.green); + myCH.DrawHull(gContext, w, h); + } + list.DrawPoints(gContext, w, h); + + g.drawImage(buffer, 0, 0, this); + myCH.ClearHull(); + delTri.ClearDelaunay(); + myVor.dVoronoiDiagramGenerator(); + toPaint = false; + + } + } + + public void update(Graphics g) { + paint(g); + } + + public void SetPaint() // needed for the applet + { + repaint(); + } + + public void processMouseMotionEvent(MouseEvent e) { + int xset = 0, yset = 0; + cVertexList listCur = list; + if (e.getID() != MouseEvent.MOUSE_DRAGGED) + return; + xset = e.getX(); + yset = e.getY(); + if (movingV == null) { + movingV = listCur.FindVertex(xset, yset, w, h); + if (movingV == null) { + System.out.println("There is no vertex to be moved"); + return; + } + } + listCur.ResetVertex(movingV, xset, yset); + toPaint = true; + repaint(); + + } + + public void processMouseEvent(MouseEvent e) { + int xset = 0, yset = 0; + cVertex vNear = new cVertex(); + cVertexList listCur = list; + + if (e.getID() != MouseEvent.MOUSE_CLICKED + && e.getID() != MouseEvent.MOUSE_RELEASED) + return; + if (e.getID() == MouseEvent.MOUSE_RELEASED) + movingV = null; + + xset = e.getX(); + yset = e.getY(); + if (e.getID() == MouseEvent.MOUSE_CLICKED + && e.getButton() == MouseEvent.BUTTON1) { + listCur.SetVertex(xset, yset); + toPaint = true; + // list.PrintVertices(); + repaint(); + } + if (e.getID() == MouseEvent.MOUSE_CLICKED + && e.getButton() == MouseEvent.BUTTON3) { + vNear = listCur.GetNearVertex(xset, yset); + if (vNear != null) { + listCur.Delete(vNear); + if (listCur.n == 0) { + toClear = true; + CoorClear(); + } + } else + System.out.println("No vertex can be deleted."); + toPaint = true; + repaint(); + } + } + + public void run() { + while (Thread.currentThread() == animator) { + if (simde) { + gContext.setColor(Color.lightGray); + gContext.fillRect(0, 0, CanW, CanH); + list.DrawPoints(gContext, w, h); + delTri.DeSim(true, gContext, w, h,this); + toPaint = true; + delTri.Start(list); + delTri.DeSim(false, null, 0, 0,null); + if (delTri.toDraw) { + gContext.setColor(Color.blue); + delTri.DrawDelaunayTri(gContext, w, h); + delTri.DrawCircle(gContext, w, h); + toPaint = true; + list.DrawPoints(gContext, w, h); + repaint(); + try { + Thread.sleep(1200); + } + catch (InterruptedException e) { + break; + } + } + simde = false; + buffer = createImage(CanW, CanH); + gContext = buffer.getGraphics(); + delTri.ClearDelaunay(); + toPaint = false; + } + else if (simvo) { + gContext.setColor(Color.lightGray); + gContext.fillRect(0, 0, CanW, CanH); + list.DrawPoints(gContext, w, h); + myVor = new voronoi(); + myVor.VorSim(true, gContext, w, h,this); + myVor.Sort(list); + gContext.setColor(Color.red); + myVor.DrawVor(gContext); + list.DrawPoints(gContext, w, h); + toPaint = true; + repaint(); + try { + + Thread.sleep(1200); + } catch (InterruptedException e) { + break; + } + simvo = false; + buffer = createImage(CanW, CanH); + gContext = buffer.getGraphics(); + toPaint = false; + } + try { + + Thread.sleep(100); + } catch (InterruptedException e) { + break; + } + + } + } + + public void start() { + animator = new Thread(this); + animator.start(); + } + + public void stop() { + animator = null; + CoorClear(); + } +} \ No newline at end of file diff --git a/voronoi/cEdge.java b/voronoi/cEdge.java new file mode 100644 index 0000000..1b7e6d8 --- /dev/null +++ b/voronoi/cEdge.java @@ -0,0 +1,23 @@ +package voronoi; +public class cEdge { + + cFace adjface[]; + + cVertex endpts[]; + + cFace newface; + + boolean delete; + + cEdge next, prev; + + cEdge() { + adjface = new cFace[2]; + adjface[0] = adjface[1] = null; + endpts = new cVertex[2]; + endpts[0] = endpts[1] = null; + newface = null; + delete = false; + next = prev = null; + } +} diff --git a/voronoi/cEdgeList.java b/voronoi/cEdgeList.java new file mode 100644 index 0000000..ad75511 --- /dev/null +++ b/voronoi/cEdgeList.java @@ -0,0 +1,61 @@ +package voronoi; +class cEdgeList { + int n; + cEdge head; + + cEdgeList() { + head = null; + n = 0; + } + + public void InitHead(cEdge h) { + head = new cEdge(); + head = h; + head.next = head.prev = head; + n = 1; + } + + public void InsertBefore(cEdge newE, cEdge oldE) { + if (head == null) + InitHead(newE); + else { + oldE.prev.next = newE; + newE.prev = oldE.prev; + newE.next = oldE; + oldE.prev = newE; + n++; + } + } + + public void InsertBeforeHead(cEdge e) { + if (head == null) + InitHead(e); + else { + InsertBefore(e, head); + } + } + + public cEdge MakeNullEdge() { + cEdge e = new cEdge(); + InsertBeforeHead(e); + return e; + } + + public void Delete(cEdge e) { + + if (head == head.next) + head = null; + else if (e == head) + head = head.next; + + e.prev.next = e.next; + e.next.prev = e.prev; + n--; + } + + public void ClearEdgeList() { + if (head != null) + head = null; + n = 0; + } +} diff --git a/voronoi/cFace.java b/voronoi/cFace.java new file mode 100644 index 0000000..034fd9e --- /dev/null +++ b/voronoi/cFace.java @@ -0,0 +1,22 @@ +package voronoi; +public class cFace { + + cEdge edge[]; + + cVertex vertex[]; + + boolean visible; + boolean lower; + + cFace next, prev; + + cFace() { + edge = new cEdge[3]; + edge[0] = edge[1] = edge[2] = null; + vertex = new cVertex[3]; + vertex[0] = vertex[1] = vertex[2] = null; + visible =false; + lower = true; + next = prev = null; + } +} diff --git a/voronoi/cFaceList.java b/voronoi/cFaceList.java new file mode 100644 index 0000000..a80bc4b --- /dev/null +++ b/voronoi/cFaceList.java @@ -0,0 +1,62 @@ +package voronoi; +class cFaceList { + int n; + + cFace head; + + cFaceList() { + head = null; + n = 0; + } + + public void InitHead(cFace h) { + head = new cFace(); + head = h; + head.next = head.prev = head; + n = 1; + } + + public void InsertBefore(cFace newF, cFace oldF) { + if (head == null) + InitHead(newF); + else { + oldF.prev.next = newF; + newF.prev = oldF.prev; + newF.next = oldF; + oldF.prev = newF; + n++; + } + } + + public void InsertBeforeHead(cFace e) { + if (head == null) + InitHead(e); + else { + InsertBefore(e, head); + } + } + + public cFace MakeNullFace() { + cFace f = new cFace(); + InsertBeforeHead(f); + return f; + } + + public void Delete(cFace e) { + + if (head == head.next) + head = null; + else if (e == head) + head = head.next; + + e.prev.next = e.next; + e.next.prev = e.prev; + n--; + } + + public void ClearFaceList() { + if (head != null) + head = null; + n = 0; + } +} diff --git a/voronoi/cPointd.java b/voronoi/cPointd.java new file mode 100644 index 0000000..1254b36 --- /dev/null +++ b/voronoi/cPointd.java @@ -0,0 +1,15 @@ +package voronoi; +class cPointd { + double x; + + double y; + + cPointd() { + x = y = 0; + } + + cPointd(int x, int y) { + this.x = x; + this.y = y; + } +} diff --git a/voronoi/cPointi.java b/voronoi/cPointi.java new file mode 100644 index 0000000..c538c28 --- /dev/null +++ b/voronoi/cPointi.java @@ -0,0 +1,107 @@ +package voronoi; +class cPointi { + int x; + + int y; + + int z; + + cPointi() { + x = y = z = 0; + } + + cPointi(int x, int y) { + this.x = x; + this.y = y; + this.z = 0; + } + + cPointi(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public int Area2(cPointi a, cPointi b, cPointi c) { + int area = ((c.x - b.x) * (a.y - b.y)) - ((a.x - b.x) * (c.y - b.y)); + return area; + } + + public int AreaSign(cPointi a, cPointi b, cPointi c) { + double area2; + + area2 = (b.x - a.x) * (double) (c.y - a.y) - (c.x - a.x) + * (double) (b.y - a.y); + + if (area2 > 0.5) + return 1; + else if (area2 < -0.5) + return -1; + else + return 0; + } + + public boolean Left(cPointi a, cPointi b, cPointi c) { + return AreaSign(a, b, c) > 0; + } + + public boolean LeftOn(cPointi a, cPointi b, cPointi c) { + return AreaSign(a, b, c) >= 0; + } + + /* + * returns the distance of two points + */ + public double Dist(cPointi p, cPointi p1) { + double l = Math.sqrt(Math.pow((p.x - p1.x), 2) + + Math.pow((p.y - p1.y), 2)); + return l; + } + + public boolean Collinear(cPointi a, cPointi b, cPointi c) { + return AreaSign(a, b, c) == 0; + } + + public boolean Between(cPointi a, cPointi b, cPointi c) { + if (!Collinear(a, b, c)) + return false; + + if (a.x != b.x) + return ((a.x <= c.x) && (c.x <= b.x)) + || ((a.x >= c.x) && (c.x >= b.x)); + else + return ((a.y <= c.y) && (c.y <= b.y)) + || ((a.y >= c.y) && (c.y >= b.y)); + } + + /* + * Returns the distance of the input point from its perp. proj. to the e1 + * edge. Uses method detailed in comp.graphics.algorithms FAQ + */ + double DistEdgePoint(cPointi a, cPointi b, cPointi c) { + double r, s; + double length; + double dproj = 0.0; + length = Math.sqrt(Math.pow((b.x - a.x), 2) + Math.pow((b.y - a.y), 2)); + + if (length == 0.0) { + System.out.println("DistEdgePoint: Length = 0"); + } + r = (((a.y - c.y) * (a.y - b.y)) - ((a.x - c.x) * (b.x - a.x))) + / (length * length); + s = (((a.y - c.y) * (b.x - a.x)) - ((a.x - c.x) * (b.y - a.y))) + / (length * length); + + dproj = Math.abs(s * length); + + if ((s != 0.0) && ((0.0 <= r) && (r <= 1.0))) + return dproj; + if ((s == 0.0) && Between(a, b, c)) + return 0.0; + else { + double ca = Dist(a, c); + double cb = Dist(b, c); + return Math.min(ca, cb); + } + } +} diff --git a/voronoi/cVertex.java b/voronoi/cVertex.java new file mode 100644 index 0000000..1704141 --- /dev/null +++ b/voronoi/cVertex.java @@ -0,0 +1,51 @@ +package voronoi; +class cVertex { + + cVertex prev, next; + cPointi v; + boolean ear = false; + int vnum; + cEdge duplicate; + boolean onhull; + boolean mark; + + cVertex() { + prev = next = null; + v = new cPointi(); + vnum = 0; + duplicate = null; + onhull = false; + mark = false; + } + + cVertex(int i, int j) { + v = new cPointi(); + v.x = i; + v.y = j; + v.z = i * i + j* j; + prev = next = null; + } + + cVertex(int x, int y, int z) { + v = new cPointi(); + v.x = x; + v.y = y; + v.z = z; + prev = next = null; + } + + public void ResetVertex3D() + { + v.z = v.x * v.x + v.y * v.y; + } + +} + + + + + + + + + diff --git a/voronoi/cVertexList.java b/voronoi/cVertexList.java new file mode 100644 index 0000000..bcd6fe4 --- /dev/null +++ b/voronoi/cVertexList.java @@ -0,0 +1,233 @@ +package voronoi; + +import java.awt.Color; +import java.awt.Graphics; + +/** + * Speichert verteces (Eckpunkte, Knoten, Punkte...) + * + * @author + * + */ +class cVertexList { + int n; // 0 means empty; 1 means one vertex; etc. + + int j; + + cVertex head; + + cVertexList() { + head = null; + n = 0; + } + + public cVertex GetElement(int index) { + + cVertex v = new cVertex(); + if (index <= n) { + v = head; + for (int i = 0; i < index; i++) + v = v.next; + + } else + // element not found + v = new cVertex(10000, 10000); + + return v; + } + + public cVertex MakeNullVertex() { + cVertex v = new cVertex(); + InsertBeforeHead(v); + return v; + } + + public void InitHead(cVertex h) { + head = new cVertex(); + head = h; + head.next = head.prev = head; + n = 1; + } + + public void ClearVertexList() { + if (head != null) + head = null; + n = 0; + } + + public void InsertBeforeHead(cVertex ver) { + if (head == null) + InitHead(ver); + else { + InsertBefore(ver, head); + } + } + + public void InsertBefore(cVertex newV, cVertex oldV) { + if (head == null) + InitHead(newV); + else { + oldV.prev.next = newV; + newV.prev = oldV.prev; + newV.next = oldV; + oldV.prev = newV; + n++; + } + } + + public void SetVertex(int x, int y) { + cVertex v = new cVertex(x, y); + InsertBeforeHead(v); + } + + public void AddVertex(int x, int y) { + cVertex v = new cVertex(x, y); + // gets vertex of 1st vertex of the closest edge to the point + cVertex vNear = GetEdge(x, y); + if (vNear != null) + InsertBefore(v, vNear.next); + } + + public void ResetVertex(cVertex resV, int x, int y) { + resV.v.x = x; + resV.v.y = y; + } + + public void ResetVertex(cVertex resV, int x, int y, int vnum, boolean mark) { + resV.v.x = x; + resV.v.y = y; + resV.vnum = vnum; + resV.mark = mark; + } + + public void Delete(cVertex ver) { + if (head == head.next) + head = null; + else if (ver == head) + head = head.next; + + ver.prev.next = ver.next; + ver.next.prev = ver.prev; + n--; + } + + public void ListPart(cVertexList list, int j) { + int i = j; + cVertex temp1 = head, temp2; + do { + i--; + temp2 = new cVertex(); // Create a new vertex cell + temp2.v = temp1.v; // Fill it with the same cPointi as in list + temp2.mark = temp1.mark; + temp2.ear = temp1.ear; + temp2.duplicate = temp1.duplicate; + temp2.onhull = temp1.onhull; + temp2.vnum = temp1.vnum; + list.InsertBeforeHead(temp2); + temp1 = temp1.next; + } while (i >= 0); + } + + public void ListCopy(cVertexList list) { + cVertex temp1 = head, temp2; + do { + temp2 = new cVertex(); // Create a new vertex cell + temp2.v = temp1.v; // Fill it with the same cPointi as in list + temp2.mark = temp1.mark; + temp2.ear = temp1.ear; + temp2.duplicate = temp1.duplicate; + temp2.onhull = temp1.onhull; + temp2.vnum = temp1.vnum; + list.InsertBeforeHead(temp2); + temp1 = temp1.next; + } while (temp1 != head); + } + + public cVertex GetNearVertex(int x, int y) { + cVertex vnear = null, vtemp = head; + double dist = -1.0, dx, dy, mindist = 0.0; + + if (vtemp == null) + return vnear; + + do { + dx = vtemp.v.x - x; + dy = vtemp.v.y - y; + dist = dx * dx + dy * dy; + + // Initialize on first pass (when vnear==null); + // otherwise update if new winner + if (vnear == null || dist < mindist) { + mindist = dist; + vnear = vtemp; + } + vtemp = vtemp.next; + } while (vtemp != head); + + return vnear; + } + + public cVertex FindVertex(int x, int y, int w, int h) { + cVertex notfound = null; + cVertex temp = head; + + if (n > 0) { + do { + temp = temp.next; + if ((temp.v.x <= x + (w / 2)) && (temp.v.x >= x - (w / 2)) + && (temp.v.y <= y + (h / 2)) + && (temp.v.y >= y - (h / 2))) + return temp; + } while (temp != head); + } + return notfound; + } + + public cVertex GetEdge(int x, int y) { + cVertex vnear = null, vtemp = head; + double mindist = 0.0, dist = -1.0; + cPointi p = new cPointi(); + + // input query point + p.x = x; + p.y = y; + + if (vtemp == null) + return vnear; + + do { + dist = p.DistEdgePoint(vtemp.v, vtemp.next.v, p); + if (vnear == null || dist < mindist) { + mindist = dist; + vnear = vtemp; + } + vtemp = vtemp.next; + } while (vtemp != head); + + return vnear; + } + + /** + * zeichnet die vertices + * + * @param g + * @param w + * @param h + */ + public void DrawPoints(Graphics g, int w, int h) { + // vertex painting loop + if (n == 0) + System.out.println("No drawing is possible."); + else { + cVertex v = head; + + g.setColor(Color.black); + do { + g.fillOval(v.v.x - (int) (w / 2), v.v.y - (int) (h / 2), w, h); + v = v.next; + } while (v != head.prev); + g.fillOval(v.v.x - (int) (w / 2), v.v.y - (int) (h / 2), w, h); + } + } + +} diff --git a/voronoi/erstesVoronoi.png b/voronoi/erstesVoronoi.png new file mode 100644 index 0000000..40e9745 Binary files /dev/null and b/voronoi/erstesVoronoi.png differ diff --git a/voronoi/sweepLineVD.java b/voronoi/sweepLineVD.java new file mode 100644 index 0000000..214b7c3 --- /dev/null +++ b/voronoi/sweepLineVD.java @@ -0,0 +1,73 @@ +package voronoi; + +import helper.ListBTS; + +import java.awt.geom.Point2D; +import java.util.ArrayList; +import java.util.List; + +import DataStructure.GSMMap; +import DataStructure.SingleBTS; + +public class sweepLineVD { + private GSMMap map; + + // private ArrayList pointmap = new ArrayList(); + + /** + * @param args + */ + public static void main(String[] args) { + // TODO Auto-generated method stub + + } + + public sweepLineVD(GSMMap map) { + this.map = map; + } + + public void interpolate() { + SingleBTS[] btscontent = map.content(); + for (SingleBTS extrapolateThis : btscontent) { + doVoronoi(extrapolateThis); + } + } + + private void doVoronoi(SingleBTS extrapolateThis) { + // extract only x/y points out of gsmmap with this arfcn + List pointmap = getPointMap(extrapolateThis); + // start voronoi sweep now and build voronoi diagram + voronoisweep(pointmap); + + } + + @SuppressWarnings("unused") + private void voronoisweep(List pointmap) { + // sweepline from y=0 to max(y) + double sweepline = 0; + + } + + private List getPointMap(SingleBTS extrapolateThis) { + // have mappoint sorted for x-coordinates + ArrayList pointmap = new ArrayList(); + for (int x = 0; x < map.Xcoords.length; x++) { + for (int y = 0; y < map.Ycoords.length; y++) { + if (ListBTS.contains(map.map[x][y], extrapolateThis)) { + pointmap.add(new Point2D.Double(x, y)); + } + } + + } + return pointmap; + + } +} + +/* + * class Point { public double x; public double y; + * + * public Point(double x, double y) { this.x = x; this.y = y; } } class Line { + * + * } + */ \ No newline at end of file diff --git a/voronoi/voronoi.java b/voronoi/voronoi.java new file mode 100644 index 0000000..f699e73 --- /dev/null +++ b/voronoi/voronoi.java @@ -0,0 +1,2228 @@ +package voronoi; + +//code kommt von http://shaneosullivan.wordpress.com/2007/04/05/fortunes-sweep-line-voronoi-algorithm-implemented-in-java/ + +/* + * The author of this software is Steven Fortune. Copyright (c) 1994 by AT&T + * Bell Laboratories. + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + */ + +/* + * This code was originally written by Stephan Fortune in C code. I, Shane O'Sullivan, + * have since modified it, encapsulating it in a C++ class and, fixing memory leaks and + * adding accessors to the Voronoi Edges. + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + */ + +/* + * Java Version by Zhenyu Pan + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + */ + +import helper.ListBTS; + +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.geom.Line2D; +import java.awt.geom.Path2D; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import DataStructure.GSMMap; + +class Freenode { + Freenode nextfree; + + Freenode getnext() { + return nextfree; + } + + public void setnext(Freenode newf) { + nextfree = new Freenode(); + nextfree = newf; + } +} + +class Freelist { + public Freenode head; + + Freelist() { + head = null; + } + + public void free() { + while (head != null) { + head = head.nextfree; + } + } +} + +/** + * Punkt im Raum (double) + * + * + */ +class Point { + double x, y; + + public Point() { + } + + public Point(int x, int y) { + this.x = x; + this.y = y; + } + + public Point(double x, double y) { + this.x = x; + this.y = y; + } + + public void setPoint(double x, double y) { + this.x = x; + this.y = y; + } +} + +/** + * used both for sites and for vertices. its a point: Site.Point Vertices auf + * deutsch: Eckpunkt, Ecke, Knoten + * + * + */ + +class Site { + Point coord; + + int sitenumbr; + + public Site() { + coord = new Point(); + } + + /** + * Richy. True if s matches current Site + * + * @param s + * @return + */ + public boolean equals(Site s) { + return ((int) s.coord.x == (int) this.coord.x && (int) s.coord.y == (int) this.coord.y); + } +} + +/** + * Stores 4 points in 2 arrays. EP: Endpoints: Lines reg: the two points this + * line bisects! The two points this line belongs to + * + */ +class Edge { + public double a = 0, b = 0, c = 0; + + Site[] ep; + + Site[] reg; + + int edgenumbr; + + Edge() { + ep = new Site[2]; + reg = new Site[2]; + } +} + +/** + * Two points in 2d space make a line WATCHPOINT here! + */ +class GraphEdge { + public double x1, y1, x2, y2; + public Site correspondingPt; + + GraphEdge next; +} + +/** + * Speichert zu jeder HalfEdge weitere HalfEdges für Links und Rechts. Speichert + * zusätzlich eine Edge:ELedge Speichert auch ein vertex: vertex + * + * @author richy + * + */ +class Halfedge { + Halfedge ELleft, ELright; + + Edge ELedge; + + boolean deleted; + + int ELpm; + + Site vertex; + + double ystar; + + Halfedge PQnext; + + Halfedge() { + PQnext = null; + } +} + +class Hfreelist extends Freelist { + Halfedge hfl; + + Hfreelist() { + hfl = new Halfedge(); + } +} + +class Sfreelist extends Freelist { + Site sfl; + + Sfreelist() { + sfl = new Site(); + } +} + +class Efreelist extends Freelist { + Edge efl; + + Efreelist() { + efl = new Edge(); + } +} + +public class voronoi { + + double borderMinX, borderMaxX, borderMinY, borderMaxY; + + int siteidx; + // ArrayList corresponding = new ArrayList(); + // // richy + // ArrayList polygon = new ArrayList(); + // // richy + ArrayList edges = new ArrayList(); // edges sortieren!!! + + int zoomfactor; // richy + + boolean isGenerated = false; + + double xmin, xmax, ymin, ymax, deltax, deltay; + + int nvertices; + + int nedges; + + int nsites; + + Hfreelist hfl; + + Efreelist efl; + + Sfreelist sfl; + + Site[] sites; // watchpoint here! + + Site bottomsite; + + int sqrt_nsites; + + double minDistanceBetweenSites; + + int PQcount; + + int PQmin; + + int PQhashsize; + + Halfedge PQhash[]; + + public static int le = 0; + + public static int re = 1; + + int ELhashsize; + + Halfedge ELhash[]; + + Halfedge ELleftend, ELrightend; + + GraphEdge allEdges; + + GraphEdge iteratorEdges; + + Boolean VorSim; + + Graphics g; + + Canvas c; + + int w; + + int h; + + double lasty; + + public voronoi() { + siteidx = 0; + sites = null; + + allEdges = null; + iteratorEdges = null; + minDistanceBetweenSites = 0; + + VorSim = false; + g = null; + c = null; + w = h = 0; + lasty = 0; + } + + public Point2D getNearestPoint(int x, int y) { + if (!isGenerated) { + generateVoronoi(0, 2000, 0, 2000); + } + double dist = Double.MAX_VALUE; + double temp_dist = Double.MAX_VALUE; + double distX = 0; + double distY = 0; + int index = 0; + for (int i = sites.length - 1; i >= 0; i--) { + distX = x - sites[i].coord.x; + distY = y - sites[i].coord.y; + temp_dist = Math.sqrt(Math.pow(distX, 2) + Math.pow(distY, 2)); + if (temp_dist < dist) { + dist = temp_dist; + index = i; + } + } + Point2D result = new Point2D.Double(); + result.setLocation(sites[index].coord.x, sites[index].coord.y); + return result; + } + + /** + * Calculates the area of the given polygon + * + * @param poly + * @return area of poly + */ + public double area(Path2D poly) { + try { + double area = 0; + ArrayList points = new ArrayList(20); + PathIterator itr = poly.getPathIterator(null); + // make list out of polygon. see + // http://anklick-bar.de/matheprojekt/kurbel-gauss.pdf + double[] itrresult = new double[6]; + while (!itr.isDone()) { + + itr.currentSegment(itrresult); + points.add(new Point(itrresult[0], itrresult[1])); + itr.next(); + } + Point[] list = new Point[points.size() + 2]; + + for (int i = 0; i < points.size(); i++) { + list[i] = points.get(i); + } + list[points.size()] = points.get(0); + list[points.size() + 1] = points.get(1); + for (int i = 1; i <= points.size(); i++) { + // area of polygon is left to the line + // area = area + (list[i + 1].y - list[i - 1].y) * list[i].x; + area = area + (list[i + 1].x - list[i - 1].x) * list[i].y; + } + + // testing: count number of pixel that are in the polygon + // boolean[][] containing = new boolean[poly.getBounds().width][poly + // .getBounds().height]; + // int x = poly.getBounds().x; + // int y = poly.getBounds().y; + // int xlimit = poly.getBounds().width; + // int ylimit = poly.getBounds().height; + // int area2 = 0; + // for (int xi = 0; xi <= xlimit; xi++) { + // for (int yi = 0; yi <= ylimit; yi++) { + // if (poly.contains(xi + x, yi + y)) { + // area2++; + // } + // } + // } + // System.out.println("Fläche mit Pixeln: " + area2); + // System.out.flush(); + + return area / 2; + } catch (Exception e) { + return 0; + } + + } + + /* + * public Polygon crossSection(Polygon poly1, Polygon poly2) { // always + * check two points. if both are within the first polygon, take // them into + * the new polygon. If one is inside, the other is // outside,take inside + * point+intersection point. + * + * for (int i = 0; i < poly2.npoints - 1; i++) { Point pt1 = new + * Point(poly2.xpoints[i], poly2.ypoints[i]); Point pt2 = new + * Point(poly2.xpoints[i + 1], poly2.ypoints[i + 1]); ArrayList + * output = new ArrayList(); if (poly1.contains(pt1.x, pt1.y)) { if + * (poly1.contains(pt2.x, pt2.y)) { // both points in poly1:add + * output.add(pt1); output.add(pt2); } else { // pt1 is in polygon, pt2 + * not.add pt1 and intersection with // poly1 // poly1. } } } + * + * // check points on poly2 that are within poly1 ArrayList + * containingPTs = new ArrayList(poly2.npoints); for (int i = 0; i < + * poly2.npoints; i++) { if (poly1.contains(poly2.xpoints[i], + * poly2.ypoints[i])) { containingPTs .add(new Point(poly2.xpoints[i], + * poly2.ypoints[i])); } } return null; } + */ + + public double intersectArea(Path2D poly1, Path2D poly2) { + // check the bounding box! + Rectangle2D box = getBox(poly1, poly2); + if (box.isEmpty()) + return 0; + if (box.getWidth() < 0.00001 || box.getHeight() < 0.00001) { + return box.getHeight() * box.getWidth(); + } + double area = 0; + // double maxX = box.getMaxX(); + // double minX = box.getMinX(); + // double maxY = box.getMaxY(); + // double minY = box.getMinY(); + double stepX = (box.getMaxX() - box.getMinX()) / 42; // accuracy + double stepY = (box.getMaxY() - box.getMinY()) / 42; // accuracy + + for (double x = box.getMinX(); x <= box.getMaxX(); x += stepX) { + for (double y = box.getMinY(); y <= box.getMaxY(); y += stepY) { + if (poly1.contains(x, y) && poly2.contains(x, y)) { + area += stepX * stepY; + } + } + } + // for (int x = box.x; x <= box.width + box.x; x++) { + // for (int y = box.y; y <= box.height + box.y; y++) { + // if (poly1.contains(x, y) && poly2.contains(x, y)) + // area++; + // hier darf doch kein int drüberlaufen.klar, dass die fläche + // dann nicht gemessen werden kann! + // System. + // } + // } + return area; + } + + public double drawIntersectArea(Path2D poly1, Path2D poly2, Graphics2D g) { + // check the bounding box! + Rectangle2D box = getBox(poly1, poly2); + if (box.isEmpty()) + return 0; + if (box.getWidth() < 0.00001 || box.getHeight() < 0.00001) { + return box.getHeight() * box.getWidth(); + } + double area = 0; + // double maxX = box.getMaxX(); + // double minX = box.getMinX(); + // double maxY = box.getMaxY(); + // double minY = box.getMinY(); + double stepX = (box.getMaxX() - box.getMinX()) / 50; + double stepY = (box.getMaxY() - box.getMinY()) / 50; + stepX = 1; + stepY = 1; + Random r = new Random(); + g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255))); + for (double x = box.getMinX(); x <= box.getMaxX(); x += stepX) { + for (double y = box.getMinY(); y <= box.getMaxY(); y += stepY) { + if (poly1.contains(x, y) && poly2.contains(x, y)) { + area += stepX * stepY; + g.fillRect((int) x, (int) y, 1, 1); + } + } + } + // for (int x = box.x; x <= box.width + box.x; x++) { + // for (int y = box.y; y <= box.height + box.y; y++) { + // if (poly1.contains(x, y) && poly2.contains(x, y)) + // area++; + // hier darf doch kein int drüberlaufen.klar, dass die fläche + // dann nicht gemessen werden kann! + // System. + // } + // } + return area; + } + + private Rectangle2D getBox(Path2D poly1, Path2D poly2) { + + // TODO Auto-generated method stub + Rectangle2D rect1 = poly1.getBounds2D(); + Rectangle2D rect2 = poly2.getBounds2D(); + Rectangle2D box = new Rectangle2D.Double(); + Rectangle2D.intersect(rect1, rect2, box); + // maximum x + // int x = Math.max(rect1.x, rect2.x); + // int y = Math.max(rect1.y, rect2.y); + // int width = Math.min(rect1.width, rect2.width); + // int height = Math.min(rect1.height, rect2.height); + // Rectangle result = new Rectangle(x, y, width, height); + // return result; + return box; + + } + + /** + * Gets a list of lines. Sorts the lines so that a polygon can be formed out + * of it! list gets cleared during this process!!! + * + * @param list + * @return + */ + private Path2D sortLineList(List list) { + if (list.isEmpty()) { + return null; + } + + // during the voronoi process, lines may be created where start and + // endpoint are the same. remove them! Careful, rounding errors appear! + for (int i = 0; i < list.size(); i++) { + Line2D check = list.get(i); + if (Math.abs(check.getP1().getX() - check.getP2().getX()) < 0.0001d + && Math.abs(check.getP1().getY() - check.getP2().getY()) < 0.0001d) { + list.remove(i); + i--; + } + } + + // now, we traverse the list and sesarch the points + // Polygon result = new Polygon(); + Path2D path = new Path2D.Double(); + /* + * Line2D current = list.remove(0); result.addPoint((int) + * current.getX1(), (int) current.getY1()); result.addPoint((int) + * current.getX2(), (int) current.getY2()); current.setLine(0, 0, + * current.getX2(), current.getY2()); + * + * + * while (!list.isEmpty()) { // formerly: !list.isEmpty() for (int i = + * 0; i < list.size(); i++) { if (commonConnectionPT(current, + * list.get(i))) { Point now = getCommonPT(current, list.get(i)); + * result.addPoint((int) now.x, (int) now.y); current = list.remove(i); + * break; } } } + */ + try { + // initialize. Take first point + Point currPT = new Point(); + currPT.x = list.get(0).getX1(); + currPT.y = list.get(0).getY1(); + // path.moveTo(currPT.x, currPT.y); + boolean firstloop = true; + while (!list.isEmpty()) { + + // traverse all points, look for a match + for (int i = list.size() - 1; i >= 0; i--) { + if (LineContainsPT(currPT, list.get(i))) { + // a line containing the current point is found. Add + // this + // point to the polygon. + // result.addPoint((int) currPT.x, (int) currPT.y); + if (firstloop) { + // cannot do this otherwise: Taking the first + // element from list would result in wrong Paths, + // because then also the next endpoint would be gone + // away + firstloop = false; + path.moveTo(currPT.x, currPT.y); + } else { + path.lineTo(currPT.x, currPT.y); + } + // path.moveTo(currPT.x, currPT.y); + // get the neighbor point of the current line + // in next iteration, search a line that contains the + // new point + currPT = theOtherPoint(currPT, list.get(i)); + // remove the line that contained the point + list.remove(i); + break; + // TODO: if list contains a line with negativ x or y + // value, change it to zero maybe? + } + // HACK:if only one line is left, add the points + // this part is only reached if all lines were traversed but + // nothing was found! + if (list.size() == 1) { + // result.addPoint((int) list.get(0).getX1(), (int) list + // .get(0).getY1()); + // result.addPoint((int) list.get(0).getX2(), (int) list + // .get(0).getY2()); + list.remove(0); + } + } + } + // result.npoints = list.size(); + path.closePath(); + return path; + } catch (Exception e) { + // System.out.println("kann polygon nicht bauen"); + return null; + } + } + + private Point theOtherPoint(Point currPT, Line2D line2d) { + Point result = new Point(); + // take in count rounding errors by doubles! Do Math.abs(x1-x2)<0.001 + if (Math.abs(currPT.x - line2d.getX1()) < 0.0001 + && Math.abs(currPT.y - line2d.getY1()) < 0.0001) { + result.x = line2d.getX2(); + result.y = line2d.getY2(); + return result; + } else if (Math.abs(currPT.x - line2d.getX2()) < 0.0001 + && Math.abs(currPT.y - line2d.getY2()) < 0.0001) { + result.x = line2d.getX1(); + result.y = line2d.getY1(); + return result; + } + return null; + } + + private boolean LineContainsPT(Point currPT, Line2D line2d) { + // tolerance of 0.001 + if (Math.abs(currPT.x - line2d.getX1()) < 0.001 + && Math.abs(currPT.y - line2d.getY1()) < 0.001) { + return true; + } + if (Math.abs(currPT.x - line2d.getX2()) < 0.001 + && Math.abs(currPT.y - line2d.getY2()) < 0.001) { + return true; + } + return false; + } + + /** + * Gets the point where both lines are connected to each other! + * + * @param current + * @param line2d + * @return + */ + @SuppressWarnings("unused") + private Point getCommonPT(Line2D line1, Line2D line2) { + // TODO Auto-generated method stub + Point point = new Point(); + if (line1.getX1() == line2.getX1() && line1.getY1() == line2.getY1()) { + point.x = line1.getX1(); + point.y = line1.getY1(); + } else if (line1.getX2() == line2.getX2() + && line1.getY2() == line2.getY2()) { + point.x = line1.getX1(); + point.y = line1.getY1(); + } else if (line1.getX2() == line2.getX1() + && line1.getY2() == line2.getY1()) { + point.x = line1.getX1(); + point.y = line1.getY1(); + } else if (line1.getX1() == line2.getX2() + && line1.getY1() == line2.getY2()) { + point.x = line1.getX1(); + point.y = line1.getY1(); + } else { + return null; + } + return point; + } + + /** + * Checks if the two lines have a common starting point! (Only check left + * part?!) + * + * @param line1 + * @param line2 + * @return + */ + @SuppressWarnings("unused") + private boolean commonConnectionPT(Line2D line1, Line2D line2) { + if (line1.getX1() == line2.getX1() && line1.getY1() == line2.getY1()) { + return true; + } + if (line1.getX2() == line2.getX2() && line1.getY2() == line2.getY2()) { + return true; + } + if (line1.getX2() == line2.getX1() && line1.getY2() == line2.getY1()) { + return true; + } + if (line1.getX1() == line2.getX2() && line1.getY1() == line2.getY2()) { + return true; + } + return false; + } + + /** + * Returns the polygon for the point in x,y. Point x,y must be a + * Measurement. The Point must exist. + * + * @param x + * @param y + * @return + */ + public Path2D getPoly(int x, int y) { + if (!isGenerated) { + // todo:change the parameters according to GSMmap-size! + // Edge.reg[] gibt an, zu welchen Punkten die Linie gehört! + generateVoronoi(0, 2000, 0, 2000); + } + Edge currEdge; + Site s = new Site(); + ArrayList lines = new ArrayList(); + s.coord = new Point(x, y); + + // TODO: check lines for null-values. if so, clip it to the max value of + // the voronoi + + for (int i = 0; i < edges.size(); i++) { + try { + currEdge = edges.get(i); + // see if x/y matches the lines in edges + if (s.equals(currEdge.reg[0])) { + + double x1 = currEdge.ep[0].coord.x; + double y1 = currEdge.ep[0].coord.y; + double x2 = currEdge.ep[1].coord.x; + double y2 = currEdge.ep[1].coord.y; + lines.add(new Line2D.Double(x1, y1, x2, y2)); + + // lines.add(makeToLine(currEdge)); + } + // lines.add(new Line2D.Double(x1,y1,); + // vielleicht gut, wenn man prüft, ob currEdge[0]oder[1] die + // Kante + // beinhaltet... eigentlich unnötig. kann in ein test eingebaut + // werden + else if (s.equals(currEdge.reg[1])) { + + double x1 = currEdge.ep[0].coord.x; + double y1 = currEdge.ep[0].coord.y; + double x2 = currEdge.ep[1].coord.x; + double y2 = currEdge.ep[1].coord.y; + lines.add(new Line2D.Double(x1, y1, x2, y2)); + + // lines.add(makeToLine(currEdge)); + } + + // linien zu polygon verschmelzen + } catch (Exception e) { + // System.out.println("Mindetens eine Linie ist null"); + return null; + } + } + // System.out.println("anzahl der Linien: " + lines.size()); + + // Polygon result = new Polygon(); + Path2D result = sortLineList(lines); + + return result; + } + + @SuppressWarnings("unused") + private Line2D makeToLine(Edge currEdge) { + // TODO Auto-generated method stub + // check for null references. if so, set it to a max value; + /* + * double middle_of_x = (xmax - xmin) / 2; double middle_of_y = (ymax - + * ymin) / 2; if (currEdge.ep[0] == null) { // first endpoint is null. + * Check where the other endpoint is[1]. // clip // accordingly + * currEdge.ep[0] = new Site(); currEdge.ep[0].coord = new Point(); // + * check for x if (currEdge.ep[1].coord.x < middle_of_x) { + * currEdge.ep[0].coord.x = 0; } else { currEdge.ep[0].coord.x = xmax; } + * // check for y if (currEdge.ep[1].coord.y < middle_of_y) { + * currEdge.ep[0].coord.y = 0; } else { currEdge.ep[0].coord.y = ymax; } + * + * } else if (currEdge.ep[1] == null) { currEdge.ep[1] = new Site(); + * currEdge.ep[1].coord = new Point(); if (currEdge.ep[0].coord.x < + * middle_of_x) { currEdge.ep[1].coord.x = 0; } else { + * currEdge.ep[1].coord.x = xmax; } // check for y if + * (currEdge.ep[0].coord.y < middle_of_y) { currEdge.ep[1].coord.y = 0; + * } else { currEdge.ep[1].coord.y = ymax; } } + */ + // now, build line + double x1 = currEdge.ep[0].coord.x; + double x2 = currEdge.ep[1].coord.x; + double y1 = currEdge.ep[0].coord.y; + double y2 = currEdge.ep[1].coord.y; + Line2D result = new Line2D.Double(); + result.setLine(x1, y1, x2, y2); + return result; + + } + + /** + * Get the neighbors of a point. Only these neighbors are in relationship + * with the given point. Lets say you insert a point for interpolation, than + * you would check for his neihgbors in order to see which polygons you need + * for calculation + * + * @param x + * @param y + * @return + */ + public ArrayList getDirectNeighbors(double x, double y) { + Site s = new Site(); + s.coord.x = x; + s.coord.y = y; + Edge currEdge; + ArrayList result = new ArrayList(); + + for (int i = edges.size() - 1; i >= 0; i--) { + Point2D currPT = new Point2D.Double(); + currEdge = edges.get(i); + // check if this edge has something to do with the coordinate x,y + if (s.equals(currEdge.reg[0])) { + currPT.setLocation(currEdge.reg[1].coord.x, + currEdge.reg[1].coord.y); + result.add(currPT); + } else if (s.equals(currEdge.reg[1])) { + currPT.setLocation(currEdge.reg[0].coord.x, + currEdge.reg[0].coord.y); + result.add(currPT); + } + } + return result; + } + + /** + * Returns the size of the area of the voronoi region at x,y + * + * @param x + * @param y + * @return + */ + public double areaOf(int x, int y) { + return area(getPoly(x, y)); + } + + public void VorSim(boolean vorsim, Graphics vorg, int vorw, int vorh, + Canvas Can) { + VorSim = vorsim; + c = Can; + g = vorg; + w = vorw; + h = vorh; + } + + void cleanupSites() { + if (sites != null) + for (int i = 0; i < sites.length; i++) + sites[i] = null; + sites = null; + } + + void cleanupEdges() { + GraphEdge geCurrent = allEdges; + + while (geCurrent != null && geCurrent.next != null) { + @SuppressWarnings("unused") + GraphEdge freeCurrent = geCurrent; + geCurrent = geCurrent.next; + freeCurrent = null; + } + allEdges = null; + } + + /** + * löscht wohl das diagram + */ + void dVoronoiDiagramGenerator() { + cleanupSites(); + cleanupEdges(); + sfl = null; + efl = null; + } + + /** + * Site compare. Liefert -1,1 zurück, je nachdem welcher x oder y Wert + * größer ist + * + * @param p1 + * @param p2 + * @return + */ + int scomp(Site p1, Site p2) { + Point s1 = p1.coord, s2 = p2.coord; + if (s1.y < s2.y) + return (-1); + if (s1.y > s2.y) + return (1); + if (s1.x < s2.x) + return (-1); + if (s1.x > s2.x) + return (1); + return (0); + } + + /** + * sortiert von sites die ersten n einträge + * + * @param sites + * @param n + */ + void qsort(Site[] sites, int n) { + Site tmp; + if (n == 1) + return; + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + if (scomp(sites[i], sites[j]) > 0) { + tmp = sites[i]; + sites[i] = sites[j]; + sites[j] = tmp; + } + } + } + } + + /** + * fügt Punkte hinzu? Sortiert automatisch + * + * @param xValues + * @param yValues + * @param numPoints + */ + public void sortNode(double xValues[], double yValues[], int numPoints) { + // richy start + dVoronoiDiagramGenerator(); + // richy end + int i; + nsites = numPoints; + sites = new Site[nsites]; + // richy start + double sn = (double) nsites + 4; + sqrt_nsites = (int) Math.sqrt(sn); + minDistanceBetweenSites = 3; + nvertices = 0; + sfl = new Sfreelist(); + nedges = 0; + efl = new Efreelist(); + // richy end + xmin = xValues[0]; + ymin = yValues[0]; + xmax = xValues[0]; + ymax = yValues[0]; + // for all x and y values given + for (i = 0; i < nsites; i++) { + // generate new site with x,y values + sites[i] = new Site(); + sites[i].coord.setPoint(xValues[i], yValues[i]); + sites[i].sitenumbr = i; + + // update min and max + if (xValues[i] < xmin) + xmin = xValues[i]; + else if (xValues[i] > xmax) + xmax = xValues[i]; + + if (yValues[i] < ymin) + ymin = yValues[i]; + else if (yValues[i] > ymax) + ymax = yValues[i]; + } + // sort the recently added sites + qsort(sites, nsites); + deltay = ymax - ymin; + deltax = xmax - xmin; + } + + /** + * Inserts point into Voronoi. Uses a gsmmap and a ARFCN. + * + * @param map + * @param resize + * multiplied to each coordinate to have a larger distance + * between points. 1 if not wanted! + */ + public void sortNode(GSMMap map, int arfcn, int resize) { + double x = Double.NaN; + double y = Double.NaN; + sortNode(map, arfcn, resize, x, y); + } + + /** + * Inserts point into Voronoi. Uses a gsmmap and a ARFCN. Adds one + * additional point: x,y + * + * @param map + * @param resize + * multiplied to each coordinate to have a larger distance + * between points. 1 if not wanted! + */ + public void sortNode(GSMMap map, int arfcn, int resize, double xcoord, + double ycoord) { + ArrayList xVal = new ArrayList(); + ArrayList yVal = new ArrayList(); + if (!Double.isNaN(xcoord) && !Double.isNaN(ycoord)) { + xVal.add(xcoord); + yVal.add(ycoord); + } + edges = new ArrayList(map.numberOfCoordinates); + zoomfactor = resize; + // get xValues + for (int x = 0; x < map.Xcoords.length; x++) { + for (int y = 0; y < map.Ycoords.length; y++) { + if (ListBTS.contains(map.map[x][y], arfcn)) { + xVal.add((double) x); + yVal.add((double) y); + } + } + } + double xArray[] = new double[xVal.size()]; + for (int x = 0; x < xArray.length; x++) { + xArray[x] = xVal.get(x) * resize; + } + + double yArray[] = new double[yVal.size()]; + for (int y = 0; y < yArray.length; y++) { + yArray[y] = yVal.get(y) * resize; + } + + sortNode(xArray, yArray, xVal.size()); + } + + /** + * return a single in-storage site from array sites. A site is a point + * + * @return the next site in the storage + */ + Site nextone() { + Site s; + if (siteidx < nsites) { + s = sites[siteidx]; + siteidx += 1; + return (s); + } else + return (null); + } + + /** + * to bisect: halbieren. + * + * @param s1 + * @param s2 + * @return + */ + Edge bisect(Site s1, Site s2) { + double dx, dy, adx, ady; + Edge newedge; + + newedge = new Edge(); + // RICHY: hier ist der ganze geile scheiß, den ich suche!!!!!!!!!! + + // store the sites that this edge is bisecting: reg + // Jede edge speichern und dann anzeigen! + newedge.reg[0] = s1; + newedge.reg[1] = s2; + + // to begin with, there are no endpoints on the bisector - it goes to + // infinity: ep: Endpoints of Line + newedge.ep[0] = null; + newedge.ep[1] = null; + + // get the difference in x dist between the sites + dx = s2.coord.x - s1.coord.x; + dy = s2.coord.y - s1.coord.y; + // make sure that the difference in positive. Ternary operator + adx = dx > 0 ? dx : -dx; + ady = dy > 0 ? dy : -dy; + newedge.c = (double) (s1.coord.x * dx + s1.coord.y * dy + (dx * dx + dy + * dy) * 0.5);// get the slope of the line + + if (adx > ady) { + newedge.a = 1.0f; + newedge.b = dy / dx; + newedge.c /= dx;// set formula of line, with x fixed to 1 + } else { + newedge.b = 1.0f; + newedge.a = dx / dy; + newedge.c /= dy;// set formula of line, with y fixed to 1 + } + + // sets a number to that edge + newedge.edgenumbr = nedges; + + // increses the edge counter for the next call + nedges += 1; + // RICHY: diese Änderung wars. Beim einfügen ist newedge noch quasi + // leer, aber das ändert sich während voronoi_bd() läuft, weil ja nur + // die Referenz in der ArrayList steht und nicht eine Kopie des Objektes + // prüfe, ob newedge nicht schon drin ist! + edges.add(newedge); // TODO: das wieder einkommentieren zur not + return (newedge); + } + + void resetIterator() { + iteratorEdges = allEdges; + } + + /** + * + * @return + */ + GraphEdge getNext() { + if (iteratorEdges != null) { + GraphEdge temp = iteratorEdges; + iteratorEdges = iteratorEdges.next; + return temp; + } + return null; + } + + /** + * Fügt Punkte zum Voronoi Diagram hinzu? Vertex: Knoten, Eckpunkt + * + * @param list + */ + void Sort(cVertexList list) { + double xValues[]; + double yValues[]; + int count; + + dVoronoiDiagramGenerator(); + + nsites = list.n; + minDistanceBetweenSites = 3; + + nvertices = 0; + sfl = new Sfreelist(); + + nedges = 0; + efl = new Efreelist(); + + double sn = (double) nsites + 4; + sqrt_nsites = (int) Math.sqrt(sn); + + count = list.n; + xValues = new double[count]; + yValues = new double[count]; + for (int i = 0; i < count; i++) { + xValues[i] = list.GetElement(i).v.x; + yValues[i] = list.GetElement(i).v.y; + } + sortNode(xValues, yValues, count); + } + + /** + * gives the Site v a vertice number. Increses the number then for the next + * call + * + * @param v + */ + void makevertex(Site v) { + v.sitenumbr = nvertices; + nvertices += 1; + } + + boolean PQinitialize() { + PQcount = 0; + PQmin = 0; + PQhashsize = 4 * sqrt_nsites; + PQhash = new Halfedge[PQhashsize]; + + for (int i = 0; i < PQhashsize; i += 1) + PQhash[i] = new Halfedge(); + return true; + } + + int PQbucket(Halfedge he) { + int bucket; + + bucket = (int) ((he.ystar - ymin) / deltay * PQhashsize); + if (bucket < 0) + bucket = 0; + if (bucket >= PQhashsize) + bucket = PQhashsize - 1; + if (bucket < PQmin) + PQmin = bucket; + return (bucket); + } + + /** + * push the HalfEdge into the ordered linked list of vertices. vertices: + * Ecke + * + * @param he + * @param v + * @param offset + */ + void PQinsert(Halfedge he, Site v, double offset, Site s) { + // Site s hab ich eingefügt + Halfedge last, next; + + he.vertex = v; + he.ystar = (double) (v.coord.y + offset); + last = PQhash[PQbucket(he)]; + while ((next = last.PQnext) != null + && (he.ystar > next.ystar || (he.ystar == next.ystar && v.coord.x > next.vertex.coord.x))) { + last = next; + } + he.PQnext = last.PQnext; + last.PQnext = he; + PQcount += 1; + } + + // remove the HalfEdge from the list of vertices + void PQdelete(Halfedge he) { + Halfedge last; + + if (he.vertex != null) { + last = PQhash[PQbucket(he)]; + while (last.PQnext != he) + last = last.PQnext; + + last.PQnext = he.PQnext; + PQcount -= 1; + he.vertex = null; + } + } + + boolean PQempty() { + return (PQcount == 0); + } + + Point PQ_min() { + Point answer = new Point(); + + while (PQhash[PQmin].PQnext == null) { + PQmin += 1; + } + answer.x = PQhash[PQmin].PQnext.vertex.coord.x; + answer.y = PQhash[PQmin].PQnext.ystar; + return (answer); + } + + Halfedge PQextractmin() { + Halfedge curr; + + curr = PQhash[PQmin].PQnext; + PQhash[PQmin].PQnext = curr.PQnext; + PQcount -= 1; + return (curr); + } + + Halfedge HEcreate(Edge e, int pm) { + Halfedge answer; + answer = new Halfedge(); + answer.ELedge = e; + answer.ELpm = pm; + answer.PQnext = null; + answer.vertex = null; + return (answer); + } + + boolean ELinitialize() { + int i; + ELhashsize = 2 * sqrt_nsites; + ELhash = new Halfedge[ELhashsize]; + + for (i = 0; i < ELhashsize; i += 1) + ELhash[i] = null; + ELleftend = HEcreate(null, 0); + ELrightend = HEcreate(null, 0); + ELleftend.ELleft = null; + ELleftend.ELright = ELrightend; + ELrightend.ELleft = ELleftend; + ELrightend.ELright = null; + ELhash[0] = ELleftend; + ELhash[ELhashsize - 1] = ELrightend; + + return true; + } + + /** + * returns right edge of halfedge??? + * + * @param he + * @return + */ + Halfedge ELright(Halfedge he) { + return (he.ELright); + } + + Halfedge ELleft(Halfedge he) { + return (he.ELleft); + } + + Site leftreg(Halfedge he) { + if (he.ELedge == null) + return (bottomsite); + return (he.ELpm == le ? he.ELedge.reg[le] : he.ELedge.reg[re]); + } + + /** + * makes both Halfedges to neighbors + * + * @param lb + * @param newHe + */ + void ELinsert(Halfedge lb, Halfedge newHe) { + newHe.ELleft = lb; + newHe.ELright = lb.ELright; + (lb.ELright).ELleft = newHe; + lb.ELright = newHe; + } + + /* + * This delete routine can't reclaim node, since pointers from hash table + * may be present. + */ + void ELdelete(Halfedge he) { + (he.ELleft).ELright = he.ELright; + (he.ELright).ELleft = he.ELleft; + he.deleted = true; + } + + /* Get entry from hash table, pruning any deleted nodes */ + Halfedge ELgethash(int b) { + Halfedge he; + + if (b < 0 || b >= ELhashsize) + return (null); + he = ELhash[b]; + if (he == null || !he.deleted) + return (he); + + /* Hash table points to deleted half edge. Patch as necessary. */ + ELhash[b] = null; + return (null); + } + + /** + * gets left Edge of Point p + * + * @param p + * @return + */ + Halfedge ELleftbnd(Point p) { + int i, bucket; + Halfedge he; + + /* Use hash table to get close to desired halfedge */ + // use the hash function to find the place in the hash map that this + // HalfEdge should be + bucket = (int) ((p.x - xmin) / deltax * ELhashsize); + + // make sure that the bucket position in within the range of the hash + // array + if (bucket < 0) + bucket = 0; + if (bucket >= ELhashsize) + bucket = ELhashsize - 1; + + he = ELgethash(bucket); + if (he == null) + // if the HE isn't found, search backwards and forwards in the hash map + // for the first non-null entry + { + for (i = 1; i < ELhashsize; i += 1) { + if ((he = ELgethash(bucket - i)) != null) + break; + if ((he = ELgethash(bucket + i)) != null) + break; + } + } + /* Now search linear list of halfedges for the correct one */ + if (he == ELleftend || (he != ELrightend && right_of(he, p))) { + // keep going right on the list until either the end is reached, or + // you find the 1st edge which the point isn't to the right of + do { + he = he.ELright; + } while (he != ELrightend && right_of(he, p)); + he = he.ELleft; + } else + // if the point is to the left of the HalfEdge, then search left for + // the HE just to the left of the point + do { + he = he.ELleft; + } while (he != ELleftend && !right_of(he, p)); + + /* Update hash table and reference counts */ + if (bucket > 0 && bucket < ELhashsize - 1) { + ELhash[bucket] = he; + } + return (he); + } + + GraphEdge pushGraphEdge(double x1, double y1, double x2, double y2, Site v) { + GraphEdge newEdge = new GraphEdge(); + newEdge.next = allEdges; + allEdges = newEdge; + newEdge.x1 = x1; + newEdge.y1 = y1; + newEdge.x2 = x2; + newEdge.y2 = y2; + newEdge.correspondingPt = v; + return newEdge; + } + + GraphEdge line(double x1, double y1, double x2, double y2, Site v) { + GraphEdge result = pushGraphEdge(x1, y1, x2, y2, v); + if (VorSim) { + g.setColor(Color.red); + g.drawLine((int) x1, (int) y1, (int) x2, (int) y2); + c.repaint(); + try { + Thread.sleep(500); + } catch (InterruptedException ee) { + ; + } + } + return result; + } + + GraphEdge clip_line(Edge e, Site v) { + double pxmin, pxmax, pymin, pymax; + Site s1, s2; + double x1 = 0, x2 = 0, y1 = 0, y2 = 0; + + x1 = e.reg[0].coord.x; + x2 = e.reg[1].coord.x; + y1 = e.reg[0].coord.y; + y2 = e.reg[1].coord.y; + + // if the distance between the two points this line was created from is + // less than the square root of 2, then ignore it + if (Math.sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1))) < minDistanceBetweenSites) { + return null; + } + pxmin = borderMinX; + pxmax = borderMaxX; + pymin = borderMinY; + pymax = borderMaxY; + + if (e.a == 1.0 && e.b >= 0.0) { + s1 = e.ep[1]; + s2 = e.ep[0]; + } else { + s1 = e.ep[0]; + s2 = e.ep[1]; + } + + if (e.a == 1.0) { + y1 = pymin; + if (s1 != null && s1.coord.y > pymin) { + y1 = s1.coord.y; + } + if (y1 > pymax) { + y1 = pymax; + } + x1 = e.c - e.b * y1; + y2 = pymax; + if (s2 != null && s2.coord.y < pymax) + y2 = s2.coord.y; + + if (y2 < pymin) { + y2 = pymin; + } + x2 = (e.c) - (e.b) * y2; + if (((x1 > pxmax) & (x2 > pxmax)) | ((x1 < pxmin) & (x2 < pxmin))) { + return null; + } + if (x1 > pxmax) { + x1 = pxmax; + y1 = (e.c - x1) / e.b; + } + if (x1 < pxmin) { + x1 = pxmin; + y1 = (e.c - x1) / e.b; + } + if (x2 > pxmax) { + x2 = pxmax; + y2 = (e.c - x2) / e.b; + } + if (x2 < pxmin) { + x2 = pxmin; + y2 = (e.c - x2) / e.b; + } + } else { + x1 = pxmin; + if (s1 != null && s1.coord.x > pxmin) + x1 = s1.coord.x; + if (x1 > pxmax) { + x1 = pxmax; + } + y1 = e.c - e.a * x1; + x2 = pxmax; + if (s2 != null && s2.coord.x < pxmax) + x2 = s2.coord.x; + if (x2 < pxmin) { + x2 = pxmin; + } + y2 = e.c - e.a * x2; + if (((y1 > pymax) & (y2 > pymax)) | ((y1 < pymin) & (y2 < pymin))) { + return null; + } + if (y1 > pymax) { + y1 = pymax; + x1 = (e.c - y1) / e.a; + } + if (y1 < pymin) { + y1 = pymin; + x1 = (e.c - y1) / e.a; + } + if (y2 > pymax) { + y2 = pymax; + x2 = (e.c - y2) / e.a; + } + if (y2 < pymin) { + y2 = pymin; + x2 = (e.c - y2) / e.a; + } + } + + return line(x1, y1, x2, y2, v); + } + + GraphEdge endpoint(Edge e, int lr, Site s) { + e.ep[lr] = s; + if (e.ep[re - lr] == null) + return null; + return clip_line(e, s); + } + + /* returns 1 if p is to right of halfedge e */ + boolean right_of(Halfedge el, Point p) { + Edge e; + Site topsite; + boolean right_of_site; + boolean above, fast; + double dxp, dyp, dxs, t1, t2, t3, yl; + + e = el.ELedge; + topsite = e.reg[1]; + if (p.x > topsite.coord.x) + right_of_site = true; + else + right_of_site = false; + if (right_of_site && el.ELpm == le) + return (true); + if (!right_of_site && el.ELpm == re) + return (false); + + if (e.a == 1.0) { + dyp = p.y - topsite.coord.y; + dxp = p.x - topsite.coord.x; + fast = false; + if ((!right_of_site & (e.b < 0.0)) | (right_of_site & (e.b >= 0.0))) { + above = dyp >= e.b * dxp; + fast = above; + } else { + above = p.x + p.y * e.b > e.c; + if (e.b < 0.0) + above = !above; + if (!above) + fast = true; + } + if (!fast) { + dxs = topsite.coord.x - (e.reg[0]).coord.x; + above = e.b * (dxp * dxp - dyp * dyp) < dxs * dyp + * (1.0 + 2.0 * dxp / dxs + e.b * e.b); + if (e.b < 0.0) + above = !above; + } + } else /* e.b==1.0 */ + { + yl = e.c - e.a * p.x; + t1 = p.y - yl; + t2 = p.x - topsite.coord.x; + t3 = yl - topsite.coord.y; + above = t1 * t1 > t2 * t2 + t3 * t3; + } + return (el.ELpm == le ? above : !above); + } + + /** + * Bringt rechte (oder Linke?) Site von he zurück. Falls es das nicht gibt, + * wird bottomsite zurückgeliefert + * + * @param he + * @return + */ + Site rightreg(Halfedge he) { + if (he.ELedge == (Edge) null) + // if this halfedge has no edge, return the bottom site (whatever + // that is) + return (bottomsite); + + // if the ELpm field is zero, return the site 0 that this edge bisects, + // otherwise return site number 1 + return (he.ELpm == le ? he.ELedge.reg[re] : he.ELedge.reg[le]); + } + + /** + * Distance between two points + */ + double dist(Site s, Site t) { + double dx, dy; + dx = s.coord.x - t.coord.x; + dy = s.coord.y - t.coord.y; + return (double) (Math.sqrt(dx * dx + dy * dy)); + } + + /** + * create a new site where the HalfEdges el1 and el2 intersect - note that + * the Point in the argument list is not used, don't know why it's there + * + * @param el1 + * @param el2 + * @return + */ + Site intersect(Halfedge el1, Halfedge el2) { + Edge e1, e2, e; + Halfedge el; + double d, xint, yint; + boolean right_of_site; + Site v; + + e1 = el1.ELedge; + e2 = el2.ELedge; + if (e1 == null || e2 == null) + return null; + + // if the two edges bisect the same parent, return null + if (e1.reg[1] == e2.reg[1]) + return null; + + d = e1.a * e2.b - e1.b * e2.a; + if (-1.0e-10 < d && d < 1.0e-10) + return null; + + xint = (e1.c * e2.b - e2.c * e1.b) / d; + yint = (e2.c * e1.a - e1.c * e2.a) / d; + + if ((e1.reg[1].coord.y < e2.reg[1].coord.y) + || (e1.reg[1].coord.y == e2.reg[1].coord.y && e1.reg[1].coord.x < e2.reg[1].coord.x)) { + el = el1; + e = e1; + } else { + el = el2; + e = e2; + } + + right_of_site = xint >= e.reg[1].coord.x; + if ((right_of_site && el.ELpm == le) + || (!right_of_site && el.ELpm == re)) + return null; + + // create a new site at the point of intersection - this is a new vector + // event waiting to happen + v = new Site(); + v.coord.x = xint; + v.coord.y = yint; + return (v); + } + + /** + * Zeigt sachen an, wenn VorSim = 1. Sonst tut es nichts + * + * @param s1 + * @param s2 + * @param s3 + */ + void out_triple(Site s1, Site s2, Site s3) { + + if (VorSim) { + double P1X = s1.coord.x; + double P1Y = s1.coord.y; + double P2X = s2.coord.x; + double P2Y = s2.coord.y; + double P3X = s3.coord.x; + double P3Y = s3.coord.y; + + double l1a = P2X - P1X; + double l1b = P2Y - P1Y; + double l1c = (P1Y * P1Y - P2Y * P2Y + P1X * P1X - P2X * P2X) * 0.5000; + double l2a = P2X - P3X; + double l2b = P2Y - P3Y; + double l2c = (P3Y * P3Y - P2Y * P2Y + P3X * P3X - P2X * P2X) * 0.5000; + + if (l1a * l2b == l1b * l2a) + return; + double x = (l1c * l2b - l1b * l2c) / (l1b * l2a - l1a * l2b); + double y = (l1a * l2c - l1c * l2a) / (l1b * l2a - l1a * l2b); + + double d = Math.sqrt(Math.pow(s1.coord.x - x, 2) + + Math.pow(s1.coord.y - y, 2)); + + g.setColor(Color.red); + g.fillOval((int) P1X - (int) (w / 2), (int) P1Y - (int) (h / 2), w, + h); + g.fillOval((int) P2X - (int) (w / 2), (int) P2Y - (int) (h / 2), w, + h); + g.fillOval((int) P3X - (int) (w / 2), (int) P3Y - (int) (h / 2), w, + h); + g.setColor(Color.blue); + g.drawOval((int) (x - d), (int) (y - d), (int) (2 * d), + (int) (2 * d)); + c.repaint(); + try { + Thread.sleep(300); + } catch (InterruptedException ee) { + ; + } + g.setColor(Color.lightGray); + g.drawOval((int) (x - d), (int) (y - d), (int) (2 * d), + (int) (2 * d)); + g.setColor(Color.black); + g.fillOval((int) P1X - (int) (w / 2), (int) P1Y - (int) (h / 2), w, + h); + g.fillOval((int) P2X - (int) (w / 2), (int) P2Y - (int) (h / 2), w, + h); + g.fillOval((int) P3X - (int) (w / 2), (int) P3Y - (int) (h / 2), w, + h); + c.repaint(); + } + } + + int beachline_bake[] = null; + + /** + * tut nichts wenn VorSim == false + */ + void out_beachline() { + if (VorSim) { + if (beachline_bake == null) { + beachline_bake = new int[(int) (borderMaxX - borderMinX)]; + for (int x = (int) borderMinX; x < (int) borderMaxX; x++) { + beachline_bake[x] = 0; + } + } + for (int x = (int) borderMinX; x < (int) borderMaxX; x++) { + g.setColor(Color.lightGray); + g.fillOval(x, beachline_bake[x], 1, 1); + + Site s = sites[siteidx - 1]; + double y0 = s.coord.y; + Halfedge he = ELleftend; + int y = (int) 0; + do { + Site v = rightreg(he); + double x1 = v.coord.x; + double y1 = v.coord.y; + int y2 = (int) ((y0 * y0 - (x1 - x) * (x1 - x) - y1 * y1) / (2 * y0 - 2 * y1)); + if (y2 > y) + y = y2; + he = he.ELright; + } while (he.ELright != null); + if (y != 0) { + g.setColor(Color.red); + g.fillOval(x, y, 1, 1); + c.repaint(); + beachline_bake[x] = y; + } + } + try { + Thread.sleep(1000); + } catch (InterruptedException ee) { + ; + } + } + } + + /** + * Does nothing when VorSim isn't enabled + * + * @param s1 + */ + void out_site(Site s1) { + + if (VorSim) { + if (s1 == null) + return; + double P1X = s1.coord.x; + double P1Y = s1.coord.y; + g.setColor(Color.lightGray); + g.drawLine((int) borderMinX, (int) lasty, (int) borderMaxX, + (int) lasty); + g.setColor(Color.black); + g.drawLine((int) borderMinX, (int) P1Y, (int) borderMaxX, (int) P1Y); + g.setColor(Color.red); + g.fillOval((int) P1X - (int) (w / 2), (int) P1Y - (int) (h / 2), w, + h); + c.repaint(); + try { + Thread.sleep(1000); + } catch (InterruptedException ee) { + ; + } + g.setColor(Color.black); + g.drawLine((int) borderMinX, (int) P1Y, (int) borderMaxX, (int) P1Y); + g.fillOval((int) P1X - (int) (w / 2), (int) P1Y - (int) (h / 2), w, + h); + c.repaint(); + lasty = P1Y; + } + } + + /* + * implicit parameters: nsites, sqrt_nsites, xmin, xmax, ymin, ymax, deltax, + * deltay (can all be estimates). Performance suffers if they are wrong; + * better to make nsites, deltax, and deltay too big than too small. (?) + */ + + /** + * der eigentliche algorithmus + */ + boolean voronoi_bd() { + isGenerated = true; + // clear edges + edges.clear(); + edges = new ArrayList(200); + // clear other lists + // corresponding.clear(); + Site newsite, bottom, top, temp, p; + Site v; + Point newintstar = null; + int pm; + Halfedge lbnd, rbnd, llbnd, rrbnd, bisector; + Edge e; + + PQinitialize(); + ELinitialize(); + + bottomsite = nextone(); + out_site(bottomsite); + newsite = nextone(); + while (true) { + if (!PQempty()) + newintstar = PQ_min(); + // if the lowest site has a smaller y value than the lowest vector + // intersection, + // process the site otherwise process the vector intersection + + if (newsite != null + && (PQempty() || newsite.coord.y < newintstar.y || (newsite.coord.y == newintstar.y && newsite.coord.x < newintstar.x))) { + out_site(newsite); + /* new site is smallest -this is a site event */ + // get the first HalfEdge to the LEFT of the new site + // richy: left bound + lbnd = ELleftbnd((newsite.coord)); + // get the first HalfEdge to the RIGHT of the new site + // richy: right bound + rbnd = ELright(lbnd); + // if this halfedge has no edge,bot =bottom site (whatever that + // is) + bottom = rightreg(lbnd); + // create a new edge that bisects. Baue Halbierende + e = bisect(bottom, newsite); // richy: e gehört zu bottom, + // newsite + + // create a new HalfEdge, setting its ELpm field to 0 + bisector = HEcreate(e, le); // richy: e in HalfEdge wandeln? + // insert this new bisector (Halbierende) edge between the left + // and right + // vectors in a linked list + ELinsert(lbnd, bisector); + + // if the new bisector intersects with the left edge, + // remove the left edge's vertex, and put in the new one + // p wird hier zugewiesen. p scheint aber "nur" ein Schnittpunkt + // zweier Kanten zu sein + if ((p = intersect(lbnd, bisector)) != null) { + PQdelete(lbnd); + PQinsert(lbnd, p, dist(p, newsite), newsite); + } + lbnd = bisector; + // create a new HalfEdge, setting its ELpm field to 1 + bisector = HEcreate(e, re); + // insert the new HE to the right of the original bisector + // earlier in the IF stmt + ELinsert(lbnd, bisector); + + // if this new bisector intersects with the new HalfEdge + if ((p = intersect(bisector, rbnd)) != null) { + // push the HE into the ordered linked list of vertices + PQinsert(bisector, p, dist(p, newsite), newsite); // PQinsert + // ändern + // Richy:hier werden die Kanten tatsächlich eingefügt. + // Vielleicht + // das isert hier machen!!!!!!! + // edges.add(e); + } + out_beachline(); + newsite = nextone(); // (nur) hier wird eine neue Site geholt! + } else if (!PQempty()) + /* intersection is smallest - this is a vector event */ + // richy: vertices are created here + { + // pop the HalfEdge with the lowest vector off the ordered list + // of vectors + lbnd = PQextractmin(); // lbnd: left bound? + // get the HalfEdge to the left of the above HE + llbnd = ELleft(lbnd); // richy: left of left bound + // get the HalfEdge to the right of the above HE + rbnd = ELright(lbnd); + // get the HalfEdge to the right of the HE to the right of the + // lowest HE + rrbnd = ELright(rbnd); + // get the Site to the left of the left HE which it bisects + bottom = leftreg(lbnd); + // get the Site to the right of the right HE which it bisects + top = rightreg(rbnd); + + // output the triple of sites, stating that a circle goes + // through them + out_triple(bottom, top, rightreg(lbnd)); + + v = lbnd.vertex; // get the vertex that caused this event + makevertex(v); // set the vertex number - couldn't do this + // earlier since we didn't know when it would be processed + // GraphEdge one = endpoint(lbnd.ELedge, lbnd.ELpm, v); // + // richy: + // bottom + // and + // top maybe? + // diese zwei endpoints könnten eine zu bottom und top + // zugehörige kante sein! + + // set the endpoint of + // the left HalfEdge to be this vector + // GraphEdge two = endpoint(rbnd.ELedge, rbnd.ELpm, v); + // set the endpoint of the right HalfEdge to + // be this vector + // richy linien zeugs: die Kanten one und two gehören zu punkte + // top&bottom + /* + * PointAndLines tempP2D1 = new PointAndLines(); tempP2D1.coord + * = bottom.coord; Line2D line1 = new Line2D.Double(); if (one + * != null) line1.setLine(one.x1, one.y1, one.x2, one.y2); + * Line2D line2 = new Line2D.Double(); if (two != null) + * line2.setLine(two.x1, two.y1, two.x2, two.y2); + * tempP2D1.corrLines.add(line1); tempP2D1.corrLines.add(line2); + * corresponding.add(tempP2D1); + */ + PointAndLines tempP2D1 = new PointAndLines(); + tempP2D1.coord = bottom.coord; + Line2D line1 = new Line2D.Double(); + line1.setLine(bottom.coord.x, bottom.coord.y, v.coord.x, + v.coord.y); + if (line1 != null) { + tempP2D1.corrLines.add(line1); + } + // corresponding.add(tempP2D1); + + ELdelete(lbnd); // mark the lowest HE for + // deletion - can't delete yet because there might be pointers + // to it in Hash Map + PQdelete(rbnd); + // remove all vertex events to do with the right HE + ELdelete(rbnd); // mark the right HE for + // deletion - can't delete yet because there might be pointers + // to it in Hash Map + pm = le; // set the pm variable to zero + + // richy: v and newsite seem to be the points that are involved + // in this line. + // or bottom and top? + + if (bottom.coord.y > top.coord.y) + // if the site to the left of the event is higher than the + // Site + { // to the right of it, then swap them and set the 'pm' + // variable to 1 + temp = bottom; + bottom = top; + top = temp; + pm = re; + } + e = bisect(bottom, top); // create an Edge (or line) + // that is between the two Sites. This creates the formula of + // the line, and assigns a line number to it + bisector = HEcreate(e, pm); // create a HE from the Edge 'e', + // and make it point to that edge + // with its ELedge field + ELinsert(llbnd, bisector); // insert the new bisector to the + // right of the left HE + endpoint(e, re - pm, v); // set one endpoint to the new edge + // to be the vector point 'v'. + // If the site to the left of this bisector is higher than the + // right Site, then this endpoint + // is put in position 0; otherwise in pos 1 + + // if left HE and the new bisector intersect, then delete + // the left HE, and reinsert it + if ((p = intersect(llbnd, bisector)) != null) { + PQdelete(llbnd); + PQinsert(llbnd, p, dist(p, bottom), p); + } + + // if right HE and the new bisector intersect, then + // reinsert it + if ((p = intersect(bisector, rrbnd)) != null) { + PQinsert(bisector, p, dist(p, bottom), p); + } + + // hier startet eine neue Ieration + // PointAndVertices verts = new PointAndVertices(); + // if (bottom != null) { + // verts.Punkt.x = bottom.coord.x; + // verts.Punkt.y = bottom.coord.y; + // } + // nun an den Punkt die äußeren Kanten anfügen + Point point = null; + if (lbnd != null && lbnd.vertex != null) { + point = new Point(); + point.x = (int) lbnd.vertex.coord.x; + point.y = (int) lbnd.vertex.coord.y; + // verts.polygon.add(point); + } + if (llbnd != null && llbnd.vertex != null) { + point = new Point(); + point.x = (int) llbnd.vertex.coord.x; + point.y = (int) llbnd.vertex.coord.y; + // verts.polygon.add(point); + } + if (rbnd != null && rbnd.vertex != null) { + point = new Point(); + point.x = (int) rbnd.vertex.coord.x; + point.y = (int) rbnd.vertex.coord.y; + // verts.polygon.add(point); + } + + // polygon.add(verts); + + // richy: schaue mal e, lbnd, rbdn und llbnd an + + } else + break; + } // hier ist die while (true) Schleife zu ende + + for (lbnd = ELright(ELleftend); lbnd != ELrightend; lbnd = ELright(lbnd)) { + e = lbnd.ELedge; + clip_line(e, null); + } + endsim(); + return true; + } + + /** + * Generates Voronoi + * + * @param minX + * @param maxX + * maximum x size of diagram + * @param minY + * @param maxY + * maximum y size of diagram + * @return + */ + public boolean generateVoronoi(double minX, double maxX, double minY, + double maxY) { + edges = new ArrayList(1000); + double temp = 0; + if (minX > maxX) { + temp = minX; + minX = maxX; + maxX = temp; + } + if (minY > maxY) { + temp = minY; + minY = maxY; + maxY = temp; + } + borderMinX = minX; + borderMinY = minY; + borderMaxX = maxX; + borderMaxY = maxY; + + siteidx = 0; + voronoi_bd(); + isGenerated = true; + + // clean edges + // cleanEdgeList(); + + return true; + } + + @SuppressWarnings("unused") + private void cleanEdgeList() { + ArrayList result = new ArrayList(); + Edge temp; + for (int i = 0; i < edges.size(); i++) { + temp = edges.get(i); + // search if temp is only once in edges. if so, go on. else, delete + // the others + for (int j = i; j < edges.size(); j++) { + // if (temp.ep[0].equals(edges.get(j).ep[0])) + } + } + + } + + void endsim() { + if (VorSim) { + g.setColor(Color.lightGray); + g.drawLine((int) borderMinX, (int) lasty, (int) borderMaxX, + (int) lasty); + if (beachline_bake != null) { + for (int x = (int) borderMinX; x < (int) borderMaxX; x++) { + g.setColor(Color.lightGray); + g.fillOval(x, beachline_bake[x], 1, 1); + + } + } + c.repaint(); + } + + } + + /** + * Zeichnet das Diagramm in Graphics g + * + * @param g + */ + public void DrawVor(Graphics g) { + double minX, maxX, minY, maxY; + minX = 0; + minY = 0; + maxX = 1500; + maxY = 1500; + + generateVoronoi(minX, maxX, minY, maxY); + + resetIterator(); + GraphEdge temp = null; + g.setColor(Color.black); + + // vom Entwickler gemachte Schleife + while ((temp = getNext()) != null) { + g.drawLine((int) temp.x1, (int) temp.y1, (int) temp.x2, + (int) temp.y2); + if (temp.correspondingPt != null) { + g.drawRect((int) temp.correspondingPt.coord.x - 1, + (int) temp.correspondingPt.coord.y - 1, 2, 2);// Eckpunkte + } + + } + + /* + * g.setColor(Color.black); Random r = new Random(); // corresponding + * malen g.setColor(Color.green); for (PointAndLines points : + * corresponding) { if (points == null || points.coord.y != 224 || + * points.coord.x != 344) continue; // g.setColor(new + * Color(r.nextInt(256), r.nextInt(256), // r.nextInt(256))); + * g.setColor(Color.blue); g.drawRect((int) points.coord.x - 1, (int) + * points.coord.y - 1, 2, 2); for (Line2D line : points.corrLines) { + * g.drawLine((int) line.getX1(), (int) line.getY1(), (int) + * line.getX2(), (int) line.getY2()); } } + * + * // Points and Vertices zeichnen! g.setColor(Color.red); for + * (PointAndVertices current : polygon) { if (current.Punkt.x != 344 || + * current.Punkt.y != 224) continue; g.drawRect((int) current.Punkt.x, + * (int) current.Punkt.y, 2, 2); for (Point points : current.polygon) { + * if (points != null) g.drawRect((int) points.x, (int) points.y, 2, 2); + * + * } } /* + * + * // start richy // draw the points? // halfedges malen + * resetIterator(); Halfedge bla; g.setColor(Color.yellow); /* while + * ((bla = ELleftend.PQnext) != null) { g.drawRect((int) + * bla.vertex.coord.x, (int) bla.vertex.coord.y, 2, 2); if + * ((bla.ELedge.ep[0].coord.x == 344 || bla.ELedge.ep[1].coord.x == 344) + * && (bla.ELedge.ep[0].coord.y == 224 || bla.ELedge.ep[1].coord.y == + * 224)) { g.drawRect((int) bla.ELedge.ep[0].coord.x, (int) + * bla.ELedge.ep[1].coord.y, 2, 2); g.drawLine((int) + * bla.ELedge.reg[0].coord.x, (int) bla.ELedge.reg[0].coord.y, (int) + * bla.ELedge.reg[1].coord.x, (int) bla.ELedge.reg[1].coord.y); } } + */ + + // Siehe edges! + /* + * g.setColor(Color.yellow); for (Edge tempedge : edges) { if + * ((tempedge.reg[0].coord.x == 272 && tempedge.reg[0].coord.y == 136) + * || (tempedge.reg[1].coord.x == 272 && tempedge.reg[1].coord.y == + * 136)) { try { g.drawRect((int) tempedge.reg[0].coord.x - 1, (int) + * tempedge.reg[0].coord.y - 1, 3, 3); g.drawLine((int) + * tempedge.ep[0].coord.x, (int) tempedge.ep[0].coord.y, (int) + * tempedge.ep[1].coord.x, (int) tempedge.ep[1].coord.y); } catch + * (Exception e) { System.out.println("Hat nicht geklappt"); } } }/* + * // + * + * // end richy return; } + */ + } + /* + * public Weight[] getWeights(int x, int y, voronoi original) { Polygon + * interpolator = getPoly(x, y); // get the neighbors of this x,y + * ArrayList neighbors = getDirectNeighbors(x, y); // get the + * polygons for each neighbor out of original + * + * return null; } + */ + +} + +class PointAndLines { + Point coord; + ArrayList corrLines = new ArrayList(); + + // constructor not needed! + + public void removeDuplicates() { + // ArrayList resultList = new ArrayList(10); + // Line2D result; + for (int i = 0; i < corrLines.size(); i++) { + + } + } + + public boolean contains(Line2D line) { + for (int i = 0; i < corrLines.size(); i++) { + Line2D current = corrLines.get(i); + if (current.getX1() == line.getX1() + && current.getX2() == line.getX2() + && current.getY1() == line.getY1() + && current.getY2() == line.getY2()) + return true; + } + return false; + } +} + +/** + * Should store a Point and the corresponding intersections of the voronoi + * + * @author richy + * + */ +class PointAndVertices { + Point Punkt = new Point(); + ArrayList polygon = new ArrayList(10); +} diff --git a/voronoiTest.java b/voronoiTest.java new file mode 100644 index 0000000..0fdb4f1 --- /dev/null +++ b/voronoiTest.java @@ -0,0 +1,222 @@ +import helper.ListBTS; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.geom.Path2D; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; + +import voronoi.voronoi; +import DataStructure.GSMMap; +import Parse.NMEAParse; +import Parse.sqlreader; + +public class voronoiTest extends Frame { + static voronoi vTest = new voronoi(); + static GSMMap map; + static int arfcn; + static int zoom; + private int x = 272; + private int y = 136; + private int xmouse = 0; + private int ymouse = 0; + /** + * + */ + private static final long serialVersionUID = 1L; + + /** + * @param args + * @throws SQLException + * @throws ClassNotFoundException + * @throws IOException + */ + + public static void main(String[] args) throws ClassNotFoundException, + SQLException, IOException { // TODO Auto-generated method stub + // sqlreader sql = new sqlreader(new NMEAParse("campus1.log"), + // 262026003662195l, 3000l); + sqlreader sql = new sqlreader(new NMEAParse("nachGPN.log"), + 262026003662195l, 3000l); + map = new GSMMap(sql, 0.00004); + map.average(); + map.removeOutlier(); + // GoogleOut average = new GoogleOut(map, "average-all.kml"); + + vTest = new voronoi(); + // vTest.sortNode(map, map.getUniqueBTSlist()[0].ARFCN,10); + arfcn = 877; + zoom = 10; + vTest.sortNode(map, arfcn, zoom, 20, 20); + vTest.generateVoronoi(0, 1500, 0, 1500); + voronoiTest zeichnedass = new voronoiTest(); + zeichnedass.setVisible(true); + } + + public voronoiTest() { + setSize(750, 750); + addWindowListener(new closeFrame());// funktioniert, weil die Klasse von + // Frame erbt + addMouseListener(new mouse()); + } + + public void paint(Graphics gr) { + Graphics2D g = (Graphics2D) gr; + vTest.DrawVor(g); + g.setColor(Color.black); + /* + * //draws the points in gsmmap for (int x = 0; x < map.Xcoords.length; + * x++) { for (int y = 0; y < map.Ycoords.length; y++) { if + * (ListBTS.contains(map.map[x][y], arfcn)) { // Punkte zeichnen + * g.drawRect(x * zoom - 1, y * zoom - 1, 2, 2); } + * + * } } + */ + g.setColor(Color.magenta); + Path2D test = vTest.getPoly(x, y); + if (test != null) { + + g.fill(vTest.getPoly(x, y)); + Path2D poly = vTest.getPoly(x, y); + System.out.println("Polygon: "); + PathIterator itr = poly.getPathIterator(null); + System.out.println(""); + while (!itr.isDone()) { + double[] result = new double[6]; + itr.currentSegment(result); + System.out.print(result[0] + "," + result[1] + " "); + itr.next(); + } + System.out.println(""); + + // for (int i = 0; i < poly.npoints; i++) { + // System.out.print(poly.xpoints[i] + "," + poly.ypoints[i] + " "); + // } + // show neighbors + ArrayList neigh = vTest.getDirectNeighbors(x, y); + for (int i = 0; i < neigh.size(); i++) { + g.setColor(Color.green); + g.fillRect((int) neigh.get(i).getX(), + (int) neigh.get(i).getY(), 2, 2); + } + g.fillRect(160, 160, 5, 5); + System.out.println(""); + System.out.println("Mouse in polygon: " + poly.contains(x, y)); + System.out.println("Fläche: " + vTest.area(poly)); + } else + System.out.println("Null-Polygon;"); + g.setColor(Color.black); + for (int x = 0; x < map.Xcoords.length; x++) { + for (int y = 0; y < map.Ycoords.length; y++) { + if (ListBTS.contains(map.map[x][y], arfcn)) { + g.drawRect(x * zoom - 1, y * zoom - 1, 3, 3); + } + } + } + + // draw cut with new voronoi + voronoi voronoi2 = new voronoi(); + voronoi2.sortNode(map, arfcn, zoom, xmouse / zoom, ymouse / zoom); + voronoi2.generateVoronoi(0, 2000, 0, 2000); + g.setColor(Color.gray); + Point2D mouse = voronoi2.getNearestPoint(xmouse, ymouse); + Path2D interpolationPoly = voronoi2.getPoly((int) mouse.getX(), + (int) mouse.getY()); + g.draw(interpolationPoly); + // show neighbors of voronoi2 + ArrayList neigh2 = voronoi2.getDirectNeighbors(mouse.getX(), + mouse.getY()); + g.drawOval((int) mouse.getX(), (int) mouse.getY(), 3, 3); + + for (Point2D currneigh2 : neigh2) { + g.fillRect((int) currneigh2.getX() - 2, + (int) currneigh2.getY() - 2, 5, 5); + // fill cut with Color + // vTest.drawIntersectArea( + // interpolationPoly, + // vTest.getPoly((int) currneigh2.getX(), + // (int) currneigh2.getY()), g); + + } + + } + + public Dimension getPreferredSize() { + return new Dimension(300, 500); + } + + public void processMouseEvent(MouseEvent e) { + if (e.getID() == MouseEvent.MOUSE_CLICKED + && e.getButton() == MouseEvent.BUTTON1) { + System.out.println("Maus bei:" + e.getX() + "," + e.getY()); + Point2D mouse = vTest.getNearestPoint(e.getX(), e.getY()); + x = (int) mouse.getX(); + y = (int) mouse.getY(); + xmouse = (int) e.getX(); + ymouse = (int) e.getY(); + + System.out.println("Maustreffer bei: " + x + "," + y); + repaint(); + } + } + +} + +/** + * Diese Klasse ist ein WindowsAdapter. Dieser kann auf WindowsEvents hören. + * Automatisch wird dann windowsClosing ausgeführt + * + * @author richy + * + */ +class closeFrame extends WindowAdapter { + public void windowClosing(WindowEvent e) { + System.exit(0); + } +} + +class mouse implements MouseListener { + public void processMouseEvent(MouseEvent e) { + System.out.println("bla"); + } + + @Override + public void mouseClicked(MouseEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void mouseEntered(MouseEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void mouseExited(MouseEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void mousePressed(MouseEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void mouseReleased(MouseEvent e) { + // TODO Auto-generated method stub + + } +} -- cgit v1.2.3-55-g7522