Опубликован: 27.09.2006 | Уровень: для всех | Доступ: свободно | ВУЗ: Московский государственный индустриальный университет
Лекция 11:
Проект "Выпуклая оболочка"
Текст эталонного проекта
Данная секция содержит исходный текст программы, являющейся итогом работы над проектом "Выпуклая оболочка".
Эталонный проект
//Класс, описывающий точку (Point) на плоскости (R2). class R2Point { private double x, y; public R2Point(double x, double y) { this.x = x; this.y = y; } public R2Point() throws Exception { x = Xterm.inputDouble("x -> "); y = Xterm.inputDouble("y -> "); } public static double dist(R2Point a, R2Point b) { return Math.sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } public static double area(R2Point a, R2Point b, R2Point c) { return 0.5*((a.x-c.x)*(b.y-c.y)-(a.y-c.y)*(b.x-c.x)); } public static boolean equal(R2Point a, R2Point b) { return a.x==b.x && a.y==b.y; } public static boolean isTriangle(R2Point a, R2Point b, R2Point c) { return area(a, b, c) != 0.0; } public boolean inside(R2Point a, R2Point b) { return (a.x <= x && x <= b.x || a.x >= x && x >= b.x) && (a.y <= y && y <= b.y || a.y >= y && y >= b.y); } public boolean light(R2Point a, R2Point b) { double s = area(a, b, this); return s < 0.0 || ( s == 0.0 && ! inside(a, b)); } } // Непрерывная реализация дека. class Deq { private final static int DEFSIZE = 16; private R2Point[] array; private int size, head, tail; private int forward(int index) { return ++index < array.length ? index : 0; } private int backward(int index) { return --index >= 0 ? index : array.length - 1; } public Deq(int size) { array = new R2Point[size]; this.size = head = 0; tail = array.length - 1; } public Deq() { this(DEFSIZE); } public int length() { return size; } public void pushFront(R2Point p) { array[head=backward(head)] = p; size += 1; } public void pushBack(R2Point p) { array[tail=forward(tail)] = p; size += 1; } public R2Point popFront() { R2Point p = front(); head = forward(head); size -= 1; return p; } public R2Point popBack() { R2Point p = back(); tail = backward(tail); size -= 1; return p; } public R2Point front() { return array[head]; } public R2Point back() { return array[tail]; } } // Интерфейс, задающий новый тип - фигуру. interface Figure { public double perimeter(); public double area(); public Figure add(R2Point p); } // Класс "нульугольник", реализующий интерфейс фигуры. class Void implements Figure { public double perimeter() { return 0.0; } public double area() { return 0.0; } public Figure add(R2Point p) { return new Point(p); } } // Класс "одноугольник", реализующий интерфейс фигуры. class Point implements Figure { private R2Point p; public Point(R2Point p) { this.p = p; } public double perimeter() { return 0.0; } public double area() { return 0.0; } public Figure add(R2Point q) { if (!R2Point.equal(p,q)) return new Segment(p, q); else return this; } } // Класс "двуугольник", реализующий интерфейс фигуры. class Segment implements Figure { private R2Point p, q; public Segment(R2Point p, R2Point q) { this.p = p; this.q = q; } public double perimeter() { return 2.0 * R2Point.dist(p, q); } public double area() { return 0.0; } public Figure add(R2Point r) { if (R2Point.isTriangle(p, q, r)) return new Polygon(p, q, r); if (q.inside(p, r)) q = r; if (p.inside(r, q)) p = r; return this; } } // Класс "многоугольник", реализующий интерфейс фигуры. class Polygon extends Deq implements Figure { private double s, p; private void grow(R2Point a, R2Point b, R2Point t) { p -= R2Point.dist(a, b); s += Math.abs(R2Point.area(a, b, t)); } public Polygon(R2Point a, R2Point b, R2Point c) { pushFront(b); if (b.light(a, c)) { pushFront(a); pushBack(c); } else { pushFront(c); pushBack(a); } p = R2Point.dist(a, b) + R2Point.dist(b, c) + R2Point.dist(c, a); s = Math.abs(R2Point.area(a, b, c)); } public double perimeter() { return p; } public double area() { return s; } public Figure add(R2Point t) { int i; // Ищем освещенные ребра, просматривая их одно за другим. for (i=length(); i>0 && !t.light(back(),front()); i--) pushBack(popFront()); // УТВЕРЖДЕНИЕ: либо ребро [back(),front()] освещено из t, // либо освещенных ребер нет совсем. if (i>0) { R2Point x; grow(back(), front(), t); // Удаляем все освещенные ребра из начала дека. for (x = popFront(); t.light(x, front()); x = popFront()) grow(x, front(), t ); pushFront(x); // Удаляем все освещенные ребра из конца дека. for (x = popBack(); t.light(back(), x); x = popBack()) grow(back(), x, t); pushBack(x); // Завершаем обработку добавляемой точки. p += R2Point.dist(back(), t) + R2Point.dist(t, front()); pushFront(t); } return this; } } // Класс "выпуклая оболочка". class Convex { private Figure fig; public Convex() { fig = new Void(); } public void add(R2Point p) { fig = fig.add(p); } public double area() { return fig.area(); } public double perimeter() { return fig.perimeter(); } } // Тест для выпуклой оболочки. class ConvexTest { public static void main(String[] args) throws Exception { Convex convex = new Convex(); while (true) { convex.add(new R2Point()); Xterm.println("S = " + convex.area() + " , P = " + convex.perimeter()); } } }