package skyline;
/**
* Voorstelling van een skyline.
* Het is NIET toegelaten bestaande methodes en/of signaturen te wijzigen, maar
* het staat je vrij naar behoefte methodes en velden toe te voegen.
* @author Timbermont Bouke
**/
public class Skyline implements Comparable {
/**
* Array met coordinaten van de skyline.
* Deze array bestaat uit een reeks van x-coordinaten en
* de hoogtes die ze verbinden, gerangschikt van links naar
* rechts.
**/
protected final int [] coords;
/**
* Creatie van een nieuwe instantie van Skyline
* bestaande uit 1 enkel gebouw
* @param left linkse positie van het gebouw
* @param height hoogte van het gebouw
* @param right rechtse positie van het gebouw
**/
public Skyline(int left,int height,int right) {
this(new int [] {left,height,right,0});
}
public Skyline(Building building) {
this(new int[] {building.getLeft(),building.getHeight(),building.getRight(),0});
}
/**
* Creatie van een nieuwe instantie van Skyline; het argument
* wordt niet gekopieerd en mag dus niet gewijzigd worden!!
* @param coords array met coordinaten van de skyline
**/
public Skyline(int [] coords) {
this.coords = coords; // ! referentie wordt geregistreerd.
}
/**
* Statische methode die een merge doet van twee skylines.
* !! Merk hierbij op dat de twee skylines die als parameter
* van de methode meegegeven worden door het aanroepen van deze
* methode niet mogen gewijzigd worden.
* @param skyLine1 de eerste skyline
* @param skyLine2 de tweede skyline
* @return de merge van de twee skylines
**/
public static Skyline merge(Skyline skyline1, Skyline skyline2){
int[] newCoords = new int[skyline1.coords.length + skyline2.coords.length];
int s1=0,s2=0;
for(int i=0;i<newCoords.length;i+=2){
if(s1>=skyline1.coords.length||s2>=skyline2.coords.length){
if(s1>=skyline1.coords.length){
newCoords[i]=skyline2.coords[s2];
s2+=2;
}else{
newCoords[i]=skyline1.coords[s1];
s1+=2;
}
}else{//einde if 1
if(skyline1.coords[s1]<skyline2.coords[s2]){
newCoords[i]=skyline1.coords[s1];
s1+=2;
}else{newCoords[i]=skyline2.coords[s2];
s2+=2;
}
}//einde else 1
}//einde for
newCoords=fillIn(newCoords,skyline1.coords);
newCoords=fillIn(newCoords,skyline2.coords);
newCoords=clean(newCoords,false);
newCoords=clean(newCoords,true);
return new Skyline(newCoords);
}
/* De volgende methode neemt 2 arrays, en vult de tweede in de eerste in,
*hierbij is naruurlijkd e vereiste dat de coordinaten op elkaar zijn afgestemd,
*en dat de eerste minstens even groot is als de tweede array.
*@param newCoords de skyline die veranderd wordt
*@param sl de skyline die wordt gekopieerd op de andere
*@return de som van de skylines
*/
private static int[] fillIn(int[]newCoords,int[]sl){
int nc=0,s=0;
while(s<sl.length-2){
while(newCoords[nc]<sl[s])nc+=2;
while(nc+2<newCoords.length && newCoords[nc+2]<=sl[s+2]){
newCoords[nc+1]=Math.max(sl[s+1],newCoords[nc+1]);
nc+=2;
}
s+=2;
}
return newCoords;
}
/* De volgende methoden haalt overbodige elementen uit de array. De tweede
*parameter die wordtmeegegeven bepaalt of dubbele hoogtes of coordinaten
*worden weggehaalt(0=coordinaten, 1=hoogtes)
*@param coords de op te kuisen skyline
*@praram h boolean die aangeeft of er hoogtes of coordinaten worden opgeruimd
*/
private static int[] clean(int[] coords,boolean hoogte){
boolean[] check=new boolean[coords.length];
for(int i=(hoogte)?1:0;i<check.length-2;i+=2){
check[i+1]=coords[i]==coords[i+2];
check[i+2]=coords[i]==coords[i+2];
}
int j=0;
for(int i=0;i<check.length;i++)if(check[i])j++;
int[] newCoords=new int[coords.length-j];
j=0;
for(int i=0;i<check.length;i++){
if(!check[i]){
newCoords[j]=coords[i];
j++;
}
}
return newCoords;
}
/**
* Geeft een stringvoorstellling van de skyline
* @return een stringvoorstelling van de skyline
**/
public String toString(){
StringBuffer buf = new StringBuffer();
buf.append('(');
for(int i=0;i<coords.length-1;i++)
buf.append(coords[i] +",");
buf.append(coords[coords.length-1] + ")");
return buf.toString();
}
/**
* Geeft de oppervlakte van de skyline
* @return de opppervlakte van de skyline
*/
public int getSurface() {
int n = coords.length;
int surface = 0;
for (int i = 0; i < n-2; i += 2){
surface += (coords[i+2]-coords[i])*coords[i+1];
}
return surface;
}
/**
* Definieert een ordening op skylines
*/
public int compareTo(Object obj) {
Skyline skyline = (Skyline)obj;
for (int i = 0; i < Math.min(coords.length, skyline.coords.length); i++) {
if (coords[i] < skyline.coords[i]) return -1;
if (coords[i] > skyline.coords[i]) return 1;
}
if (coords.length < skyline.coords.length) return -1;
else if (coords.length > skyline.coords.length) return 1;
else return 0;
}
}