Skip to content

Commit fb78e4f

Browse files
committed
Refactor Heap into its own class
1 parent 0551e8e commit fb78e4f

File tree

3 files changed

+195
-169
lines changed

3 files changed

+195
-169
lines changed

src/GeomAlgoTest.hx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ class GeomAlgoTest extends Sprite {
133133
// VISVALINGAM-WHYATT SIMPLIFICATION
134134
setSlot(0, 3);
135135
startTime = Timer.stamp();
136-
var simplifiedPolyVW = VisvalingamWhyatt.simplify(perimeter, SimplificationMethod.Ratio(.1));
136+
var simplifiedPolyVW = VisvalingamWhyatt.simplify(perimeter, SimplificationMethod.MaxPoints(simplifiedPolyRDP.length));
137137
trace('Visv-Whyatt : ${Timer.stamp() - startTime}');
138138
drawPoly(simplifiedPolyVW, X + clipRect.x, Y + clipRect.y);
139139
addChild(getTextField("Visv-Whyatt\n" + simplifiedPolyVW.length + " pts", X, Y));

src/hxGeomAlgo/Heap.hx

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
/**
2+
* Heap implementation.
3+
*
4+
* Based on:
5+
*
6+
* @see http://en.wikipedia.org/wiki/Binary_heap (Binary Heap)
7+
* @see https://github.com/jonasmalacofilho/dheap (Haxe - Jonas Malaco Filho)
8+
*
9+
* @author azrafe7
10+
*/
11+
12+
package hxGeomAlgo;
13+
14+
import hxGeomAlgo.Debug;
15+
16+
17+
/** Heap elements must implement this interface. */
18+
interface Heapable<T> {
19+
20+
/** Used internally by Heap. Do not modify. */
21+
var position:Int;
22+
23+
/**
24+
* Returns the result of comparing `this` to `other`, where the result is expected to be:
25+
* less than zero if `this` < `other`
26+
* equal to zero if `this` == `other`
27+
* greater than zero if `this` > `other`
28+
*/
29+
function compare(other:T):Int;
30+
}
31+
32+
33+
/**
34+
* Heap implementation (over Array).
35+
*
36+
* Note: depending on the compare function (i.e. if it's ascending or descending),
37+
* it will act as a MinHeap or MaxHeap (meaning that `pop()` will return the smallest
38+
* or the largest element respectively).
39+
*
40+
* @author azrafe7
41+
*/
42+
class Heap<T:Heapable<T>>
43+
{
44+
private var data:Array<T>;
45+
46+
public function new():Void
47+
{
48+
data = new Array<T>();
49+
}
50+
51+
/** Number of elements in the Heap. */
52+
public var length(default, null):Int = 0;
53+
54+
/** Inserts `obj` into the Heap. */
55+
public function push(obj:T):Void
56+
{
57+
var i = length;
58+
set(obj, i);
59+
length++;
60+
if (length > 1) bubbleUp(i);
61+
}
62+
63+
/** Returns the root element (i.e. the smallest or largest, depending on compare()) and removes it from the Heap. Or null if the Heap is empty. */
64+
public function pop():T
65+
{
66+
if (length == 0) return null;
67+
68+
var res = data[0];
69+
var len = length;
70+
var lastObj = data[len - 1];
71+
data[len - 1] = null;
72+
length--;
73+
if (len > 1) {
74+
set(lastObj, 0);
75+
bubbleDown(0);
76+
}
77+
78+
return res;
79+
}
80+
81+
/** Returns the root element (i.e. the smallest or largest, depending on compare()) without removing it from the Heap. Or null if the Heap is empty. */
82+
public function top():T
83+
{
84+
return length > 0 ? data[0] : null;
85+
}
86+
87+
/** Removes `obj` from the Heap. Checks for correctness are only done in debug. */
88+
public function remove(obj:T):Int
89+
{
90+
var pos = obj.position;
91+
Debug.assert((pos >= 0 && pos < length), "Object not found.");
92+
Debug.assert(data[pos] == obj, '`obj` and retrieved object at $pos don\'t match.');
93+
94+
var len = length;
95+
var lastObj = data[len - 1];
96+
data[len - 1] = null;
97+
length--;
98+
if (pos != len - 1) {
99+
set(lastObj, pos);
100+
lastObj.compare(obj) < 0 ? bubbleUp(pos) : bubbleDown(pos);
101+
}
102+
return pos;
103+
}
104+
105+
inline public function clear():Void
106+
{
107+
#if (flash || js)
108+
untyped data.length = 0;
109+
#else
110+
data.splice(0, length);
111+
#end
112+
length = 0;
113+
}
114+
115+
private function bubbleDown(i:Int):Void
116+
{
117+
var left = leftOf(i);
118+
var right = rightOf(i);
119+
var curr = i;
120+
if (left < length && data[left].compare(data[curr]) < 0) curr = left;
121+
if (right < length && data[right].compare(data[curr]) < 0) curr = right;
122+
if (curr != i) {
123+
swap(curr, i);
124+
bubbleDown(curr);
125+
}
126+
}
127+
128+
private function bubbleUp(i:Int):Void
129+
{
130+
while (i > 0 && !(data[i].compare(data[parentOf(i)]) > 0)) {
131+
var parent = parentOf(i);
132+
swap(parent, i);
133+
i = parent;
134+
}
135+
}
136+
137+
public function validate():Void
138+
{
139+
if (length > 0) _validate(0);
140+
}
141+
142+
public function toArray():Array<T>
143+
{
144+
return [].concat(data);
145+
}
146+
147+
private function _validate(i:Int):Void
148+
{
149+
var len = length;
150+
var left = leftOf(i);
151+
var right = rightOf(i);
152+
153+
if (left < len) {
154+
Debug.assert(data[i].compare(data[left]) <= 0, 'Broken heap invariant (parent@$i > leftChild@$left).');
155+
_validate(leftOf(i));
156+
}
157+
if (right < len) {
158+
Debug.assert(data[i].compare(data[right]) <= 0, 'Broken heap invariant (parent@$i > rightChild@$right).');
159+
_validate(rightOf(i));
160+
}
161+
}
162+
163+
private function set(obj:T, index:Int):Void
164+
{
165+
data[index] = obj;
166+
obj.position = index;
167+
}
168+
169+
inline private function leftOf(i:Int):Int
170+
{
171+
return 2 * i + 1;
172+
}
173+
174+
inline private function rightOf(i:Int):Int
175+
{
176+
return 2 * i + 2;
177+
}
178+
179+
inline private function parentOf(i:Int):Int
180+
{
181+
return (i - 1) >> 1;
182+
}
183+
184+
inline private function swap(i:Int, j:Int):Void
185+
{
186+
var temp = data[i];
187+
set(data[j], i);
188+
set(temp, j);
189+
}
190+
}

0 commit comments

Comments
 (0)