Apply fixjsstyle to libtess.js
This commit is contained in:
@@ -35,18 +35,21 @@
|
||||
// require libtess
|
||||
/*global libtess */
|
||||
|
||||
|
||||
// TODO(bckenny): better typing for DictKey? actually libtess.ActiveRegion
|
||||
/** @typedef {Object} */
|
||||
libtess.dictKey;
|
||||
|
||||
// TODO(bckenny): better typing for all of this, really. no need not to eg use tess as frame directly
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* [Dict description]
|
||||
*
|
||||
* @constructor
|
||||
* @param {Object} frame [description]
|
||||
* @param {function(Object, Object, Object): boolean} leq [description]
|
||||
* @param {Object} frame [description].
|
||||
* @param {function(Object, Object, Object): boolean} leq [description].
|
||||
*/
|
||||
libtess.Dict = function(frame, leq) {
|
||||
/**
|
||||
@@ -72,29 +75,31 @@ libtess.Dict = function(frame, leq) {
|
||||
this.leq_ = /** @type {function(Object, libtess.dictKey, libtess.dictKey): boolean} */(leq);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [deleteDict description]
|
||||
*/
|
||||
libtess.Dict.prototype.deleteDict = function() {
|
||||
// TODO(bckenny): unnecessary, I think.
|
||||
// for (var node = libtess.head.next; node !== libtess.head; node = node.next) {
|
||||
// memFree(node);
|
||||
// memFree(node);
|
||||
// }
|
||||
// memFree(dict);
|
||||
|
||||
|
||||
// NOTE(bckenny): nulled at callsite (sweep.doneEdgeDict_)
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [insertBefore description]
|
||||
* @param {libtess.DictNode} node [description]
|
||||
* @param {Object} key [description]
|
||||
* @return {libtess.DictNode} [description]
|
||||
* @param {libtess.DictNode} node [description].
|
||||
* @param {Object} key [description].
|
||||
* @return {libtess.DictNode} [description].
|
||||
*/
|
||||
libtess.Dict.prototype.insertBefore = function(node, key) {
|
||||
do {
|
||||
node = node.prev;
|
||||
} while(node.key !== null && !this.leq_(this.frame, node.key, key));
|
||||
} while (node.key !== null && !this.leq_(this.frame, node.key, key));
|
||||
|
||||
var newNode = new libtess.DictNode();
|
||||
|
||||
@@ -107,19 +112,21 @@ libtess.Dict.prototype.insertBefore = function(node, key) {
|
||||
return newNode;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [insert description]
|
||||
* @param {Object} key [description]
|
||||
* @return {libtess.DictNode} [description]
|
||||
* @param {Object} key [description].
|
||||
* @return {libtess.DictNode} [description].
|
||||
*/
|
||||
libtess.Dict.prototype.insert = function(key) {
|
||||
// NOTE(bckenny): from a macro in dict.h/dict-list.h
|
||||
return this.insertBefore(this.head, key);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [deleteNode description]
|
||||
* @param {libtess.DictNode} node [description]
|
||||
* @param {libtess.DictNode} node [description].
|
||||
*/
|
||||
libtess.Dict.prototype.deleteNode = function(node) {
|
||||
// NOTE(bckenny): nulled at callsite (sweep.deleteRegion_)
|
||||
@@ -128,36 +135,39 @@ libtess.Dict.prototype.deleteNode = function(node) {
|
||||
// memFree( node ); TODO(bckenny)
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Search returns the node with the smallest key greater than or equal
|
||||
* to the given key. If there is no such key, returns a node whose
|
||||
* key is null. Similarly, max(d).getSucc() has a null key, etc.
|
||||
*
|
||||
* @param {Object} key [description]
|
||||
* @return {libtess.DictNode} [description]
|
||||
* @param {Object} key [description].
|
||||
* @return {libtess.DictNode} [description].
|
||||
*/
|
||||
libtess.Dict.prototype.search = function(key) {
|
||||
var node = this.head;
|
||||
|
||||
do {
|
||||
node = node.next;
|
||||
} while(node.key !== null && !this.leq_(this.frame, key, node.key));
|
||||
} while (node.key !== null && !this.leq_(this.frame, key, node.key));
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [getMin description]
|
||||
* @return {libtess.DictNode} [description]
|
||||
* @return {libtess.DictNode} [description].
|
||||
*/
|
||||
libtess.Dict.prototype.getMin = function() {
|
||||
// NOTE(bckenny): from a macro in dict.h/dict-list.h
|
||||
return this.head.next;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [getMax description]
|
||||
* @return {libtess.DictNode} [description]
|
||||
* @return {libtess.DictNode} [description].
|
||||
*/
|
||||
libtess.Dict.prototype.getMax = function() {
|
||||
// NOTE(bckenny): from a macro in dict.h/dict-list.h
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
|
||||
// TODO(bckenny): better typing for DictKey?
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* [DictNode description]
|
||||
* @constructor
|
||||
@@ -55,7 +57,7 @@ libtess.DictNode = function() {
|
||||
* @type {libtess.DictNode}
|
||||
*/
|
||||
this.next = null;
|
||||
|
||||
|
||||
/**
|
||||
* [prev description]
|
||||
* @type {libtess.DictNode}
|
||||
@@ -63,26 +65,29 @@ libtess.DictNode = function() {
|
||||
this.prev = null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [getKey description]
|
||||
* @return {libtess.dictKey} [description]
|
||||
* @return {libtess.dictKey} [description].
|
||||
*/
|
||||
libtess.DictNode.prototype.getKey = function() {
|
||||
return this.key;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [getSucc description]
|
||||
* @return {libtess.DictNode} [description]
|
||||
* @return {libtess.DictNode} [description].
|
||||
*/
|
||||
libtess.DictNode.prototype.getSucc = function() {
|
||||
// TODO(bckenny): unabreviated naming?
|
||||
return this.next;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [getPred description]
|
||||
* @return {libtess.DictNode} [description]
|
||||
* @return {libtess.DictNode} [description].
|
||||
*/
|
||||
libtess.DictNode.prototype.getPred = function() {
|
||||
// TODO(bckenny): unabreviated naming?
|
||||
|
||||
@@ -45,28 +45,31 @@ libtess.geom = function() {
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [vertEq description]
|
||||
*
|
||||
* @param {libtess.GluVertex} u [description]
|
||||
* @param {libtess.GluVertex} v [description]
|
||||
* @return {boolean} [description]
|
||||
* @param {libtess.GluVertex} u [description].
|
||||
* @param {libtess.GluVertex} v [description].
|
||||
* @return {boolean} [description].
|
||||
*/
|
||||
libtess.geom.vertEq = function(u, v) {
|
||||
return u.s === v.s && u.t === v.t;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if u is lexicographically <= v.
|
||||
*
|
||||
* @param {libtess.GluVertex} u [description]
|
||||
* @param {libtess.GluVertex} v [description]
|
||||
* @param {libtess.GluVertex} u [description].
|
||||
* @param {libtess.GluVertex} v [description].
|
||||
* @return {boolean}
|
||||
*/
|
||||
libtess.geom.vertLeq = function(u, v) {
|
||||
return (u.s < v.s) || (u.s === v.s && u.t <= v.t);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Given three vertices u,v,w such that geom.vertLeq(u,v) && geom.vertLeq(v,w),
|
||||
* evaluates the t-coord of the edge uw at the s-coord of the vertex v.
|
||||
@@ -78,16 +81,16 @@ libtess.geom.vertLeq = function(u, v) {
|
||||
* let r be the negated result (this evaluates (uw)(v.s)), then
|
||||
* r is guaranteed to satisfy MIN(u.t,w.t) <= r <= MAX(u.t,w.t).
|
||||
*
|
||||
* @param {libtess.GluVertex} u [description]
|
||||
* @param {libtess.GluVertex} v [description]
|
||||
* @param {libtess.GluVertex} w [description]
|
||||
* @return {number} double
|
||||
* @param {libtess.GluVertex} u [description].
|
||||
* @param {libtess.GluVertex} v [description].
|
||||
* @param {libtess.GluVertex} w [description].
|
||||
* @return {number} double.
|
||||
*/
|
||||
libtess.geom.edgeEval = function(u, v, w) {
|
||||
var gapL, gapR;
|
||||
|
||||
libtess.assert(libtess.geom.vertLeq(u, v) && libtess.geom.vertLeq(v, w));
|
||||
|
||||
|
||||
gapL = v.s - u.s;
|
||||
gapR = w.s - v.s;
|
||||
|
||||
@@ -103,21 +106,22 @@ libtess.geom.edgeEval = function(u, v, w) {
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a number whose sign matches geom.edgeEval(u,v,w) but which
|
||||
* is cheaper to evaluate. Returns > 0, == 0 , or < 0
|
||||
* as v is above, on, or below the edge uw.
|
||||
*
|
||||
* @param {libtess.GluVertex} u [description]
|
||||
* @param {libtess.GluVertex} v [description]
|
||||
* @param {libtess.GluVertex} w [description]
|
||||
* @return {number} double
|
||||
* @param {libtess.GluVertex} u [description].
|
||||
* @param {libtess.GluVertex} v [description].
|
||||
* @param {libtess.GluVertex} w [description].
|
||||
* @return {number} double.
|
||||
*/
|
||||
libtess.geom.edgeSign = function(u, v, w) {
|
||||
var gapL, gapR;
|
||||
|
||||
libtess.assert(libtess.geom.vertLeq(u, v) && libtess.geom.vertLeq(v, w));
|
||||
|
||||
|
||||
gapL = v.s - u.s;
|
||||
gapR = w.s - v.s;
|
||||
|
||||
@@ -129,18 +133,20 @@ libtess.geom.edgeSign = function(u, v, w) {
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Version of VertLeq with s and t transposed.
|
||||
* Returns true if u is lexicographically <= v.
|
||||
*
|
||||
* @param {libtess.GluVertex} u [description]
|
||||
* @param {libtess.GluVertex} v [description]
|
||||
* @param {libtess.GluVertex} u [description].
|
||||
* @param {libtess.GluVertex} v [description].
|
||||
* @return {boolean}
|
||||
*/
|
||||
libtess.geom.transLeq = function(u, v) {
|
||||
return (u.t < v.t) || (u.t === v.t && u.s <= v.s);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Version of geom.edgeEval with s and t transposed.
|
||||
* Given three vertices u,v,w such that geom.transLeq(u,v) && geom.transLeq(v,w),
|
||||
@@ -153,16 +159,16 @@ libtess.geom.transLeq = function(u, v) {
|
||||
* let r be the negated result (this evaluates (uw)(v.t)), then
|
||||
* r is guaranteed to satisfy MIN(u.s,w.s) <= r <= MAX(u.s,w.s).
|
||||
*
|
||||
* @param {libtess.GluVertex} u [description]
|
||||
* @param {libtess.GluVertex} v [description]
|
||||
* @param {libtess.GluVertex} w [description]
|
||||
* @return {number} double
|
||||
* @param {libtess.GluVertex} u [description].
|
||||
* @param {libtess.GluVertex} v [description].
|
||||
* @param {libtess.GluVertex} w [description].
|
||||
* @return {number} double.
|
||||
*/
|
||||
libtess.geom.transEval = function(u, v, w) {
|
||||
var gapL, gapR;
|
||||
|
||||
libtess.assert(libtess.geom.transLeq(u, v) && libtess.geom.transLeq(v, w));
|
||||
|
||||
|
||||
gapL = v.t - u.t;
|
||||
gapR = w.t - v.t;
|
||||
|
||||
@@ -178,22 +184,23 @@ libtess.geom.transEval = function(u, v, w) {
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Version of geom.edgeSign with s and t transposed.
|
||||
* Returns a number whose sign matches geom.transEval(u,v,w) but which
|
||||
* is cheaper to evaluate. Returns > 0, == 0 , or < 0
|
||||
* as v is above, on, or below the edge uw.
|
||||
*
|
||||
* @param {libtess.GluVertex} u [description]
|
||||
* @param {libtess.GluVertex} v [description]
|
||||
* @param {libtess.GluVertex} w [description]
|
||||
* @return {number} double
|
||||
* @param {libtess.GluVertex} u [description].
|
||||
* @param {libtess.GluVertex} v [description].
|
||||
* @param {libtess.GluVertex} w [description].
|
||||
* @return {number} double.
|
||||
*/
|
||||
libtess.geom.transSign = function(u, v, w) {
|
||||
var gapL, gapR;
|
||||
|
||||
libtess.assert(libtess.geom.transLeq(u, v) && libtess.geom.transLeq(v, w));
|
||||
|
||||
|
||||
gapL = v.t - u.t;
|
||||
gapR = w.t - v.t;
|
||||
|
||||
@@ -205,37 +212,41 @@ libtess.geom.transSign = function(u, v, w) {
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [edgeGoesLeft description]
|
||||
*
|
||||
* @param {libtess.GluHalfEdge} e [description]
|
||||
* @return {boolean} [description]
|
||||
* @param {libtess.GluHalfEdge} e [description].
|
||||
* @return {boolean} [description].
|
||||
*/
|
||||
libtess.geom.edgeGoesLeft = function(e) {
|
||||
return libtess.geom.vertLeq(e.dst(), e.org);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [edgeGoesRight description]
|
||||
*
|
||||
* @param {libtess.GluHalfEdge} e [description]
|
||||
* @return {boolean} [description]
|
||||
* @param {libtess.GluHalfEdge} e [description].
|
||||
* @return {boolean} [description].
|
||||
*/
|
||||
libtess.geom.edgeGoesRight = function(e) {
|
||||
return libtess.geom.vertLeq(e.org, e.dst());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [vertL1dist description]
|
||||
*
|
||||
* @param {libtess.GluVertex} u [description]
|
||||
* @param {libtess.GluVertex} v [description]
|
||||
* @return {number} [description]
|
||||
* @param {libtess.GluVertex} u [description].
|
||||
* @param {libtess.GluVertex} v [description].
|
||||
* @return {number} [description].
|
||||
*/
|
||||
libtess.geom.vertL1dist = function(u, v) {
|
||||
return Math.abs(u.s - v.s) + Math.abs(u.t - v.t);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* For almost-degenerate situations, the results are not reliable.
|
||||
* Unless the floating-point arithmetic can be performed without
|
||||
@@ -243,15 +254,16 @@ libtess.geom.vertL1dist = function(u, v) {
|
||||
* on some degenerate inputs, so the client must have some way to
|
||||
* handle this situation.
|
||||
*
|
||||
* @param {libtess.GluVertex} u [description]
|
||||
* @param {libtess.GluVertex} v [description]
|
||||
* @param {libtess.GluVertex} w [description]
|
||||
* @param {libtess.GluVertex} u [description].
|
||||
* @param {libtess.GluVertex} v [description].
|
||||
* @param {libtess.GluVertex} w [description].
|
||||
* @return {boolean}
|
||||
*/
|
||||
libtess.geom.vertCCW = function(u, v, w) {
|
||||
return (u.s*(v.t - w.t) + v.s*(w.t - u.t) + w.s*(u.t - v.t)) >= 0;
|
||||
return (u.s * (v.t - w.t) + v.s * (w.t - u.t) + w.s * (u.t - v.t)) >= 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Given parameters a,x,b,y returns the value (b*x+a*y)/(a+b),
|
||||
* or (x+y)/2 if a==b==0. It requires that a,b >= 0, and enforces
|
||||
@@ -262,11 +274,11 @@ libtess.geom.vertCCW = function(u, v, w) {
|
||||
* even when a and b differ greatly in magnitude.
|
||||
*
|
||||
* @private
|
||||
* @param {number} a [description]
|
||||
* @param {number} x [description]
|
||||
* @param {number} b [description]
|
||||
* @param {number} y [description]
|
||||
* @return {number} [description]
|
||||
* @param {number} a [description].
|
||||
* @param {number} x [description].
|
||||
* @param {number} b [description].
|
||||
* @param {number} y [description].
|
||||
* @return {number} [description].
|
||||
*/
|
||||
libtess.geom.interpolate_ = function(a, x, b, y) {
|
||||
//(a = (a < 0) ? 0 : a, b = (b < 0) ? 0 : b, ((a <= b) ? ((b == 0) ? ((x+y) / 2) : (x + (y-x) * (a/(a+b)))) : (y + (x-y) * (b/(a+b)))))
|
||||
@@ -275,25 +287,26 @@ libtess.geom.interpolate_ = function(a, x, b, y) {
|
||||
|
||||
if (a <= b) {
|
||||
if (b === 0) {
|
||||
return (x+y) / 2;
|
||||
return (x + y) / 2;
|
||||
} else {
|
||||
return x + (y-x) * (a/(a+b));
|
||||
return x + (y - x) * (a / (a + b));
|
||||
}
|
||||
} else {
|
||||
return y + (x-y) * (b/(a+b));
|
||||
return y + (x - y) * (b / (a + b));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Given edges (o1,d1) and (o2,d2), compute their point of intersection.
|
||||
* The computed point is guaranteed to lie in the intersection of the
|
||||
* bounding rectangles defined by each edge.
|
||||
*
|
||||
* @param {libtess.GluVertex} o1 [description]
|
||||
* @param {libtess.GluVertex} d1 [description]
|
||||
* @param {libtess.GluVertex} o2 [description]
|
||||
* @param {libtess.GluVertex} d2 [description]
|
||||
* @param {libtess.GluVertex} v output
|
||||
* @param {libtess.GluVertex} o1 [description].
|
||||
* @param {libtess.GluVertex} d1 [description].
|
||||
* @param {libtess.GluVertex} o2 [description].
|
||||
* @param {libtess.GluVertex} d2 [description].
|
||||
* @param {libtess.GluVertex} v output.
|
||||
*/
|
||||
libtess.geom.edgeIntersect = function(o1, d1, o2, d2, v) {
|
||||
/* This is certainly not the most efficient way to find the intersection
|
||||
@@ -305,7 +318,7 @@ libtess.geom.edgeIntersect = function(o1, d1, o2, d2, v) {
|
||||
*/
|
||||
var z1, z2;
|
||||
var tmp;
|
||||
|
||||
|
||||
if (!libtess.geom.vertLeq(o1, d1)) {
|
||||
// Swap(o1, d1);
|
||||
tmp = o1;
|
||||
@@ -337,14 +350,14 @@ libtess.geom.edgeIntersect = function(o1, d1, o2, d2, v) {
|
||||
// Interpolate between o2 and d1
|
||||
z1 = libtess.geom.edgeEval(o1, o2, d1);
|
||||
z2 = libtess.geom.edgeEval(o2, d1, d2);
|
||||
if (z1+z2 < 0) { z1 = -z1; z2 = -z2; }
|
||||
if (z1 + z2 < 0) { z1 = -z1; z2 = -z2; }
|
||||
v.s = libtess.geom.interpolate_(z1, o2.s, z2, d1.s);
|
||||
|
||||
} else {
|
||||
// Interpolate between o2 and d2
|
||||
z1 = libtess.geom.edgeSign(o1, o2, d1);
|
||||
z2 = -libtess.geom.edgeSign(o1, d2, d1);
|
||||
if (z1+z2 < 0) { z1 = -z1; z2 = -z2; }
|
||||
if (z1 + z2 < 0) { z1 = -z1; z2 = -z2; }
|
||||
v.s = libtess.geom.interpolate_(z1, o2.s, z2, d2.s);
|
||||
}
|
||||
|
||||
@@ -380,14 +393,14 @@ libtess.geom.edgeIntersect = function(o1, d1, o2, d2, v) {
|
||||
// Interpolate between o2 and d1
|
||||
z1 = libtess.geom.transEval(o1, o2, d1);
|
||||
z2 = libtess.geom.transEval(o2, d1, d2);
|
||||
if (z1+z2 < 0) { z1 = -z1; z2 = -z2; }
|
||||
if (z1 + z2 < 0) { z1 = -z1; z2 = -z2; }
|
||||
v.t = libtess.geom.interpolate_(z1, o2.t, z2, d1.t);
|
||||
|
||||
} else {
|
||||
// Interpolate between o2 and d2
|
||||
z1 = libtess.geom.transSign(o1, o2, d1);
|
||||
z2 = -libtess.geom.transSign(o1, d2, d1);
|
||||
if (z1+z2 < 0) { z1 = -z1; z2 = -z2; }
|
||||
if (z1 + z2 < 0) { z1 = -z1; z2 = -z2; }
|
||||
v.t = libtess.geom.interpolate_(z1, o2.t, z2, d2.t);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -32,13 +32,15 @@
|
||||
* @author Brendan Kenny
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Base namespace.
|
||||
*/
|
||||
var libtess = libtess || {};
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} [DEBUG description]
|
||||
* @define {boolean} [DEBUG description].
|
||||
*/
|
||||
libtess.DEBUG = false;
|
||||
|
||||
@@ -55,6 +57,7 @@ libtess.assert = function(condition, opt_message) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [sweepDebugEvent description]
|
||||
* @param {libtess.GluTesselator} tess
|
||||
@@ -64,6 +67,7 @@ libtess.sweepDebugEvent = function(tess) {
|
||||
// sweep event updated
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [GLU_TESS_MAX_COORD description]
|
||||
* @type {number}
|
||||
@@ -72,6 +76,7 @@ libtess.sweepDebugEvent = function(tess) {
|
||||
libtess.GLU_TESS_MAX_COORD = 1e150;
|
||||
// NOTE(bckenny): from glu.pl generator
|
||||
|
||||
|
||||
/**
|
||||
* [TRUE_PROJECT description]
|
||||
* TODO(bckenny): see alg-outline for description
|
||||
@@ -80,6 +85,7 @@ libtess.GLU_TESS_MAX_COORD = 1e150;
|
||||
*/
|
||||
libtess.TRUE_PROJECT = false;
|
||||
|
||||
|
||||
/**
|
||||
* We cache vertex data for single-contour polygons so that we can
|
||||
* try a quick-and-dirty decomposition first.
|
||||
@@ -88,6 +94,7 @@ libtess.TRUE_PROJECT = false;
|
||||
*/
|
||||
libtess.TESS_MAX_CACHE = 100;
|
||||
|
||||
|
||||
/**
|
||||
* [GLU_TESS_DEFAULT_TOLERANCE description]
|
||||
* @type {number}
|
||||
@@ -95,6 +102,7 @@ libtess.TESS_MAX_CACHE = 100;
|
||||
*/
|
||||
libtess.GLU_TESS_DEFAULT_TOLERANCE = 0.0;
|
||||
|
||||
|
||||
/**
|
||||
* The begin/end calls must be properly nested. We keep track of
|
||||
* the current state to enforce the ordering.
|
||||
@@ -108,6 +116,7 @@ libtess.tessState = {
|
||||
T_IN_CONTOUR: 2
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The input contours parition the plane into regions. A winding
|
||||
* rule determines which of these regions are inside the polygon.
|
||||
@@ -139,6 +148,7 @@ libtess.windingRule = {
|
||||
GLU_TESS_WINDING_ABS_GEQ_TWO: 100134
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The type of primitive return from a "begin" callback. GL_LINE_LOOP is only
|
||||
* returned when GLU_TESS_BOUNDARY_ONLY is true. Values of enum match WebGL
|
||||
@@ -155,6 +165,7 @@ libtess.primitiveType = {
|
||||
GL_TRIANGLE_FAN: 6
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The types of errors provided to error callback.
|
||||
* @enum {number}
|
||||
@@ -170,6 +181,7 @@ libtess.errorType = {
|
||||
GLU_TESS_NEED_COMBINE_CALLBACK: 100156
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* GLU enums necessary for this project.
|
||||
* see enumglu.spec
|
||||
@@ -203,9 +215,11 @@ libtess.gluEnum = {
|
||||
GLU_TESS_COMBINE_DATA: 100111
|
||||
};
|
||||
|
||||
|
||||
/** @typedef {number} */
|
||||
libtess.PQHandle;
|
||||
|
||||
|
||||
// TODO(bckenny): better typing on key?
|
||||
/** @typedef {Object} */
|
||||
libtess.PQKey;
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
// require libtess
|
||||
/*global libtess */
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Cached vertex data for single-countour polygons for quick-and-dirty
|
||||
* decomposition.
|
||||
@@ -47,7 +49,7 @@ libtess.CachedVertex = function() {
|
||||
*/
|
||||
this.coords = [0, 0, 0];
|
||||
// TODO(bckenny): better way to init?
|
||||
|
||||
|
||||
/**
|
||||
* [data description]
|
||||
* @type {Object}
|
||||
|
||||
@@ -47,6 +47,8 @@
|
||||
// TODO(bckenny): create more javascript-y API, e.g. make gluTessEndPolygon async,
|
||||
// don't require so many temp objects created
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* [GluTesselator description]
|
||||
*
|
||||
@@ -97,13 +99,13 @@ libtess.GluTesselator = function() {
|
||||
*/
|
||||
this.normal = [0, 0, 0];
|
||||
// TODO(bckenny): better way to init these arrays?
|
||||
|
||||
|
||||
/**
|
||||
* unit vector in s-direction (debugging)
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this.sUnit = [0, 0, 0];
|
||||
|
||||
|
||||
/**
|
||||
* unit vector in t-direction (debugging)
|
||||
* @type {Array.<number>}
|
||||
@@ -270,7 +272,7 @@ libtess.GluTesselator = function() {
|
||||
*/
|
||||
this.emptyCache = false;
|
||||
// TODO(bckenny): possibly rename to be clear it's a boolean
|
||||
|
||||
|
||||
/**
|
||||
* number of cached vertices
|
||||
* @type {number}
|
||||
@@ -289,6 +291,7 @@ libtess.GluTesselator = function() {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Destory the tesselator object. See README.
|
||||
*/
|
||||
@@ -298,10 +301,11 @@ libtess.GluTesselator.prototype.gluDeleteTess = function() {
|
||||
// memFree(tess); TODO(bckenny)
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set properties for control over tesselation. See README.
|
||||
* @param {libtess.gluEnum} which [description]
|
||||
* @param {number|boolean} value [description]
|
||||
* @param {libtess.gluEnum} which [description].
|
||||
* @param {number|boolean} value [description].
|
||||
*/
|
||||
libtess.GluTesselator.prototype.gluTessProperty = function(which, value) {
|
||||
// TODO(bckenny): split into more setters?
|
||||
@@ -342,10 +346,11 @@ libtess.GluTesselator.prototype.gluTessProperty = function(which, value) {
|
||||
this.callErrorOrErrorData(libtess.gluEnum.GLU_INVALID_VALUE);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns tessellator property
|
||||
* @param {libtess.gluEnum} which [description]
|
||||
* @return {number|boolean} [description]
|
||||
* @param {libtess.gluEnum} which [description].
|
||||
* @return {number|boolean} [description].
|
||||
*/
|
||||
libtess.GluTesselator.prototype.gluGetTessProperty = function(which) {
|
||||
// TODO(bckenny): as above, split into more getters? and improve on switch statement
|
||||
@@ -373,10 +378,11 @@ libtess.GluTesselator.prototype.gluGetTessProperty = function(which) {
|
||||
default:
|
||||
this.callErrorOrErrorData(libtess.gluEnum.GLU_INVALID_ENUM);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Lets the user supply the polygon normal, if known. All input data
|
||||
* is projected into a plane perpendicular to the normal before
|
||||
@@ -386,9 +392,9 @@ libtess.GluTesselator.prototype.gluGetTessProperty = function(which) {
|
||||
* you know that all polygons lie in the x-y plane, call
|
||||
* "tess.gluTessNormal(0.0, 0.0, 1.0)" before rendering any polygons.
|
||||
*
|
||||
* @param {number} x [description]
|
||||
* @param {number} y [description]
|
||||
* @param {number} z [description]
|
||||
* @param {number} x [description].
|
||||
* @param {number} y [description].
|
||||
* @param {number} z [description].
|
||||
*/
|
||||
libtess.GluTesselator.prototype.gluTessNormal = function(x, y, z) {
|
||||
this.normal[0] = x;
|
||||
@@ -396,17 +402,18 @@ libtess.GluTesselator.prototype.gluTessNormal = function(x, y, z) {
|
||||
this.normal[2] = z;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Specify callbacks. See README. A null or undefined opt_fn removes current callback.
|
||||
*
|
||||
* @param {libtess.gluEnum} which [description]
|
||||
* @param {?function()=} opt_fn [description]
|
||||
* @param {libtess.gluEnum} which [description].
|
||||
* @param {?function()=} opt_fn [description].
|
||||
*/
|
||||
libtess.GluTesselator.prototype.gluTessCallback = function(which, opt_fn) {
|
||||
var fn = !opt_fn ? null : opt_fn;
|
||||
// TODO(bckenny): better opt_fn typing?
|
||||
|
||||
switch(which) {
|
||||
switch (which) {
|
||||
case libtess.gluEnum.GLU_TESS_BEGIN:
|
||||
this.callBegin_ = /** @type {function(libtess.primitiveType)} */ (fn);
|
||||
return;
|
||||
@@ -473,12 +480,13 @@ libtess.GluTesselator.prototype.gluTessCallback = function(which, opt_fn) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Specify a vertex and associated data. Must be within calls to
|
||||
* beginContour/endContour. See README.
|
||||
*
|
||||
* @param {Array.<number>} coords [description]
|
||||
* @param {Object} data [description]
|
||||
* @param {Array.<number>} coords [description].
|
||||
* @param {Object} data [description].
|
||||
*/
|
||||
libtess.GluTesselator.prototype.gluTessVertex = function(coords, data) {
|
||||
var tooLarge = false;
|
||||
@@ -523,9 +531,10 @@ libtess.GluTesselator.prototype.gluTessVertex = function(coords, data) {
|
||||
this.addVertex_(clamped, data);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [gluTessBeginPolygon description]
|
||||
* @param {Object} data Client data for current polygon
|
||||
* @param {Object} data Client data for current polygon.
|
||||
*/
|
||||
libtess.GluTesselator.prototype.gluTessBeginPolygon = function(data) {
|
||||
this.requireState_(libtess.tessState.T_DORMANT);
|
||||
@@ -538,6 +547,7 @@ libtess.GluTesselator.prototype.gluTessBeginPolygon = function(data) {
|
||||
this.polygonData_ = data;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [gluTessBeginContour description]
|
||||
*/
|
||||
@@ -555,6 +565,7 @@ libtess.GluTesselator.prototype.gluTessBeginContour = function() {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [gluTessEndContour description]
|
||||
*/
|
||||
@@ -563,6 +574,7 @@ libtess.GluTesselator.prototype.gluTessEndContour = function() {
|
||||
this.state = libtess.tessState.T_IN_POLYGON;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [gluTessEndPolygon description]
|
||||
*/
|
||||
@@ -644,6 +656,7 @@ libtess.GluTesselator.prototype.gluTessEndPolygon = function() {
|
||||
this.mesh = null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the tessellator to its original dormant state.
|
||||
* @private
|
||||
@@ -657,10 +670,11 @@ libtess.GluTesselator.prototype.makeDormant_ = function() {
|
||||
this.mesh = null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [requireState_ description]
|
||||
* @private
|
||||
* @param {libtess.tessState} state [description]
|
||||
* @param {libtess.tessState} state [description].
|
||||
*/
|
||||
libtess.GluTesselator.prototype.requireState_ = function(state) {
|
||||
if (this.state !== state) {
|
||||
@@ -668,10 +682,11 @@ libtess.GluTesselator.prototype.requireState_ = function(state) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [gotoState_ description]
|
||||
* @private
|
||||
* @param {libtess.tessState} newState [description]
|
||||
* @param {libtess.tessState} newState [description].
|
||||
*/
|
||||
libtess.GluTesselator.prototype.gotoState_ = function(newState) {
|
||||
while (this.state !== newState) {
|
||||
@@ -711,11 +726,12 @@ libtess.GluTesselator.prototype.gotoState_ = function(newState) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [addVertex_ description]
|
||||
* @private
|
||||
* @param {Array.<number>} coords [description]
|
||||
* @param {Object} data [description]
|
||||
* @param {Array.<number>} coords [description].
|
||||
* @param {Object} data [description].
|
||||
*/
|
||||
libtess.GluTesselator.prototype.addVertex_ = function(coords, data) {
|
||||
var e = this.lastEdge_;
|
||||
@@ -736,7 +752,7 @@ libtess.GluTesselator.prototype.addVertex_ = function(coords, data) {
|
||||
e.org.coords[0] = coords[0];
|
||||
e.org.coords[1] = coords[1];
|
||||
e.org.coords[2] = coords[2];
|
||||
|
||||
|
||||
// The winding of an edge says how the winding number changes as we
|
||||
// cross from the edge''s right face to its left face. We add the
|
||||
// vertices in such an order that a CCW contour will add +1 to
|
||||
@@ -747,11 +763,12 @@ libtess.GluTesselator.prototype.addVertex_ = function(coords, data) {
|
||||
this.lastEdge_ = e;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [cacheVertex_ description]
|
||||
* @private
|
||||
* @param {Array.<number>} coords [description]
|
||||
* @param {Object} data [description]
|
||||
* @param {Array.<number>} coords [description].
|
||||
* @param {Object} data [description].
|
||||
*/
|
||||
libtess.GluTesselator.prototype.cacheVertex_ = function(coords, data) {
|
||||
var v = this.cache[this.cacheCount];
|
||||
@@ -763,6 +780,7 @@ libtess.GluTesselator.prototype.cacheVertex_ = function(coords, data) {
|
||||
++this.cacheCount;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [emptyCache_ description]
|
||||
* @private
|
||||
@@ -780,13 +798,14 @@ libtess.GluTesselator.prototype.emptyCache_ = function() {
|
||||
this.emptyCache = false;
|
||||
};
|
||||
|
||||
|
||||
// TODO(bckenny): all following conditional callbacks could be simplified
|
||||
// TODO(bckenny): using null for now, but may rework
|
||||
// TODO(bckenny): should add documentation that references in callback are volatile (or make a copy)
|
||||
// see README callback descriptions
|
||||
/**
|
||||
* [callBeginOrBeginData description]
|
||||
* @param {libtess.primitiveType} type [description]
|
||||
* @param {libtess.primitiveType} type [description].
|
||||
*/
|
||||
libtess.GluTesselator.prototype.callBeginOrBeginData = function(type) {
|
||||
if (this.callBeginData_) {
|
||||
@@ -797,9 +816,10 @@ libtess.GluTesselator.prototype.callBeginOrBeginData = function(type) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [callVertexOrVertexData description]
|
||||
* @param {Object} data [description]
|
||||
* @param {Object} data [description].
|
||||
*/
|
||||
libtess.GluTesselator.prototype.callVertexOrVertexData = function(data) {
|
||||
if (this.callVertexData_) {
|
||||
@@ -810,9 +830,10 @@ libtess.GluTesselator.prototype.callVertexOrVertexData = function(data) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [callEdgeFlagOrEdgeFlagData description]
|
||||
* @param {boolean} flag [description]
|
||||
* @param {boolean} flag [description].
|
||||
*/
|
||||
libtess.GluTesselator.prototype.callEdgeFlagOrEdgeFlagData = function(flag) {
|
||||
if (this.callEdgeFlagData_) {
|
||||
@@ -823,6 +844,7 @@ libtess.GluTesselator.prototype.callEdgeFlagOrEdgeFlagData = function(flag) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [callEndOrEndData description]
|
||||
*/
|
||||
@@ -835,12 +857,13 @@ libtess.GluTesselator.prototype.callEndOrEndData = function() {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [callCombineOrCombineData description]
|
||||
* @param {Array.<number>} coords [description]
|
||||
* @param {Array.<Object>} data [description]
|
||||
* @param {Array.<number>} weight [description]
|
||||
* @return {Object} Interpolated vertex
|
||||
* @param {Array.<number>} coords [description].
|
||||
* @param {Array.<Object>} data [description].
|
||||
* @param {Array.<number>} weight [description].
|
||||
* @return {Object} Interpolated vertex.
|
||||
*/
|
||||
libtess.GluTesselator.prototype.callCombineOrCombineData =
|
||||
function(coords, data, weight) {
|
||||
@@ -860,10 +883,11 @@ libtess.GluTesselator.prototype.callCombineOrCombineData =
|
||||
return interpData;
|
||||
};
|
||||
|
||||
|
||||
// TODO(bckenny): combine the enums in libtess
|
||||
/**
|
||||
* [callErrorOrErrorData description]
|
||||
* @param {(libtess.errorType|libtess.gluEnum)} errno [description]
|
||||
* @param {(libtess.errorType|libtess.gluEnum)} errno [description].
|
||||
*/
|
||||
libtess.GluTesselator.prototype.callErrorOrErrorData = function(errno) {
|
||||
if (this.callErrorData_) {
|
||||
|
||||
@@ -48,12 +48,13 @@ libtess.mesh = function() {
|
||||
|
||||
/****************** Basic Edge Operations **********************/
|
||||
|
||||
|
||||
/**
|
||||
* makeEdge creates one edge, two vertices, and a loop (face).
|
||||
* The loop consists of the two new half-edges.
|
||||
*
|
||||
* @param {libtess.GluMesh} mesh [description]
|
||||
* @return {libtess.GluHalfEdge} [description]
|
||||
* @param {libtess.GluMesh} mesh [description].
|
||||
* @return {libtess.GluHalfEdge} [description].
|
||||
*/
|
||||
libtess.mesh.makeEdge = function(mesh) {
|
||||
// TODO(bckenny): probably move to GluMesh, but needs Make* methods with it
|
||||
@@ -62,12 +63,13 @@ libtess.mesh.makeEdge = function(mesh) {
|
||||
|
||||
// complete edge with vertices and face (see mesh.makeEdgePair_)
|
||||
libtess.mesh.makeVertex_(e, mesh.vHead);
|
||||
libtess.mesh.makeVertex_(e.sym, mesh.vHead );
|
||||
libtess.mesh.makeVertex_(e.sym, mesh.vHead);
|
||||
libtess.mesh.makeFace_(e, mesh.fHead);
|
||||
|
||||
return e;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* meshSplice(eOrg, eDst) is the basic operation for changing the
|
||||
* mesh connectivity and topology. It changes the mesh so that
|
||||
@@ -92,8 +94,8 @@ libtess.mesh.makeEdge = function(mesh) {
|
||||
* If eDst == eOrg.oNext, the new vertex will have a single edge.
|
||||
* If eDst == eOrg.oPrev(), the old vertex will have a single edge.
|
||||
*
|
||||
* @param {libtess.GluHalfEdge} eOrg [description]
|
||||
* @param {libtess.GluHalfEdge} eDst [description]
|
||||
* @param {libtess.GluHalfEdge} eOrg [description].
|
||||
* @param {libtess.GluHalfEdge} eDst [description].
|
||||
*/
|
||||
libtess.mesh.meshSplice = function(eOrg, eDst) {
|
||||
// TODO: more descriptive name?
|
||||
@@ -135,6 +137,7 @@ libtess.mesh.meshSplice = function(eOrg, eDst) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* deleteEdge(eDel) removes the edge eDel. There are several cases:
|
||||
* if (eDel.lFace != eDel.rFace()), we join two loops into one; the loop
|
||||
@@ -146,7 +149,7 @@ libtess.mesh.meshSplice = function(eOrg, eDst) {
|
||||
* plus a few calls to memFree, but this would allocate and delete
|
||||
* unnecessary vertices and faces.
|
||||
*
|
||||
* @param {libtess.GluHalfEdge} eDel [description]
|
||||
* @param {libtess.GluHalfEdge} eDel [description].
|
||||
*/
|
||||
libtess.mesh.deleteEdge = function(eDel) {
|
||||
var eDelSym = eDel.sym;
|
||||
@@ -160,7 +163,7 @@ libtess.mesh.deleteEdge = function(eDel) {
|
||||
libtess.mesh.killFace_(eDel.lFace, eDel.rFace());
|
||||
}
|
||||
|
||||
if (eDel.oNext === eDel ) {
|
||||
if (eDel.oNext === eDel) {
|
||||
libtess.mesh.killVertex_(eDel.org, null);
|
||||
|
||||
} else {
|
||||
@@ -178,7 +181,7 @@ libtess.mesh.deleteEdge = function(eDel) {
|
||||
|
||||
// Claim: the mesh is now in a consistent state, except that eDel.org
|
||||
// may have been deleted. Now we disconnect eDel.dst().
|
||||
if (eDelSym.oNext === eDelSym ) {
|
||||
if (eDelSym.oNext === eDelSym) {
|
||||
libtess.mesh.killVertex_(eDelSym.org, null);
|
||||
libtess.mesh.killFace_(eDelSym.lFace, null);
|
||||
|
||||
@@ -199,13 +202,14 @@ libtess.mesh.deleteEdge = function(eDel) {
|
||||
* operations above. They are provided for convenience and efficiency.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* addEdgeVertex(eOrg) creates a new edge eNew such that
|
||||
* eNew == eOrg.lNext, and eNew.dst() is a newly created vertex.
|
||||
* eOrg and eNew will have the same left face.
|
||||
*
|
||||
* @param {libtess.GluHalfEdge} eOrg [description]
|
||||
* @return {libtess.GluHalfEdge} [description]
|
||||
* @param {libtess.GluHalfEdge} eOrg [description].
|
||||
* @return {libtess.GluHalfEdge} [description].
|
||||
*/
|
||||
libtess.mesh.addEdgeVertex = function(eOrg) {
|
||||
// TODO(bckenny): why is it named this?
|
||||
@@ -219,20 +223,21 @@ libtess.mesh.addEdgeVertex = function(eOrg) {
|
||||
// Set the vertex and face information
|
||||
eNew.org = eOrg.dst();
|
||||
|
||||
libtess.mesh.makeVertex_(eNewSym, eNew.org );
|
||||
libtess.mesh.makeVertex_(eNewSym, eNew.org);
|
||||
|
||||
eNew.lFace = eNewSym.lFace = eOrg.lFace;
|
||||
|
||||
return eNew;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* splitEdge(eOrg) splits eOrg into two edges eOrg and eNew,
|
||||
* such that eNew == eOrg.lNext. The new vertex is eOrg.dst() == eNew.org.
|
||||
* eOrg and eNew will have the same left face.
|
||||
*
|
||||
* @param {libtess.GluHalfEdge} eOrg [description]
|
||||
* @return {!libtess.GluHalfEdge} [description]
|
||||
* @param {libtess.GluHalfEdge} eOrg [description].
|
||||
* @return {!libtess.GluHalfEdge} [description].
|
||||
*/
|
||||
libtess.mesh.splitEdge = function(eOrg) {
|
||||
var tempHalfEdge = libtess.mesh.addEdgeVertex(eOrg);
|
||||
@@ -252,6 +257,7 @@ libtess.mesh.splitEdge = function(eOrg) {
|
||||
return eNew;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* connect(eOrg, eDst) creates a new edge from eOrg.dst()
|
||||
* to eDst.org, and returns the corresponding half-edge eNew.
|
||||
@@ -263,9 +269,9 @@ libtess.mesh.splitEdge = function(eOrg) {
|
||||
* If (eOrg.lNext == eDst), the old face is reduced to a single edge.
|
||||
* If (eOrg.lNext.lNext == eDst), the old face is reduced to two edges.
|
||||
*
|
||||
* @param {libtess.GluHalfEdge} eOrg [description]
|
||||
* @param {libtess.GluHalfEdge} eDst [description]
|
||||
* @return {!libtess.GluHalfEdge} [description]
|
||||
* @param {libtess.GluHalfEdge} eOrg [description].
|
||||
* @param {libtess.GluHalfEdge} eDst [description].
|
||||
* @return {!libtess.GluHalfEdge} [description].
|
||||
*/
|
||||
libtess.mesh.connect = function(eOrg, eDst) {
|
||||
var joiningLoops = false;
|
||||
@@ -292,13 +298,14 @@ libtess.mesh.connect = function(eOrg, eDst) {
|
||||
|
||||
if (!joiningLoops) {
|
||||
// We split one loop into two -- the new loop is eNew.lFace
|
||||
libtess.mesh.makeFace_(eNew, eOrg.lFace );
|
||||
libtess.mesh.makeFace_(eNew, eOrg.lFace);
|
||||
}
|
||||
return eNew;
|
||||
};
|
||||
|
||||
/******************** Other Operations **********************/
|
||||
|
||||
|
||||
/**
|
||||
* zapFace(fZap) destroys a face and removes it from the
|
||||
* global face list. All edges of fZap will have a null pointer as their
|
||||
@@ -307,7 +314,7 @@ libtess.mesh.connect = function(eOrg, eDst) {
|
||||
* An entire mesh can be deleted by zapping its faces, one at a time,
|
||||
* in any order. Zapped faces cannot be used in further mesh operations!
|
||||
*
|
||||
* @param {libtess.GluFace} fZap [description]
|
||||
* @param {libtess.GluFace} fZap [description].
|
||||
*/
|
||||
libtess.mesh.zapFace = function(fZap) {
|
||||
var eStart = fZap.anEdge;
|
||||
@@ -343,7 +350,7 @@ libtess.mesh.zapFace = function(fZap) {
|
||||
}
|
||||
libtess.mesh.killEdge_(e);
|
||||
}
|
||||
} while(e !== eStart);
|
||||
} while (e !== eStart);
|
||||
|
||||
// delete from circular doubly-linked list
|
||||
var fPrev = fZap.prev;
|
||||
@@ -355,13 +362,14 @@ libtess.mesh.zapFace = function(fZap) {
|
||||
// TODO(bckenny): probably null at callsite
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* meshUnion() forms the union of all structures in
|
||||
* both meshes, and returns the new mesh (the old meshes are destroyed).
|
||||
*
|
||||
* @param {libtess.GluMesh} mesh1 [description]
|
||||
* @param {libtess.GluMesh} mesh2 [description]
|
||||
* @return {libtess.GluMesh} [description]
|
||||
* @param {libtess.GluMesh} mesh1 [description].
|
||||
* @param {libtess.GluMesh} mesh2 [description].
|
||||
* @return {libtess.GluMesh} [description].
|
||||
*/
|
||||
libtess.mesh.meshUnion = function(mesh1, mesh2) {
|
||||
// TODO(bceknny): probably move to GluMesh method
|
||||
@@ -400,9 +408,10 @@ libtess.mesh.meshUnion = function(mesh1, mesh2) {
|
||||
return mesh1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* deleteMesh(mesh) will free all storage for any valid mesh.
|
||||
* @param {libtess.GluMesh} mesh [description]
|
||||
* @param {libtess.GluMesh} mesh [description].
|
||||
*/
|
||||
libtess.mesh.deleteMesh = function(mesh) {
|
||||
// TODO(bckenny): unnecessary, I think.
|
||||
@@ -412,6 +421,7 @@ libtess.mesh.deleteMesh = function(mesh) {
|
||||
|
||||
/************************ Utility Routines ************************/
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new pair of half-edges which form their own loop.
|
||||
* No vertex or face structures are allocated, but these must be assigned
|
||||
@@ -420,8 +430,8 @@ libtess.mesh.deleteMesh = function(mesh) {
|
||||
* TODO(bckenny): warning about eNext strictly being first of pair? (see code)
|
||||
*
|
||||
* @private
|
||||
* @param {libtess.GluHalfEdge} eNext [description]
|
||||
* @return {libtess.GluHalfEdge} [description]
|
||||
* @param {libtess.GluHalfEdge} eNext [description].
|
||||
* @return {libtess.GluHalfEdge} [description].
|
||||
*/
|
||||
libtess.mesh.makeEdgePair_ = function(eNext) {
|
||||
var e = new libtess.GluHalfEdge();
|
||||
@@ -430,7 +440,7 @@ libtess.mesh.makeEdgePair_ = function(eNext) {
|
||||
// TODO(bckenny): how do we ensure this? see above comment in jsdoc
|
||||
// Make sure eNext points to the first edge of the edge pair
|
||||
// if (eNext->Sym < eNext ) { eNext = eNext->Sym; }
|
||||
|
||||
|
||||
// NOTE(bckenny): check this for bugs in current implementation!
|
||||
|
||||
// Insert in circular doubly-linked list before eNext.
|
||||
@@ -452,6 +462,7 @@ libtess.mesh.makeEdgePair_ = function(eNext) {
|
||||
return e;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* splice_ is best described by the Guibas/Stolfi paper or the
|
||||
* CS348a notes. Basically, it modifies the mesh so that
|
||||
@@ -460,8 +471,8 @@ libtess.mesh.makeEdgePair_ = function(eNext) {
|
||||
* For more explanation see mesh.meshSplice below.
|
||||
*
|
||||
* @private
|
||||
* @param {libtess.GluHalfEdge} a [description]
|
||||
* @param {libtess.GluHalfEdge} b [description]
|
||||
* @param {libtess.GluHalfEdge} a [description].
|
||||
* @param {libtess.GluHalfEdge} b [description].
|
||||
*/
|
||||
libtess.mesh.splice_ = function(a, b) {
|
||||
var aONext = a.oNext;
|
||||
@@ -473,6 +484,7 @@ libtess.mesh.splice_ = function(a, b) {
|
||||
b.oNext = aONext;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* makeVertex_(eOrig, vNext) attaches a new vertex and makes it the
|
||||
* origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives
|
||||
@@ -483,8 +495,8 @@ libtess.mesh.splice_ = function(a, b) {
|
||||
* NOTE: unlike original, acutally allocates new vertex.
|
||||
*
|
||||
* @private
|
||||
* @param {libtess.GluHalfEdge} eOrig [description]
|
||||
* @param {libtess.GluVertex} vNext [description]
|
||||
* @param {libtess.GluHalfEdge} eOrig [description].
|
||||
* @param {libtess.GluVertex} vNext [description].
|
||||
*/
|
||||
libtess.mesh.makeVertex_ = function(eOrig, vNext) {
|
||||
// insert in circular doubly-linked list before vNext
|
||||
@@ -502,9 +514,10 @@ libtess.mesh.makeVertex_ = function(eOrig, vNext) {
|
||||
do {
|
||||
e.org = vNew;
|
||||
e = e.oNext;
|
||||
} while(e !== eOrig);
|
||||
} while (e !== eOrig);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* makeFace_(eOrig, fNext) attaches a new face and makes it the left
|
||||
* face of all edges in the face loop to which eOrig belongs. "fNext" gives
|
||||
@@ -515,8 +528,8 @@ libtess.mesh.makeVertex_ = function(eOrig, vNext) {
|
||||
* NOTE: unlike original, acutally allocates new face.
|
||||
*
|
||||
* @private
|
||||
* @param {libtess.GluHalfEdge} eOrig [description]
|
||||
* @param {libtess.GluFace} fNext [description]
|
||||
* @param {libtess.GluHalfEdge} eOrig [description].
|
||||
* @param {libtess.GluFace} fNext [description].
|
||||
*/
|
||||
libtess.mesh.makeFace_ = function(eOrig, fNext) {
|
||||
// insert in circular doubly-linked list before fNext
|
||||
@@ -536,15 +549,16 @@ libtess.mesh.makeFace_ = function(eOrig, fNext) {
|
||||
do {
|
||||
e.lFace = fNew;
|
||||
e = e.lNext;
|
||||
} while(e !== eOrig);
|
||||
} while (e !== eOrig);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* killEdge_ destroys an edge (the half-edges eDel and eDel.sym),
|
||||
* and removes from the global edge list.
|
||||
*
|
||||
* @private
|
||||
* @param {libtess.GluHalfEdge} eDel [description]
|
||||
* @param {libtess.GluHalfEdge} eDel [description].
|
||||
*/
|
||||
libtess.mesh.killEdge_ = function(eDel) {
|
||||
// TODO(bckenny): in this case, no need to worry(?), but check when checking mesh.makeEdgePair_
|
||||
@@ -561,13 +575,14 @@ libtess.mesh.killEdge_ = function(eDel) {
|
||||
// TODO(bckenny): need to null at callsites?
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* killVertex_ destroys a vertex and removes it from the global
|
||||
* vertex list. It updates the vertex loop to point to a given new vertex.
|
||||
*
|
||||
* @private
|
||||
* @param {libtess.GluVertex} vDel [description]
|
||||
* @param {libtess.GluVertex} newOrg [description]
|
||||
* @param {libtess.GluVertex} vDel [description].
|
||||
* @param {libtess.GluVertex} newOrg [description].
|
||||
*/
|
||||
libtess.mesh.killVertex_ = function(vDel, newOrg) {
|
||||
var eStart = vDel.anEdge;
|
||||
@@ -577,7 +592,7 @@ libtess.mesh.killVertex_ = function(vDel, newOrg) {
|
||||
do {
|
||||
e.org = newOrg;
|
||||
e = e.oNext;
|
||||
} while(e !== eStart);
|
||||
} while (e !== eStart);
|
||||
|
||||
// delete from circular doubly-linked list
|
||||
var vPrev = vDel.prev;
|
||||
@@ -589,13 +604,14 @@ libtess.mesh.killVertex_ = function(vDel, newOrg) {
|
||||
// TODO(bckenny): need to null at callsites?
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* killFace_ destroys a face and removes it from the global face
|
||||
* list. It updates the face loop to point to a given new face.
|
||||
*
|
||||
* @private
|
||||
* @param {libtess.GluFace} fDel [description]
|
||||
* @param {libtess.GluFace} newLFace [description]
|
||||
* @param {libtess.GluFace} fDel [description].
|
||||
* @param {libtess.GluFace} newLFace [description].
|
||||
*/
|
||||
libtess.mesh.killFace_ = function(fDel, newLFace) {
|
||||
var eStart = fDel.anEdge;
|
||||
@@ -605,7 +621,7 @@ libtess.mesh.killFace_ = function(fDel, newLFace) {
|
||||
do {
|
||||
e.lFace = newLFace;
|
||||
e = e.lNext;
|
||||
} while(e !== eStart);
|
||||
} while (e !== eStart);
|
||||
|
||||
// delete from circular doubly-linked list
|
||||
var fPrev = fDel.prev;
|
||||
|
||||
@@ -36,14 +36,16 @@
|
||||
// requre libtess.GluHalfEdge
|
||||
/*global libtess */
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Each face has a pointer to the next and previous faces in the
|
||||
* circular list, and a pointer to a half-edge with this face as
|
||||
* the left face (null if this is the dummy header). There is also
|
||||
* a field "data" for client data.
|
||||
*
|
||||
* @param {libtess.GluFace=} opt_nextFace [description]
|
||||
* @param {libtess.GluFace=} opt_prevFace [description]
|
||||
* @param {libtess.GluFace=} opt_nextFace [description].
|
||||
* @param {libtess.GluFace=} opt_prevFace [description].
|
||||
* @constructor
|
||||
*/
|
||||
libtess.GluFace = function(opt_nextFace, opt_prevFace) {
|
||||
@@ -66,7 +68,7 @@ libtess.GluFace = function(opt_nextFace, opt_prevFace) {
|
||||
* @type {libtess.GluHalfEdge}
|
||||
*/
|
||||
this.anEdge = null;
|
||||
|
||||
|
||||
/**
|
||||
* room for client's data
|
||||
* @type {Object}
|
||||
@@ -78,13 +80,13 @@ libtess.GluFace = function(opt_nextFace, opt_prevFace) {
|
||||
* @type {libtess.GluFace}
|
||||
*/
|
||||
this.trail = null;
|
||||
|
||||
|
||||
/**
|
||||
* Flag for conversion to strips.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.marked = false;
|
||||
|
||||
|
||||
/**
|
||||
* This face is in the polygon interior.
|
||||
* @type {boolean}
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
// require libtess.ActiveRegion
|
||||
/*global libtess */
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The fundamental data structure is the "half-edge". Two half-edges
|
||||
* go together to make an edge, but they point in opposite directions.
|
||||
@@ -63,12 +65,12 @@
|
||||
* e.sym stores a pointer in the opposite direction, thus it is
|
||||
* always true that e.sym.next.sym.next === e.
|
||||
*
|
||||
* @param {libtess.GluHalfEdge=} opt_nextEdge [description]
|
||||
* @param {libtess.GluHalfEdge=} opt_nextEdge [description].
|
||||
* @constructor
|
||||
*/
|
||||
libtess.GluHalfEdge = function(opt_nextEdge) {
|
||||
// TODO(bckenny): are these the right defaults? (from gl_meshNewMesh requirements)
|
||||
|
||||
|
||||
/**
|
||||
* doubly-linked list (prev==sym->next)
|
||||
* @type {!libtess.GluHalfEdge}
|
||||
@@ -108,7 +110,7 @@ libtess.GluHalfEdge = function(opt_nextEdge) {
|
||||
|
||||
// Internal data (keep hidden)
|
||||
// NOTE(bckenny): can't be private, though...
|
||||
|
||||
|
||||
/**
|
||||
* a region with this upper edge (see sweep.js)
|
||||
* @type {libtess.ActiveRegion}
|
||||
@@ -126,65 +128,73 @@ libtess.GluHalfEdge = function(opt_nextEdge) {
|
||||
// TODO(bckenny): using methods as aliases for sym connections for now.
|
||||
// not sure about this approach. getters? renames?
|
||||
|
||||
|
||||
/**
|
||||
* [rFace description]
|
||||
* @return {libtess.GluFace} [description]
|
||||
* @return {libtess.GluFace} [description].
|
||||
*/
|
||||
libtess.GluHalfEdge.prototype.rFace = function() {
|
||||
return this.sym.lFace;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [dst description]
|
||||
* @return {libtess.GluVertex} [description]
|
||||
* @return {libtess.GluVertex} [description].
|
||||
*/
|
||||
libtess.GluHalfEdge.prototype.dst = function() {
|
||||
return this.sym.org;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [oPrev description]
|
||||
* @return {libtess.GluHalfEdge} [description]
|
||||
* @return {libtess.GluHalfEdge} [description].
|
||||
*/
|
||||
libtess.GluHalfEdge.prototype.oPrev = function() {
|
||||
return this.sym.lNext;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [lPrev description]
|
||||
* @return {libtess.GluHalfEdge} [description]
|
||||
* @return {libtess.GluHalfEdge} [description].
|
||||
*/
|
||||
libtess.GluHalfEdge.prototype.lPrev = function() {
|
||||
return this.oNext.sym;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [dPrev description]
|
||||
* @return {libtess.GluHalfEdge} [description]
|
||||
* @return {libtess.GluHalfEdge} [description].
|
||||
*/
|
||||
libtess.GluHalfEdge.prototype.dPrev = function() {
|
||||
return this.lNext.sym;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [rPrev description]
|
||||
* @return {libtess.GluHalfEdge} [description]
|
||||
* @return {libtess.GluHalfEdge} [description].
|
||||
*/
|
||||
libtess.GluHalfEdge.prototype.rPrev = function() {
|
||||
return this.sym.oNext;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [dNext description]
|
||||
* @return {libtess.GluHalfEdge} [description]
|
||||
* @return {libtess.GluHalfEdge} [description].
|
||||
*/
|
||||
libtess.GluHalfEdge.prototype.dNext = function() {
|
||||
return this.rPrev().sym;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [rNext description]
|
||||
* @return {libtess.GluHalfEdge} [description]
|
||||
* @return {libtess.GluHalfEdge} [description].
|
||||
*/
|
||||
libtess.GluHalfEdge.prototype.rNext = function() {
|
||||
return this.oPrev().sym;
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
// require libtess.GluVertex
|
||||
/*global libtess */
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new mesh with no edges, no vertices,
|
||||
* and no loops (what we usually call a "face").
|
||||
@@ -61,7 +63,7 @@ libtess.GluMesh = function() {
|
||||
* @type {libtess.GluHalfEdge}
|
||||
*/
|
||||
this.eHead = new libtess.GluHalfEdge();
|
||||
|
||||
|
||||
/**
|
||||
* and its symmetric counterpart
|
||||
* @type {libtess.GluHalfEdge}
|
||||
@@ -73,6 +75,7 @@ libtess.GluMesh = function() {
|
||||
this.eHeadSym.sym = this.eHead;
|
||||
};
|
||||
|
||||
|
||||
// TODO(bckenny): #ifndef NDEBUG
|
||||
/**
|
||||
* Checks mesh for self-consistency.
|
||||
@@ -85,7 +88,7 @@ libtess.GluMesh.prototype.checkMesh = function() {
|
||||
var fHead = this.fHead;
|
||||
var vHead = this.vHead;
|
||||
var eHead = this.eHead;
|
||||
|
||||
|
||||
var e;
|
||||
|
||||
// faces
|
||||
@@ -101,7 +104,7 @@ libtess.GluMesh.prototype.checkMesh = function() {
|
||||
libtess.assert(e.oNext.sym.lNext === e);
|
||||
libtess.assert(e.lFace === f);
|
||||
e = e.lNext;
|
||||
} while(e !== f.anEdge);
|
||||
} while (e !== f.anEdge);
|
||||
}
|
||||
libtess.assert(f.prev === fPrev && f.anEdge === null && f.data === null);
|
||||
|
||||
@@ -118,7 +121,7 @@ libtess.GluMesh.prototype.checkMesh = function() {
|
||||
libtess.assert(e.oNext.sym.lNext === e);
|
||||
libtess.assert(e.org === v);
|
||||
e = e.oNext;
|
||||
} while(e !== v.anEdge);
|
||||
} while (e !== v.anEdge);
|
||||
}
|
||||
libtess.assert(v.prev === vPrev && v.anEdge === null && v.data === null);
|
||||
|
||||
|
||||
@@ -35,14 +35,16 @@
|
||||
// requre libtess.GluHalfEdge
|
||||
/*global libtess */
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Each vertex has a pointer to next and previous vertices in the
|
||||
* circular list, and a pointer to a half-edge with this vertex as
|
||||
* the origin (null if this is the dummy header). There is also a
|
||||
* field "data" for client data.
|
||||
*
|
||||
* @param {libtess.GluVertex=} opt_nextVertex [description]
|
||||
* @param {libtess.GluVertex=} opt_prevVertex [description]
|
||||
* @param {libtess.GluVertex=} opt_nextVertex [description].
|
||||
* @param {libtess.GluVertex=} opt_prevVertex [description].
|
||||
* @constructor
|
||||
*/
|
||||
libtess.GluVertex = function(opt_nextVertex, opt_prevVertex) {
|
||||
@@ -65,7 +67,7 @@ libtess.GluVertex = function(opt_nextVertex, opt_prevVertex) {
|
||||
* @type {libtess.GluHalfEdge}
|
||||
*/
|
||||
this.anEdge = null;
|
||||
|
||||
|
||||
/**
|
||||
* The client's data.
|
||||
* @type {Object}
|
||||
|
||||
@@ -40,6 +40,7 @@ libtess.normal = function() {
|
||||
|
||||
};
|
||||
|
||||
|
||||
// TODO(bckenny): NOTE:
|
||||
/* The "feature merging" is not intended to be complete. There are
|
||||
* special cases where edges are nearly parallel to the sweep line
|
||||
@@ -62,6 +63,7 @@ libtess.normal = function() {
|
||||
*/
|
||||
libtess.normal.S_UNIT_X_ = 1.0;
|
||||
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
@@ -69,15 +71,16 @@ libtess.normal.S_UNIT_X_ = 1.0;
|
||||
*/
|
||||
libtess.normal.S_UNIT_Y_ = 0.0;
|
||||
|
||||
|
||||
/**
|
||||
* projectPolygon determines the polygon normal
|
||||
* and projects vertices onto the plane of the polygon.
|
||||
*
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
*/
|
||||
libtess.normal.projectPolygon = function(tess) {
|
||||
var computedNormal = false;
|
||||
|
||||
|
||||
var norm = [0, 0, 0];
|
||||
norm[0] = tess.normal[0]; // TODO(bckenny): better way to init these?
|
||||
norm[1] = tess.normal[1];
|
||||
@@ -97,8 +100,8 @@ libtess.normal.projectPolygon = function(tess) {
|
||||
libtess.normal.normalize_(norm);
|
||||
|
||||
sUnit[i] = 0;
|
||||
sUnit[(i+1)%3] = libtess.normal.S_UNIT_X_;
|
||||
sUnit[(i+2)%3] = libtess.normal.S_UNIT_Y_;
|
||||
sUnit[(i + 1) % 3] = libtess.normal.S_UNIT_X_;
|
||||
sUnit[(i + 2) % 3] = libtess.normal.S_UNIT_Y_;
|
||||
|
||||
// Now make it exactly perpendicular
|
||||
var w = libtess.normal.dot_(sUnit, norm);
|
||||
@@ -108,20 +111,20 @@ libtess.normal.projectPolygon = function(tess) {
|
||||
libtess.normal.normalize_(sUnit);
|
||||
|
||||
// Choose tUnit so that (sUnit,tUnit,norm) form a right-handed frame
|
||||
tUnit[0] = norm[1]*sUnit[2] - norm[2]*sUnit[1];
|
||||
tUnit[1] = norm[2]*sUnit[0] - norm[0]*sUnit[2];
|
||||
tUnit[2] = norm[0]*sUnit[1] - norm[1]*sUnit[0];
|
||||
tUnit[0] = norm[1] * sUnit[2] - norm[2] * sUnit[1];
|
||||
tUnit[1] = norm[2] * sUnit[0] - norm[0] * sUnit[2];
|
||||
tUnit[2] = norm[0] * sUnit[1] - norm[1] * sUnit[0];
|
||||
libtess.normal.normalize_(tUnit);
|
||||
|
||||
} else {
|
||||
// Project perpendicular to a coordinate axis -- better numerically
|
||||
sUnit[i] = 0;
|
||||
sUnit[(i+1)%3] = libtess.normal.S_UNIT_X_;
|
||||
sUnit[(i+2)%3] = libtess.normal.S_UNIT_Y_;
|
||||
|
||||
sUnit[(i + 1) % 3] = libtess.normal.S_UNIT_X_;
|
||||
sUnit[(i + 2) % 3] = libtess.normal.S_UNIT_Y_;
|
||||
|
||||
tUnit[i] = 0;
|
||||
tUnit[(i+1)%3] = (norm[i] > 0) ? -libtess.normal.S_UNIT_Y_ : libtess.normal.S_UNIT_Y_;
|
||||
tUnit[(i+2)%3] = (norm[i] > 0) ? libtess.normal.S_UNIT_X_ : -libtess.normal.S_UNIT_X_;
|
||||
tUnit[(i + 1) % 3] = (norm[i] > 0) ? -libtess.normal.S_UNIT_Y_ : libtess.normal.S_UNIT_Y_;
|
||||
tUnit[(i + 2) % 3] = (norm[i] > 0) ? libtess.normal.S_UNIT_X_ : -libtess.normal.S_UNIT_X_;
|
||||
}
|
||||
|
||||
// Project the vertices onto the sweep plane
|
||||
@@ -136,24 +139,26 @@ libtess.normal.projectPolygon = function(tess) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Dot product.
|
||||
* @private
|
||||
* @param {Array.<number>} u [description]
|
||||
* @param {Array.<number>} v [description]
|
||||
* @return {number} [description]
|
||||
* @param {Array.<number>} u [description].
|
||||
* @param {Array.<number>} v [description].
|
||||
* @return {number} [description].
|
||||
*/
|
||||
libtess.normal.dot_ = function(u, v) {
|
||||
return u[0]*v[0] + u[1]*v[1] + u[2]*v[2];
|
||||
return u[0] * v[0] + u[1] * v[1] + u[2] * v[2];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Normalize vector v
|
||||
* @private
|
||||
* @param {Array.<number>} v [description]
|
||||
* @param {Array.<number>} v [description].
|
||||
*/
|
||||
libtess.normal.normalize_ = function(v) {
|
||||
var len = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
|
||||
var len = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
|
||||
|
||||
libtess.assert(len > 0);
|
||||
len = Math.sqrt(len);
|
||||
@@ -162,10 +167,11 @@ libtess.normal.normalize_ = function(v) {
|
||||
v[2] /= len;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the index of the longest component of vector v.
|
||||
* @private
|
||||
* @param {Array.<number>} v [description]
|
||||
* @param {Array.<number>} v [description].
|
||||
* @return {number} The index of the longest component.
|
||||
*/
|
||||
libtess.normal.longAxis_ = function(v) {
|
||||
@@ -181,12 +187,13 @@ libtess.normal.longAxis_ = function(v) {
|
||||
return i;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [computeNormal description]
|
||||
*
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {Array.<number>} norm [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {Array.<number>} norm [description].
|
||||
*/
|
||||
libtess.normal.computeNormal_ = function(tess, norm) {
|
||||
// TODO(bckenny): better way to init these
|
||||
@@ -238,10 +245,10 @@ libtess.normal.computeNormal_ = function(tess, norm) {
|
||||
d2[0] = v.coords[0] - v2.coords[0];
|
||||
d2[1] = v.coords[1] - v2.coords[1];
|
||||
d2[2] = v.coords[2] - v2.coords[2];
|
||||
tNorm[0] = d1[1]*d2[2] - d1[2]*d2[1];
|
||||
tNorm[1] = d1[2]*d2[0] - d1[0]*d2[2];
|
||||
tNorm[2] = d1[0]*d2[1] - d1[1]*d2[0];
|
||||
var tLen2 = tNorm[0]*tNorm[0] + tNorm[1]*tNorm[1] + tNorm[2]*tNorm[2];
|
||||
tNorm[0] = d1[1] * d2[2] - d1[2] * d2[1];
|
||||
tNorm[1] = d1[2] * d2[0] - d1[0] * d2[2];
|
||||
tNorm[2] = d1[0] * d2[1] - d1[1] * d2[0];
|
||||
var tLen2 = tNorm[0] * tNorm[0] + tNorm[1] * tNorm[1] + tNorm[2] * tNorm[2];
|
||||
if (tLen2 > maxLen2) {
|
||||
maxLen2 = tLen2;
|
||||
norm[0] = tNorm[0];
|
||||
@@ -257,11 +264,12 @@ libtess.normal.computeNormal_ = function(tess, norm) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [checkOrientation description]
|
||||
*
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
*/
|
||||
libtess.normal.checkOrientation_ = function(tess) {
|
||||
// When we compute the normal automatically, we choose the orientation
|
||||
@@ -274,7 +282,7 @@ libtess.normal.checkOrientation_ = function(tess) {
|
||||
do {
|
||||
area += (e.org.s - e.dst().s) * (e.org.t + e.dst().t);
|
||||
e = e.lNext;
|
||||
} while(e !== f.anEdge);
|
||||
} while (e !== f.anEdge);
|
||||
}
|
||||
|
||||
if (area < 0) {
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
|
||||
// TODO(bckenny): more specific typing on key
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* [PQHandleElem description]
|
||||
* @constructor
|
||||
@@ -49,7 +51,7 @@ libtess.PQHandleElem = function() {
|
||||
* @type {libtess.PQKey}
|
||||
*/
|
||||
this.key = null;
|
||||
|
||||
|
||||
/**
|
||||
* [node description]
|
||||
* @type {libtess.PQHandle}
|
||||
@@ -57,14 +59,15 @@ libtess.PQHandleElem = function() {
|
||||
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]
|
||||
* @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);
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
// TODO(bckenny): maybe just have these created inline as literals
|
||||
// (or unboxed directly - PQHandle is just an array index number)
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* [PQNode description]
|
||||
* @constructor
|
||||
@@ -50,14 +52,15 @@ libtess.PQNode = function() {
|
||||
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]
|
||||
* @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);
|
||||
|
||||
@@ -39,10 +39,12 @@
|
||||
// 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]
|
||||
* @param {function(Object, Object): boolean} leq [description].
|
||||
*/
|
||||
libtess.PriorityQ = function(leq) {
|
||||
/**
|
||||
@@ -51,21 +53,21 @@ libtess.PriorityQ = function(leq) {
|
||||
* @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
|
||||
@@ -97,6 +99,7 @@ libtess.PriorityQ = function(leq) {
|
||||
this.heap_ = new libtess.PriorityQHeap(this.leq_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [INIT_SIZE_ description]
|
||||
* @private
|
||||
@@ -105,6 +108,7 @@ libtess.PriorityQ = function(leq) {
|
||||
*/
|
||||
libtess.PriorityQ.INIT_SIZE_ = 32;
|
||||
|
||||
|
||||
/**
|
||||
* [deleteQ description]
|
||||
*/
|
||||
@@ -117,6 +121,7 @@ libtess.PriorityQ.prototype.deleteQ = function() {
|
||||
// NOTE(bckenny): nulled at callsite (sweep.donePriorityQ_)
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [init description]
|
||||
*/
|
||||
@@ -154,16 +159,17 @@ libtess.PriorityQ.prototype.init = function() {
|
||||
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]]));
|
||||
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]
|
||||
* @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.
|
||||
@@ -181,18 +187,19 @@ libtess.PriorityQ.prototype.insert = function(keyNew) {
|
||||
this.keys_[curr] = keyNew;
|
||||
|
||||
// Negative handles index the sorted array.
|
||||
return -(curr+1);
|
||||
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]
|
||||
* @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?
|
||||
@@ -213,12 +220,13 @@ libtess.PriorityQ.prototype.PQKeyRealloc_ = function(oldArray, size) {
|
||||
return newArray;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [keyLessThan_ description]
|
||||
* @private
|
||||
* @param {number} x [description]
|
||||
* @param {number} y [description]
|
||||
* @return {boolean} [description]
|
||||
* @param {number} x [description].
|
||||
* @param {number} y [description].
|
||||
* @return {boolean} [description].
|
||||
*/
|
||||
libtess.PriorityQ.prototype.keyLessThan_ = function(x, y) {
|
||||
// NOTE(bckenny): was macro LT
|
||||
@@ -227,12 +235,13 @@ libtess.PriorityQ.prototype.keyLessThan_ = function(x, y) {
|
||||
return !this.leq_(keyY, keyX);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [keyGreaterThan_ description]
|
||||
* @private
|
||||
* @param {number} x [description]
|
||||
* @param {number} y [description]
|
||||
* @return {boolean} [description]
|
||||
* @param {number} x [description].
|
||||
* @param {number} y [description].
|
||||
* @return {boolean} [description].
|
||||
*/
|
||||
libtess.PriorityQ.prototype.keyGreaterThan_ = function(x, y) {
|
||||
// NOTE(bckenny): was macro GT
|
||||
@@ -241,16 +250,17 @@ libtess.PriorityQ.prototype.keyGreaterThan_ = function(x, y) {
|
||||
return !this.leq_(keyX, keyY);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [extractMin description]
|
||||
* @return {libtess.PQKey} [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]];
|
||||
var sortMin = this.keys_[this.order_[this.size_ - 1]];
|
||||
if (!this.heap_.isEmpty()) {
|
||||
var heapMin = this.heap_.minimum();
|
||||
if (this.leq_(heapMin, sortMin)) {
|
||||
@@ -260,21 +270,22 @@ libtess.PriorityQ.prototype.extractMin = function() {
|
||||
|
||||
do {
|
||||
--this.size_;
|
||||
} while(this.size_ > 0 && this.keys_[this.order_[this.size_-1]] === null);
|
||||
} while (this.size_ > 0 && this.keys_[this.order_[this.size_ - 1]] === null);
|
||||
|
||||
return sortMin;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [minimum description]
|
||||
* @return {libtess.PQKey} [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]];
|
||||
var sortMin = this.keys_[this.order_[this.size_ - 1]];
|
||||
if (!this.heap_.isEmpty()) {
|
||||
var heapMin = this.heap_.minimum();
|
||||
if (this.leq_(heapMin, sortMin)) {
|
||||
@@ -285,29 +296,31 @@ libtess.PriorityQ.prototype.minimum = function() {
|
||||
return sortMin;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [isEmpty description]
|
||||
* @return {boolean} [description]
|
||||
* @return {boolean} [description].
|
||||
*/
|
||||
libtess.PriorityQ.prototype.isEmpty = function() {
|
||||
return (this.size_ === 0) && this.heap_.isEmpty();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [remove description]
|
||||
* @param {libtess.PQHandle} curr [description]
|
||||
* @param {libtess.PQHandle} curr [description].
|
||||
*/
|
||||
libtess.PriorityQ.prototype.remove = function(curr) {
|
||||
if (curr >= 0) {
|
||||
this.heap_.remove(curr);
|
||||
return;
|
||||
}
|
||||
curr = -(curr+1);
|
||||
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) {
|
||||
while (this.size_ > 0 && this.keys_[this.order_[this.size_ - 1]] === null) {
|
||||
--this.size_;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -39,10 +39,12 @@
|
||||
|
||||
// TODO(bckenny): keys appear to always be GluVertex in this case?
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* [PriorityQHeap description]
|
||||
* @constructor
|
||||
* @param {function(libtess.PQKey, libtess.PQKey): boolean} leq [description]
|
||||
* @param {function(libtess.PQKey, libtess.PQKey): boolean} leq [description].
|
||||
*/
|
||||
libtess.PriorityQHeap = function(leq) {
|
||||
/**
|
||||
@@ -102,11 +104,12 @@ libtess.PriorityQHeap = function(leq) {
|
||||
* @type {function(libtess.PQKey, libtess.PQKey): boolean}
|
||||
*/
|
||||
this.leq_ = leq;
|
||||
|
||||
|
||||
// so that minimum returns null
|
||||
this.nodes_[1].handle = 1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [INIT_SIZE_ description]
|
||||
* @private
|
||||
@@ -115,6 +118,7 @@ libtess.PriorityQHeap = function(leq) {
|
||||
*/
|
||||
libtess.PriorityQHeap.INIT_SIZE_ = 32;
|
||||
|
||||
|
||||
/**
|
||||
* [deleteHeap description]
|
||||
*/
|
||||
@@ -125,19 +129,21 @@ libtess.PriorityQHeap.prototype.deleteHeap = function() {
|
||||
// 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) {
|
||||
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.
|
||||
@@ -147,7 +153,7 @@ libtess.PriorityQHeap.prototype.insert = function(keyNew) {
|
||||
var curr = ++this.size_;
|
||||
|
||||
// if the heap overflows, double its size.
|
||||
if ((curr*2) > this.max_) {
|
||||
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);
|
||||
@@ -172,6 +178,7 @@ libtess.PriorityQHeap.prototype.insert = function(keyNew) {
|
||||
return free;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the heap is empty.
|
||||
*/
|
||||
@@ -179,19 +186,21 @@ 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]
|
||||
* @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]
|
||||
* @return {libtess.PQKey} [description].
|
||||
*/
|
||||
libtess.PriorityQHeap.prototype.extractMin = function() {
|
||||
var n = this.nodes_;
|
||||
@@ -207,7 +216,7 @@ libtess.PriorityQHeap.prototype.extractMin = function() {
|
||||
h[hMin].node = this.freeList_;
|
||||
this.freeList_ = hMin;
|
||||
|
||||
if (--this.size_ > 0 ) {
|
||||
if (--this.size_ > 0) {
|
||||
this.floatDown_(1);
|
||||
}
|
||||
}
|
||||
@@ -215,9 +224,10 @@ libtess.PriorityQHeap.prototype.extractMin = function() {
|
||||
return min;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove key associated with handle hCurr (returned from insert) from heap.
|
||||
* @param {libtess.PQHandle} hCurr [description]
|
||||
* @param {libtess.PQHandle} hCurr [description].
|
||||
*/
|
||||
libtess.PriorityQHeap.prototype.remove = function(hCurr) {
|
||||
var n = this.nodes_;
|
||||
@@ -230,7 +240,7 @@ libtess.PriorityQHeap.prototype.remove = function(hCurr) {
|
||||
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)) {
|
||||
if (curr <= 1 || this.leq_(h[n[curr >> 1].handle].key, h[n[curr].handle].key)) {
|
||||
this.floatDown_(curr);
|
||||
} else {
|
||||
this.floatUp_(curr);
|
||||
@@ -242,21 +252,22 @@ libtess.PriorityQHeap.prototype.remove = function(hCurr) {
|
||||
this.freeList_ = hCurr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [floatDown_ description]
|
||||
* @private
|
||||
* @param {libtess.PQHandle} curr [description]
|
||||
* @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( ;; ) {
|
||||
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)) {
|
||||
if (child < this.size_ && this.leq_(h[n[child + 1].handle].key, h[n[child].handle].key)) {
|
||||
++child;
|
||||
}
|
||||
|
||||
@@ -274,17 +285,18 @@ libtess.PriorityQHeap.prototype.floatDown_ = function(curr) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [floatUp_ description]
|
||||
* @private
|
||||
* @param {libtess.PQHandle} curr [description]
|
||||
* @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( ;; ) {
|
||||
for (;; ) {
|
||||
var parent = curr >> 1;
|
||||
var hParent = n[parent].handle;
|
||||
if (parent === 0 || this.leq_(h[hParent].key, h[hCurr].key)) {
|
||||
|
||||
@@ -46,6 +46,7 @@ libtess.render = function() {
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [SIGN_INCONSISTENT_ description]
|
||||
* @type {number}
|
||||
@@ -54,6 +55,7 @@ libtess.render = function() {
|
||||
*/
|
||||
libtess.render.SIGN_INCONSISTENT_ = 2;
|
||||
|
||||
|
||||
/**
|
||||
* render.renderMesh(tess, mesh) takes a mesh and breaks it into triangle
|
||||
* fans, strips, and separate triangles. A substantial effort is made
|
||||
@@ -62,18 +64,18 @@ libtess.render.SIGN_INCONSISTENT_ = 2;
|
||||
*
|
||||
* The rendering output is provided as callbacks (see the api).
|
||||
*
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.GluMesh} mesh [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.GluMesh} mesh [description].
|
||||
*/
|
||||
libtess.render.renderMesh = function(tess, mesh) {
|
||||
// Make a list of separate triangles so we can render them all at once
|
||||
tess.lonelyTriList = null;
|
||||
|
||||
var f;
|
||||
for(f = mesh.fHead.next; f !== mesh.fHead; f = f.next) {
|
||||
for (f = mesh.fHead.next; f !== mesh.fHead; f = f.next) {
|
||||
f.marked = false;
|
||||
}
|
||||
for(f = mesh.fHead.next; f !== mesh.fHead; f = f.next) {
|
||||
for (f = mesh.fHead.next; f !== mesh.fHead; f = f.next) {
|
||||
// We examine all faces in an arbitrary order. Whenever we find
|
||||
// an unprocessed face F, we output a group of faces including F
|
||||
// whose size is maximum.
|
||||
@@ -94,8 +96,8 @@ libtess.render.renderMesh = function(tess, mesh) {
|
||||
* contour for each face marked "inside". The rendering output is
|
||||
* provided as callbacks (see the api).
|
||||
*
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.GluMesh} mesh [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.GluMesh} mesh [description].
|
||||
*/
|
||||
libtess.render.renderBoundary = function(tess, mesh) {
|
||||
for (var f = mesh.fHead.next; f !== mesh.fHead; f = f.next) {
|
||||
@@ -113,6 +115,7 @@ libtess.render.renderBoundary = function(tess, mesh) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* render.renderCache(tess) takes a single contour and tries to render it
|
||||
* as a triangle fan. This handles convex polygons, as well as some
|
||||
@@ -121,8 +124,8 @@ libtess.render.renderBoundary = function(tess, mesh) {
|
||||
* Returns true if the polygon was successfully rendered. The rendering
|
||||
* output is provided as callbacks (see the api).
|
||||
*
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @return {boolean} [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @return {boolean} [description].
|
||||
*/
|
||||
libtess.render.renderCache = function(tess) {
|
||||
if (tess.cacheCount < 3) {
|
||||
@@ -150,7 +153,7 @@ libtess.render.renderCache = function(tess) {
|
||||
}
|
||||
|
||||
// make sure we do the right thing for each winding rule
|
||||
switch(tess.windingRule) {
|
||||
switch (tess.windingRule) {
|
||||
case libtess.windingRule.GLU_TESS_WINDING_ODD:
|
||||
case libtess.windingRule.GLU_TESS_WINDING_NONZERO:
|
||||
break;
|
||||
@@ -180,11 +183,11 @@ libtess.render.renderCache = function(tess) {
|
||||
|
||||
tess.callVertexOrVertexData(tess.cache[v0].data);
|
||||
if (sign > 0) {
|
||||
for (vc = v0+1; vc < vn; ++vc) {
|
||||
for (vc = v0 + 1; vc < vn; ++vc) {
|
||||
tess.callVertexOrVertexData(tess.cache[vc].data);
|
||||
}
|
||||
} else {
|
||||
for(vc = vn-1; vc > v0; --vc) {
|
||||
for (vc = vn - 1; vc > v0; --vc) {
|
||||
tess.callVertexOrVertexData(tess.cache[vc].data);
|
||||
}
|
||||
}
|
||||
@@ -196,18 +199,19 @@ libtess.render.renderCache = function(tess) {
|
||||
/**
|
||||
* Returns true if face has been marked temporarily.
|
||||
* @private
|
||||
* @param {libtess.GluFace} f [description]
|
||||
* @return {boolean} [description]
|
||||
* @param {libtess.GluFace} f [description].
|
||||
* @return {boolean} [description].
|
||||
*/
|
||||
libtess.render.marked_ = function(f) {
|
||||
// NOTE(bckenny): originally macro
|
||||
return (!f.inside || f.marked);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [freeTrail description]
|
||||
* @private
|
||||
* @param {libtess.GluFace} t [description]
|
||||
* @param {libtess.GluFace} t [description].
|
||||
*/
|
||||
libtess.render.freeTrail_ = function(t) {
|
||||
// NOTE(bckenny): originally macro
|
||||
@@ -217,22 +221,23 @@ libtess.render.freeTrail_ = function(t) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* eOrig.lFace is the face we want to render. We want to find the size
|
||||
* of a maximal fan around eOrig.org. To do this we just walk around
|
||||
* the origin vertex as far as possible in both directions.
|
||||
* @private
|
||||
* @param {libtess.GluHalfEdge} eOrig [description]
|
||||
* @return {libtess.FaceCount} [description]
|
||||
* @param {libtess.GluHalfEdge} eOrig [description].
|
||||
* @return {libtess.FaceCount} [description].
|
||||
*/
|
||||
libtess.render.maximumFan_ = function(eOrig) {
|
||||
// TODO(bckenny): probably have dest FaceCount passed in (see renderMaximumFaceGroup)
|
||||
var newFace = new libtess.FaceCount(0, null, libtess.render.renderFan_);
|
||||
|
||||
|
||||
var trail = null;
|
||||
var e;
|
||||
|
||||
for(e = eOrig; !libtess.render.marked_(e.lFace); e = e.oNext) {
|
||||
for (e = eOrig; !libtess.render.marked_(e.lFace); e = e.oNext) {
|
||||
// NOTE(bckenny): AddToTrail(e.lFace, trail) macro
|
||||
e.lFace.trail = trail;
|
||||
trail = e.lFace;
|
||||
@@ -240,7 +245,7 @@ libtess.render.maximumFan_ = function(eOrig) {
|
||||
|
||||
++newFace.size;
|
||||
}
|
||||
for(e = eOrig; !libtess.render.marked_(e.rFace()); e = e.oPrev()) {
|
||||
for (e = eOrig; !libtess.render.marked_(e.rFace()); e = e.oPrev()) {
|
||||
// NOTE(bckenny): AddToTrail(e.rFace(), trail) macro
|
||||
e.rFace().trail = trail;
|
||||
trail = e.rFace();
|
||||
@@ -254,6 +259,7 @@ libtess.render.maximumFan_ = function(eOrig) {
|
||||
return newFace;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Here we are looking for a maximal strip that contains the vertices
|
||||
* eOrig.org, eOrig.dst(), eOrig.lNext.dst() (in that order or the
|
||||
@@ -265,8 +271,8 @@ libtess.render.maximumFan_ = function(eOrig) {
|
||||
* We walk the strip starting on a side with an even number of triangles;
|
||||
* if both side have an odd number, we are forced to shorten one side.
|
||||
* @private
|
||||
* @param {libtess.GluHalfEdge} eOrig [description]
|
||||
* @return {libtess.FaceCount} [description]
|
||||
* @param {libtess.GluHalfEdge} eOrig [description].
|
||||
* @return {libtess.FaceCount} [description].
|
||||
*/
|
||||
libtess.render.maximumStrip_ = function(eOrig) {
|
||||
// TODO(bckenny): probably have dest FaceCount passed in (see renderMaximumFaceGroup)
|
||||
@@ -335,14 +341,15 @@ libtess.render.maximumStrip_ = function(eOrig) {
|
||||
return newFace;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Render as many CCW triangles as possible in a fan starting from
|
||||
* edge "e". The fan *should* contain exactly "size" triangles
|
||||
* (otherwise we've goofed up somewhere).
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.GluHalfEdge} e [description]
|
||||
* @param {number} size [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.GluHalfEdge} e [description].
|
||||
* @param {number} size [description].
|
||||
*/
|
||||
libtess.render.renderFan_ = function(tess, e, size) {
|
||||
tess.callBeginOrBeginData(libtess.primitiveType.GL_TRIANGLE_FAN);
|
||||
@@ -360,14 +367,15 @@ libtess.render.renderFan_ = function(tess, e, size) {
|
||||
tess.callEndOrEndData();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Render as many CCW triangles as possible in a strip starting from
|
||||
* edge e. The strip *should* contain exactly "size" triangles
|
||||
* (otherwise we've goofed up somewhere).
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.GluHalfEdge} e [description]
|
||||
* @param {number} size [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.GluHalfEdge} e [description].
|
||||
* @param {number} size [description].
|
||||
*/
|
||||
libtess.render.renderStrip_ = function(tess, e, size) {
|
||||
tess.callBeginOrBeginData(libtess.primitiveType.GL_TRIANGLE_STRIP);
|
||||
@@ -393,13 +401,14 @@ libtess.render.renderStrip_ = function(tess, e, size) {
|
||||
tess.callEndOrEndData();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Just add the triangle to a triangle list, so we can render all
|
||||
* the separate triangles at once.
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.GluHalfEdge} e [description]
|
||||
* @param {number} size [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.GluHalfEdge} e [description].
|
||||
* @param {number} size [description].
|
||||
*/
|
||||
libtess.render.renderTriangle_ = function(tess, e, size) {
|
||||
libtess.assert(size === 1);
|
||||
@@ -409,6 +418,7 @@ libtess.render.renderTriangle_ = function(tess, e, size) {
|
||||
e.lFace.marked = true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* We want to find the largest triangle fan or strip of unmarked faces
|
||||
* which includes the given face fOrig. There are 3 possible fans
|
||||
@@ -417,8 +427,8 @@ libtess.render.renderTriangle_ = function(tess, e, size) {
|
||||
* is to try all of these, and take the primitive which uses the most
|
||||
* triangles (a greedy approach).
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.GluFace} fOrig [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.GluFace} fOrig [description].
|
||||
*/
|
||||
libtess.render.renderMaximumFaceGroup_ = function(tess, fOrig) {
|
||||
var e = fOrig.anEdge;
|
||||
@@ -460,12 +470,13 @@ libtess.render.renderMaximumFaceGroup_ = function(tess, fOrig) {
|
||||
max.render(tess, max.eStart, max.size);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Now we render all the separate triangles which could not be
|
||||
* grouped into a triangle fan or strip.
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.GluFace} head [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.GluFace} head [description].
|
||||
*/
|
||||
libtess.render.renderLonelyTriangles_ = function(tess, head) {
|
||||
// TODO(bckenny): edgeState needs to be boolean, but != on first call
|
||||
@@ -476,7 +487,7 @@ libtess.render.renderLonelyTriangles_ = function(tess, head) {
|
||||
|
||||
tess.callBeginOrBeginData(libtess.primitiveType.GL_TRIANGLES);
|
||||
|
||||
for(; f !== null; f = f.trail) {
|
||||
for (; f !== null; f = f.trail) {
|
||||
// Loop once for each edge (there will always be 3 edges)
|
||||
var e = f.anEdge;
|
||||
do {
|
||||
@@ -499,6 +510,7 @@ libtess.render.renderLonelyTriangles_ = function(tess, head) {
|
||||
tess.callEndOrEndData();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* If check==false, we compute the polygon normal and place it in norm[].
|
||||
* If check==true, we check that each triangle in the fan from v0 has a
|
||||
@@ -507,10 +519,10 @@ libtess.render.renderLonelyTriangles_ = function(tess, head) {
|
||||
* are degenerate return 0; otherwise (no consistent orientation) return
|
||||
* render.SIGN_INCONSISTENT_.
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {Array.<number>} norm [description]
|
||||
* @param {boolean} check [description]
|
||||
* @return {number} int
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {Array.<number>} norm [description].
|
||||
* @param {boolean} check [description].
|
||||
* @return {number} int.
|
||||
*/
|
||||
libtess.render.computeNormal_ = function(tess, norm, check) {
|
||||
/* Find the polygon normal. It is important to get a reasonable
|
||||
@@ -537,7 +549,7 @@ libtess.render.computeNormal_ = function(tess, norm, check) {
|
||||
var vc = v0 + 1;
|
||||
var vert0 = tess.cache[v0];
|
||||
var vertc = tess.cache[vc];
|
||||
|
||||
|
||||
var xc = vertc.coords[0] - vert0.coords[0];
|
||||
var yc = vertc.coords[1] - vert0.coords[1];
|
||||
var zc = vertc.coords[2] - vert0.coords[2];
|
||||
@@ -554,11 +566,11 @@ libtess.render.computeNormal_ = function(tess, norm, check) {
|
||||
|
||||
// Compute (vp - v0) cross (vc - v0)
|
||||
var n = [0, 0, 0]; // TODO(bckenny): better init?
|
||||
n[0] = yp*zc - zp*yc;
|
||||
n[1] = zp*xc - xp*zc;
|
||||
n[2] = xp*yc - yp*xc;
|
||||
n[0] = yp * zc - zp * yc;
|
||||
n[1] = zp * xc - xp * zc;
|
||||
n[2] = xp * yc - yp * xc;
|
||||
|
||||
var dot = n[0]*norm[0] + n[1]*norm[1] + n[2]*norm[2];
|
||||
var dot = n[0] * norm[0] + n[1] * norm[1] + n[2] * norm[2];
|
||||
if (!check) {
|
||||
// Reverse the contribution of back-facing triangles to get
|
||||
// a reasonable normal for self-intersecting polygons (see above)
|
||||
|
||||
@@ -39,15 +39,17 @@
|
||||
|
||||
// TODO(bckenny): Used only in private functions of render.js
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This structure remembers the information we need about a primitive
|
||||
* to be able to render it later, once we have determined which
|
||||
* primitive is able to use the most triangles.
|
||||
*
|
||||
* @constructor
|
||||
* @param {number} size [description]
|
||||
* @param {libtess.GluHalfEdge} eStart [description]
|
||||
* @param {!function(libtess.GluTesselator, libtess.GluHalfEdge, number)} renderFunction [description]
|
||||
* @param {number} size [description].
|
||||
* @param {libtess.GluHalfEdge} eStart [description].
|
||||
* @param {!function(libtess.GluTesselator, libtess.GluHalfEdge, number)} renderFunction [description].
|
||||
*/
|
||||
libtess.FaceCount = function(size, eStart, renderFunction) {
|
||||
/**
|
||||
|
||||
@@ -74,6 +74,7 @@ libtess.sweep = function() {
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Make the sentinel coordinates big enough that they will never be
|
||||
* merged with real input features. (Even with the largest possible
|
||||
@@ -85,6 +86,7 @@ libtess.sweep = function() {
|
||||
*/
|
||||
libtess.sweep.SENTINEL_COORD_ = 4 * libtess.GLU_TESS_MAX_COORD;
|
||||
|
||||
|
||||
/**
|
||||
* Because vertices at exactly the same location are merged together
|
||||
* before we process the sweep event, some degenerate cases can't occur.
|
||||
@@ -98,6 +100,7 @@ libtess.sweep.SENTINEL_COORD_ = 4 * libtess.GLU_TESS_MAX_COORD;
|
||||
*/
|
||||
libtess.sweep.TOLERANCE_NONZERO_ = false;
|
||||
|
||||
|
||||
/**
|
||||
* computeInterior(tess) computes the planar arrangement specified
|
||||
* by the given contours, and further subdivides this arrangement
|
||||
@@ -105,7 +108,7 @@ libtess.sweep.TOLERANCE_NONZERO_ = false;
|
||||
* to the polygon, according to the rule given by tess.windingRule.
|
||||
* Each interior region is guaranteed be monotone.
|
||||
*
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
*/
|
||||
libtess.sweep.computeInterior = function(tess) {
|
||||
tess.fatalError = false;
|
||||
@@ -121,12 +124,12 @@ libtess.sweep.computeInterior = function(tess) {
|
||||
// TODO(bckenny): don't need the cast if pq's key is better typed
|
||||
var v;
|
||||
while ((v = /** @type {libtess.GluVertex} */(tess.pq.extractMin())) !== null) {
|
||||
for ( ;; ) {
|
||||
for (;; ) {
|
||||
var vNext = /** @type {libtess.GluVertex} */(tess.pq.minimum());
|
||||
if (vNext === null || !libtess.geom.vertEq(vNext, v)) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* Merge together all vertices at exactly the same location.
|
||||
* This is more efficient than processing them one at a time,
|
||||
* simplifies the code (see connectLeftDegenerate), and is also
|
||||
@@ -161,13 +164,12 @@ libtess.sweep.computeInterior = function(tess) {
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* When we merge two edges into one, we need to compute the combined
|
||||
* winding of the new edge.
|
||||
* @private
|
||||
* @param {libtess.GluHalfEdge} eDst [description]
|
||||
* @param {libtess.GluHalfEdge} eSrc [description]
|
||||
* @param {libtess.GluHalfEdge} eDst [description].
|
||||
* @param {libtess.GluHalfEdge} eSrc [description].
|
||||
*/
|
||||
libtess.sweep.addWinding_ = function(eDst, eSrc) {
|
||||
// NOTE(bckenny): from AddWinding macro
|
||||
@@ -175,6 +177,7 @@ libtess.sweep.addWinding_ = function(eDst, eSrc) {
|
||||
eDst.sym.winding += eSrc.sym.winding;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Both edges must be directed from right to left (this is the canonical
|
||||
* direction for the upper edge of each region).
|
||||
@@ -187,10 +190,10 @@ libtess.sweep.addWinding_ = function(eDst, eSrc) {
|
||||
* we sort the edges by slope (they would otherwise compare equally).
|
||||
*
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.ActiveRegion} reg1 [description]
|
||||
* @param {libtess.ActiveRegion} reg2 [description]
|
||||
* @return {boolean} [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.ActiveRegion} reg1 [description].
|
||||
* @param {libtess.ActiveRegion} reg2 [description].
|
||||
* @return {boolean} [description].
|
||||
*/
|
||||
libtess.sweep.edgeLeq_ = function(tess, reg1, reg2) {
|
||||
var event = tess.event;
|
||||
@@ -221,11 +224,12 @@ libtess.sweep.edgeLeq_ = function(tess, reg1, reg2) {
|
||||
return (t1 >= t2);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [deleteRegion_ description]
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.ActiveRegion} reg [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.ActiveRegion} reg [description].
|
||||
*/
|
||||
libtess.sweep.deleteRegion_ = function(tess, reg) {
|
||||
if (reg.fixUpperEdge) {
|
||||
@@ -244,11 +248,12 @@ libtess.sweep.deleteRegion_ = function(tess, reg) {
|
||||
// TODO(bckenny): may need to null at callsite
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Replace an upper edge which needs fixing (see connectRightVertex).
|
||||
* @private
|
||||
* @param {libtess.ActiveRegion} reg [description]
|
||||
* @param {libtess.GluHalfEdge} newEdge [description]
|
||||
* @param {libtess.ActiveRegion} reg [description].
|
||||
* @param {libtess.GluHalfEdge} newEdge [description].
|
||||
*/
|
||||
libtess.sweep.fixUpperEdge_ = function(reg, newEdge) {
|
||||
libtess.assert(reg.fixUpperEdge);
|
||||
@@ -259,11 +264,12 @@ libtess.sweep.fixUpperEdge_ = function(reg, newEdge) {
|
||||
newEdge.activeRegion = reg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Find the region above the uppermost edge with the same origin.
|
||||
* @private
|
||||
* @param {libtess.ActiveRegion} reg [description]
|
||||
* @return {libtess.ActiveRegion} [description]
|
||||
* @param {libtess.ActiveRegion} reg [description].
|
||||
* @return {libtess.ActiveRegion} [description].
|
||||
*/
|
||||
libtess.sweep.topLeftRegion_ = function(reg) {
|
||||
var org = reg.eUp.org;
|
||||
@@ -284,11 +290,12 @@ libtess.sweep.topLeftRegion_ = function(reg) {
|
||||
return reg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Find the region above the uppermost edge with the same destination.
|
||||
* @private
|
||||
* @param {libtess.ActiveRegion} reg [description]
|
||||
* @return {libtess.ActiveRegion} [description]
|
||||
* @param {libtess.ActiveRegion} reg [description].
|
||||
* @return {libtess.ActiveRegion} [description].
|
||||
*/
|
||||
libtess.sweep.topRightRegion_ = function(reg) {
|
||||
var dst = reg.eUp.dst();
|
||||
@@ -300,6 +307,7 @@ libtess.sweep.topRightRegion_ = function(reg) {
|
||||
return reg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Add a new active region to the sweep line, *somewhere* below "regAbove"
|
||||
* (according to where the new edge belongs in the sweep-line dictionary).
|
||||
@@ -307,9 +315,9 @@ libtess.sweep.topRightRegion_ = function(reg) {
|
||||
* Winding number and "inside" flag are not updated.
|
||||
*
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.ActiveRegion} regAbove [description]
|
||||
* @param {libtess.GluHalfEdge} eNewUp [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.ActiveRegion} regAbove [description].
|
||||
* @param {libtess.GluHalfEdge} eNewUp [description].
|
||||
*/
|
||||
libtess.sweep.addRegionBelow_ = function(tess, regAbove, eNewUp) {
|
||||
var regNew = new libtess.ActiveRegion();
|
||||
@@ -321,15 +329,16 @@ libtess.sweep.addRegionBelow_ = function(tess, regAbove, eNewUp) {
|
||||
return regNew;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [isWindingInside_ description]
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {number} n int
|
||||
* @return {boolean} [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {number} n int.
|
||||
* @return {boolean} [description].
|
||||
*/
|
||||
libtess.sweep.isWindingInside_ = function(tess, n) {
|
||||
switch(tess.windingRule) {
|
||||
switch (tess.windingRule) {
|
||||
case libtess.windingRule.GLU_TESS_WINDING_ODD:
|
||||
return ((n & 1) !== 0);
|
||||
case libtess.windingRule.GLU_TESS_WINDING_NONZERO:
|
||||
@@ -347,17 +356,19 @@ libtess.sweep.isWindingInside_ = function(tess, n) {
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [computeWinding_ description]
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.ActiveRegion} reg [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.ActiveRegion} reg [description].
|
||||
*/
|
||||
libtess.sweep.computeWinding_ = function(tess, reg) {
|
||||
reg.windingNumber = reg.regionAbove().windingNumber + reg.eUp.winding;
|
||||
reg.inside = libtess.sweep.isWindingInside_(tess, reg.windingNumber);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Delete a region from the sweep line. This happens when the upper
|
||||
* and lower chains of a region meet (at a vertex on the sweep line).
|
||||
@@ -366,8 +377,8 @@ libtess.sweep.computeWinding_ = function(tess, reg) {
|
||||
* changing, this face may not have even existed until now).
|
||||
*
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.ActiveRegion} reg [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.ActiveRegion} reg [description].
|
||||
*/
|
||||
libtess.sweep.finishRegion_ = function(tess, reg) {
|
||||
// TODO(bckenny): may need to null reg at callsite
|
||||
@@ -380,6 +391,7 @@ libtess.sweep.finishRegion_ = function(tess, reg) {
|
||||
libtess.sweep.deleteRegion_(tess, reg);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* We are given a vertex with one or more left-going edges. All affected
|
||||
* edges should be in the edge dictionary. Starting at regFirst.eUp,
|
||||
@@ -393,10 +405,10 @@ libtess.sweep.finishRegion_ = function(tess, reg) {
|
||||
* same as in the dictionary.
|
||||
*
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.ActiveRegion} regFirst [description]
|
||||
* @param {libtess.ActiveRegion} regLast [description]
|
||||
* @return {libtess.GluHalfEdge} [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.ActiveRegion} regFirst [description].
|
||||
* @param {libtess.ActiveRegion} regLast [description].
|
||||
* @return {libtess.GluHalfEdge} [description].
|
||||
*/
|
||||
libtess.sweep.finishLeftRegions_ = function(tess, regFirst, regLast) {
|
||||
var regPrev = regFirst;
|
||||
@@ -439,6 +451,7 @@ libtess.sweep.finishLeftRegions_ = function(tess, regFirst, regLast) {
|
||||
return ePrev;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Purpose: insert right-going edges into the edge dictionary, and update
|
||||
* winding numbers and mesh connectivity appropriately. All right-going
|
||||
@@ -450,12 +463,12 @@ libtess.sweep.finishLeftRegions_ = function(tess, regFirst, regLast) {
|
||||
* should be null.
|
||||
*
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.ActiveRegion} regUp [description]
|
||||
* @param {libtess.GluHalfEdge} eFirst [description]
|
||||
* @param {libtess.GluHalfEdge} eLast [description]
|
||||
* @param {libtess.GluHalfEdge} eTopLeft [description]
|
||||
* @param {boolean} cleanUp [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.ActiveRegion} regUp [description].
|
||||
* @param {libtess.GluHalfEdge} eFirst [description].
|
||||
* @param {libtess.GluHalfEdge} eLast [description].
|
||||
* @param {libtess.GluHalfEdge} eTopLeft [description].
|
||||
* @param {boolean} cleanUp [description].
|
||||
*/
|
||||
libtess.sweep.addRightEdges_ = function(tess, regUp, eFirst, eLast, eTopLeft, cleanUp) {
|
||||
var firstTime = true;
|
||||
@@ -477,7 +490,7 @@ libtess.sweep.addRightEdges_ = function(tess, regUp, eFirst, eLast, eTopLeft, cl
|
||||
var regPrev = regUp;
|
||||
var ePrev = eTopLeft;
|
||||
var reg;
|
||||
for( ;; ) {
|
||||
for (;; ) {
|
||||
reg = regPrev.regionBelow();
|
||||
e = reg.eUp.sym;
|
||||
if (e.org !== ePrev.org) {
|
||||
@@ -515,14 +528,15 @@ libtess.sweep.addRightEdges_ = function(tess, regUp, eFirst, eLast, eTopLeft, cl
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [callCombine_ description]
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.GluVertex} isect [description]
|
||||
* @param {Array.<Object>} data [description]
|
||||
* @param {Array.<number>} weights [description]
|
||||
* @param {boolean} needed [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.GluVertex} isect [description].
|
||||
* @param {Array.<Object>} data [description].
|
||||
* @param {Array.<number>} weights [description].
|
||||
* @param {boolean} needed [description].
|
||||
*/
|
||||
libtess.sweep.callCombine_ = function(tess, isect, data, weights, needed) {
|
||||
// Copy coord data in case the callback changes it.
|
||||
@@ -549,13 +563,14 @@ libtess.sweep.callCombine_ = function(tess, isect, data, weights, needed) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Two vertices with idential coordinates are combined into one.
|
||||
* e1.org is kept, while e2.org is discarded.
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.GluHalfEdge} e1 [description]
|
||||
* @param {libtess.GluHalfEdge} e2 [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.GluHalfEdge} e1 [description].
|
||||
* @param {libtess.GluHalfEdge} e2 [description].
|
||||
*/
|
||||
libtess.sweep.spliceMergeVertices_ = function(tess, e1, e2) {
|
||||
// TODO(bckenny): better way to init these? save them?
|
||||
@@ -568,6 +583,7 @@ libtess.sweep.spliceMergeVertices_ = function(tess, e1, e2) {
|
||||
libtess.mesh.meshSplice(e1, e2);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Find some weights which describe how the intersection vertex is
|
||||
* a linear combination of org and dst. Each of the two edges
|
||||
@@ -576,11 +592,11 @@ libtess.sweep.spliceMergeVertices_ = function(tess, e1, e2) {
|
||||
* relative distance to "isect".
|
||||
*
|
||||
* @private
|
||||
* @param {libtess.GluVertex} isect [description]
|
||||
* @param {libtess.GluVertex} org [description]
|
||||
* @param {libtess.GluVertex} dst [description]
|
||||
* @param {Array.<number>} weights [description]
|
||||
* @param {number} weightIndex Index into weights for first weight to supply
|
||||
* @param {libtess.GluVertex} isect [description].
|
||||
* @param {libtess.GluVertex} org [description].
|
||||
* @param {libtess.GluVertex} dst [description].
|
||||
* @param {Array.<number>} weights [description].
|
||||
* @param {number} weightIndex Index into weights for first weight to supply.
|
||||
*/
|
||||
libtess.sweep.vertexWeights_ = function(isect, org, dst, weights, weightIndex) {
|
||||
// TODO(bckenny): think through how we can use L1dist here and be correct for coords
|
||||
@@ -594,22 +610,23 @@ libtess.sweep.vertexWeights_ = function(isect, org, dst, weights, weightIndex) {
|
||||
var i1 = weightIndex + 1;
|
||||
weights[i0] = 0.5 * t2 / (t1 + t2);
|
||||
weights[i1] = 0.5 * t1 / (t1 + t2);
|
||||
isect.coords[0] += weights[i0]*org.coords[0] + weights[i1]*dst.coords[0];
|
||||
isect.coords[1] += weights[i0]*org.coords[1] + weights[i1]*dst.coords[1];
|
||||
isect.coords[2] += weights[i0]*org.coords[2] + weights[i1]*dst.coords[2];
|
||||
isect.coords[0] += weights[i0] * org.coords[0] + weights[i1] * dst.coords[0];
|
||||
isect.coords[1] += weights[i0] * org.coords[1] + weights[i1] * dst.coords[1];
|
||||
isect.coords[2] += weights[i0] * org.coords[2] + weights[i1] * dst.coords[2];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* We've computed a new intersection point, now we need a "data" pointer
|
||||
* from the user so that we can refer to this new vertex in the
|
||||
* rendering callbacks.
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.GluVertex} isect [description]
|
||||
* @param {libtess.GluVertex} orgUp [description]
|
||||
* @param {libtess.GluVertex} dstUp [description]
|
||||
* @param {libtess.GluVertex} orgLo [description]
|
||||
* @param {libtess.GluVertex} dstLo [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.GluVertex} isect [description].
|
||||
* @param {libtess.GluVertex} orgUp [description].
|
||||
* @param {libtess.GluVertex} dstUp [description].
|
||||
* @param {libtess.GluVertex} orgLo [description].
|
||||
* @param {libtess.GluVertex} dstLo [description].
|
||||
*/
|
||||
libtess.sweep.getIntersectData_ = function(tess, isect, orgUp, dstUp, orgLo, dstLo) {
|
||||
// TODO(bckenny): called for every intersection event, should these be from a pool?
|
||||
@@ -633,6 +650,7 @@ libtess.sweep.getIntersectData_ = function(tess, isect, orgUp, dstUp, orgLo, dst
|
||||
libtess.sweep.callCombine_(tess, isect, data, weights, true);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check the upper and lower edge of regUp, to make sure that the
|
||||
* eUp.org is above eLo, or eLo.org is below eUp (depending on which
|
||||
@@ -659,9 +677,9 @@ libtess.sweep.getIntersectData_ = function(tess, isect, orgUp, dstUp, orgLo, dst
|
||||
* Basically this is a combinatorial solution to a numerical problem.
|
||||
*
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.ActiveRegion} regUp [description]
|
||||
* @return {boolean} [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.ActiveRegion} regUp [description].
|
||||
* @return {boolean} [description].
|
||||
*/
|
||||
libtess.sweep.checkForRightSplice_ = function(tess, regUp) {
|
||||
// TODO(bckenny): fully learn how these two checks work
|
||||
@@ -703,6 +721,7 @@ libtess.sweep.checkForRightSplice_ = function(tess, regUp) {
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check the upper and lower edge of regUp to make sure that the
|
||||
* eUp.dst() is above eLo, or eLo.dst() is below eUp (depending on which
|
||||
@@ -722,9 +741,9 @@ libtess.sweep.checkForRightSplice_ = function(tess, regUp) {
|
||||
* other edge.
|
||||
*
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess description]
|
||||
* @param {libtess.ActiveRegion} regUp [description]
|
||||
* @return {boolean} [description]
|
||||
* @param {libtess.GluTesselator} tess description].
|
||||
* @param {libtess.ActiveRegion} regUp [description].
|
||||
* @return {boolean} [description].
|
||||
*/
|
||||
libtess.sweep.checkForLeftSplice_ = function(tess, regUp) {
|
||||
var regLo = regUp.regionBelow();
|
||||
@@ -760,6 +779,7 @@ libtess.sweep.checkForLeftSplice_ = function(tess, regUp) {
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check the upper and lower edges of the given region to see if
|
||||
* they intersect. If so, create the intersection and add it
|
||||
@@ -770,9 +790,9 @@ libtess.sweep.checkForLeftSplice_ = function(tess, regUp) {
|
||||
* checked for intersections, and possibly regUp has been deleted.
|
||||
*
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.ActiveRegion} regUp [description]
|
||||
* @return {boolean} [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.ActiveRegion} regUp [description].
|
||||
* @return {boolean} [description].
|
||||
*/
|
||||
libtess.sweep.checkForIntersect_ = function(tess, regUp) {
|
||||
var regLo = regUp.regionBelow();
|
||||
@@ -787,7 +807,7 @@ libtess.sweep.checkForIntersect_ = function(tess, regUp) {
|
||||
|
||||
libtess.assert(!libtess.geom.vertEq(dstLo, dstUp));
|
||||
libtess.assert(libtess.geom.edgeSign(dstUp, tess.event, orgUp) <= 0);
|
||||
libtess.assert(libtess.geom.edgeSign(dstLo, tess.event, orgLo) >= 0 );
|
||||
libtess.assert(libtess.geom.edgeSign(dstLo, tess.event, orgLo) >= 0);
|
||||
libtess.assert(orgUp !== tess.event && orgLo !== tess.event);
|
||||
libtess.assert(!regUp.fixUpperEdge && !regLo.fixUpperEdge);
|
||||
|
||||
@@ -814,10 +834,10 @@ libtess.sweep.checkForIntersect_ = function(tess, regUp) {
|
||||
}
|
||||
|
||||
// At this point the edges intersect, at least marginally
|
||||
libtess.sweepDebugEvent( tess );
|
||||
libtess.sweepDebugEvent(tess);
|
||||
|
||||
libtess.geom.edgeIntersect(dstUp, orgUp, dstLo, orgLo, isect);
|
||||
|
||||
|
||||
// The following properties are guaranteed:
|
||||
libtess.assert(Math.min(orgUp.t, dstUp.t) <= isect.t);
|
||||
libtess.assert(isect.t <= Math.max(orgLo.t, dstLo.t));
|
||||
@@ -926,6 +946,7 @@ libtess.sweep.checkForIntersect_ = function(tess, regUp) {
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* When the upper or lower edge of any region changes, the region is
|
||||
* marked "dirty". This routine walks through all the dirty regions
|
||||
@@ -934,13 +955,13 @@ libtess.sweep.checkForIntersect_ = function(tess, regUp) {
|
||||
* new dirty regions can be created as we make changes to restore
|
||||
* the invariants.
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.ActiveRegion} regUp [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.ActiveRegion} regUp [description].
|
||||
*/
|
||||
libtess.sweep.walkDirtyRegions_ = function(tess, regUp) {
|
||||
var regLo = regUp.regionBelow();
|
||||
|
||||
for ( ;; ) {
|
||||
for (;; ) {
|
||||
// Find the lowest dirty region (we walk from the bottom up).
|
||||
while (regLo.dirty) {
|
||||
regUp = regLo;
|
||||
@@ -1013,6 +1034,7 @@ libtess.sweep.walkDirtyRegions_ = function(tess, regUp) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Purpose: connect a "right" vertex vEvent (one where all edges go left)
|
||||
* to the unprocessed portion of the mesh. Since there are no right-going
|
||||
@@ -1045,9 +1067,9 @@ libtess.sweep.walkDirtyRegions_ = function(tess, regUp) {
|
||||
* closest one, in which case we won't need to make any changes.
|
||||
*
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.ActiveRegion} regUp [description]
|
||||
* @param {libtess.GluHalfEdge} eBottomLeft [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.ActiveRegion} regUp [description].
|
||||
* @param {libtess.GluHalfEdge} eBottomLeft [description].
|
||||
*/
|
||||
libtess.sweep.connectRightVertex_ = function(tess, regUp, eBottomLeft) {
|
||||
var eTopLeft = eBottomLeft.oNext;
|
||||
@@ -1096,14 +1118,15 @@ libtess.sweep.connectRightVertex_ = function(tess, regUp, eBottomLeft) {
|
||||
libtess.sweep.walkDirtyRegions_(tess, regUp);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The event vertex lies exacty on an already-processed edge or vertex.
|
||||
* Adding the new vertex involves splicing it into the already-processed
|
||||
* part of the mesh.
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.ActiveRegion} regUp [description]
|
||||
* @param {libtess.GluVertex} vEvent [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.ActiveRegion} regUp [description].
|
||||
* @param {libtess.GluVertex} vEvent [description].
|
||||
*/
|
||||
libtess.sweep.connectLeftDegenerate_ = function(tess, regUp, vEvent) {
|
||||
var e = regUp.eUp;
|
||||
@@ -1114,7 +1137,7 @@ libtess.sweep.connectLeftDegenerate_ = function(tess, regUp, vEvent) {
|
||||
libtess.sweep.spliceMergeVertices_(tess, e, vEvent.anEdge);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!libtess.geom.vertEq(e.dst(), vEvent)) {
|
||||
// General case -- splice vEvent into edge e which passes through it
|
||||
libtess.mesh.splitEdge(e.sym);
|
||||
@@ -1126,7 +1149,7 @@ libtess.sweep.connectLeftDegenerate_ = function(tess, regUp, vEvent) {
|
||||
}
|
||||
|
||||
libtess.mesh.meshSplice(vEvent.anEdge, e);
|
||||
|
||||
|
||||
// recurse
|
||||
libtess.sweep.sweepEvent_(tess, vEvent);
|
||||
return;
|
||||
@@ -1144,7 +1167,7 @@ libtess.sweep.connectLeftDegenerate_ = function(tess, regUp, vEvent) {
|
||||
if (reg.fixUpperEdge) {
|
||||
// Here e.dst() has only a single fixable edge going right.
|
||||
// We can delete it since now we have some real right-going edges.
|
||||
|
||||
|
||||
// there are some left edges too
|
||||
libtess.assert(eTopLeft !== eTopRight);
|
||||
libtess.sweep.deleteRegion_(tess, reg); // TODO(bckenny): something to null?
|
||||
@@ -1161,6 +1184,7 @@ libtess.sweep.connectLeftDegenerate_ = function(tess, regUp, vEvent) {
|
||||
libtess.sweep.addRightEdges_(tess, regUp, eTopRight.oNext, eLast, eTopLeft, true);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Connect a "left" vertex (one where both edges go right)
|
||||
* to the processed portion of the mesh. Let R be the active region
|
||||
@@ -1177,8 +1201,8 @@ libtess.sweep.connectLeftDegenerate_ = function(tess, regUp, vEvent) {
|
||||
* - merging with an already-processed portion of U or L
|
||||
*
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.GluVertex} vEvent [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.GluVertex} vEvent [description].
|
||||
*/
|
||||
libtess.sweep.connectLeftVertex_ = function(tess, vEvent) {
|
||||
// TODO(bckenny): tmp only used for sweep. better to keep tmp across calls?
|
||||
@@ -1228,17 +1252,18 @@ libtess.sweep.connectLeftVertex_ = function(tess, vEvent) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Does everything necessary when the sweep line crosses a vertex.
|
||||
* Updates the mesh and the edge dictionary.
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.GluVertex} vEvent [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {libtess.GluVertex} vEvent [description].
|
||||
*/
|
||||
libtess.sweep.sweepEvent_ = function(tess, vEvent) {
|
||||
tess.event = vEvent; // for access in edgeLeq_ // TODO(bckenny): wuh?
|
||||
libtess.sweepDebugEvent( tess );
|
||||
|
||||
libtess.sweepDebugEvent(tess);
|
||||
|
||||
/* Check if this vertex is the right endpoint of an edge that is
|
||||
* already in the dictionary. In this case we don't need to waste
|
||||
* time searching for the location to insert new edges.
|
||||
@@ -1279,12 +1304,13 @@ libtess.sweep.sweepEvent_ = function(tess, vEvent) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* We add two sentinel edges above and below all other edges,
|
||||
* to avoid special cases at the top and bottom.
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {number} t [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
* @param {number} t [description].
|
||||
*/
|
||||
libtess.sweep.addSentinel_ = function(tess, t) {
|
||||
var reg = new libtess.ActiveRegion();
|
||||
@@ -1306,11 +1332,12 @@ libtess.sweep.addSentinel_ = function(tess, t) {
|
||||
reg.nodeUp = tess.dict.insert(reg);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* We maintain an ordering of edge intersections with the sweep line.
|
||||
* This order is maintained in a dynamic dictionary.
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
*/
|
||||
libtess.sweep.initEdgeDict_ = function(tess) {
|
||||
// TODO(bckenny): need to cast edgeLeq_?
|
||||
@@ -1321,10 +1348,11 @@ libtess.sweep.initEdgeDict_ = function(tess) {
|
||||
libtess.sweep.addSentinel_(tess, libtess.sweep.SENTINEL_COORD_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [doneEdgeDict_ description]
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
*/
|
||||
libtess.sweep.doneEdgeDict_ = function(tess) {
|
||||
var fixedEdges = 0;
|
||||
@@ -1346,10 +1374,11 @@ libtess.sweep.doneEdgeDict_ = function(tess) {
|
||||
tess.dict = null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove zero-length edges, and contours with fewer than 3 vertices.
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
*/
|
||||
libtess.sweep.removeDegenerateEdges_ = function(tess) {
|
||||
var eHead = tess.mesh.eHead;
|
||||
@@ -1358,7 +1387,7 @@ libtess.sweep.removeDegenerateEdges_ = function(tess) {
|
||||
for (var e = eHead.next; e !== eHead; e = eNext) {
|
||||
eNext = e.next;
|
||||
var eLNext = e.lNext;
|
||||
|
||||
|
||||
if (libtess.geom.vertEq(e.org, e.dst()) && e.lNext.lNext !== e) {
|
||||
// Zero-length edge, contour has at least 3 edges
|
||||
libtess.sweep.spliceMergeVertices_(tess, eLNext, e); // deletes e.org
|
||||
@@ -1376,7 +1405,7 @@ libtess.sweep.removeDegenerateEdges_ = function(tess) {
|
||||
libtess.mesh.deleteEdge(eLNext);
|
||||
}
|
||||
|
||||
if (e === eNext || e === eNext.sym ) {
|
||||
if (e === eNext || e === eNext.sym) {
|
||||
eNext = eNext.next;
|
||||
}
|
||||
libtess.mesh.deleteEdge(e);
|
||||
@@ -1384,11 +1413,12 @@ libtess.sweep.removeDegenerateEdges_ = function(tess) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Construct priority queue and insert all vertices into it, which determines
|
||||
* the order in which vertices cross the sweep line.
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
*/
|
||||
libtess.sweep.initPriorityQ_ = function(tess) {
|
||||
// TODO(bckenny): libtess.geom.vertLeq needs cast?
|
||||
@@ -1405,10 +1435,11 @@ libtess.sweep.initPriorityQ_ = function(tess) {
|
||||
pq.init();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [donePriorityQ_ description]
|
||||
* @private
|
||||
* @param {libtess.GluTesselator} tess [description]
|
||||
* @param {libtess.GluTesselator} tess [description].
|
||||
*/
|
||||
libtess.sweep.donePriorityQ_ = function(tess) {
|
||||
// TODO(bckenny): probably don't need deleteQ. check that function for comment
|
||||
@@ -1416,6 +1447,7 @@ libtess.sweep.donePriorityQ_ = function(tess) {
|
||||
tess.pq = null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Delete any degenerate faces with only two edges. walkDirtyRegions()
|
||||
* will catch almost all of these, but it won't catch degenerate faces
|
||||
@@ -1431,7 +1463,7 @@ libtess.sweep.donePriorityQ_ = function(tess) {
|
||||
* will sometimes be keeping a pointer to that edge.
|
||||
*
|
||||
* @private
|
||||
* @param {libtess.GluMesh} mesh [description]
|
||||
* @param {libtess.GluMesh} mesh [description].
|
||||
*/
|
||||
libtess.sweep.removeDegenerateFaces_ = function(mesh) {
|
||||
var fNext;
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
// TODO(bckenny): apparently only visible outside of sweep for debugging routines.
|
||||
// find out if we can hide
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* For each pair of adjacent edges crossing the sweep line, there is
|
||||
* an ActiveRegion to represent the region between them. The active
|
||||
@@ -75,13 +77,13 @@ libtess.ActiveRegion = function() {
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.inside = false;
|
||||
|
||||
|
||||
/**
|
||||
* marks fake edges at t = +/-infinity
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.sentinel = false;
|
||||
|
||||
|
||||
/**
|
||||
* Marks regions where the upper or lower edge has changed, but we haven't
|
||||
* checked whether they intersect yet.
|
||||
@@ -97,18 +99,20 @@ libtess.ActiveRegion = function() {
|
||||
this.fixUpperEdge = false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [regionBelow description]
|
||||
* @return {libtess.ActiveRegion} [description]
|
||||
* @return {libtess.ActiveRegion} [description].
|
||||
*/
|
||||
libtess.ActiveRegion.prototype.regionBelow = function() {
|
||||
// TODO(bckenny): better typing? or is cast unavoidable
|
||||
return /** @type {libtess.ActiveRegion} */ (this.nodeUp.getPred().getKey());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* [regionAbove description]
|
||||
* @return {libtess.ActiveRegion} [description]
|
||||
* @return {libtess.ActiveRegion} [description].
|
||||
*/
|
||||
libtess.ActiveRegion.prototype.regionAbove = function() {
|
||||
// TODO(bckenny): better typing? or is cast unavoidable
|
||||
|
||||
@@ -42,6 +42,7 @@ libtess.tessmono = function() {
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* tessellateMonoRegion(face) tessellates a monotone region
|
||||
* (what else would it do??). The region must consist of a single
|
||||
@@ -52,7 +53,7 @@ libtess.tessmono = function() {
|
||||
* Tessellation consists of adding interior edges (actually pairs of
|
||||
* half-edges), to split the region into non-overlapping triangles.
|
||||
* @private
|
||||
* @param {libtess.GluFace} face [description]
|
||||
* @param {libtess.GluFace} face [description].
|
||||
*/
|
||||
libtess.tessmono.tessellateMonoRegion_ = function(face) {
|
||||
/* The basic idea is explained in Preparata and Shamos (which I don''t
|
||||
@@ -84,7 +85,7 @@ libtess.tessmono.tessellateMonoRegion_ = function(face) {
|
||||
|
||||
for (; libtess.geom.vertLeq(up.dst(), up.org); up = up.lPrev()) { }
|
||||
for (; libtess.geom.vertLeq(up.org, up.dst()); up = up.lNext) { }
|
||||
|
||||
|
||||
var lo = up.lPrev();
|
||||
|
||||
var tempHalfEdge;
|
||||
@@ -95,7 +96,7 @@ libtess.tessmono.tessellateMonoRegion_ = function(face) {
|
||||
// are CW, given that the upper and lower chains are truly monotone.
|
||||
while (lo.lNext !== up && (libtess.geom.edgeGoesLeft(lo.lNext) ||
|
||||
libtess.geom.edgeSign(lo.org, lo.dst(), lo.lNext.dst()) <= 0)) {
|
||||
|
||||
|
||||
tempHalfEdge = libtess.mesh.connect(lo.lNext, lo);
|
||||
lo = tempHalfEdge.sym;
|
||||
}
|
||||
@@ -105,7 +106,7 @@ libtess.tessmono.tessellateMonoRegion_ = function(face) {
|
||||
// lo.org is on the left. We can make CCW triangles from up.dst().
|
||||
while (lo.lNext !== up && (libtess.geom.edgeGoesRight(up.lPrev()) ||
|
||||
libtess.geom.edgeSign(up.dst(), up.org, up.lPrev().org) >= 0)) {
|
||||
|
||||
|
||||
tempHalfEdge = libtess.mesh.connect(up, up.lPrev());
|
||||
up = tempHalfEdge.sym;
|
||||
}
|
||||
@@ -122,12 +123,13 @@ libtess.tessmono.tessellateMonoRegion_ = function(face) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* tessellateInterior(mesh) tessellates each region of
|
||||
* the mesh which is marked "inside" the polygon. Each such region
|
||||
* must be monotone.
|
||||
*
|
||||
* @param {libtess.GluMesh} mesh [description]
|
||||
* @param {libtess.GluMesh} mesh [description].
|
||||
*/
|
||||
libtess.tessmono.tessellateInterior = function(mesh) {
|
||||
var next;
|
||||
@@ -140,13 +142,14 @@ libtess.tessmono.tessellateInterior = function(mesh) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* discardExterior(mesh) zaps (ie. sets to null) all faces
|
||||
* which are not marked "inside" the polygon. Since further mesh operations
|
||||
* on null faces are not allowed, the main purpose is to clean up the
|
||||
* mesh so that exterior loops are not represented in the data structure.
|
||||
*
|
||||
* @param {libtess.GluMesh} mesh [description]
|
||||
* @param {libtess.GluMesh} mesh [description].
|
||||
*/
|
||||
libtess.tessmono.discardExterior = function(mesh) {
|
||||
var next;
|
||||
@@ -159,6 +162,7 @@ libtess.tessmono.discardExterior = function(mesh) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* setWindingNumber(mesh, value, keepOnlyBoundary) resets the
|
||||
* winding numbers on all edges so that regions marked "inside" the
|
||||
@@ -168,7 +172,7 @@ libtess.tessmono.discardExterior = function(mesh) {
|
||||
* If keepOnlyBoundary is true, it also deletes all edges which do not
|
||||
* separate an interior region from an exterior one.
|
||||
*
|
||||
* @param {libtess.GluMesh} mesh [description]
|
||||
* @param {libtess.GluMesh} mesh [description].
|
||||
* @param {number} value Winding number to set (int).
|
||||
*/
|
||||
libtess.tessmono.setWindingNumber = function(mesh, value, keepOnlyBoundary) {
|
||||
@@ -179,7 +183,7 @@ libtess.tessmono.setWindingNumber = function(mesh, value, keepOnlyBoundary) {
|
||||
if (e.rFace().inside !== e.lFace.inside) {
|
||||
// This is a boundary edge (one side is interior, one is exterior).
|
||||
e.winding = (e.lFace.inside) ? value : -value;
|
||||
|
||||
|
||||
} else {
|
||||
// Both regions are interior, or both are exterior.
|
||||
if (!keepOnlyBoundary) {
|
||||
|
||||
Reference in New Issue
Block a user