/*
OrpheusMS: MapleStory Private Server based on OdinMS
Copyright (C) 2012 Aaron Weiss <aaron@deviant-core.net>
Patrick Huy <patrick.huy@frz.cc>
Matthias Butz <matze@odinms.de>
Jan Christian Meyer <vimes@odinms.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package server.maps;
import java.awt.Point;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
*
* @author Matze
*/
public class MapleFootholdTree {
private MapleFootholdTree nw = null;
private MapleFootholdTree ne = null;
private MapleFootholdTree sw = null;
private MapleFootholdTree se = null;
private List<MapleFoothold> footholds = new LinkedList<MapleFoothold>();
private Point p1;
private Point p2;
private Point center;
private int depth = 0;
private static int maxDepth = 8;
private int maxDropX;
private int minDropX;
public MapleFootholdTree(Point p1, Point p2) {
this.p1 = p1;
this.p2 = p2;
center = new Point((p2.x - p1.x) / 2, (p2.y - p1.y) / 2);
}
public MapleFootholdTree(Point p1, Point p2, int depth) {
this.p1 = p1;
this.p2 = p2;
this.depth = depth;
center = new Point((p2.x - p1.x) / 2, (p2.y - p1.y) / 2);
}
public void insert(MapleFoothold f) {
if (depth == 0) {
if (f.getX1() > maxDropX) {
maxDropX = f.getX1();
}
if (f.getX1() < minDropX) {
minDropX = f.getX1();
}
if (f.getX2() > maxDropX) {
maxDropX = f.getX2();
}
if (f.getX2() < minDropX) {
minDropX = f.getX2();
}
}
if (depth == maxDepth || (f.getX1() >= p1.x && f.getX2() <= p2.x && f.getY1() >= p1.y && f.getY2() <= p2.y)) {
footholds.add(f);
} else {
if (nw == null) {
nw = new MapleFootholdTree(p1, center, depth + 1);
ne = new MapleFootholdTree(new Point(center.x, p1.y), new Point(p2.x, center.y), depth + 1);
sw = new MapleFootholdTree(new Point(p1.x, center.y), new Point(center.x, p2.y), depth + 1);
se = new MapleFootholdTree(center, p2, depth + 1);
}
if (f.getX2() <= center.x && f.getY2() <= center.y) {
nw.insert(f);
} else if (f.getX1() > center.x && f.getY2() <= center.y) {
ne.insert(f);
} else if (f.getX2() <= center.x && f.getY1() > center.y) {
sw.insert(f);
} else {
se.insert(f);
}
}
}
private List<MapleFoothold> getRelevants(Point p) {
return getRelevants(p, new LinkedList<MapleFoothold>());
}
private List<MapleFoothold> getRelevants(Point p, List<MapleFoothold> list) {
list.addAll(footholds);
if (nw != null) {
if (p.x <= center.x && p.y <= center.y) {
nw.getRelevants(p, list);
} else if (p.x > center.x && p.y <= center.y) {
ne.getRelevants(p, list);
} else if (p.x <= center.x && p.y > center.y) {
sw.getRelevants(p, list);
} else {
se.getRelevants(p, list);
}
}
return list;
}
private MapleFoothold findWallR(Point p1, Point p2) {
MapleFoothold ret;
for (MapleFoothold f : footholds) {
if (f.isWall() && f.getX1() >= p1.x && f.getX1() <= p2.x && f.getY1() >= p1.y && f.getY2() <= p1.y) {
return f;
}
}
if (nw != null) {
if (p1.x <= center.x && p1.y <= center.y) {
ret = nw.findWallR(p1, p2);
if (ret != null) {
return ret;
}
}
if ((p1.x > center.x || p2.x > center.x) && p1.y <= center.y) {
ret = ne.findWallR(p1, p2);
if (ret != null) {
return ret;
}
}
if (p1.x <= center.x && p1.y > center.y) {
ret = sw.findWallR(p1, p2);
if (ret != null) {
return ret;
}
}
if ((p1.x > center.x || p2.x > center.x) && p1.y > center.y) {
ret = se.findWallR(p1, p2);
if (ret != null) {
return ret;
}
}
}
return null;
}
public MapleFoothold findWall(Point p1, Point p2) {
if (p1.y != p2.y) {
throw new IllegalArgumentException();
}
return findWallR(p1, p2);
}
public MapleFoothold findBelow(Point p) {
List<MapleFoothold> relevants = getRelevants(p);
List<MapleFoothold> xMatches = new LinkedList<MapleFoothold>();
for (MapleFoothold fh : relevants) {
if (fh.getX1() <= p.x && fh.getX2() >= p.x) {
xMatches.add(fh);
}
}
Collections.sort(xMatches);
for (MapleFoothold fh : xMatches) {
if (!fh.isWall() && fh.getY1() != fh.getY2()) {
int calcY;
double s1 = Math.abs(fh.getY2() - fh.getY1());
double s2 = Math.abs(fh.getX2() - fh.getX1());
double s4 = Math.abs(p.x - fh.getX1());
double alpha = Math.atan(s2 / s1);
double beta = Math.atan(s1 / s2);
double s5 = Math.cos(alpha) * (s4 / Math.cos(beta));
if (fh.getY2() < fh.getY1()) {
calcY = fh.getY1() - (int) s5;
} else {
calcY = fh.getY1() + (int) s5;
}
if (calcY >= p.y) {
return fh;
}
} else if (!fh.isWall()) {
if (fh.getY1() >= p.y) {
return fh;
}
}
}
return null;
}
public int getX1() {
return p1.x;
}
public int getX2() {
return p2.x;
}
public int getY1() {
return p1.y;
}
public int getY2() {
return p2.y;
}
public int getMaxDropX() {
return maxDropX;
}
public int getMinDropX() {
return minDropX;
}
}