summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Zahoransky2011-11-07 16:29:56 +0100
committerRichard Zahoransky2011-11-07 16:29:56 +0100
commit08d5f7b0a0b24c042aa5976f66bf3a1b5b754478 (patch)
treeba5388774100c1b218cb264927c3bb3669fd7e06
parentinit (diff)
downloadlocalization-08d5f7b0a0b24c042aa5976f66bf3a1b5b754478.tar.gz
localization-08d5f7b0a0b24c042aa5976f66bf3a1b5b754478.tar.xz
localization-08d5f7b0a0b24c042aa5976f66bf3a1b5b754478.zip
Localization Code. How-To will follow...
-rw-r--r--.classpath10
-rw-r--r--.project19
-rw-r--r--DataStructure/BayesAll.java380
-rw-r--r--DataStructure/GPScoordinate.java88
-rw-r--r--DataStructure/GSMMap.java1275
-rw-r--r--DataStructure/GSMMapInterpolatorOld.java200
-rw-r--r--DataStructure/GoogleOut.java598
-rw-r--r--DataStructure/Interpolator.java366
-rw-r--r--DataStructure/MeasurementReport.java60
-rw-r--r--DataStructure/MobilePhone.java337
-rw-r--r--DataStructure/NormDistribution.java77
-rw-r--r--DataStructure/PhoneContainer.java106
-rw-r--r--DataStructure/PossibilityObject.java21
-rw-r--r--DataStructure/ResultScore.java54
-rw-r--r--DataStructure/ScoreElement.java21
-rw-r--r--DataStructure/SingleBTS.java775
-rw-r--r--DataStructure/Weight.java19
-rw-r--r--DataStructure/gsmBayes.java752
-rw-r--r--DataStructure/jdom.jarbin0 -> 152797 bytes
-rw-r--r--DataStructure/ratioElem.java114
-rw-r--r--DoGsmMap.java87
-rw-r--r--GSMMapping.java128
-rw-r--r--Interpolate.java43
-rw-r--r--MapSearch.java123
-rw-r--r--Parse/CalcVariance.java65
-rw-r--r--Parse/MapInverse.java115
-rw-r--r--Parse/NMEAParse.java224
-rw-r--r--Parse/SqlPoller.java47
-rw-r--r--Parse/SqlPollerDate.java406
-rw-r--r--Parse/SqlPollerUnThreaded.java370
-rw-r--r--Parse/sqlreader.java483
-rw-r--r--Variance.java45
-rw-r--r--VoronoiInterpolate.java50
-rw-r--r--delaunay/ArraySet.java104
-rw-r--r--delaunay/DelaunayAp.java429
-rw-r--r--delaunay/Graph.java108
-rw-r--r--delaunay/Pnt.java470
-rw-r--r--delaunay/Triangle.java152
-rw-r--r--delaunay/Triangulation.java281
-rw-r--r--gui/GUI.java69
-rw-r--r--gui/ListTest.java47
-rw-r--r--gui/Localization.java291
-rw-r--r--gui/LocalizationNew.java773
-rw-r--r--gui/MapShow.java38
-rw-r--r--gui/MapTest.java119
-rw-r--r--gui/MapViewer.java54
-rw-r--r--gui/ShowMapStrength.java309
-rw-r--r--gui/Start.java64
-rw-r--r--gui/test.java72
-rw-r--r--helper/Distance.java75
-rw-r--r--helper/Extrapolate.java508
-rw-r--r--helper/FunctionFit.java91
-rw-r--r--helper/LMfunc.java37
-rw-r--r--helper/ListBTS.java300
-rw-r--r--helper/ListGPS.java191
-rw-r--r--helper/Polygons.java34
-rw-r--r--lookup/BTSLut.java200
-rw-r--r--lookup/GSMLut.java88
-rw-r--r--lookup/ILut.java18
-rw-r--r--lookup/RatioLut.java41
-rw-r--r--lookup/ResultScore.java101
-rw-r--r--lookup/ScoreElement.java44
-rw-r--r--mysql-connector-java-5.1.14-bin.jarbin0 -> 775688 bytes
-rw-r--r--parallel-strictdB-BER.objbin0 -> 50796259 bytes
-rw-r--r--swingx-beaninfo.jarbin0 -> 222643 bytes
-rw-r--r--swingx-ws.jarbin0 -> 328767 bytes
-rw-r--r--swingx.jarbin0 -> 1402344 bytes
-rw-r--r--testing/testsVar.java26
-rw-r--r--voronoi/Classtest.java36
-rw-r--r--voronoi/CompGeom.java35
-rw-r--r--voronoi/CompGeomTest.java132
-rw-r--r--voronoi/ConvexHull2D.java233
-rw-r--r--voronoi/DelaunayTri.java612
-rw-r--r--voronoi/GeomCanvas.java297
-rw-r--r--voronoi/cEdge.java23
-rw-r--r--voronoi/cEdgeList.java61
-rw-r--r--voronoi/cFace.java22
-rw-r--r--voronoi/cFaceList.java62
-rw-r--r--voronoi/cPointd.java15
-rw-r--r--voronoi/cPointi.java107
-rw-r--r--voronoi/cVertex.java51
-rw-r--r--voronoi/cVertexList.java233
-rw-r--r--voronoi/erstesVoronoi.pngbin0 -> 120990 bytes
-rw-r--r--voronoi/sweepLineVD.java73
-rw-r--r--voronoi/voronoi.java2228
-rw-r--r--voronoiTest.java222
86 files changed, 17034 insertions, 0 deletions
diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..303ee3b
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path=""/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+ <classpathentry kind="lib" path="swingx.jar"/>
+ <classpathentry kind="lib" path="swingx-beaninfo.jar"/>
+ <classpathentry kind="lib" path="swingx-ws.jar"/>
+ <classpathentry kind="lib" path="mysql-connector-java-5.1.14-bin.jar"/>
+ <classpathentry kind="output" path=""/>
+</classpath>
diff --git a/.project b/.project
new file mode 100644
index 0000000..b6b206f
--- /dev/null
+++ b/.project
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>GSMMapping</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.jem.beaninfo.BeanInfoNature</nature>
+ </natures>
+</projectDescription>
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<SingleBTS> MR;
+ ArrayList<ratioElem>[][] 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<SingleBTS> 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<ratioElem> 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<ratioElem> 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<ratioElem> 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<ratioElem> MRphone,
+ ArrayList<ratioElem> 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<ratioElem>[][] computeMapRatio() {
+ ArrayList<ratioElem>[][] 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<ratioElem>(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<ratioElem> computeAllRatios(ArrayList<SingleBTS> MR) {
+ SingleBTS[] content = map.content();
+ ArrayList<ratioElem> result = new ArrayList<ratioElem>(
+ 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<ratioElem> computeRatios(ArrayList<SingleBTS> MR) {
+ ArrayList<ratioElem> result = new ArrayList<ratioElem>(
+ 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<PossibilityObject> result = new ArrayList<PossibilityObject>(
+ 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<ratioElem> RSSVector;
+ public double totalProbability;
+
+ public computeTotalProbability(ArrayList<ratioElem> 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<Date>, 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<JXMapViewer>, Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 7231890635513775719L;
+ public double minX;
+ public double maxX;
+ public double minY;
+ public double maxY;
+ public double[] Xcoords;
+ public double[] Ycoords;
+ public double accuracy;
+ public ArrayList<SingleBTS>[][] map;
+ // public ArrayList<SingleBTS>[][] buffer;
+ public SingleBTS[] btsnames; // names of BTS from sql databse
+ private SingleBTS[] btsarray; // btsarray from sqlreader.
+ private GPScoordinate[] gpsarray;
+ public long IMSI;
+ private int matrixsize;
+ private boolean isAveraged = false;
+ private SingleBTS[] mapcontent;
+ public int numberOfCoordinates;
+ public PaintEnum whatToPaint = PaintEnum.DL;
+ public int indexToPaint;
+
+ // Constructor
+ public GSMMap(sqlreader SQL, double accuracy) {
+ // search for min and max Y,X Coords
+ this.accuracy = accuracy;
+ numberOfCoordinates = SQL.gpsarray.length;
+ gpsarray = SQL.gpsarray; // measured GPS coordinates
+ btsarray = SQL.btsarray; // corresponding found BTS
+ btsnames = SQL.BtsNames;
+ this.IMSI = SQL.IMSI;
+ minX = MapHelper.getMinX(gpsarray, 0d);
+ maxX = MapHelper.getMaxX(gpsarray, 0d);
+ minY = MapHelper.getMinY(gpsarray, 0d);
+ maxY = MapHelper.getMaxY(gpsarray, 0d);
+ Xcoords = MapHelper.createArray(minX, maxX, accuracy); // 90°
+ Ycoords = MapHelper.createArray(minY, maxY, accuracy); // 180°
+ // create Array with inside ArrayList
+ ArrayList<SingleBTS>[][] map = new ArrayList[Xcoords.length][Ycoords.length];
+ this.map = map;
+ // initializa map
+ for (int x = 0; x < Xcoords.length; x++) {
+ for (int y = 0; y < Ycoords.length; y++) {
+ map[x][y] = new ArrayList<SingleBTS>();
+ }
+ }
+
+ // fill map
+ for (int i = 0; i < gpsarray.length; i++) {
+ add(gpsarray[i], btsarray[i]);
+ }
+
+ }
+
+ public void add(GPScoordinate gps, SingleBTS bts) {
+ int x = searchBestX(gps.coord2);
+ int y = searchBestY(gps.coord1);
+ map[x][y].add(bts);
+
+ }
+
+ public void add(GPScoordinate gps, ArrayList<SingleBTS> list) {
+ if (list == null)
+ return;
+ int x = searchBestX(gps.coord2);
+ int y = searchBestY(gps.coord1);
+ map[x][y].addAll(list);
+ }
+
+ /**
+ * Averages all MR that fall into one tile. Does not depend on usedBTS from
+ * sql
+ */
+ public void average() {
+ for (int x = 0; x < Xcoords.length; x++) {
+ for (int y = 0; y < Ycoords.length; y++) {
+ SingleBTS[] content = MapHelper.content(map[x][y]);
+ if (content != null) {
+ map[x][y] = generateAveragedList(map[x][y], content);
+ }
+ }
+ }
+ // after averaging the distances can be calculated pretty fast
+ calc_distances();
+ isAveraged = true;
+
+ }
+
+ /**
+ * calculates distance for every measurement report in the gsm map. Reports
+ * distance = 0 if Distance can not be computed
+ */
+ public void calc_distances() {
+ for (int x = 0; x < Xcoords.length; x++) {
+ for (int y = 0; y < Ycoords.length; y++) {
+ for (int z = 0; z < map[x][y].size(); z++) {
+ SingleBTS corr = corrBTS(map[x][y].get(z));
+ if (corr == null) {
+ // if Distance could not be calculated, skip
+ map[x][y].get(z).distance = 0.0;
+ } else {
+ // corresponding BTS was found
+ GPScoordinate coord1 = corr.coordinate;
+ GPScoordinate coord2 = getCoord(x, y);
+ map[x][y].get(z).distance = helper.Distance.calc(
+ coord1, coord2);
+ }
+ }
+
+ }
+ }
+ }
+
+ /**
+ * returns corresponding BTS from SQL-arfcn table for this MR
+ *
+ * @param mr
+ * your MR
+ * @return BTS that fits to this MR. Null if not found
+ */
+ private SingleBTS corrBTS(SingleBTS mr) {
+ for (int i = 0; i < btsnames.length; i++) {
+ if (mr.ARFCN == btsnames[i].ARFCN)
+ return btsnames[i];
+ }
+ return null;
+ }
+
+ private SingleBTS corrBTS(int arfcn) {
+ SingleBTS element = new SingleBTS(arfcn, "whatever");
+ return corrBTS(element);
+ }
+
+ public GPScoordinate getCoord(int x, int y) {
+ return new GPScoordinate(null, Ycoords[y], 'N', Xcoords[x], 'E', true);
+ }
+
+ /**
+ * Gets all BTSs that occur in the GSMmap. Note: this may be different from
+ * the BTSarray. There may be BTSs that are not stored in the sql database.
+ * For example: E-Plus BTSs
+ *
+ * @return Array with BTSs that occur in the GSMmap
+ */
+ public SingleBTS[] getUniqueBTSlist() {
+
+ ArrayList<SingleBTS> BTSlist = new ArrayList<SingleBTS>();
+ for (int x = 0; x < btsarray.length; x++) {
+ BTSlist.add(btsarray[x]);
+ }
+ return helper.ListBTS.content(BTSlist);
+
+ }
+
+ private ArrayList<SingleBTS> generateAveragedList(
+ ArrayList<SingleBTS> List, SingleBTS[] content) {
+ ArrayList<SingleBTS> output = new ArrayList<SingleBTS>();
+ // traverse every unique BTS
+ for (SingleBTS singleBTS : content) {
+ // initialize with ARFCN and Name
+ SingleBTS current = new SingleBTS(singleBTS.ARFCN, singleBTS.name);
+ // add everything from list. SingleBTS-Class takes only correct BTSs
+ for (SingleBTS measure : List) {
+ current.addBTSMeasure(measure);
+ }
+ output.add(current);
+ }
+
+ return output;
+ }
+
+ /**
+ * @param coord
+ * Coordinate in DEC
+ * @return Index where this coordinate is located within the GSMmap (x-axis)
+ */
+ public int searchBestX(double coord) {
+ // search for best fit in array
+ int found = (int) Math.round(((coord - minX) / accuracy));
+ if (found > Xcoords.length) {
+ System.out.println("gesucht nach: " + coord);
+ }
+ return found;
+ }
+
+ /**
+ * @param coord
+ * Coordinate in DEC
+ * @return Index where this coordinate is located within the GSMmap (y-axis)
+ */
+ public int searchBestY(double coord) {
+ // search for best fit in array
+ int found = (int) Math.round(((coord - minY) / accuracy));
+ // if (found == 8)
+ // System.out.println("Gesucht nach: " + coord + " Gefunden bei " +
+ // found);
+ return found;
+ }
+
+ public ArrayList<SingleBTS> getBTSList(GPScoordinate gps) {
+ int x = searchBestX(gps.coord2);
+ int y = searchBestY(gps.coord1);
+ return map[x][y];
+ }
+
+ public ArrayList<SingleBTS> getBTSList(double coordX, double coordY) {
+ // you could create a new GPScoordinate and use
+ // getBTSList(GPScoordinate)
+ // but maybe it's slower?
+ int x = searchBestX(coordX);
+ int y = searchBestY(coordY);
+ return map[x][y];
+
+ }
+
+ public SingleBTS getFirstBTS() {
+ return btsarray[0];
+ }
+
+ /**
+ * gets all the BTS that are stored in this map. content is ordered as the
+ * BTS appear in the map (or lets say... not sorted at all)
+ *
+ * @return
+ */
+ public SingleBTS[] content() {
+ if (mapcontent == null || mapcontent.length == 0) {
+ mapcontent = ListBTS.content(Arrays.asList(btsarray));
+ }
+
+ return mapcontent;
+ }
+
+ /**
+ * gets all BTS in this map that are not from the RZ-GSM
+ *
+ * @return
+ */
+ public SingleBTS[] contentForeignBTS() {
+ content(); // fill mapcontent
+ LinkedList<SingleBTS> result = new LinkedList<SingleBTS>();
+ for (int i = 0; i < mapcontent.length; i++) {
+
+ if (!ListBTS.contains(Arrays.asList(btsnames), mapcontent[i])) {
+ // current Element is not a RZ-GSM bts. Store it
+ result.add(mapcontent[i]);
+ }
+ }
+ if (result == null || result.isEmpty()) {
+ return null;
+ } else {
+ return result.toArray(new SingleBTS[1]);
+ }
+
+ }
+
+ /**
+ * Gets the first BTS out of the map that matches the arfcn of the given one
+ *
+ * @param bts
+ * @return
+ */
+ public SingleBTS getFirstBTSmatch(SingleBTS bts) {
+ for (SingleBTS element : btsarray) {
+ if (element.ARFCN == bts.ARFCN)
+ return element;
+ }
+ return null;
+ }
+
+ public boolean contains(SingleBTS bts) {
+ for (SingleBTS element : btsarray) {
+ if (element.ARFCN == bts.ARFCN)
+ return true;
+ }
+ return false;
+ }
+
+ public void gnuPlotSignalStrength(int ARFCN, int phonecount)
+ throws IOException {
+ // for each Tile: check if ARFCN exists. If so, ouput a file
+ // To calculate decimal deg. to meters, see
+ // http://www.sunearthtools.com/dp/tools/conversion.php?lang=eng
+ int placecount = 0;
+ // coordinates of BTS 877
+ // int BTSXCoord = searchBestX(7.834994d);
+ // int BTSYCoord = searchBestY(48.012708d);
+ File output = new File(IMSI + ".dat");
+ FileWriter fw = new FileWriter(output);
+ fw.append("#Uplink, Mobile Phone: " + IMSI);
+ fw.append("\r\n");
+ fw.append("#x y min max variance");
+ fw.append("\r\n");
+ // for every tile in GSMMap
+ for (int x = 0; x < Xcoords.length; x++) {
+ for (int y = 0; y < Ycoords.length; y++) {
+ for (SingleBTS bts : map[x][y]) {
+ // only full BTS are able to be drawn (uplink)
+ if (bts.ARFCN == ARFCN && bts.fullBTS) {
+ placecount++;
+ // double distance = Math.sqrt(Math.pow(x - BTSXCoord,
+ // 2)
+ // + Math.pow(y - BTSYCoord, 2));
+ double distance = helper.Distance.calc(48.012708,
+ 7.834994, Ycoords[y], Xcoords[x]);
+ // to meters (rough guess): one tile is 8m*8m
+ // distance = distance * 8;
+ // output Signalstrength, min, max and variance
+ NumberFormat nf = DecimalFormat.getInstance(Locale.US);
+ nf.setMaximumFractionDigits(15);
+ fw.append(distance + " " + nf.format(bts.getULmW())
+ + " " + nf.format(bts.minULmW()) + " "
+ + nf.format(bts.maxULmW()) + " "
+ + bts.getVarianceULmW());
+ fw.append("\r\n");
+ }
+ }
+ }
+ }
+ fw.close();
+ }
+
+ /**
+ * Outputs all receivable DLs for given phones. Distance to BTS with arfcn
+ * distanceARFCN is calculated
+ *
+ * @param arfcn
+ * @param distanceArfcn
+ * @throws IOException
+ */
+ public void gnuPlotDLAll(int[] arfcn, int distanceArfcn) throws IOException {
+ File output = new File("delta" + IMSI + ".dat");
+ FileWriter fw = new FileWriter(output);
+ fw.append("#DL all BTS\r\n");
+ String BTSs = "";
+ for (int i : arfcn) {
+ BTSs += "arfcn:" + Integer.toString(i) + " ";
+ }
+ fw.append("#Place " + BTSs + " 877UL 880UL \r\n");
+ for (int x = 0; x < Xcoords.length; x++) {
+ for (int y = 0; y < Ycoords.length; y++) {
+ if (map[x][y] == null || map[x][y].isEmpty()) {
+ continue;
+ }
+ SingleBTS reference = corrBTS(distanceArfcn);
+ fw.append(Double.toString(helper.Distance.calc(
+ reference.coordinate, getCoord(x, y))));
+ // TODO: here, distance to specified arfcn
+ fw.append(Integer.toString(x * Xcoords.length + y) + " ");
+ for (int i : arfcn) {
+ SingleBTS current = helper.ListBTS.getARFCN(map[x][y], i);
+
+ if (current != null) {
+ fw.append(Double.toString(current.getDldB()) + " ");
+ } else {
+ fw.append("NaN ");
+ }
+
+ }
+ SingleBTS uplink = helper.ListBTS.getARFCN(map[x][y], 877);
+ if (uplink != null && uplink.getUldB() != 0) {
+ fw.append(uplink.getUldB() + " ");
+ } else {
+ fw.append("NaN ");
+ }
+ uplink = helper.ListBTS.getARFCN(map[x][y], 880);
+ if (uplink != null && uplink.getUldB() != 0) {
+ fw.append(uplink.getUldB() + " ");
+ } else {
+ fw.append("NaN ");
+ }
+ fw.append("\r\n");
+
+ }
+ }
+ fw.close();
+ }
+
+ public void gnuPlotDeltaBTS(int ARFCN1, int ARFCN2) throws IOException {
+ // draw the ratio of ARFCN1/ARFCN2 and output in a GNUPlot readable file
+
+ // create FileWriter
+ File output = new File("delta" + IMSI + ".dat");
+ FileWriter fw = new FileWriter(output);
+ fw.append("# Delta between BTS " + ARFCN1 + " and " + ARFCN2
+ + " in dBm and mW\r\n");
+ fw.append("# Delta(dBm) Delta(mW) Ratio(dBm) Ratio(mW) DL:"
+ + ARFCN1
+ + " DL:"
+ + ARFCN2
+ + " Delta(strict_dBm) Ratio(strict_dBm) Carrier_Ratio(to 101 dB) \r\n");
+ SingleBTS bts1 = null;
+ SingleBTS bts2 = null;
+ for (int x = 0; x < Xcoords.length; x++) {
+ for (int y = 0; y < Ycoords.length; y++) {
+ bts1 = null;
+ bts2 = null;
+ for (SingleBTS bts : map[x][y]) {
+ if (bts.ARFCN == ARFCN1) {
+ bts1 = bts;
+ }
+ if (bts.ARFCN == ARFCN2) {
+ bts2 = bts;
+ }
+ }
+ // check if both BTS were found
+ if (bts1 != null && bts2 != null) {
+ // make the output. Only Downlink possible!
+ fw.append((bts1.getDldB() - bts2.getDldB())
+ + " "
+ + (bts1.getDLmW() - bts2.getDLmW())
+ + " "
+ + (bts1.getDldB() / bts2.getDldB())
+ + " "
+ + (bts1.getDLmW() / bts2.getDLmW())
+ + " "
+ + bts1.getDldB()
+ + " "
+ + bts2.getDldB()
+ + " "
+ + (bts1.getStrictDLdBAverage() - bts2
+ .getStrictDLdBAverage())
+ + " "
+ + (bts1.getStrictDLdBAverage() / bts2
+ .getStrictDLdBAverage())
+ + " "
+ + (10 * Math.log10(bts2.getDLmW() / bts1.getDLmW()))
+ + "\r\n");
+
+ }
+ }
+ }
+ fw.close();
+
+ }
+
+ /**
+ * removes outliers in each MR. Needs average() first. Otherwise each
+ * SingleBTS only holds one MR!
+ */
+ public void removeOutlier() {
+ for (int x = 0; x < Xcoords.length; x++) {
+ for (int y = 0; y < Ycoords.length; y++) {
+ for (int z = 0; z < map[x][y].size(); z++) {
+ map[x][y].get(z).removeOutlier();
+ }
+
+ }
+ }
+
+ }
+
+ public double getDistance(int x1, int x2, int y1, int y2) {
+ return helper.Distance.calc(Ycoords[y1], Xcoords[x1], Ycoords[y2],
+ Xcoords[x2]);
+
+ }
+
+ /**
+ * Extrapolations the map. For every Point a square eith size size*size is
+ * examined. A log function gets derived and the current point is calculated
+ *
+ * @param size
+ * @return not yet implemented
+ */
+ public boolean extrapolate(int size) {
+ matrixsize = size;
+ // System.out
+ // .println("WARNING: not correct implemented. map overrides buffer. Therefor UL-part of existing BTSs in map where only DL is available will not be stored");
+ // this might not be a problem: on places where a DL exists but no UL,
+ // the phone will always connect to the better cell, so a UL will
+ // actually never be received (only partyl correct)
+
+ // create buffer to store extrapolation
+ // buffer = new ArrayList[map.length][map[0].length];//not needed
+ // initialize
+ // for (int map2X = 0; map2X < buffer.length; map2X++) {
+ // for (int map2Y = 0; map2Y < buffer[0].length; map2Y++) {
+ // buffer[map2X][map2Y] = new ArrayList<SingleBTS>();
+ // }
+ // }
+
+ // take one of the BTS from the sql table arfcn
+ // traverse every place of the map
+ // try if extrapolation is needed or possible
+ // boundary of 3
+
+ // do RZ-GSM BTS first
+ for (SingleBTS extrapolateThis : btsnames) {
+ for (int x = size; x < Xcoords.length - size; x++) {
+ for (int y = size; y < Ycoords.length - size; y++) {
+ checkAndDoExtrapolation(x, y, extrapolateThis);
+ }
+ }
+ }
+
+ // do foreign BTS afterwards
+
+ // unset interpolated flag to prepare for new run. This means that
+ // getSurrounding will get the newly interpolated MR in the next run
+ unsetInterpolated();
+
+ for (SingleBTS extrapolateThis : contentForeignBTS()) {
+ for (int x = size; x < Xcoords.length - size; x++) {
+ for (int y = size; y < Ycoords.length - size; y++) {
+ extrapolateForeignDL(x, y, extrapolateThis);
+ }
+ }
+ }
+
+ // now do the extrapolation for foreign BTS. Calculate a delta between
+ // two BTS
+ // extrapolateForeign();
+
+ return false;
+ }
+
+ /*
+ * private void extrapolateForeign() { SingleBTS[] foreign =
+ * contentForeignBTS(); for (SingleBTS extrapolateThis : foreign) { for (int
+ * x = 2; x < Xcoords.length - 2; x++) { for (int y = 2; y < Ycoords.length
+ * - 2; y++) { for (int i = 0; i < directions.values().length; i++) {
+ * extrapolateForeignDL(directions.values()[i], x, y, extrapolateThis); } }
+ * }
+ *
+ * }
+ *
+ * }
+ */
+
+ /**
+ *
+ * @param direction
+ * which direction to extrapolate
+ * @param x
+ * map coordinate
+ * @param y
+ * map coordinate
+ * @param extrapolateThis
+ * BTS to extrapolate
+ */
+ private void extrapolateForeignDL(int x, int y, SingleBTS extrapolateThis) {
+ SingleBTS bts1 = null;
+ SingleBTS bts2 = null;
+ for (int i = 0; i < directions.values().length; i++) {
+ directions direction = directions.values()[i];
+ switch (direction) {
+ case DOWN:
+ bts1 = ListBTS.getARFCN(map[x - 1][y], extrapolateThis);
+ bts2 = ListBTS.getARFCN(map[x - 2][y], extrapolateThis);
+ break;
+ case UP:
+ bts1 = ListBTS.getARFCN(map[x + 1][y], extrapolateThis);
+ bts2 = ListBTS.getARFCN(map[x + 2][y], extrapolateThis);
+ break;
+ case LEFT:
+ bts1 = ListBTS.getARFCN(map[x][y - 1], extrapolateThis);
+ bts2 = ListBTS.getARFCN(map[x][y - 2], extrapolateThis);
+ break;
+ case RIGHT:
+ bts1 = ListBTS.getARFCN(map[x][y + 1], extrapolateThis);
+ bts2 = ListBTS.getARFCN(map[x][y + 2], extrapolateThis);
+ break;
+ case UPLEFT:
+ bts1 = ListBTS.getARFCN(map[x][y + 1], extrapolateThis);
+ bts2 = ListBTS.getARFCN(map[x][y + 2], extrapolateThis);
+ break;
+ default:
+ break;
+ }
+ // do interpolation. Average extrapolated bts between all.
+ insertForeignBTS(x, y, bts1, bts2, extrapolateThis);
+
+ }
+
+ }
+
+ /**
+ * Gets two BTS values, extrapolates from bts1 to bts2 and then guesses
+ * bts3. Bts3 gets updated or inserted into map[x][y].
+ *
+ * @param x
+ * @param y
+ * @param bts1
+ * @param bts2
+ * @param extrapolateThis
+ */
+ private void insertForeignBTS(int x, int y, SingleBTS bts1, SingleBTS bts2,
+ SingleBTS extrapolateThis) {
+ // boolean contains = ListBTS.contains(map[x][y], extrapolateThis);
+ // check if map[x][y]already contains the corresponding bts
+ if (bts1 == null || bts2 == null)
+ return; // nothing one can do
+ SingleBTS update = null;
+ if (ListBTS.contains(map[x][y], extrapolateThis)) {
+ if (!ListBTS.getARFCN(map[x][y], extrapolateThis).isInterpolated()) {
+ return;// is already measured! Do not change!
+ }
+ // map[x][y] contains a corresponding bts that is interpolated.
+ // update it
+ update = ListBTS.removeARFCN(map[x][y], extrapolateThis);
+
+ } else {
+ update = new SingleBTS(extrapolateThis.ARFCN, extrapolateThis.name);
+
+ }
+ update.interpolated.add(true);
+ // TODO: völlig falsch hier!!!
+ double DL = bts1.getDldB() + bts2.getDldB();
+ DL = DL / 2d;
+ update.addDl(DL);
+ // insert into map[x][y]
+ map[x][y].add(update);
+
+ }
+
+ /**
+ * adds a new boolean value (false) to each SingleBTS. A new extrapolation
+ * round starts. This means, that extrapolated BTS from the last run may now
+ * be used for extrapolation
+ */
+ private void unsetInterpolated() {
+ for (int x = 0; x < map.length; x++) {
+ for (int y = 0; y < map[0].length; y++) {
+ for (int z = 0; z < map[x][y].size(); z++) {
+ map[x][y].get(z).interpolated.add(false);
+ }
+ }
+ }
+
+ }
+
+ public boolean hasAMeasurement(int x, int y) {
+ boolean result = !(map[x][y] == null || map[x][y].isEmpty());
+ return result;
+ }
+
+ public boolean[][] getAllocation() {
+ boolean[][] result = new boolean[Xcoords.length][Ycoords.length];
+ for (int x = 0; x < Xcoords.length; x++) {
+ for (int y = 0; y < Ycoords.length; y++) {
+ result[x][y] = hasAMeasurement(x, y);
+ }
+ }
+ return result;
+ }
+
+ public long countTilesWMeasures() {
+ boolean[][] allocation = getAllocation();
+ long count = 0;
+ for (int x = 0; x < Xcoords.length; x++) {
+ for (int y = 0; y < Ycoords.length; y++) {
+ if (allocation[x][y])
+ count++;
+ }
+
+ }
+ return count;
+ }
+
+ /*
+ * private void merge() { for (int x = 0; x < map.length; x++) { for (int y
+ * = 0; y < map[0].length; y++) { if (map[x][y] != null &&
+ * !map[x][y].isEmpty()) { buffer[x][y] = map[x][y]; } } } map = buffer;
+ *
+ * }
+ */
+
+ /**
+ * Checks what kind of extrapolation is needed, if any
+ *
+ * @param x
+ * Coordinate in GSM map
+ * @param y
+ * Coordinate in GSM map
+ * @param extrapolateThis
+ * what BTS should be interpolated
+ */
+ private void checkAndDoExtrapolation(int x, int y, SingleBTS extrapolateThis) {
+ // check current x/y coordinate if extrapolateThis is existing
+ if (helper.ListBTS.contains(map[x][y], extrapolateThis)) {
+ if (helper.ListBTS.containsUL(map[x][y], extrapolateThis)) {
+ return; // nothing to do
+ }
+ // only uplink must be interpolated
+ tryExtrapolateUL(x, y, extrapolateThis);
+ } else {
+ tryExtrapolateDL(x, y, extrapolateThis);
+ // uplink and downlink must be interpolated.
+ // only downlink here. it the next run, the uplink will be
+ // interpolated
+ }
+
+ }
+
+ private boolean tryExtrapolateUL(int x, int y, SingleBTS extrapolateThis) {
+ // check if extrapolateThis is a foreign BTS
+ if (isForeign(extrapolateThis)) {
+ // extrapolateThis is not a RZ-GSM BTS. Uplink not available
+ return false;
+ }
+
+ // TODO: create copy of map. Place Extrapolation inside of this copy.
+ // Merge both at the end
+ // get Distance of this place to coordinates in extrapolateThis
+ double xval = helper.Distance.calc(extrapolateThis.coordinate,
+ getCoord(x, y));
+ ArrayList<SingleBTS> surrounding = getSurrounding(x, y, matrixsize,
+ extrapolateThis);
+
+ // create empty array
+
+ // do extrapolation
+ if (surrounding != null && !surrounding.isEmpty()) {
+ SingleBTS extrapolated = helper.Extrapolate.extrapolateLogUL(
+ surrounding, xval, extrapolateThis, 49);
+ if (extrapolated == null) {
+ return false;
+ } else {
+ // take out the extrapolated BTS from map. Update UL,
+ // reintegrate
+ SingleBTS element = helper.ListBTS.removeARFCN(map[x][y],
+ extrapolateThis);
+ element.addUl(extrapolated.getUldB());
+ element.interpolated.add(true);
+ element.distance = xval;
+ map[x][y].add(element);
+ // buffer[x][y].add(element);
+ return true;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ private boolean tryExtrapolateDL(int x, int y, SingleBTS extrapolateThis) {
+
+ // if (isForeign(extrapolateThis)) {
+ // do interpolation step by step because distances to corresponding
+ // BTS is unknown.
+ // eight directions and some special cases
+ // extrapolateForeignDL(x, y, extrapolateThis);
+ // return true;
+ // }
+
+ // TODO: create copy of map. Place Extrapolation inside of this copy.
+ // Merge both at the end
+ // get x/y Distance to corresponding this BTS
+
+ // extrapolate to value of x:
+ // double xval = helper.Distance.calc(extrapolateThis.coordinate.coord1,
+ // extrapolateThis.coordinate.coord2, Ycoords[y], Xcoords[x]);
+ double xval = helper.Distance.calc(extrapolateThis.coordinate,
+ getCoord(x, y));
+
+ ArrayList<SingleBTS> surrounding = getSurrounding(x, y, matrixsize,
+ extrapolateThis);
+ SingleBTS extrapolated = helper.Extrapolate.extrapolateLogDL(
+ surrounding, xval, extrapolateThis, 44);
+
+ // add extrapolated BTS to GSM map only if not null. Add distance
+ if (extrapolated != null) {
+ extrapolated.distance = xval;
+ extrapolated.interpolated.add(true);
+ map[x][y].add(extrapolated);
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Copies all SingleBTS of given surrounding into one linked list. If a
+ * Measurement was newly interpolated, it will be ignored and not added to
+ * the list
+ *
+ * @param x
+ * GSM map coordinate
+ * @param y
+ * GSm map coordinate
+ * @param size
+ * size of matrix where size specifies length and width. must be
+ * unequal
+ * @param extrapolateThis
+ * indicates which BTS.arfcn should be taken. Only matching
+ * arfcn's are copied to the list
+ * @return linked list with all bts in that area. Null if no matching BTS
+ * where found
+ */
+ private ArrayList<SingleBTS> getSurrounding(int x, int y, int size,
+ SingleBTS extrapolateThis) {
+ int max = (size - 1) / 2;
+ ArrayList<SingleBTS> list = new ArrayList<SingleBTS>();
+ // int max_x = map.length;
+ // int max_y = map[0].length;
+ for (int i = -1 * ((size - 1) / 2); i <= max; i++) {
+ for (int j = -1 * ((size - 1) / 2); j <= max; j++) {
+ // check boundaries
+ if (x + i > 0 && x + i < map.length && y + j > 0
+ && y + j < map[0].length) {
+ for (SingleBTS element : map[x + i][y + j]) {
+ if (element.ARFCN == extrapolateThis.ARFCN
+ && !element.newlyInterpolated()) {
+ // Boundaries okay, arfcn okay, was not interpolated
+ // in the last run
+ list.add(element);
+ }
+ }
+ }
+ }
+ }
+ // remove null elements
+ return helper.ListBTS.removeNullElements(list);
+
+ }
+
+ /**
+ * returns true if the BTS arfcn is not part of the RZ-GSM. Note that no
+ * check is done if arfcn is contained within the map
+ *
+ * @param arfcn
+ * which BTS to check
+ * @return True if arfcn is foreign. That means it is not part of the RZ-GSM
+ */
+ public boolean isForeign(SingleBTS arfcn) {
+ return (!ListBTS.contains(Arrays.asList(btsnames), arfcn));
+ }
+
+ /**
+ *
+ * @param MRlist
+ * Live MR from SQL database or List of Measurements to search
+ * @param thresholddBm
+ * take each MR +/- threshold_dB. Elements that are within
+ * threshold_dB get returned
+ * @return Coordinates that match to ANY of the provided MR, not to all! It
+ * is not the intersection!
+ */
+ public ArrayList<GPScoordinate> find(List<SingleBTS> MRlist,
+ double thresholddBm) {
+ // check if map got averaged
+ if (!isAveraged) {
+ System.out.println("Needs Average first!");
+ return null; // mabye average the MRlist first?
+ }
+
+ LinkedList<GPScoordinate> result = new LinkedList<GPScoordinate>();
+ // Iterator over MRlist
+ Iterator<SingleBTS> itr = MRlist.iterator();
+ while (itr.hasNext()) {
+ SingleBTS MR = itr.next();
+ result.addAll(find(MR, thresholddBm));
+ }
+ return new ArrayList<GPScoordinate>(result);
+
+ }
+
+ /**
+ *
+ * @param MR
+ * One measurement point
+ * @param thresholddBm
+ * search within this threshold_dB for coordinates
+ * (threshold_dB+/-MR)
+ * @return coordinates that match to the MR
+ */
+ public ArrayList<GPScoordinate> find(SingleBTS MR, double thresholddBm) {
+ LinkedList<GPScoordinate> result = new LinkedList<GPScoordinate>();
+ SingleBTS reference;
+ for (int x = 0; x < Xcoords.length; x++) {
+ for (int y = 0; y < Ycoords.length; y++) {
+ if (helper.ListBTS.contains(map[x][y], MR)) {
+ // test DL first
+ reference = helper.ListBTS.getARFCN(map[x][y], MR);
+ if ((reference.getDldB() + thresholddBm > MR.getDldB())
+ && (MR.getDldB() > reference.getDldB()
+ - thresholddBm)) {
+ // the MR fits with this coordinate
+ result.add(getCoord(x, y));
+ }
+ // test UL
+ reference = helper.ListBTS.getARFCN(map[x][y], MR);
+ if ((reference.getUldB() + thresholddBm > MR.getUldB())
+ && (MR.getUldB() > reference.getUldB()
+ - thresholddBm)) {
+ // the MR fits with this coordinate
+ result.add(getCoord(x, y));
+ }
+
+ }
+ }
+ }
+ return new ArrayList<GPScoordinate>(result);
+ }
+
+ public void merge(GSMMap map2) {
+ // TODO: check & possible increase boundaries first!
+ for (int x = 0; x < map2.Xcoords.length; x++) {
+ for (int y = 0; y < map2.Ycoords.length; y++) {
+ add(map2.getCoord(x, y), map2.map[x][y]);
+ average();
+ }
+ }
+ }
+
+ private enum directions {
+ UP, DOWN, LEFT, RIGHT, UPLEFT, UPRIGHT, DOWNRIGHT, DOWNLEFT, LEFTRIGHT, UPDOWN
+ }
+
+ public enum PaintEnum {
+ variance, UL, DL, DLexpected, BERSubUL, BERSubDL, OverallCoverageDL, OverallCoverageBER
+ }
+
+ @Override
+ public void paint(Graphics2D g, JXMapViewer OSmap, int w, int h) {
+ // TODO Auto-generated method stub
+ g = (Graphics2D) g.create();
+ g.setColor(Color.BLACK);
+ g.drawString(whatToPaint.toString(), 50, 30);
+ // convert from viewport to world bitmap
+ Rectangle rect = ((org.jdesktop.swingx.JXMapViewer) OSmap)
+ .getViewportBounds();
+ g.translate(-rect.x, -rect.y);
+
+ // draw each rectangle
+ for (int x = 0; x < Xcoords.length; x++) {
+ for (int y = 0; y < Ycoords.length; y++) {
+ SingleBTS current = ListBTS.getARFCN(map[x][y],
+ content()[indexToPaint]);
+ if (current != null
+ || whatToPaint == PaintEnum.OverallCoverageDL
+ || whatToPaint == PaintEnum.OverallCoverageBER) {
+ // if (hasAMeasurement(x, y)) {
+ // try {
+ // draw it
+ double coordX = Xcoords[x];
+ double coordY = Ycoords[y];
+ // double accuracy = accuracy;
+ Polygon tile = new Polygon();
+
+ GeoPosition pos1 = new GeoPosition(coordY - accuracy / 2,
+ coordX + accuracy / 2);
+ GeoPosition pos2 = new GeoPosition(coordY + accuracy / 2,
+ coordX + accuracy / 2);
+ GeoPosition pos3 = new GeoPosition(coordY + accuracy / 2,
+ coordX - accuracy / 2);
+ GeoPosition pos4 = new GeoPosition(coordY - accuracy / 2,
+ coordX - accuracy / 2);
+ Point2D pt1 = OSmap.getTileFactory().geoToPixel(pos1,
+ OSmap.getZoom());
+ Point2D pt2 = OSmap.getTileFactory().geoToPixel(pos2,
+ OSmap.getZoom());
+ Point2D pt3 = OSmap.getTileFactory().geoToPixel(pos3,
+ OSmap.getZoom());
+ Point2D pt4 = OSmap.getTileFactory().geoToPixel(pos4,
+ OSmap.getZoom());
+
+ // finally, draw it!
+ tile.addPoint((int) pt1.getX(), (int) pt1.getY());
+ tile.addPoint((int) pt2.getX(), (int) pt2.getY());
+ tile.addPoint((int) pt3.getX(), (int) pt3.getY());
+ tile.addPoint((int) pt4.getX(), (int) pt4.getY());
+ // Depending to what is set in whatToPaint
+ Color color = null;
+ if (whatToPaint == PaintEnum.DL) {
+ color = getColordB((int) current.getDldB());
+
+ } else if (whatToPaint == PaintEnum.DLexpected) {
+ // color = getColorStd(current.getVarianceDLdB());
+ color = getColordB((int) current.getStrictDLdBAverage());
+ } else if (whatToPaint == PaintEnum.variance) {
+ color = getColorStd(current.getTrueVarianceDLdB());
+ } else if (whatToPaint == PaintEnum.BERSubUL) {
+ if (current.ulQsub.isEmpty() || current.getULQsub() < 0)
+ continue;
+ color = getColorBER(current.getULQsub());
+ } else if (whatToPaint == PaintEnum.BERSubDL) {
+ if (current.dlQsub.isEmpty() || current.getDLQsub() < 0)
+ continue;
+ color = getColorBER(current.getDLQsub());
+ } else if (whatToPaint == PaintEnum.OverallCoverageDL
+ && hasAMeasurement(x, y)) {
+ SingleBTS bts1 = ListBTS.getARFCN(map[x][y], 880);
+ SingleBTS bts2 = ListBTS.getARFCN(map[x][y], 877);
+ if (bts1 != null && bts2 != null) {
+ // double bts1 = ListBTS.getARFCN(map[x][y],
+ // 880).getStrictDLdBAverage();
+ color = getColordB((int) Math.max(
+ bts1.getStrictDLdBAverage(),
+ bts2.getStrictDLdBAverage()));
+ } else if (bts2 != null) {
+ color = getColordB((int) bts2
+ .getStrictDLdBAverage());
+ } else if (bts1 != null) {
+ color = getColordB((int) bts1
+ .getStrictDLdBAverage());
+ }
+ } else if (whatToPaint == PaintEnum.OverallCoverageBER
+ && hasAMeasurement(x, y)) {
+ SingleBTS bts1 = ListBTS.getARFCN(map[x][y], 880);
+ SingleBTS bts2 = ListBTS.getARFCN(map[x][y], 877);
+ if (bts1 != null && bts2 != null) {
+ // double bts1 = ListBTS.getARFCN(map[x][y],
+ // 880).getStrictDLdBAverage();
+ color = getColorBER((int) Math.max(
+ bts1.getULQsub(), bts2.getULQsub()));
+ } else if (bts2 != null) {
+ color = getColorBER((int) bts2.getULQsub());
+ } else if (bts1 != null) {
+ color = getColorBER((int) bts1.getULQsub());
+ }
+ }
+ if (color != null) {
+ g.setColor(color);
+ g.fill(tile);
+ // g.setColor(Color.black);
+ // g.draw(tile);
+ // g.draw(tile);
+ }
+ try {
+ // Messungen schwarz umranden
+ if (!current.isInterpolated()) {
+ // g.setColor(Color.BLACK);
+ // g.draw(tile);
+ }
+ } catch (NullPointerException e) {
+
+ }
+
+ }
+ }
+ }
+ g.dispose();
+ }
+
+ private Color getColorBER(double dlQ) {
+ // between 0...7
+ int green = 0;
+ int red = 0;
+ if (dlQ < 3.5) {
+ green = 255;
+ red = (int) (255 * (dlQ / 3.5));
+ } else {
+ red = 255;
+ green = 255 - ((int) (255 * ((dlQ - 3.5) / 3.5)));
+ if (green < 0)
+ green = 0;
+ }
+
+ if (green < 0 || red < 0)
+ return null;
+
+ if (green > 255)
+ green = 255;
+ if (red > 255)
+ red = 255;
+
+ return new Color(red, green, 0, 185);
+ }
+
+ private Color getColordB(int strength) {
+
+ int green = 0;
+ int red = 0;
+ // yellow at -75
+ if (strength > -75) {
+ green = 255;
+ red = 256 - Math.abs((256 / 28) * (-75 - strength));
+
+ } else {
+ // transient green from now on
+ red = 255;
+ green = Math.abs((256 / 34) * (-110 - strength));
+ }
+ // int green = 256 - Math.abs((256 / 90) * (-120 - strength));
+ // int red = Math.abs((256 / 90) * (-120 - strength));
+ // int result = red << 24 | green
+ if ((green > 255) || (red > 255))
+ System.out.println("Zu groß bei strength= " + strength + ",Rot: "
+ + red + "Grün: " + green);
+ if (green > 255)
+ green = 255;
+ if (red > 255)
+ red = 255;
+ // return ("7f00" + Integer.toHexString(red) +
+ // Integer.toHexString(green));
+ // return ("ff00" + Integer.toHexString(red) +
+ // Integer.toHexString(green));
+ // return ("ff00" + Integer.toHexString(red) +
+ // Integer.toHexString(green));
+
+ Color result = new Color(red, green, 0, 185);
+
+ // return ("ff00" + Integer.toHexString(green) +
+ // Integer.toHexString(red));
+ return result;
+
+ }
+
+ private Color getColorStd(double var) {
+
+ double std = Math.sqrt(var);
+ // Std between 0...7
+ int green = 0;
+ int red = 0;
+ if (std < 3.5) {
+ green = 255;
+ red = (int) (255 * (std / 3.5));
+ } else {
+ red = 255;
+ green = 255 - ((int) (255 * ((std - 3.5) / 3.5)));
+ if (green < 0)
+ green = 0;
+ }
+ if (green > 255)
+ green = 255;
+ if (red > 255)
+ red = 255;
+
+ return new Color(red, green, 0, 185);
+ }
+
+ @SuppressWarnings("unused")
+ private Color getColorVar(double var) {
+ // let var be between 0 and 40
+ // 0...5: only a shade of green
+ // 5...15: between green and red
+ // 15...20: red
+ double middle = 25;
+
+ int green = 0;
+ int red = 0;
+ if (var < middle) {
+ green = 255;
+ red = (int) (255 * (var / middle));
+ } else {
+ red = 255;
+ green = 255 - ((int) (255 * ((var - middle) / middle)));
+ if (green < 0)
+ green = 0;
+ }
+ if (green > 255)
+ green = 255;
+ if (red > 255)
+ red = 255;
+
+ if (var > 20) {
+ // System.out.println("Brakepoiint");
+ }
+
+ return new Color(red, green, 0, 185);
+ }
+
+}
+
+final class MapHelper {
+ static public double getMaxX(GPScoordinate[] gps, double offset) {
+ double max = -181;
+ for (GPScoordinate current : gps) {
+ if (current.coord2 > max)
+ max = current.coord2;
+ }
+ return max;
+ // return max + offset;
+
+ }
+
+ static public double getMinX(GPScoordinate[] gps, double offset) {
+ double min = 181;
+ for (GPScoordinate current : gps) {
+ if (current.coord2 < min)
+ min = current.coord2;
+ }
+ return min;
+ // return min - offset;
+ }
+
+ static public double getMaxY(GPScoordinate[] gps, double offset) {
+ double max = -181;
+ for (GPScoordinate current : gps) {
+ if (current.coord1 > max)
+ max = current.coord1;
+ }
+ return max;
+ // return max + offset;
+ }
+
+ static public double getMinY(GPScoordinate[] gps, double offset) {
+ double min = 181;
+ for (GPScoordinate current : gps) {
+ if (current.coord1 < min)
+ min = current.coord1;
+ }
+ return min;
+ // return min - offset;
+ }
+
+ static public double[] createArray(double begin, double end, double accuracy) {
+ // add 1 to make sure even the last measurement fits in and doesn't
+ // through index out of bounds!
+ int size = (int) Math.ceil((end - begin) / accuracy) + 1;
+ double[] array = new double[size];
+ for (int i = 0; i < size; i++) {
+ array[i] = i * accuracy + begin;
+ }
+ return array;
+ }
+
+ /**
+ * ListBTS all the unique SingleBTS's that occur in this list
+ *
+ * @param list
+ * ListBTS with SingleBTS's
+ * @return Array with the unique SingleBTS's. That is, every BTS in this
+ * Array occurs also in the list. Null if the list was empty
+ */
+ static SingleBTS[] content(ArrayList<SingleBTS> list) {
+ // get first element of list.
+ // traverse list and delete every occurence of first element
+ // get next element
+ // copy list to destroy reference
+ ArrayList<SingleBTS> list2 = (ArrayList<SingleBTS>) list.clone();
+ if (list2.isEmpty())
+ return null;
+ // int count = 0;
+ ArrayList<SingleBTS> output = new ArrayList<SingleBTS>();
+ while (!list2.isEmpty()) {
+ SingleBTS bts = list2.get(0);
+ list2.remove(0);
+ output.add(bts);
+ // remove the just added bts from the BTS-list
+ for (int i = 0; i < list2.size(); i++) {
+ if (list2.get(i).ARFCN == bts.ARFCN) {
+ list2.remove(i);
+ i--;
+
+ }
+
+ }
+
+ }
+ return output.toArray(new SingleBTS[1]);
+ }
+}
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<SingleBTS> list = new ArrayList<SingleBTS>();
+ 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<SingleBTS> 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<SingleBTS> 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<MeasurementReport> MRlog;
+ // private LinkedList<GPScoordinate> 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("</Folder> \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("</Folder> \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("</Folder> \n");
+ }
+ }
+
+ br.write("</Document>");
+ br.write("</kml>");
+ 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("<open>1</open>\n");
+ br.write(" <Folder>\n");
+ br.write("<name>MR " + upDown + "" + btsname.ARFCN + ": "
+ + btsname.name + "</name>\n");
+ br.write(" <visibility>1</visibility>\n");
+ br.write("<description>MR from " + foundBTS.time.toString()
+ + "</description>\n");
+ br.write(" <LookAt>\n");
+ br.write("<longitude>" + (map.maxX + map.minX) / 2 + "</longitude>\n");
+ br.write("<latitude>" + (map.maxY + map.minY) / 2 + "</latitude>\n");
+ br.write("<altitude>0</altitude>\n");
+ br.write("<heading>0.0</heading>\n");
+ br.write("<tilt>0</tilt>\n");
+ br.write("<range>276.0</range>\n");
+ br.write("</LookAt>\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<SingleBTS> 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<SingleBTS> 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("<Placemark> \n");
+ br.write("<visibility>1</visibility>\n");
+ br.write("<name>" + name + "</name>\n");
+
+ writeStyleIdentifier(singleBTS, uplink);
+
+ br.write("<Polygon>\n");
+ br.write("<tessellate>1</tessellate>\n");
+ br.write("<outerBoundaryIs>\n");
+ br.write("<LinearRing>\n");
+ br.write("<coordinates>\n");
+
+ writePolygonCoordinates(coordX, coordY, map.accuracy);
+
+ br.write("</coordinates>\n");
+ br.write("</LinearRing>\n");
+ br.write("</outerBoundaryIs>\n");
+ br.write("</Polygon>\n");
+ br.write("</Placemark>\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("<styleUrl>#I" + btsRXvalue + "</styleUrl>\n");
+ } else if (bts.fullBTS) {
+ // show the nice FullBTS line around
+ br.write("<styleUrl>#F" + btsRXvalue + "</styleUrl>\n");
+ } else {
+ // no line
+ br.write("<styleUrl>#" + btsRXvalue + "</styleUrl>\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<GPScoordinate> GPSlog,
+ LinkedList<MeasurementReport> 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("<open>1</open>");
+ br.write(" <Folder>");
+ br.write("<name>Measurement Report " + map.IMSI + "</name>");
+ br.write(" <visibility>1</visibility>");
+ br.write("<description>MR from " + GPSlog.getFirst().time.toString()
+ + "</description>");
+ br.write(" <LookAt>");
+ br.write("<longitude>" + GPSlog.getFirst().coord2 + "</longitude>");
+ br.write("<latitude>" + GPSlog.getFirst().coord1 + "</latitude>");
+ br.write("<altitude>0</altitude>");
+ br.write("<heading>-34.82469740081282</heading>");
+ br.write("<tilt>0</tilt>");
+ br.write("<range>276.7870053764046</range>");
+ br.write("</LookAt>");
+
+ // write content
+ int i = 0;
+ int discarded = 0;
+ Iterator<GPScoordinate> 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("<Placemark> \n");
+ br.write("<visibility>1</visibility>");
+ br.write("<name>" + MR.toString() + "</name>");
+ // br.write("<PolyStyle>");
+ // br.write("<color>bf00ff00</color>");
+ // br.write("</PolyStyle>");
+
+ // dl: Downlink - Network to phone
+ // up: Uplink - Phone to Network (has better perception for some
+ // reason)
+ br.write("<styleUrl>#" + MRlog.get(i).getFirstBTSdl()
+ + "</styleUrl>");
+
+ br.write("<Polygon>");
+ br.write("<tessellate>1</tessellate>");
+ br.write("<outerBoundaryIs>");
+ br.write("<LinearRing>");
+ br.write("<coordinates>");
+ // 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("</coordinates>");
+ br.write("</LinearRing>");
+ br.write("</outerBoundaryIs>");
+ br.write("</Polygon>");
+ br.write("</Placemark>\n");
+ } else {
+ discarded++;
+
+ }
+
+ i++;
+ }
+ br.write("</Folder>");
+ br.write("</Document>");
+ br.write("</kml>");
+ br.flush();
+ br.close();
+ System.out.println("Discarded Coordinates: " + discarded);
+
+ }
+
+ @SuppressWarnings("unused")
+ private int getMin() {
+ Iterator<MeasurementReport> 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<MeasurementReport> 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<MeasurementReport> 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("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ br.write("<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n");
+ br.write(" <Document>\n");
+ br.write("<name>Measurement Report " + map.IMSI + "</name>\n");
+ br.write("<open>1</open>\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("<Style id=\"" + style + "\"> \n");
+ br.write("<PolyStyle> \n");
+ br.write("<color>" + getColor(style) + "</color> \n");
+ br.write("</PolyStyle> \n");
+ br.write("<LineStyle>\n");
+ // br.write("<color>" + getColor(style) + "</color>\n");
+ br.write("<color>" + 00000000 + "</color>\n");
+ br.write("</LineStyle>\n");
+ br.write("</Style> \n");
+ }
+
+ // styles for Full BTS: full white ffffff, no transparency:ff
+ for (int style = -30; style >= -120; style--) {
+ br.write("<Style id=\"F" + style + "\"> \n");
+ br.write("<PolyStyle> \n");
+ br.write("<color>" + getColor(style) + "</color> \n");
+ br.write("</PolyStyle> \n");
+ br.write("<LineStyle>\n");
+ // // br.write("<color>" + getColor(style) + "</color>\n");
+ br.write("<color>" + "ffffffff" + "</color>\n");
+ br.write("<width>2</width>\n");
+ br.write("</LineStyle>\n");
+ br.write("</Style> \n");
+ }
+
+ // styles for Interpolated BTS: full black 000000, no transparency:ff
+ for (int style = -30; style >= -120; style--) {
+ br.write("<Style id=\"I" + style + "\">\n");
+ br.write("<PolyStyle>\n");
+ br.write("<color>" + getColor(style) + "</color>\n");
+ br.write("</PolyStyle>\n");
+ br.write("<LineStyle>\n");
+ // br.write("<color>" + getColor(style) + "</color>\n");
+ br.write("<color>" + "ff000000" + "</color>\n");
+ br.write("<width>2</width>\n");
+ br.write("</LineStyle>\n");
+ br.write("</Style>\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("</Folder> \n");
+ br.write("</Document>");
+ br.write("</kml>");
+ 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("<Placemark> \n");
+ br.write("<visibility>1</visibility>\n");
+ br.write("<name>" + score + "</name>\n");
+
+ br.write("<styleUrl>#" + score + "</styleUrl>\n");
+
+ br.write("<Polygon>\n");
+ br.write("<tessellate>1</tessellate>\n");
+ br.write("<outerBoundaryIs>\n");
+ br.write("<LinearRing>\n");
+ br.write("<coordinates>\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("</coordinates>\n");
+ br.write("</LinearRing>\n");
+ br.write("</outerBoundaryIs>\n");
+ br.write("</Polygon>\n");
+ br.write("</Placemark>\n");
+
+ }
+
+ private void writeProbHeader(BufferedWriter br) throws IOException {
+ br.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ br.write("<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n");
+ br.write(" <Document>\n");
+ br.write("<name> Probability map </name> \n");
+ br.flush();
+ br.write("<open>1</open>\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("<Style id=\"" + style + "\"> \n");
+ br.write("<PolyStyle> \n");
+ br.write("<color>" + getProbabilityColor(style) + "</color> \n");
+ br.write("</PolyStyle> \n");
+ br.write("<LineStyle>\n");
+ // br.write("<color>" + getColor(style) + "</color>\n");
+ br.write("<color>" + 00000000 + "</color>\n");
+ br.write("</LineStyle>\n");
+ br.write("</Style> \n");
+ }
+ br.write(" <Folder>\n");
+ br.write("<name>Probability</name>");
+ br.write(" <visibility>1</visibility>\n");
+ br.write("<description>Probability Map</description>\n");
+ br.write(" <LookAt>\n");
+ br.write("<longitude>" + (map.maxX + map.minX) / 2 + "</longitude>\n");
+ br.write("<latitude>" + (map.maxY + map.minY) / 2 + "</latitude>\n");
+ br.write("<altitude>0</altitude>\n");
+ br.write("<heading>0.0</heading>\n");
+ br.write("<tilt>0</tilt>\n");
+ br.write("<range>276.0</range>\n");
+ br.write("</LookAt>\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<SingleBTS>[][] 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<SingleBTS>();
+ }
+ }
+
+ }
+
+ /**
+ * 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<Point2D> neighbors = secondary.getDirectNeighbors(x, y);
+
+ // calculate intersection of voronoi region for each neighbor
+ ArrayList<Weight> weights = new ArrayList<Weight>(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<SingleBTS> MR = new LinkedList<SingleBTS>();
+ public Date time = new Date();
+
+ // Constructor
+ public MeasurementReport() {
+ // MR = new LinkedList<SingleBTS>();
+ }
+
+ // 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<JXMapViewer> {
+ public ArrayList<SingleBTS> 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<SingleBTS>();
+ }
+
+ public MobilePhone(BayesAll bayes) {
+ MR = new ArrayList<SingleBTS>();
+ 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<SingleBTS> 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<SingleBTS> 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<SingleBTS> 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<SingleBTS> filterTime(ArrayList<SingleBTS> MR, long time) {
+ ArrayList<SingleBTS> temporalMR = new ArrayList<SingleBTS>(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<JXMapViewer> {
+
+ private ArrayList<MobilePhone> phones = new ArrayList<MobilePhone>();
+ private ArrayList<ImsiColor> colors = new ArrayList<ImsiColor>();
+
+ 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<PossibilityObject> {
+ 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<ScoreElement> scores = new ArrayList<ScoreElement>();
+ GSMMap map;
+
+ /**
+ * Gets score for every Coordinate
+ *
+ * @param list
+ */
+ public ResultScore(GSMMap map) {
+ this.map = map;
+
+ }
+
+ public ArrayList<ScoreElement> find(LinkedList<SingleBTS> MR,
+ double thresholdDBm) {
+ ArrayList<GPScoordinate> 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<SingleBTS> 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<SingleBTS>, 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<Boolean> interpolated = new LinkedList<Boolean>();
+ // 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<Double> RXul = new ArrayList<Double>(); // Strength
+ // Up-link
+ private ArrayList<Double> RXdl = new ArrayList<Double>(); // 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<Double> dlQsub = new ArrayList<Double>();
+ // public ArrayList<Double> dlQfull = new ArrayList<Double>();
+ public ArrayList<Double> ulQsub = new ArrayList<Double>();
+
+ // public ArrayList<Double> ulQfull = new ArrayList<Double>();
+
+ // 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<SingleBTS> testlist = new ArrayList<SingleBTS>();
+ // testlist.add(new SingleBTS(999, "letzte"));
+ // testlist.add(new SingleBTS(124, "zweite"));
+ // testlist.add(new SingleBTS(123, "erste"));
+ // ArrayList<SingleBTS> testlistcopy = new
+ // ArrayList<SingleBTS>(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<SingleBTS> MR = getMR106();
+ ArrayList<SingleBTS> 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<SingleBTS> gettheater() {
+ ArrayList<SingleBTS> MR2 = new ArrayList<SingleBTS>();
+ ArrayList<SingleBTS> MR = new ArrayList<SingleBTS>();
+ 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<SingleBTS> getArt() {
+ ArrayList<SingleBTS> MR = new ArrayList<SingleBTS>();
+ 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<SingleBTS> getMR101() {
+ ArrayList<SingleBTS> MR = new ArrayList<SingleBTS>();
+ 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<SingleBTS> getMR106() {
+ ArrayList<SingleBTS> MR = new ArrayList<SingleBTS>();
+ 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<SingleBTS> get79() {
+ ArrayList<SingleBTS> MR = new ArrayList<SingleBTS>();
+
+ 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<SingleBTS> MR2 = new ArrayList<SingleBTS>();
+ 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<SingleBTS> getBermuda() {
+ ArrayList<SingleBTS> MR = new ArrayList<SingleBTS>();
+
+ 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<SingleBTS> getMensa() {
+ ArrayList<SingleBTS> MR = new ArrayList<SingleBTS>();
+ 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<SingleBTS> subtractBTS(ArrayList<SingleBTS> MR,
+ double value) {
+ ArrayList<SingleBTS> result = new ArrayList<SingleBTS>();
+ 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<PossibilityObject> result = new ArrayList<PossibilityObject>(
+ 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<SingleBTS> 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<SingleBTS> 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<SingleBTS> 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<SingleBTS> sortedMR = new ArrayList<SingleBTS>(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<SingleBTS> mR,
+ SingleBTS[] content) {
+ ArrayList<SingleBTS> result = new ArrayList<SingleBTS>(content.length);
+ ArrayList<SingleBTS> NaNs = new ArrayList<SingleBTS>(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<SingleBTS> substituteMR(List<SingleBTS> mR,
+ SingleBTS[] content) {
+ // TODO Auto-generated method stub
+ ArrayList<SingleBTS> result = new ArrayList<SingleBTS>(content.length);
+ // ArrayList<SingleBTS> NaNs = new ArrayList<SingleBTS>(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<SingleBTS> RSSVector = new ArrayList<SingleBTS>(
+ // map.map[x][y]);
+ ArrayList<SingleBTS> 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<SingleBTS> rssVector,
+ List<SingleBTS> 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<SingleBTS> {
+
+ 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
--- /dev/null
+++ b/DataStructure/jdom.jar
Binary files 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<SingleBTS> MR = getMR_greenhouse();
+ Date start = new Date();
+ ArrayList<ScoreElement> 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<SingleBTS> getMR_greenhouse() {
+ LinkedList<SingleBTS> testlist = new LinkedList<SingleBTS>();
+ 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<SingleBTS> getMR_Mensa() {
+ LinkedList<SingleBTS> testlist = new LinkedList<SingleBTS>();
+ 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<SingleBTS> getMR_Door51() {
+ LinkedList<SingleBTS> testlist = new LinkedList<SingleBTS>();
+ 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<iLut>[] 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<iLut>();
+ }
+
+ // traverse GSMmap, fill received
+
+ // ArrayList<Double> receive = new ArrayList<Double>();
+
+ // 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<GPScoordinate> DL = new ArrayList<GPScoordinate>();
+ ArrayList<GPScoordinate> UL = new ArrayList<GPScoordinate>();
+
+ /**
+ * 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<GPScoordinate> GPSData = new LinkedList<GPScoordinate>();
+ 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<GPScoordinate> getGPSList() {
+ // remove first coordinate. Date might be set wrong;
+ GPSData.remove();
+ return GPSData;
+ }
+
+ public double getMinX() {
+ Iterator<GPScoordinate> 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<GPScoordinate> 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<GPScoordinate> 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<GPScoordinate> 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<ArrayList<MobilePhone>> {
+ 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<MobilePhone> 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<SingleBTS> 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<SingleBTS> result = new ArrayList<SingleBTS>();
+ 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<SingleBTS> 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<SingleBTS> filterMRTime(ArrayList<SingleBTS> mRs, long l) {
+ // get max time
+ long time = getMaxTime(mRs);
+
+ // make new list. copy every entry that is l milliseconds before time
+ ArrayList<SingleBTS> newMR = new ArrayList<SingleBTS>();
+ 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<SingleBTS> getMiddle(ArrayList<SingleBTS> MR) {
+ ArrayList<SingleBTS> result = new ArrayList<SingleBTS>();
+ 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<SingleBTS> 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<SingleBTS> 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<SingleBTS> 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<SingleBTS> result = new ArrayList<SingleBTS>();
+
+ 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<SingleBTS> readNeighborList(ResultSet rs, Date timestamp)
+ throws SQLException {
+ int numOfNeigh = rs.getInt("NUM_NEIGH");
+ if (numOfNeigh == 7 || numOfNeigh == 0) {
+ return new ArrayList<SingleBTS>();
+ }
+ ArrayList<SingleBTS> result = new ArrayList<SingleBTS>();
+ 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<SingleBTS> usedBTS = new ArrayList<SingleBTS>();
+ 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<MobilePhone> results = new ArrayList<MobilePhone>();
+ public int polltime = 3000;
+ public ArrayList<MobilePhone> phones;
+ private Long[] IMSIs;
+
+ // private boolean interrupt = false;
+
+ /**
+ * @param args
+ * @throws InterruptedException
+ */
+ public static void main(String[] args) throws InterruptedException {
+
+ ArrayList<Long> blalist = new ArrayList<Long>();
+ blalist.add(1l);
+ blalist.add(1l);
+ blalist.add(1l);
+ blalist.add(3l);
+ blalist.add(4l);
+ ArrayList<Long> result = new ArrayList<Long>(new HashSet<Long>(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<MobilePhone> 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<ResultSet> rsBTS = getUsedBTS(rsMR);
+ ArrayList<MobilePhone> 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<MobilePhone> mergePhones(ArrayList<MobilePhone> phones,
+ Long[] IMSIs) {
+ ArrayList<MobilePhone> result = new ArrayList<MobilePhone>();
+ 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<MobilePhone> averagePhones(ArrayList<MobilePhone> phones) {
+ ArrayList<MobilePhone> result = new ArrayList<MobilePhone>();
+ 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<MobilePhone> mergeMrBts(ResultSet rsMR,
+ ArrayList<ResultSet> rsBTS) throws SQLException {
+ ArrayList<MobilePhone> phones = new ArrayList<MobilePhone>();
+ 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<ResultSet> 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<ResultSet> 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<ResultSet> result = new ArrayList<ResultSet>();
+ 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<Long> IMSIs = new ArrayList<Long>();
+ rs.beforeFirst();
+ while (rs.next()) {
+ IMSIs.add(rs.getLong("IMSI"));
+ }
+ // make Hashset
+ ArrayList<Long> result = new ArrayList<Long>(new HashSet<Long>(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<GPScoordinate> 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<SingleBTS> btslist = new LinkedList<SingleBTS>();
+ // 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<SingleBTS> list = new LinkedList<SingleBTS>();
+ 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<GPScoordinate> 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<SingleBTS> btslist = new LinkedList<SingleBTS>();
+ // 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<SingleBTS> btslist = new LinkedList<SingleBTS>();
+ 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<GPScoordinate> tempGPS = new ArrayList<GPScoordinate>(
+ 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<SingleBTS> tempBTS = new ArrayList<SingleBTS>(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<E> extends AbstractSet<E> {
+
+ private ArrayList<E> 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<E>(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<? extends E> collection) {
+ items = new ArrayList<E>(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<E> 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<Object, Color> 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<Object, Color>();
+ }
+
+ /**
+ * 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<Pnt> done = new HashSet<Pnt>(initialTriangle);
+ for (Triangle triangle : dt)
+ for (Pnt site: triangle) {
+ if (done.contains(site)) continue;
+ done.add(site);
+ List<Triangle> 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<N> {
+
+ private Map<N, Set<N>> theNeighbors = // Node -> adjacent nodes
+ new HashMap<N, Set<N>>();
+ private Set<N> 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<N>());
+ }
+
+ /**
+ * 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<N> 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<N> 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.
+ *
+ * <pre>
+ * -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
+ * </pre>
+ *
+ * @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<Pnt> {
+
+ 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<? extends Pnt> 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<Pnt> 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<Pnt> facetOpposite (Pnt vertex) {
+ ArraySet<Pnt> facet = new ArraySet<Pnt>(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<Pnt> iterator () {
+ return new Iterator<Pnt>() {
+ private Iterator<Pnt> 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<Triangle> {
+
+ private Triangle mostRecent = null; // Most recently "active" triangle
+ private Graph<Triangle> 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<Triangle>();
+ triGraph.add(triangle);
+ mostRecent = triangle;
+ }
+
+ /* The following two methods are required by AbstractSet */
+
+ @Override
+ public Iterator<Triangle> 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<Triangle> 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<Triangle> surroundingTriangles (Pnt site, Triangle triangle) {
+ if (!triangle.contains(site))
+ throw new IllegalArgumentException("Site not in triangle");
+ List<Triangle> list = new ArrayList<Triangle>();
+ 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<Triangle> visited = new HashSet<Triangle>();
+ 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<Triangle> 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<Triangle> getCavity (Pnt site, Triangle triangle) {
+ Set<Triangle> encroached = new HashSet<Triangle>();
+ Queue<Triangle> toBeChecked = new LinkedList<Triangle>();
+ Set<Triangle> marked = new HashSet<Triangle>();
+ 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<Triangle> cavity) {
+ Set<Set<Pnt>> boundary = new HashSet<Set<Pnt>>();
+ Set<Triangle> theTriangles = new HashSet<Triangle>();
+
+ // Find boundary facets and adjacent triangles
+ for (Triangle triangle: cavity) {
+ theTriangles.addAll(neighbors(triangle));
+ for (Pnt vertex: triangle) {
+ Set<Pnt> 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<Triangle> newTriangles = new HashSet<Triangle>();
+ for (Set<Pnt> 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<SingleBTS> filterMR(ArrayList<SingleBTS> MR,
+ JCheckBox[] btsFilter) {
+ SingleBTS[] content = map.content();
+ ArrayList<SingleBTS> result = new ArrayList<SingleBTS>();
+ for (int i = 0; i < content.length; i++) {
+ if (btsFilter[i].isSelected()) {
+ // add this BTS
+ ArrayList<SingleBTS> 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<SingleBTS> 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<MobilePhone> 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<JXMapViewer> {
+ private ArrayList<MobilePhone> phones = new ArrayList<MobilePhone>();
+
+ // private Interpolator map;
+
+ public locationPainter(ArrayList<MobilePhone> 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<JXMapViewer> 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<Long> IMSIs = new ArrayList<Long>();
+ 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<Long> IDs = new ArrayList<Long>(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<SingleBTS> result = new ArrayList<SingleBTS>();
+ for (int i = 0; i < content.length; i++) {
+ if (btsFilter[i].isSelected()) {
+ // add this BTS
+ ArrayList<SingleBTS> 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<GeoPosition> btss = new ArrayList<GeoPosition>();
+ 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<JXMapViewer> polygonOverlay = new Painter<JXMapViewer>() {
+
+ 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<GeoPosition> region = new ArrayList<GeoPosition>();
+ 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<JXMapViewer> polygonOverlay = new Painter<JXMapViewer>() {
+ *
+ * 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<JXMapViewer> {
+ 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<RegressionResult> result = new ArrayList<RegressionResult>();
+
+ // 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<RegressionResult> 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<RegressionResult> 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<RegressionResult> 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<SingleBTS> 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<SingleBTS> 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<SingleBTS> list,
+ SingleBTS extrapolateThis, int sendingStrength) {
+ ArrayList<Double> array = new ArrayList<Double>();
+
+ // 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<SingleBTS> list,
+ SingleBTS extrapolateThis, int sendingStrength) {
+ ArrayList<Double> array = new ArrayList<Double>();
+
+ 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<SingleBTS> list, SingleBTS arfcn) {
+ return contains(list, arfcn.ARFCN);
+ }
+
+ public static boolean contains(List<SingleBTS> list, int arfcn) {
+ if (list == null || list.isEmpty()) {
+ return false;
+ }
+ if (list instanceof LinkedList<?>) {
+ ListIterator<SingleBTS> 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<SingleBTS> list, SingleBTS arfcn) {
+ for (SingleBTS current : list) {
+ if (current.ARFCN == arfcn.ARFCN && current.fullBTS)
+ return true;
+ }
+ return false;
+ }
+
+ public static int countDL(LinkedList<SingleBTS> 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<SingleBTS> 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<SingleBTS> list, SingleBTS arfcn) {
+ return removeARFCN(list, arfcn.ARFCN);
+ }
+
+ public static SingleBTS removeARFCN(List<SingleBTS> list, int arfcn) {
+ ListIterator<SingleBTS> 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<SingleBTS> 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<SingleBTS> getAllARFCN(ArrayList<SingleBTS> list,
+ int arfcn) {
+ if (list == null || list.isEmpty()) {
+ return null;
+ }
+ boolean aHitWasFound = false;
+ ArrayList<SingleBTS> result = new ArrayList<SingleBTS>();
+ 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<SingleBTS> 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<SingleBTS> removeNullElements(List<SingleBTS> list) {
+ if (list == null)
+ return null;
+ ArrayList<SingleBTS> list2 = new ArrayList<SingleBTS>();
+ 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<SingleBTS> list) {
+ // get first element of list.
+ // traverse list and delete every occurence of first element
+ // get next element
+ // copy list to destroy reference
+ LinkedList<SingleBTS> list2 = new LinkedList<SingleBTS>(list);
+ if (list2.isEmpty())
+ return null;
+ // int count = 0;
+ LinkedList<SingleBTS> output = new LinkedList<SingleBTS>();
+ 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<SingleBTS> 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<SingleBTS> addMissing(LinkedList<SingleBTS> list1,
+ LinkedList<SingleBTS> list2) {
+ // LinkedList<SingleBTS> result = new LinkedList<SingleBTS>();
+ 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<SingleBTS> generateAveragedList(
+ ArrayList<SingleBTS> List, SingleBTS[] content) {
+ ArrayList<SingleBTS> output = new ArrayList<SingleBTS>();
+ // traverse every unique BTS
+ for (SingleBTS singleBTS : content) {
+ // initialize with ARFCN and Name
+ SingleBTS current = new SingleBTS(singleBTS.ARFCN, singleBTS.name);
+ // add everything from list. SingleBTS-Class takes only correct BTSs
+ for (SingleBTS measure : List) {
+ current.addBTSMeasure(measure);
+ }
+ output.add(current);
+ }
+
+ return output;
+ }
+
+ public static ArrayList<SingleBTS> generateAveragedList(
+ ArrayList<SingleBTS> 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<GPScoordinate> intersect(
+ LinkedList<GPScoordinate> list1, LinkedList<GPScoordinate> list2,
+ int threshold) {
+ LinkedList<GPScoordinate> result = new LinkedList<GPScoordinate>();
+ 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<GPScoordinate>();
+ 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<GPScoordinate> getSimilarValues(
+ LinkedList<GPScoordinate> list, GPScoordinate point, int threshold) {
+ if (list == null || list.isEmpty() || point == null)
+ return new LinkedList<GPScoordinate>();
+ LinkedList<GPScoordinate> result = new LinkedList<GPScoordinate>();
+ for (GPScoordinate element : list) {
+ if (Distance.calc(point, element) * 1000 < threshold
+ && !contains(result, element)) {
+ result.add(element);
+
+ }
+ }
+
+ return null;
+
+ }
+
+ public static LinkedList<GPScoordinate> intersect(
+ LinkedList<LinkedList<GPScoordinate>> nestedlist) {
+ LinkedList<GPScoordinate> result = new LinkedList<GPScoordinate>();
+ 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<GPScoordinate> list) {
+ // get clone. Not just reference/pointer
+ if (list == null || list.isEmpty())
+ return null;
+ ArrayList<GPScoordinate> list2 = new ArrayList<GPScoordinate>(list);
+ // int count = 0;
+ LinkedList<GPScoordinate> output = new LinkedList<GPScoordinate>();
+ 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<GPScoordinate> 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<GPScoordinate> removeNullElements(
+ LinkedList<GPScoordinate> list) {
+ if (list == null)
+ return null;
+ LinkedList<GPScoordinate> list2 = new LinkedList<GPScoordinate>();
+ 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<LinkedList<GPScoordinate>> removeAllNullElements(
+ LinkedList<LinkedList<GPScoordinate>> nestedlist) {
+ LinkedList<LinkedList<GPScoordinate>> result = new LinkedList<LinkedList<GPScoordinate>>();
+ java.util.Iterator<LinkedList<GPScoordinate>> itr = result.iterator();
+ while (itr.hasNext()) {
+ LinkedList<GPScoordinate> 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<GPScoordinate>[] possible_coords_DL = new LinkedList[69];
+ private LinkedList<GPScoordinate>[] 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<GPScoordinate>();
+ possible_coords_UL[i] = new LinkedList<GPScoordinate>();
+ }
+
+ }
+
+ 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<GPScoordinate>();
+ possible_coords_UL[i] = new LinkedList<GPScoordinate>();
+ }
+ // 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<GPScoordinate> get(SingleBTS MR) {
+ // hier muss noch das threshold_dB berücksichtigt werden!
+ if (MR == null)
+ return null;
+ LinkedList<GPScoordinate> result = new LinkedList<GPScoordinate>();
+ 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<GPScoordinate> listUL = new LinkedList<GPScoordinate>();
+ LinkedList<GPScoordinate> listDL = new LinkedList<GPScoordinate>();
+ 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<GPScoordinate> get(List<SingleBTS> MR) {
+ // create result list for each function call
+ LinkedList<GPScoordinate> list = new LinkedList<GPScoordinate>();
+ // create a nested-linked-list in order to compute the intersection
+ LinkedList<LinkedList<GPScoordinate>> nestedlist = new LinkedList<LinkedList<GPScoordinate>>();
+
+ // one list for all
+ LinkedList<GPScoordinate> resultset = new LinkedList<GPScoordinate>();
+
+ ListIterator<SingleBTS> 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<GPScoordinate>();
+ // 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<SingleBTS> 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<ILut> lookups = new ArrayList<ILut>();
+
+ /**
+ * 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<GPScoordinate> find(List<SingleBTS> MR) {
+ // traverse lookups. Build result array
+ // LinkedList<LinkedList<GPScoordinate>> set = new
+ // LinkedList<LinkedList<GPScoordinate>>();
+ LinkedList<GPScoordinate> set = new LinkedList<GPScoordinate>();
+ 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<ScoreElement> findWithScore(List<SingleBTS> MR) {
+ LinkedList<GPScoordinate> resultset = find(MR);
+ // get unique coords
+ GPScoordinate[] unique = ListGPS.content(resultset);
+ ArrayList<ScoreElement> scores = new ArrayList<ScoreElement>(
+ unique.length);
+ for (GPScoordinate coord : unique) {
+ scores.add(new ScoreElement(coord));
+ }
+ // score elements are initialized. traverse the whole result set now
+ ListIterator<GPScoordinate> 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<GPScoordinate> get(SingleBTS MR);
+
+ public void fill(GPScoordinate where, SingleBTS what);
+
+ public LinkedList<GPScoordinate> get(List<SingleBTS> 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<GPScoordinate> 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<GPScoordinate> get(List<SingleBTS> 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<ScoreElement> scores = new ArrayList<ScoreElement>();
+ GSMMap map;
+
+ /**
+ * Gets score for every Coordinate
+ *
+ * @param list
+ */
+ public ResultScore(GSMMap map) {
+ this.map = map;
+
+ }
+
+ public ArrayList<ScoreElement> find(List<SingleBTS> MR, double thresholdDBm) {
+ // looks like threshold_dB has to be as high as 25dBm
+ ArrayList<GPScoordinate> 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<SingleBTS> MR) {
+ // MR are the measured values during a call
+ // ArrayList<SingleBTS> 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<SingleBTS> 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<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; // 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
--- /dev/null
+++ b/mysql-connector-java-5.1.14-bin.jar
Binary files differ
diff --git a/parallel-strictdB-BER.obj b/parallel-strictdB-BER.obj
new file mode 100644
index 0000000..c10896a
--- /dev/null
+++ b/parallel-strictdB-BER.obj
Binary files differ
diff --git a/swingx-beaninfo.jar b/swingx-beaninfo.jar
new file mode 100644
index 0000000..639814a
--- /dev/null
+++ b/swingx-beaninfo.jar
Binary files differ
diff --git a/swingx-ws.jar b/swingx-ws.jar
new file mode 100644
index 0000000..aace70e
--- /dev/null
+++ b/swingx-ws.jar
Binary files differ
diff --git a/swingx.jar b/swingx.jar
new file mode 100644
index 0000000..e656fcf
--- /dev/null
+++ b/swingx.jar
Binary files 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
--- /dev/null
+++ b/voronoi/erstesVoronoi.png
Binary files 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<point> pointmap = new ArrayList<point>();
+
+ /**
+ * @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<Point2D> pointmap = getPointMap(extrapolateThis);
+ // start voronoi sweep now and build voronoi diagram
+ voronoisweep(pointmap);
+
+ }
+
+ @SuppressWarnings("unused")
+ private void voronoisweep(List<Point2D> pointmap) {
+ // sweepline from y=0 to max(y)
+ double sweepline = 0;
+
+ }
+
+ private List<Point2D> getPointMap(SingleBTS extrapolateThis) {
+ // have mappoint sorted for x-coordinates
+ ArrayList<Point2D> pointmap = new ArrayList<Point2D>();
+ 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<PointAndLines> corresponding = new ArrayList<PointAndLines>();
+ // // richy
+ // ArrayList<PointAndVertices> polygon = new ArrayList<PointAndVertices>();
+ // // richy
+ ArrayList<Edge> edges = new ArrayList<Edge>(); // 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<Point> points = new ArrayList<Point>(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<Point>
+ * output = new ArrayList<Point>(); 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<Point>
+ * containingPTs = new ArrayList<Point>(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<Line2D> 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<Line2D> lines = new ArrayList<Line2D>();
+ 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<Point2D> getDirectNeighbors(double x, double y) {
+ Site s = new Site();
+ s.coord.x = x;
+ s.coord.y = y;
+ Edge currEdge;
+ ArrayList<Point2D> result = new ArrayList<Point2D>();
+
+ 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<Double> xVal = new ArrayList<Double>();
+ ArrayList<Double> yVal = new ArrayList<Double>();
+ if (!Double.isNaN(xcoord) && !Double.isNaN(ycoord)) {
+ xVal.add(xcoord);
+ yVal.add(ycoord);
+ }
+ edges = new ArrayList<Edge>(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<Edge>(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<Edge>(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<Edge> result = new ArrayList<Edge>();
+ 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); } }
+ */
+
+ // <so geht das!!!!!!!!!!!!!!!!!!!!!!!> 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"); } } }/*
+ * //</so geht das>
+ *
+ * // 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<Point2D> neighbors = getDirectNeighbors(x, y); // get the
+ * polygons for each neighbor out of original
+ *
+ * return null; }
+ */
+
+}
+
+class PointAndLines {
+ Point coord;
+ ArrayList<Line2D> corrLines = new ArrayList<Line2D>();
+
+ // constructor not needed!
+
+ public void removeDuplicates() {
+ // ArrayList<Line2D> resultList = new ArrayList<Line2D>(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<Point> polygon = new ArrayList<Point>(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<Point2D> 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<Point2D> 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
+
+ }
+}