/* * Freeplane - mind map editor * Copyright (C) 2008 Joerg Mueller, Daniel Polansky, Christian Foltin, Dimitry Polivaev * * This file is modified by Dimitry Polivaev in 2008. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.freeplane.view.swing.map.cloud; import java.awt.Point; import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; import java.util.Vector; class ConvexHull { protected class thetaComparator implements Comparator<Object> { Point p0; public thetaComparator(final Point p0) { this.p0 = new Point(p0); } /* the < relation. */ public int compare(final Object p1, final Object p2) { final double comp = theta(p0, (Point) p1) - theta(p0, (Point) p2); if (((Point) p1).equals(p2)) { return 0; } if (comp > 0) { return 1; } if (comp < 0) { return -1; } int dx1, dx2, dy1, dy2; dx1 = ((Point) p1).x - (p0).x; dy1 = ((Point) p1).y - (p0).y; dx2 = ((Point) p2).x - (p0).x; dy2 = ((Point) p2).y - (p0).y; final int comp2 = (dx1 * dx1 + dy1 * dy1) - (dx2 * dx2 + dy2 * dy2); if (comp2 > 0) { return -1; } if (comp2 < 0) { return 1; } return 0; } double theta(final Point p1, final Point p2) { int dx, dy, ax, ay; double t; dx = p2.x - p1.x; ax = Math.abs(dx); dy = p2.y - p1.y; ay = Math.abs(dy); if ((dx == 0) && (dy == 0)) { t = 0; } else { t = ((double) dy) / ((double) (ax + ay)); } if (dx < 0) { t = 2f - t; } else { if (dy < 0) { t = 4f + t; } } return t * 90f; } } public Vector<Point>/* <newPoint> */calculateHull(final LinkedList<Point> coordinates) { // use a copy of coordinates since it will get modified in doGraham() return doGraham(new Vector<Point>(coordinates)); } protected int ccw(final Point p0, final Point p1, final Point p2) { int dx1, dx2, dy1, dy2; dx1 = p1.x - p0.x; dy1 = p1.y - p0.y; dx2 = p2.x - p0.x; dy2 = p2.y - p0.y; final int comp = dx1 * dy2 - dy1 * dx2; if (comp > 0) { return 1; } if (comp < 0) { return -1; } if ((dx1 * dx2 < 0) || (dy1 * dy2 < 0)) { return -1; } if (dx1 * dx1 + dy1 * dy1 >= dx2 * dx2 + dy2 * dy2) { return 0; } return 1; } Vector<Point> doGraham(final Vector<Point> p) { int i; int min, m; Point t; min = 0; for (i = 1; i < p.size(); ++i) { if (((Point) p.get(i)).y < ((Point) p.get(min)).y) { min = i; } } for (i = 0; i < p.size(); ++i) { if ((((Point) p.get(i)).y == ((Point) p.get(min)).y) && (((Point) p.get(i)).x > ((Point) p.get(min)).x)) { min = i; } } t = p.get(0); p.set(0, p.get(min)); p.set(min, t); final thetaComparator comp = new thetaComparator((Point) p.get(0)); Collections.sort(p, comp); p.add(0, new Point((Point) p.get(p.size() - 1))); m = 3; for (i = 4; i < p.size(); ++i) { while (m > 0 && ccw((Point) p.get(m), (Point) p.get(m - 1), (Point) p.get(i)) >= 0) { m--; } m++; t = (Point) p.get(m); p.set(m, p.get(i)); p.set(i, t); } p.remove(0); p.setSize(m); return p; } }