/*
* Copyright 2014 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.terasology.polyworld.graph;
import java.util.Collections;
import java.util.List;
import org.terasology.math.geom.Rect2i;
import org.terasology.math.geom.ImmutableVector2f;
import org.terasology.math.geom.Vector2f;
import com.google.common.collect.Lists;
/**
* A graph that is based on a rectangular grid.
*/
public class GridGraph implements Graph {
private final int rows;
private final int cols;
private final List<Corner> corners = Lists.newArrayList();
private final List<Region> regions = Lists.newArrayList();
private final List<Edge> edges = Lists.newArrayList();
private final Rect2i bounds;
/**
* @param bounds the bounding box
* @param rows the number of rows
* @param cols the number of columns
*/
public GridGraph(Rect2i bounds, int rows, int cols) {
this.rows = rows;
this.cols = cols;
this.bounds = bounds;
float dx = (float) bounds.width() / cols;
float dy = (float) bounds.height() / rows;
for (int r = 0; r <= rows; r++) {
for (int c = 0; c <= cols; c++) {
float x = bounds.minX() + c * dx;
float y = bounds.minY() + r * dy;
Corner corner = new Corner(new ImmutableVector2f(x, y));
corner.setBorder(r == 0 || c == 0 || r == rows || c == cols);
corners.add(corner);
}
}
for (int r = 0; r <= rows; r++) {
for (int c = 0; c <= cols; c++) {
Corner corner = getCorner(r, c);
corner.addAdjacent(getCorner(r - 1, c));
corner.addAdjacent(getCorner(r + 1, c));
corner.addAdjacent(getCorner(r, c - 1));
corner.addAdjacent(getCorner(r, c + 1));
}
}
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
float x = bounds.minX() + (c + 0.5f) * dx;
float y = bounds.minY() + (r + 0.5f) * dy;
ImmutableVector2f pos = new ImmutableVector2f(x, y);
Region reg = new Region(pos);
Corner tl = getCorner(r, c);
Corner tr = getCorner(r, c + 1);
Corner br = getCorner(r + 1, c + 1);
Corner bl = getCorner(r + 1, c);
reg.addCorner(tl);
reg.addCorner(tr);
reg.addCorner(br);
reg.addCorner(bl);
tl.addTouches(reg);
tr.addTouches(reg);
bl.addTouches(reg);
br.addTouches(reg);
regions.add(reg);
}
}
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
Region reg = getRegion(r, c);
reg.addNeigbor(getRegion(r - 1, c - 1));
reg.addNeigbor(getRegion(r - 1, c));
reg.addNeigbor(getRegion(r - 1, c + 1));
reg.addNeigbor(getRegion(r, c + 1));
reg.addNeigbor(getRegion(r, c - 1));
reg.addNeigbor(getRegion(r + 1, c - 1));
reg.addNeigbor(getRegion(r + 1, c));
reg.addNeigbor(getRegion(r + 1, c + 1));
}
}
for (int r = 1; r < rows; r++) {
for (int c = 0; c < cols; c++) {
Corner left = getCorner(r, c);
Corner right = getCorner(r, c + 1);
Region regTop = getRegion(r - 1, c);
Region regBot = getRegion(r, c);
Edge edge = new Edge(left, right, regTop, regBot);
left.addEdge(edge);
right.addEdge(edge);
regTop.addBorder(edge);
regBot.addBorder(edge);
edges.add(edge);
}
}
for (int r = 0; r < rows; r++) {
for (int c = 1; c < cols; c++) {
Corner top = getCorner(r, c);
Corner bot = getCorner(r + 1, c);
Region regLeft = getRegion(r, c - 1);
Region regRight = getRegion(r, c);
Edge edge = new Edge(top, bot, regLeft, regRight);
top.addEdge(edge);
bot.addEdge(edge);
regLeft.addBorder(edge);
regRight.addBorder(edge);
edges.add(edge);
}
}
}
private Region getRegion(int r, int c) {
if (r < 0 || r >= rows) {
return null;
}
if (c < 0 || c >= cols) {
return null;
}
int idx = r * cols + c;
return regions.get(idx);
}
private Corner getCorner(int r, int c) {
if (r < 0 || r > rows) {
return null;
}
if (c < 0 || c > cols) {
return null;
}
int idx = r * (cols + 1) + c;
return corners.get(idx);
}
@Override
public List<Region> getRegions() {
return Collections.unmodifiableList(regions);
}
@Override
public List<Edge> getEdges() {
return Collections.unmodifiableList(edges);
}
@Override
public List<Corner> getCorners() {
return Collections.unmodifiableList(corners);
}
@Override
public Rect2i getBounds() {
return bounds;
}
/**
* @return the number of rows
*/
public int getRows() {
return rows;
}
/**
* @return the number of columns
*/
public int getCols() {
return cols;
}
}