From 2241f3f27fbc6790e4831549bdf8f74eff9c85a6 Mon Sep 17 00:00:00 2001 From: Hannes Janetzek Date: Thu, 23 Jan 2014 06:11:21 +0100 Subject: [PATCH] add visvalingam-wyatt geometry simplification --- vtm/src/org/oscim/utils/MinHeap.java | 104 ++++++++++ vtm/src/org/oscim/utils/geom/SimplifyVW.java | 193 +++++++++++++++++++ 2 files changed, 297 insertions(+) create mode 100644 vtm/src/org/oscim/utils/MinHeap.java create mode 100644 vtm/src/org/oscim/utils/geom/SimplifyVW.java diff --git a/vtm/src/org/oscim/utils/MinHeap.java b/vtm/src/org/oscim/utils/MinHeap.java new file mode 100644 index 00000000..3e3b83f7 --- /dev/null +++ b/vtm/src/org/oscim/utils/MinHeap.java @@ -0,0 +1,104 @@ +package org.oscim.utils; + +public class MinHeap { + private int[] data; + private float[] heap; + + public static final class Item { + public int pos; + public float prio; + public int index; + } + + int size; + + private final Item it = new Item(); + + public MinHeap(float[] heap, int[] data) { + this.heap = heap; + this.data = data; + size = 1; + } + + public void push(float prio, int d) { + int idx = size++; + int n = idx >> 1; + while (idx > 1 && heap[n] > prio) { + heap[idx] = heap[n]; + data[idx] = data[n]; + idx = n; + n >>= 1; + } + + heap[idx] = prio; + data[idx] = d; + } + + public Item pop() { + if (size == 1) + return null; + + it.pos = data[1]; + it.prio = heap[1]; + + int idx = --size; + + if (idx > 1) { + heap[1] = heap[idx]; + data[1] = data[idx]; + heapify(); + } + return it; + } + + public int peek() { + return data[1]; + } + + private void heapify() { + float root = heap[1]; + int tmp = data[1]; + + int last = size; + int idx = 1; + + while (true) { + // left child + int c = idx << 1; + if (c > last) + break; + // right child + if (c + 1 <= last && heap[c + 1] < heap[c]) + c++; + + float val = heap[c]; + if (val >= root) + break; + + heap[idx] = val; + data[idx] = data[c]; + idx = c; + } + + heap[idx] = root; + data[idx] = tmp; + } + + public static void main(String[] args) { + MinHeap h = new MinHeap(new float[10], new int[10]); + h.push(10, 10); + h.push(12, 12); + h.push(21, 21); + h.push(31, 31); + h.push(14, 14); + h.push(2, 2); + Item it; + for (int i = 0; i < 10; i++) { + + it = h.pop(); + if (it != null) + System.out.println(it.pos + " " + it.prio); + } + + } +} diff --git a/vtm/src/org/oscim/utils/geom/SimplifyVW.java b/vtm/src/org/oscim/utils/geom/SimplifyVW.java new file mode 100644 index 00000000..bbea6c4e --- /dev/null +++ b/vtm/src/org/oscim/utils/geom/SimplifyVW.java @@ -0,0 +1,193 @@ +package org.oscim.utils.geom; + +import org.oscim.core.GeometryBuffer; +import org.oscim.utils.GeometryUtils; +import org.oscim.utils.pool.Inlist; +import org.oscim.utils.pool.Pool; + +public class SimplifyVW { + + class Item extends Inlist { + int index; + int id; + float area; + + Item prev; + } + + Pool pool = new Pool() { + @Override + protected Item createItem() { + return new Item(); + } + }; + + Item[] heap = new Item[100]; + int size = 0; + + public static void main(String[] args) { + SimplifyVW s = new SimplifyVW(); + float[] p2 = { 0, 0, 10, 0, 10, 10, 10, 10, 0, 10, 0, 0 }; + + GeometryBuffer geom = new GeometryBuffer(p2, new short[2]); + + geom.pointPos = 10; + s.simplify(geom, 0.5f); + + } + + public void simplify(GeometryBuffer geom, float minArea) { + Item prev = null; + Item first = null; + Item it; + + size = 0; + + if (heap.length < geom.pointPos >> 1) + heap = new Item[geom.pointPos >> 1]; + + first = prev = push(0, Float.MAX_VALUE); + + for (int i = 2; i < geom.pointPos - 2; i += 2) { + it = push(i, GeometryUtils.area(geom.points, i - 2, i, i + 2)); + prev.next = it; + it.prev = prev; + + prev = it; + } + + Item last = push(geom.pointPos - 2, Float.MAX_VALUE); + last.prev = prev; + prev.next = last; + + last.next = first; + first.prev = last; + + while ((it = pop()) != null) { + if (it.area > minArea) + break; + + if (it.prev == it.next) + break; + + it.prev.next = it.next; + it.next.prev = it.prev; + + if (it.prev != first) + update(geom, it.prev); + + if (it.next != first) + update(geom, it.next); + + it = pool.release(it); + } + + geom.clear(); + geom.startPolygon(); + + first.prev.next = null; + it = first; + + while (it != null) { + geom.addPoint(geom.points[it.id], geom.points[it.id + 1]); + //System.out.println(first.id + " " + first.area); + it = it.next; + } + first = pool.release(first); + } + + private void update(GeometryBuffer geom, Item it) { + remove(it); + it.area = GeometryUtils.area(geom.points, it.prev.id, it.id, it.next.id); + //System.out.println("< " + it.area); + push(it); + } + + public void push(Item it) { + heap[size] = it; + it.index = size; + up(size++); + } + + public Item push(int id, float area) { + Item it = pool.get(); + heap[size] = it; + it.index = size; + it.area = area; + it.id = id; + up(size++); + return it; + } + + public Item pop() { + if (size == 0) + return null; + + Item removed = heap[0]; + Item obj = heap[--size]; + heap[size] = null; + + if (size > 0) { + heap[obj.index = 0] = obj; + down(0); + } + return removed; + } + + public int remove(Item removed) { + if (size == 0) + throw new IllegalStateException("size == 0"); + + int i = removed.index; + Item obj = heap[--size]; + heap[size] = null; + + if (i != size) { + heap[obj.index = i] = obj; + + if (obj.area < removed.area) + up(i); + else + down(i); + } + return i; + }; + + private void up(int i) { + Item obj = heap[i]; + while (i > 0) { + int up = ((i + 1) >> 1) - 1; + Item parent = heap[up]; + + if (obj.area >= parent.area) + break; + + heap[parent.index = i] = parent; + heap[obj.index = i = up] = obj; + } + } + + private void down(int i) { + Item obj = heap[i]; + while (true) { + int right = (i + 1) << 1; + int left = right - 1; + int down = i; + + Item child = heap[down]; + + if (left < size && heap[left].area < child.area) + child = heap[down = left]; + + if (right < size && heap[right].area < child.area) { + child = heap[down = right]; + } + if (down == i) + break; + + heap[child.index = i] = child; + heap[obj.index = down] = obj; + i = down; + } + } +}