Skip to content
Permalink
025ce2e6b7
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
277 lines (264 sloc) 7 KB
import java.util.*;
import java.util.Map.*;
import java.lang.Boolean;
int reset_x = 140;
int reset_y = 460;
int reset_w = 100;
int reset_h = 25;
int calc_x = 250;
int calc_y = 460;
int calc_w = 100;
int calc_h = 25;
PShape reset;
PShape calculate;
PVector centerPoint;
ArrayList<PVector> rawInput = new ArrayList<PVector>();
Comparator<PVector> compareX, compareXRev, compareY, compareYRev;
// Triple used for returning three items
private class ReturnTriple {
public float sum;
public float dist;
public HashMap<PVector, Float> memoize;
public ReturnTriple(float sum, float dist, HashMap<PVector, Float> memoize) {
this.sum = sum;
this.dist = dist;
this.memoize = memoize;
}
}
// Setup
void setup() {
background(255);
size(500,500,P2D);
// Create buttons
reset = createShape(RECT, reset_x, reset_y, reset_w, reset_h);
calculate = createShape(RECT, calc_x, calc_y, calc_w, calc_h);
noLoop();
compareX = new Comparator<PVector>() {
public int compare(PVector p1, PVector p2) {
if (p1.x < p2.x) {
return -1;
}
else if (p2.x < p1.x) {
return 1;
}
else {
return 0;
}
}
};
compareXRev = new Comparator<PVector>() {
public int compare(PVector p1, PVector p2) {
if (p1.x > p2.x) {
return -1;
}
else if (p2.x > p1.x) {
return 1;
}
else {
return 0;
}
}
};
compareY = new Comparator<PVector>() {
public int compare(PVector p1, PVector p2) {
if (p1.y < p2.y) {
return -1;
}
else if (p2.y < p1.y) {
return 1;
}
else {
return 0;
}
}
};
compareYRev = new Comparator<PVector>() {
public int compare(PVector p1, PVector p2) {
if (p1.y > p2.y) {
return -1;
}
else if (p2.y > p1.y) {
return 1;
}
else {
return 0;
}
}
};
}
// On mouse press
void mousePressed() {
// If mouse presses reset button
if ((mouseX >= reset_x && mouseX <= (reset_x + reset_w)) &&
(mouseY >= reset_y && mouseY <= (reset_y + reset_h))) {
// Reset input and background
rawInput.clear();
centerPoint = null;
}
// If mouse presses calculate button
else if ((mouseX >= calc_x && mouseX <= (calc_x + calc_w)) &&
(mouseY >= calc_y && mouseY <= (calc_y + calc_h))) {
// Run algorithm
centerPoint = approxCenterpoint(rawInput);
if (centerPoint != null) {
System.out.println("x-coordinate: " + Float.toString(centerPoint.x));
System.out.println("y-coordinate: " + Float.toString(centerPoint.y));
}
}
else {
PVector new_point = new PVector(mouseX, mouseY);
rawInput.add(new_point);
}
redraw();
}
// Get geometric median
PVector getGeometricMedian(ArrayList<PVector> input) {
if (input.size() == 0) {
return null;
}
else if (input.size() == 1) {
return input.get(0);
}
else {
// Get the point
float x = getAxisMin(input, false);
float y = getAxisMin(input, true);
return new PVector(x, y);
}
}
// Approximate the centerpoint
PVector approxCenterpoint(ArrayList<PVector> input) {
PVector point = getGeometricMedian(input);
if (point == null) {
System.out.println("You don't have any input points!");
return null;
}
else {
return point;
}
}
// Calculate the distance with the input, memoization
float calcDist(int i, PVector currentPoint, ArrayList<PVector> input, boolean isY) {
// For each point before i, calculate distance to i
PVector prevPoint;
float sum = 0;
for (int j = 0; j < i; j++) {
prevPoint = input.get(j);
if (isY) {
sum += currentPoint.y - prevPoint.y;
}
else {
sum += currentPoint.x - prevPoint.x;
}
}
return sum;
}
// Calculate prev sum (i - 1) and the point distance from i
ReturnTriple calcLastSum(int i, PVector currentPoint, PVector nextPoint, ArrayList<PVector> input, HashMap<PVector, Float> memoize, boolean isY) {
// Calculate for squares
float sum, dist;
// If possible, reuse solution
if (memoize.containsKey(currentPoint)) {
sum = memoize.get(currentPoint);
}
// Otherwise, calculate
else {
sum = calcDist(i, currentPoint, input, isY);
memoize.put(currentPoint, sum);
}
if (isY) {
dist = nextPoint.y - currentPoint.y;
}
else {
dist = nextPoint.x - currentPoint.x;
}
return new ReturnTriple(sum, dist, memoize);
}
// Get sums and sums of squares of distances for an input
HashMap<PVector, Float> getSums(ArrayList<PVector> input, boolean isY) {
// Memoization hash tables
HashMap<PVector, Float> sumMemoize = new HashMap<PVector, Float>();
HashMap<PVector, Float> sumSquaresMemoize = new HashMap<PVector, Float>();
ReturnTriple returnTriple = new ReturnTriple(0, 0, null);
PVector currentPoint, nextPoint;
float sum, dist;
for (int i = 0; i < input.size() - 1; i++) {
currentPoint = input.get(i);
nextPoint = input.get(i + 1);
// Calculate sum
returnTriple = calcLastSum(i, currentPoint, nextPoint, input, sumMemoize, isY);
sumMemoize = returnTriple.memoize;
sumMemoize.put(nextPoint, returnTriple.sum + (i * returnTriple.dist));
// Calculate sum of squares
returnTriple = calcLastSum(i, currentPoint, nextPoint, input, sumSquaresMemoize, isY);
sumSquaresMemoize = returnTriple.memoize;
sumSquaresMemoize.put(nextPoint, returnTriple.sum + (float)(i * Math.pow(returnTriple.dist, 2)) + (2 * i * returnTriple.dist));
}
System.out.println("Printing dict...");
System.out.println(sumSquaresMemoize);
return sumSquaresMemoize;
}
// Get minimum point for given axis input
Float getAxisMin(ArrayList<PVector> input, boolean isY) {
HashMap<PVector, Float> sumSquaresLeft, sumSquaresRight;
HashMap<PVector, Float> totalSumSquares = new HashMap<PVector, Float>();
// Get left distances
if (isY) {
Collections.sort(input, compareY);
}
else {
Collections.sort(input, compareX);
}
sumSquaresLeft = getSums(input, isY);
System.out.println(sumSquaresLeft);
// Get right distances
if (isY) {
Collections.sort(input, compareYRev);
}
else {
Collections.sort(input, compareXRev);
}
sumSquaresRight = getSums(input, isY);
System.out.println(sumSquaresRight);
// Calculate total sum and store it
for (int i = 0; i < sumSquaresLeft.size(); i++) {
PVector point = input.get(i);
totalSumSquares.put(point, sumSquaresLeft.get(point) + sumSquaresRight.get(point));
}
ArrayList<Entry<PVector, Float>> sortedList = new ArrayList<Entry<PVector, Float>>(totalSumSquares.entrySet());
Collections.sort(sortedList, new Comparator<Entry<PVector, Float>>() {
public int compare(Entry<PVector, Float> entry1, Entry<PVector, Float> entry2) {
return (int)(entry1.getValue() - entry2.getValue());
}
});
// Return final point coordinate
if (isY) {
return sortedList.get(0).getKey().y;
}
else {
return sortedList.get(0).getKey().x;
}
}
// Draw
void draw() {
background(255);
shape(reset);
shape(calculate);
fill(50);
textSize(20);
text("Geometric Separators", 140, 20);
textSize(12);
text("Reset.", reset_x + 30, reset_y + 15);
text("Calculate.", calc_x + 25, calc_y + 15);
// Draw input
for (PVector point : rawInput) {
strokeWeight(4);
point(point.x, point.y);
}
// Draw center point
if (centerPoint != null) {
strokeWeight(6);
fill (255, 0, 0);
point(centerPoint.x, centerPoint.y);
}
}