package views;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.LinkedList;
import java.util.Random;
import models.Coordinates;
import models.coordinates.EquatorialCoordinates;
import models.coordinates.LocalHorizontalCoordinates;
import models.coordinates.UserCoordinates;
import models.distances.EuclidianSimple2D;
import models.distances.IDistance;
public class Cluster {
private Color color;
private Star centroid;
private LinkedList<Star> stars;
private boolean isStarsSorted;
public Cluster(Star s) {
this.centroid = s;
this.stars = new LinkedList<>();
stars.add(s);
allocateColor();
isStarsSorted = false;
}
/**
* Add a star to the cluster and update the centroid
* @param s Star to add to the cluster
*/
public void addAndMerge(Star s){
mergeCentroid(s, 1);
stars.addFirst(s);
isStarsSorted = false;
}
/**
* Add a star to the cluster without updating the centroid
* @param s Star to add to the cluster
*/
public void add(Star s){
stars.addFirst(s);
isStarsSorted = false;
}
private void mergeCentroid(Star s, int weight){
final int size = size();
final int coeffSum = size + weight;
//Merge coordinates
EquatorialCoordinates cCoordinates = centroid.getCoodinates();
EquatorialCoordinates sCoordinates = s.getCoodinates();
double alpha = cCoordinates.getAscention() * size + sCoordinates.getAscention() * weight;
alpha /= coeffSum;
double delta = cCoordinates.getDeclinaison() * size + sCoordinates.getDeclinaison() * weight;
delta /= coeffSum;
//Merge magnitude
double magnitude = centroid.getMagnitude() * size + s.getMagnitude() * weight;
magnitude /= coeffSum;
//Merge color
Color sColor = s.getColor();
int red = centroid.getColor().getRed()*size + sColor.getRed()*weight;
red /= coeffSum;
int green = centroid.getColor().getGreen()*size + sColor.getGreen()*weight;
green /= coeffSum;
int blue = centroid.getColor().getBlue()*size + sColor.getBlue()*weight;
blue /= coeffSum;
//TODO define a special spectral type
this.centroid = new Star("centroid", new EquatorialCoordinates(alpha, delta), magnitude, new Color(red, green, blue));
}
public void clear(){
stars.clear();
}
public void merge(Cluster c){
mergeCentroid(c.getCentroid(), c.size());
// this.color = size() > c.size() ? color : c.getColor();
stars.addAll(c.getStars());
isStarsSorted = false;
}
public double getStretch(IDistance d){
double stretch = 0;
for(Star s : stars){
double dist = d.get(centroid, s);
if(dist > stretch) stretch = dist;
}
return stretch;
}
public Star getCentroid() {
return centroid;
}
public int size(){
return stars.size();
}
public LinkedList<Star> getStars() {
return stars;
}
public void setStars(LinkedList<Star> s) {
this.stars = s;
}
private final double colorThreshold = 0.95;
private void allocateColor() {
Random rand = new Random();
float red = rand.nextFloat();
float green = rand.nextFloat();
float blue = rand.nextFloat();
if (blue > colorThreshold && red > colorThreshold && green > colorThreshold) {
allocateColor();
return;
}
this.color = new Color(red, green, blue);
}
public Color getColor(){
return color;
}
public void draw(Graphics g, UserCoordinates userCoordinates, Circle mapBounds, IDistance currentDistance) {
centroid.draw(g, userCoordinates, mapBounds);
LocalHorizontalCoordinates lhc = Coordinates.equatorialToLocalHorizontal(centroid.getCoodinates(), userCoordinates);
if (lhc.isVisible()) {
double maxDistance = 0;
for(Star s : stars){
double current = Math.abs(currentDistance.get(centroid, s));
if(current > maxDistance) maxDistance = current;
}
maxDistance *= mapBounds.getHeight();
//System.out.println("MaxD: "+maxDistance + "\tHeight/ "+mapBounds.getHeight());
Point point = centroid.getPoint();
g.setColor(color);
int D = (int) maxDistance/2;
g.drawOval(point.x - D/2, point.y - D/2, D, D);
}
}
public void drawConstellation(Graphics g, UserCoordinates userCoordinates, Circle mapBounds) {
if(!isStarsSorted) sortStars();
Star previousStar = null;
LocalHorizontalCoordinates sCoordinates, psCoordinates = null;
Point p1 =null, p2 = null;
for(Star s : stars){
sCoordinates = Coordinates.equatorialToLocalHorizontal(s.getCoodinates(), userCoordinates);
if(previousStar != null){
if(psCoordinates.isVisible() && sCoordinates.isVisible()){
s.draw(g, userCoordinates, mapBounds);
p1 = s.getPoint();
if(p2==null){
previousStar.draw(g, userCoordinates, mapBounds);
p2 = previousStar.getPoint();
}
g.setColor(color);
g.drawLine(p1.x, p1.y, p2.x, p2.y);
}
} else {
if(sCoordinates.isVisible()){
s.draw(g, userCoordinates, mapBounds);
p1 = s.getPoint();
}
}
previousStar = s;
psCoordinates = sCoordinates;
p2 = p1;
}
}
private void sortStars(){
EuclidianSimple2D d = new EuclidianSimple2D();
LinkedList<Star> newStars = new LinkedList<>();
Star previous = centroid;
Star closest = null;
double dist;
while(!stars.isEmpty()){
double min = Double.MAX_VALUE;
for(Star s : stars){
dist = d.get(s, previous);
if(dist < min){
min = dist;
closest = s;
}
}
stars.remove(closest);
newStars.add(closest);
previous = closest;
}
this.stars = newStars;
isStarsSorted = true;
}
}