Import libtess.js
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Copyright 2000, Silicon Graphics, Inc. All Rights Reserved.
|
||||
* Copyright 2012, Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Original Code. The Original Code is: OpenGL Sample Implementation,
|
||||
* Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
|
||||
* Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
|
||||
* Copyright in any portions created by third parties is as indicated
|
||||
* elsewhere herein. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Eric Veach, July 1994
|
||||
* @author Brendan Kenny
|
||||
*/
|
||||
|
||||
// require libtess
|
||||
/*global libtess */
|
||||
|
||||
// TODO(bckenny): more specific typing on key
|
||||
|
||||
/**
|
||||
* [PQHandleElem description]
|
||||
* @constructor
|
||||
*/
|
||||
libtess.PQHandleElem = function() {
|
||||
// TODO(bckenny): if key could instead be an indexed into another store, makes heap storage a lot easier
|
||||
|
||||
/**
|
||||
* [key description]
|
||||
* @type {libtess.PQKey}
|
||||
*/
|
||||
this.key = null;
|
||||
|
||||
/**
|
||||
* [node description]
|
||||
* @type {libtess.PQHandle}
|
||||
*/
|
||||
this.node = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Allocate a PQHandleElem array of size size. If oldArray is not null, its
|
||||
* contents are copied to the beginning of the new array. The rest of the array
|
||||
* is filled with new PQHandleElems.
|
||||
*
|
||||
* @param {?Array.<libtess.PQHandleElem>} oldArray [description]
|
||||
* @param {number} size [description]
|
||||
* @return {Array.<libtess.PQHandleElem>} [description]
|
||||
*/
|
||||
libtess.PQHandleElem.realloc = function(oldArray, size) {
|
||||
var newArray = new Array(size);
|
||||
|
||||
// TODO(bckenny): better to reallocate array? or grow array?
|
||||
var index = 0;
|
||||
if (oldArray !== null) {
|
||||
for (; index < oldArray.length; index++) {
|
||||
newArray[index] = oldArray[index];
|
||||
}
|
||||
}
|
||||
|
||||
for (; index < size; index++) {
|
||||
newArray[index] = new libtess.PQHandleElem();
|
||||
}
|
||||
|
||||
return newArray;
|
||||
};
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Copyright 2000, Silicon Graphics, Inc. All Rights Reserved.
|
||||
* Copyright 2012, Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Original Code. The Original Code is: OpenGL Sample Implementation,
|
||||
* Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
|
||||
* Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
|
||||
* Copyright in any portions created by third parties is as indicated
|
||||
* elsewhere herein. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Eric Veach, July 1994
|
||||
* @author Brendan Kenny
|
||||
*/
|
||||
|
||||
// require libtess
|
||||
/*global libtess */
|
||||
|
||||
// TODO(bckenny): maybe just have these created inline as literals
|
||||
// (or unboxed directly - PQHandle is just an array index number)
|
||||
|
||||
/**
|
||||
* [PQNode description]
|
||||
* @constructor
|
||||
*/
|
||||
libtess.PQNode = function() {
|
||||
/**
|
||||
* [handle description]
|
||||
* @type {libtess.PQHandle}
|
||||
*/
|
||||
this.handle = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Allocate a PQNode array of size size. If oldArray is not null, its contents
|
||||
* are copied to the beginning of the new array. The rest of the array is
|
||||
* filled with new PQNodes.
|
||||
*
|
||||
* @param {?Array.<libtess.PQNode>} oldArray [description]
|
||||
* @param {number} size [description]
|
||||
* @return {Array.<libtess.PQNode>} [description]
|
||||
*/
|
||||
libtess.PQNode.realloc = function(oldArray, size) {
|
||||
var newArray = new Array(size);
|
||||
|
||||
// TODO(bckenny): better to reallocate array? or grow array?
|
||||
var index = 0;
|
||||
if (oldArray !== null) {
|
||||
for (; index < oldArray.length; index++) {
|
||||
newArray[index] = oldArray[index];
|
||||
}
|
||||
}
|
||||
|
||||
for (; index < size; index++) {
|
||||
newArray[index] = new libtess.PQNode();
|
||||
}
|
||||
|
||||
return newArray;
|
||||
};
|
||||
@@ -0,0 +1,313 @@
|
||||
/**
|
||||
* Copyright 2000, Silicon Graphics, Inc. All Rights Reserved.
|
||||
* Copyright 2012, Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Original Code. The Original Code is: OpenGL Sample Implementation,
|
||||
* Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
|
||||
* Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
|
||||
* Copyright in any portions created by third parties is as indicated
|
||||
* elsewhere herein. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Eric Veach, July 1994
|
||||
* @author Brendan Kenny
|
||||
*/
|
||||
|
||||
// require libtess
|
||||
// require libtess.PriorityQHeap
|
||||
/*global libtess */
|
||||
|
||||
// TODO(bckenny): preallocating arrays may actually be hurting us in sort
|
||||
// performance (esp if theres some undefs in there)
|
||||
|
||||
/**
|
||||
* [PriorityQ description]
|
||||
* @constructor
|
||||
* @param {function(Object, Object): boolean} leq [description]
|
||||
*/
|
||||
libtess.PriorityQ = function(leq) {
|
||||
/**
|
||||
* [keys description]
|
||||
* @private
|
||||
* @type {Array.<libtess.PQKey>}
|
||||
*/
|
||||
this.keys_ = libtess.PriorityQ.prototype.PQKeyRealloc_(null, libtess.PriorityQ.INIT_SIZE_);
|
||||
|
||||
/**
|
||||
* Array of indexes into this.keys_
|
||||
* @private
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this.order_ = null;
|
||||
|
||||
/**
|
||||
* [size description]
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.size_ = 0;
|
||||
|
||||
/**
|
||||
* [max_ description]
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.max_ = libtess.PriorityQ.INIT_SIZE_;
|
||||
|
||||
/**
|
||||
* [initialized description]
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.initialized_ = false;
|
||||
|
||||
// TODO(bckenny): leq was inlined by define in original, but appears to just
|
||||
// be vertLeq, as passed. keep an eye on this as to why its not used.
|
||||
/**
|
||||
* [leq description]
|
||||
* @private
|
||||
* @type {function(libtess.PQKey, libtess.PQKey): boolean}
|
||||
*/
|
||||
this.leq_ = /** @type {function(libtess.PQKey, libtess.PQKey): boolean} */(leq);
|
||||
|
||||
/**
|
||||
* [heap_ description]
|
||||
* @private
|
||||
* @type {libtess.PriorityQHeap}
|
||||
*/
|
||||
this.heap_ = new libtess.PriorityQHeap(this.leq_);
|
||||
};
|
||||
|
||||
/**
|
||||
* [INIT_SIZE_ description]
|
||||
* @private
|
||||
* @const
|
||||
* @type {number}
|
||||
*/
|
||||
libtess.PriorityQ.INIT_SIZE_ = 32;
|
||||
|
||||
/**
|
||||
* [deleteQ description]
|
||||
*/
|
||||
libtess.PriorityQ.prototype.deleteQ = function() {
|
||||
// TODO(bckenny): unnecessary, I think.
|
||||
this.heap_.deleteHeap();
|
||||
this.heap_ = null;
|
||||
this.order_ = null;
|
||||
this.keys_ = null;
|
||||
// NOTE(bckenny): nulled at callsite (sweep.donePriorityQ_)
|
||||
};
|
||||
|
||||
/**
|
||||
* [init description]
|
||||
*/
|
||||
libtess.PriorityQ.prototype.init = function() {
|
||||
// TODO(bckenny): reuse. in theory, we don't have to empty this, as access is
|
||||
// dictated by this.size_, but array.sort doesn't know that
|
||||
this.order_ = [];
|
||||
|
||||
// Create an array of indirect pointers to the keys, so that
|
||||
// the handles we have returned are still valid.
|
||||
// TODO(bckenny): valid for when? it appears we can just store indexes into keys_, but what did this mean?
|
||||
for (var i = 0; i < this.size_; i++) {
|
||||
this.order_[i] = i;
|
||||
}
|
||||
|
||||
// sort the indirect pointers in descending order of the keys themselves
|
||||
// TODO(bckenny): make sure it's ok that keys[a] === keys[b] returns 1
|
||||
// TODO(bckenny): unstable sort means we may get slightly different polys in different
|
||||
// browsers, but only when passing in equal points
|
||||
// TODO(bckenny): make less awkward closure?
|
||||
var comparator = (function(keys, leq) {
|
||||
return function(a, b) {
|
||||
return leq(keys[a], keys[b]) ? 1 : -1;
|
||||
};
|
||||
})(this.keys_, this.leq_);
|
||||
this.order_.sort(comparator);
|
||||
|
||||
this.max_ = this.size_;
|
||||
this.initialized_ = true;
|
||||
this.heap_.init();
|
||||
|
||||
// TODO(bckenny):
|
||||
// #ifndef NDEBUG
|
||||
if (libtess.DEBUG) {
|
||||
var p = 0;
|
||||
var r = p + this.size_ - 1;
|
||||
for (i = p; i < r; ++i) {
|
||||
libtess.assert(this.leq_(this.keys_[this.order_[i+1]], this.keys_[this.order_[i]]));
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
};
|
||||
|
||||
/**
|
||||
* [insert description]
|
||||
* @param {libtess.PQKey} keyNew [description]
|
||||
* @return {libtess.PQHandle} [description]
|
||||
*/
|
||||
libtess.PriorityQ.prototype.insert = function(keyNew) {
|
||||
// NOTE(bckenny): originally returned LONG_MAX as alloc failure signal. no longer does.
|
||||
if (this.initialized_) {
|
||||
return this.heap_.insert(keyNew);
|
||||
}
|
||||
|
||||
var curr = this.size_;
|
||||
if (++this.size_ >= this.max_) {
|
||||
// If the heap overflows, double its size.
|
||||
this.max_ *= 2;
|
||||
this.keys_ = libtess.PriorityQ.prototype.PQKeyRealloc_(this.keys_, this.max_);
|
||||
}
|
||||
|
||||
this.keys_[curr] = keyNew;
|
||||
|
||||
// Negative handles index the sorted array.
|
||||
return -(curr+1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Allocate a PQKey array of size size. If oldArray is not null, its
|
||||
* contents are copied to the beginning of the new array. The rest of the array
|
||||
* is filled with nulls.
|
||||
*
|
||||
* @private
|
||||
* @param {?Array.<libtess.PQKey>} oldArray [description]
|
||||
* @param {number} size [description]
|
||||
* @return {Array.<(?libtess.PQKey)>} [description]
|
||||
*/
|
||||
libtess.PriorityQ.prototype.PQKeyRealloc_ = function(oldArray, size) {
|
||||
// TODO(bckenny): double check return type. can we have ? there?
|
||||
var newArray = new Array(size);
|
||||
|
||||
// TODO(bckenny): better to reallocate array? or grow array?
|
||||
var index = 0;
|
||||
if (oldArray !== null) {
|
||||
for (; index < oldArray.length; index++) {
|
||||
newArray[index] = oldArray[index];
|
||||
}
|
||||
}
|
||||
|
||||
for (; index < size; index++) {
|
||||
newArray[index] = null;
|
||||
}
|
||||
|
||||
return newArray;
|
||||
};
|
||||
|
||||
/**
|
||||
* [keyLessThan_ description]
|
||||
* @private
|
||||
* @param {number} x [description]
|
||||
* @param {number} y [description]
|
||||
* @return {boolean} [description]
|
||||
*/
|
||||
libtess.PriorityQ.prototype.keyLessThan_ = function(x, y) {
|
||||
// NOTE(bckenny): was macro LT
|
||||
var keyX = this.keys_[x];
|
||||
var keyY = this.keys_[y];
|
||||
return !this.leq_(keyY, keyX);
|
||||
};
|
||||
|
||||
/**
|
||||
* [keyGreaterThan_ description]
|
||||
* @private
|
||||
* @param {number} x [description]
|
||||
* @param {number} y [description]
|
||||
* @return {boolean} [description]
|
||||
*/
|
||||
libtess.PriorityQ.prototype.keyGreaterThan_ = function(x, y) {
|
||||
// NOTE(bckenny): was macro GT
|
||||
var keyX = this.keys_[x];
|
||||
var keyY = this.keys_[y];
|
||||
return !this.leq_(keyX, keyY);
|
||||
};
|
||||
|
||||
/**
|
||||
* [extractMin description]
|
||||
* @return {libtess.PQKey} [description]
|
||||
*/
|
||||
libtess.PriorityQ.prototype.extractMin = function() {
|
||||
if (this.size_ === 0) {
|
||||
return this.heap_.extractMin();
|
||||
}
|
||||
|
||||
var sortMin = this.keys_[this.order_[this.size_-1]];
|
||||
if (!this.heap_.isEmpty()) {
|
||||
var heapMin = this.heap_.minimum();
|
||||
if (this.leq_(heapMin, sortMin)) {
|
||||
return this.heap_.extractMin();
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
--this.size_;
|
||||
} while(this.size_ > 0 && this.keys_[this.order_[this.size_-1]] === null);
|
||||
|
||||
return sortMin;
|
||||
};
|
||||
|
||||
/**
|
||||
* [minimum description]
|
||||
* @return {libtess.PQKey} [description]
|
||||
*/
|
||||
libtess.PriorityQ.prototype.minimum = function() {
|
||||
if (this.size_ === 0) {
|
||||
return this.heap_.minimum();
|
||||
}
|
||||
|
||||
var sortMin = this.keys_[this.order_[this.size_-1]];
|
||||
if (!this.heap_.isEmpty()) {
|
||||
var heapMin = this.heap_.minimum();
|
||||
if (this.leq_(heapMin, sortMin)) {
|
||||
return heapMin;
|
||||
}
|
||||
}
|
||||
|
||||
return sortMin;
|
||||
};
|
||||
|
||||
/**
|
||||
* [isEmpty description]
|
||||
* @return {boolean} [description]
|
||||
*/
|
||||
libtess.PriorityQ.prototype.isEmpty = function() {
|
||||
return (this.size_ === 0) && this.heap_.isEmpty();
|
||||
};
|
||||
|
||||
/**
|
||||
* [remove description]
|
||||
* @param {libtess.PQHandle} curr [description]
|
||||
*/
|
||||
libtess.PriorityQ.prototype.remove = function(curr) {
|
||||
if (curr >= 0) {
|
||||
this.heap_.remove(curr);
|
||||
return;
|
||||
}
|
||||
curr = -(curr+1);
|
||||
|
||||
libtess.assert(curr < this.max_ && this.keys_[curr] !== null);
|
||||
|
||||
this.keys_[curr] = null;
|
||||
while(this.size_ > 0 && this.keys_[this.order_[this.size_-1]] === null) {
|
||||
--this.size_;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,300 @@
|
||||
/**
|
||||
* Copyright 2000, Silicon Graphics, Inc. All Rights Reserved.
|
||||
* Copyright 2012, Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Original Code. The Original Code is: OpenGL Sample Implementation,
|
||||
* Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
|
||||
* Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
|
||||
* Copyright in any portions created by third parties is as indicated
|
||||
* elsewhere herein. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Eric Veach, July 1994
|
||||
* @author Brendan Kenny
|
||||
*/
|
||||
|
||||
// require libtess
|
||||
// require libtess.PQNode
|
||||
// require libtess.PQHandleElem
|
||||
/*global libtess */
|
||||
|
||||
// TODO(bckenny): keys appear to always be GluVertex in this case?
|
||||
|
||||
/**
|
||||
* [PriorityQHeap description]
|
||||
* @constructor
|
||||
* @param {function(libtess.PQKey, libtess.PQKey): boolean} leq [description]
|
||||
*/
|
||||
libtess.PriorityQHeap = function(leq) {
|
||||
/**
|
||||
* The heap itself. Active nodes are stored in the range 1..size. Each node
|
||||
* stores only an index into handles.
|
||||
* @private
|
||||
* @type {Array.<libtess.PQNode>}
|
||||
*/
|
||||
this.nodes_ = libtess.PQNode.realloc(null, libtess.PriorityQHeap.INIT_SIZE_ + 1);
|
||||
|
||||
/**
|
||||
* Each handle stores a key, plus a pointer back to the node which currently
|
||||
* represents that key (ie. nodes[handles[i].node].handle == i).
|
||||
* @private
|
||||
* @type {Array.<libtess.PQHandleElem>}
|
||||
*/
|
||||
this.handles_ = libtess.PQHandleElem.realloc(null, libtess.PriorityQHeap.INIT_SIZE_ + 1);
|
||||
|
||||
// TODO(bckenny): size and max should probably be libtess.PQHandle for correct typing (see PriorityQ.js)
|
||||
/**
|
||||
* The size of the queue.
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.size_ = 0;
|
||||
|
||||
/**
|
||||
* The queue's current allocated space.
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.max_ = libtess.PriorityQHeap.INIT_SIZE_;
|
||||
|
||||
/**
|
||||
* The index of the next free hole in the handles array. Handle in that slot
|
||||
* has next item in freeList in its node propert. If there are no holes,
|
||||
* freeList === 0 and one at the end of handles must be use.
|
||||
* @private
|
||||
* @type {libtess.PQHandle}
|
||||
*/
|
||||
this.freeList_ = 0;
|
||||
|
||||
/**
|
||||
* Indicates that the heap has been initialized via init. If false, inserts
|
||||
* are fast insertions at the end of a list. If true, all inserts will now be
|
||||
* correctly ordered in the queue before returning.
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.initialized_ = false;
|
||||
|
||||
// TODO(bckenny): leq was inlined by define in original, but appears to
|
||||
// be vertLeq, as passed. Using injected version, but is it better just to manually inline?
|
||||
/**
|
||||
* [leq description]
|
||||
* @private
|
||||
* @type {function(libtess.PQKey, libtess.PQKey): boolean}
|
||||
*/
|
||||
this.leq_ = leq;
|
||||
|
||||
// so that minimum returns null
|
||||
this.nodes_[1].handle = 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* [INIT_SIZE_ description]
|
||||
* @private
|
||||
* @const
|
||||
* @type {number}
|
||||
*/
|
||||
libtess.PriorityQHeap.INIT_SIZE_ = 32;
|
||||
|
||||
/**
|
||||
* [deleteHeap description]
|
||||
*/
|
||||
libtess.PriorityQHeap.prototype.deleteHeap = function() {
|
||||
// TODO(bckenny): unnecessary, I think.
|
||||
this.handles_ = null;
|
||||
this.nodes_ = null;
|
||||
// NOTE(bckenny): nulled at callsite in PriorityQ.deleteQ
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializing ordering of the heap. Must be called before any method other than
|
||||
* insert is called to ensure correctness when removing or querying.
|
||||
*/
|
||||
libtess.PriorityQHeap.prototype.init = function() {
|
||||
// This method of building a heap is O(n), rather than O(n lg n).
|
||||
for(var i = this.size_; i >= 1; --i) {
|
||||
this.floatDown_(i);
|
||||
}
|
||||
|
||||
this.initialized_ = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Insert a new key into the heap.
|
||||
* @param {libtess.PQKey} keyNew The key to insert.
|
||||
* @return {libtess.PQHandle} A handle that can be used to remove the key.
|
||||
*/
|
||||
libtess.PriorityQHeap.prototype.insert = function(keyNew) {
|
||||
var curr = ++this.size_;
|
||||
|
||||
// if the heap overflows, double its size.
|
||||
if ((curr*2) > this.max_) {
|
||||
this.max_ *= 2;
|
||||
this.nodes_ = libtess.PQNode.realloc(this.nodes_, this.max_ + 1);
|
||||
this.handles_ = libtess.PQHandleElem.realloc(this.handles_, this.max_ + 1);
|
||||
}
|
||||
|
||||
var free;
|
||||
if (this.freeList_ === 0) {
|
||||
free = curr;
|
||||
} else {
|
||||
free = this.freeList_;
|
||||
this.freeList_ = this.handles_[free].node;
|
||||
}
|
||||
|
||||
this.nodes_[curr].handle = free;
|
||||
this.handles_[free].node = curr;
|
||||
this.handles_[free].key = keyNew;
|
||||
|
||||
if (this.initialized_) {
|
||||
this.floatUp_(curr);
|
||||
}
|
||||
|
||||
return free;
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the heap is empty.
|
||||
*/
|
||||
libtess.PriorityQHeap.prototype.isEmpty = function() {
|
||||
return this.size_ === 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the minimum key in the heap. If the heap is empty, null will be
|
||||
* returned.
|
||||
* @return {libtess.PQKey} [description]
|
||||
*/
|
||||
libtess.PriorityQHeap.prototype.minimum = function() {
|
||||
return this.handles_[this.nodes_[1].handle].key;
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the minimum key from the heap and returns it. If the heap is empty,
|
||||
* null will be returned.
|
||||
* @return {libtess.PQKey} [description]
|
||||
*/
|
||||
libtess.PriorityQHeap.prototype.extractMin = function() {
|
||||
var n = this.nodes_;
|
||||
var h = this.handles_;
|
||||
var hMin = n[1].handle;
|
||||
var min = h[hMin].key;
|
||||
|
||||
if (this.size_ > 0) {
|
||||
n[1].handle = n[this.size_].handle;
|
||||
h[n[1].handle].node = 1;
|
||||
|
||||
h[hMin].key = null;
|
||||
h[hMin].node = this.freeList_;
|
||||
this.freeList_ = hMin;
|
||||
|
||||
if (--this.size_ > 0 ) {
|
||||
this.floatDown_(1);
|
||||
}
|
||||
}
|
||||
|
||||
return min;
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove key associated with handle hCurr (returned from insert) from heap.
|
||||
* @param {libtess.PQHandle} hCurr [description]
|
||||
*/
|
||||
libtess.PriorityQHeap.prototype.remove = function(hCurr) {
|
||||
var n = this.nodes_;
|
||||
var h = this.handles_;
|
||||
|
||||
libtess.assert(hCurr >= 1 && hCurr <= this.max_ && h[hCurr].key !== null);
|
||||
|
||||
var curr = h[hCurr].node;
|
||||
n[curr].handle = n[this.size_].handle;
|
||||
h[n[curr].handle].node = curr;
|
||||
|
||||
if (curr <= --this.size_) {
|
||||
if (curr <= 1 || this.leq_(h[n[curr>>1].handle].key, h[n[curr].handle].key)) {
|
||||
this.floatDown_(curr);
|
||||
} else {
|
||||
this.floatUp_(curr);
|
||||
}
|
||||
}
|
||||
|
||||
h[hCurr].key = null;
|
||||
h[hCurr].node = this.freeList_;
|
||||
this.freeList_ = hCurr;
|
||||
};
|
||||
|
||||
/**
|
||||
* [floatDown_ description]
|
||||
* @private
|
||||
* @param {libtess.PQHandle} curr [description]
|
||||
*/
|
||||
libtess.PriorityQHeap.prototype.floatDown_ = function(curr) {
|
||||
var n = this.nodes_;
|
||||
var h = this.handles_;
|
||||
|
||||
var hCurr = n[curr].handle;
|
||||
for( ;; ) {
|
||||
// The children of node i are nodes 2i and 2i+1.
|
||||
// set child to the index of the child with the minimum key
|
||||
var child = curr << 1;
|
||||
if (child < this.size_ && this.leq_(h[n[child+1].handle].key, h[n[child].handle].key)) {
|
||||
++child;
|
||||
}
|
||||
|
||||
libtess.assert(child <= this.max_);
|
||||
|
||||
var hChild = n[child].handle;
|
||||
if (child > this.size_ || this.leq_(h[hCurr].key, h[hChild].key)) {
|
||||
n[curr].handle = hCurr;
|
||||
h[hCurr].node = curr;
|
||||
break;
|
||||
}
|
||||
n[curr].handle = hChild;
|
||||
h[hChild].node = curr;
|
||||
curr = child;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* [floatUp_ description]
|
||||
* @private
|
||||
* @param {libtess.PQHandle} curr [description]
|
||||
*/
|
||||
libtess.PriorityQHeap.prototype.floatUp_ = function(curr) {
|
||||
var n = this.nodes_;
|
||||
var h = this.handles_;
|
||||
|
||||
var hCurr = n[curr].handle;
|
||||
for( ;; ) {
|
||||
var parent = curr >> 1;
|
||||
var hParent = n[parent].handle;
|
||||
if (parent === 0 || this.leq_(h[hParent].key, h[hCurr].key)) {
|
||||
n[curr].handle = hCurr;
|
||||
h[hCurr].node = curr;
|
||||
break;
|
||||
}
|
||||
|
||||
n[curr].handle = hParent;
|
||||
h[hParent].node = curr;
|
||||
curr = parent;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user