From 8d55e8114eb4ed661a68fb80305a738cae60fed1 Mon Sep 17 00:00:00 2001 From: "Mr.doob" Date: Fri, 12 Jul 2013 10:41:46 +0200 Subject: [PATCH] Updated builds. --- build/three.js | 241 ++++++++++++++++++++++++++++++++++----------- build/three.min.js | 13 +-- 2 files changed, 188 insertions(+), 66 deletions(-) diff --git a/build/three.js b/build/three.js index 0dfdbb9069..01d1a9cb3e 100644 --- a/build/three.js +++ b/build/three.js @@ -5011,7 +5011,7 @@ THREE.Ray.prototype = { }, - at: function( t, optionalTarget ) { + at: function ( t, optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); @@ -5019,7 +5019,7 @@ THREE.Ray.prototype = { }, - recast: function() { + recast: function () { var v1 = new THREE.Vector3(); @@ -5043,7 +5043,7 @@ THREE.Ray.prototype = { }, - distanceToPoint: function() { + distanceToPoint: function () { var v1 = new THREE.Vector3(); @@ -5058,13 +5058,15 @@ THREE.Ray.prototype = { }(), - distanceSqAndPointToSegment: function( v0, v1, optionalPointOnLine, optionalPointOnSegment ) { + distanceSqAndPointToSegment: function ( v0, v1, optionalPointOnLine, optionalPointOnSegment ) { + // from http://www.geometrictools.com/LibMathematics/Distance/Wm5DistLine3Segment3.cpp // It returns the min distance between the ray (actually... the line) and the segment // defined by v0 and v1 // It can also set two optional targets : // - The closest point on the ray (...line) // - The closest point on the segment + var segCenter = v0.clone().add( v1 ).multiplyScalar( 0.5 ); var segDir = v1.clone().sub( v0 ).normalize(); var segExtent = v0.distanceTo( v1 ) *0.5; @@ -5074,53 +5076,79 @@ THREE.Ray.prototype = { var c = diff.lengthSq(); var det = Math.abs( 1 - a01 * a01 ); var b1, s0, s1, sqrDist, extDet; - if( det >= 0 ) { + + if ( det >= 0 ) { + // The line and segment are not parallel. + b1 = -diff.dot( segDir ); s1 = a01 * b0 - b1; extDet = segExtent * det; - if( s1 >= -extDet ) { - if( s1 <= extDet ) { + + if ( s1 >= -extDet ) { + + if ( s1 <= extDet ) { + // Two interior points are closest, one on the line and one // on the segment. + var invDet = 1 / det; s0 = ( a01 * b1 - b0 ) * invDet; s1 *= invDet; sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; - } - else { + + } else { + // The endpoint e1 of the segment and an interior point of // the line are closest. + s1 = segExtent; s0 = - ( a01 * s1 + b0 ); sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + } - } - else { + + } else { + // The end point e0 of the segment and an interior point of the // line are closest. + s1 = - segExtent; s0 = - ( a01 * s1 + b0 ); sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + } - } - else { + + } else { + // The line and segment are parallel. Choose the closest pair so that // one point is at segment center. + s1 = 0; s0 = - b0; sqrDist = b0 * s0 + c; + } - if(optionalPointOnLine) + + if ( optionalPointOnLine ) { + optionalPointOnLine.copy( this.direction.clone().multiplyScalar( s0 ).add( this.origin ) ); - if(optionalPointOnSegment) + + } + + if ( optionalPointOnSegment ) { + optionalPointOnSegment.copy( segDir.clone().multiplyScalar( s1 ).add( segCenter ) ); + + } + return sqrDist; + }, - isIntersectionSphere: function( sphere ) { + isIntersectionSphere: function ( sphere ) { - return ( this.distanceToPoint( sphere.center ) <= sphere.radius ); + return this.distanceToPoint( sphere.center ) <= sphere.radius; }, @@ -5128,7 +5156,9 @@ THREE.Ray.prototype = { // check if the line and plane are non-perpendicular, if they // eventually they will intersect. + var denominator = plane.normal.dot( this.direction ); + if ( denominator != 0 ) { return true; @@ -5475,6 +5505,44 @@ THREE.Frustum.prototype = { }, + intersectsBox : function() { + + var p1 = new THREE.Vector3(), + p2 = new THREE.Vector3(); + + return function( box ) { + + var planes = this.planes; + + for ( var i = 0; i < 6 ; i ++ ) { + + var plane = planes[i]; + + p1.x = plane.normal.x > 0 ? box.min.x : box.max.x; + p2.x = plane.normal.x > 0 ? box.max.x : box.min.x; + p1.y = plane.normal.y > 0 ? box.min.y : box.max.y; + p2.y = plane.normal.y > 0 ? box.max.y : box.min.y; + p1.z = plane.normal.z > 0 ? box.min.z : box.max.z; + p2.z = plane.normal.z > 0 ? box.max.z : box.min.z; + + var d1 = plane.distanceToPoint( p1 ); + var d2 = plane.distanceToPoint( p2 ); + + // if both outside plane, no intersection + + if ( d1 < 0 && d2 < 0 ) { + + return false; + + } + } + + return true; + }; + + }(), + + containsPoint: function ( point ) { var planes = this.planes; @@ -6495,7 +6563,7 @@ THREE.EventDispatcher.prototype = { intersectObject( object.getObjectForDistance( distance ), raycaster, intersects ); - } else if (object instanceof THREE.Mesh ) { + } else if ( object instanceof THREE.Mesh ) { var geometry = object.geometry; @@ -6519,7 +6587,7 @@ THREE.EventDispatcher.prototype = { var material = object.material; if ( material === undefined ) return intersects; - if ( ! geometry.dynamic ) return intersects; + if ( geometry.dynamic === false ) return intersects; var isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial; var objectMaterials = isFaceMaterial === true ? object.material.materials : null; @@ -6535,6 +6603,7 @@ THREE.EventDispatcher.prototype = { var fl; var indexed = false; + if ( geometry.attributes.index ) { indexed = true; @@ -6543,6 +6612,7 @@ THREE.EventDispatcher.prototype = { } else { fl = geometry.attributes.position.numItems / 9; + } var vA = new THREE.Vector3(); @@ -6560,24 +6630,34 @@ THREE.EventDispatcher.prototype = { for ( var i = start, il = start + count; i < il; i += 3 ) { if ( indexed ) { + a = index + geometry.attributes.index.array[ i ]; b = index + geometry.attributes.index.array[ i + 1 ]; c = index + geometry.attributes.index.array[ i + 2 ]; + } else { + a = index; b = index + 1; c = index + 2; + } - vA.set( geometry.attributes.position.array[ a * 3 ], - geometry.attributes.position.array[ a * 3 + 1 ], - geometry.attributes.position.array[ a * 3 + 2] ); - vB.set( geometry.attributes.position.array[ b * 3 ], - geometry.attributes.position.array[ b * 3 + 1 ], - geometry.attributes.position.array[ b * 3 + 2] ); - vC.set( geometry.attributes.position.array[ c * 3 ], - geometry.attributes.position.array[ c * 3 + 1 ], - geometry.attributes.position.array[ c * 3 + 2 ] ); + vA.set( + geometry.attributes.position.array[ a * 3 ], + geometry.attributes.position.array[ a * 3 + 1 ], + geometry.attributes.position.array[ a * 3 + 2 ] + ); + vB.set( + geometry.attributes.position.array[ b * 3 ], + geometry.attributes.position.array[ b * 3 + 1 ], + geometry.attributes.position.array[ b * 3 + 2 ] + ); + vC.set( + geometry.attributes.position.array[ c * 3 ], + geometry.attributes.position.array[ c * 3 + 1 ], + geometry.attributes.position.array[ c * 3 + 2 ] + ); facePlane.setFromCoplanarPoints( vA, vB, vC ); @@ -6591,25 +6671,43 @@ THREE.EventDispatcher.prototype = { // check if we hit the wrong side of a single sided face side = material.side; + if ( side !== THREE.DoubleSide ) { var planeSign = localRay.direction.dot( facePlane.normal ); + - if ( ! ( side === THREE.FrontSide ? planeSign < 0 : planeSign > 0 ) ) continue; + if ( ! ( side === THREE.FrontSide ? planeSign < 0 : planeSign > 0 ) ) { + + continue; + + } } - // this can be done using the planeDistance from localRay because localRay wasn't normalized, but ray was - if ( planeDistance < raycaster.near || planeDistance > raycaster.far ) continue; + // this can be done using the planeDistance from localRay because + // localRay wasn't normalized, but ray was + if ( planeDistance < raycaster.near || planeDistance > raycaster.far ) { - intersectPoint = localRay.at( planeDistance, intersectPoint ); // passing in intersectPoint avoids a copy + continue; + + } + + // passing in intersectPoint avoids a copy + intersectPoint = localRay.at( planeDistance, intersectPoint ); + + if ( THREE.Triangle.containsPoint( intersectPoint, vA, vB, vC ) === false ) { + + continue; - if ( ! THREE.Triangle.containsPoint( intersectPoint, vA, vB, vC ) ) continue; + } intersects.push( { - distance: planeDistance, // this works because the original ray was normalized, and the transformed localRay wasn't - point: raycaster.ray.at(planeDistance), + // this works because the original ray was normalized, + // and the transformed localRay wasn't + distance: planeDistance, + point: raycaster.ray.at( planeDistance ), face: null, faceIndex: null, object: object @@ -6657,14 +6755,20 @@ THREE.EventDispatcher.prototype = { var planeSign = localRay.direction.dot( facePlane.normal ); - if ( ! ( side === THREE.FrontSide ? planeSign < 0 : planeSign > 0 ) ) continue; + if ( ! ( side === THREE.FrontSide ? planeSign < 0 : planeSign > 0 ) ) { + + continue; + + } } - // this can be done using the planeDistance from localRay because localRay wasn't normalized, but ray was + // this can be done using the planeDistance from localRay because localRay + // wasn't normalized, but ray was if ( planeDistance < raycaster.near || planeDistance > raycaster.far ) continue; - intersectPoint = localRay.at( planeDistance, intersectPoint ); // passing in intersectPoint avoids a copy + // passing in intersectPoint avoids a copy + intersectPoint = localRay.at( planeDistance, intersectPoint ); if ( face instanceof THREE.Face3 ) { @@ -6672,7 +6776,11 @@ THREE.EventDispatcher.prototype = { b = vertices[ face.b ]; c = vertices[ face.c ]; - if ( ! THREE.Triangle.containsPoint( intersectPoint, a, b, c ) ) continue; + if ( THREE.Triangle.containsPoint( intersectPoint, a, b, c ) === false ) { + + continue; + + } } else if ( face instanceof THREE.Face4 ) { @@ -6681,20 +6789,27 @@ THREE.EventDispatcher.prototype = { c = vertices[ face.c ]; d = vertices[ face.d ]; - if ( ( ! THREE.Triangle.containsPoint( intersectPoint, a, b, d ) ) && - ( ! THREE.Triangle.containsPoint( intersectPoint, b, c, d ) ) ) continue; + if ( THREE.Triangle.containsPoint( intersectPoint, a, b, d ) === false && + THREE.Triangle.containsPoint( intersectPoint, b, c, d ) === false ) { + + continue; + + } } else { - // This is added because if we call out of this if/else group when none of the cases - // match it will add a point to the intersection list erroneously. + // This is added because if we call out of this if/else group when + // none of the cases match it will add a point to the intersection + // list erroneously. throw Error( "face type not supported" ); } intersects.push( { - distance: planeDistance, // this works because the original ray was normalized, and the transformed localRay wasn't + // this works because the original ray was normalized, + // and the transformed localRay wasn't + distance: planeDistance, point: raycaster.ray.at( planeDistance ), face: face, faceIndex: f, @@ -6706,12 +6821,9 @@ THREE.EventDispatcher.prototype = { } - } else if (object instanceof THREE.Line) { + } else if ( object instanceof THREE.Line ) { var precision = raycaster.linePrecision; - if(precision < 0) - return intersects; - var precisionSq = precision * precision; var geometry = object.geometry; @@ -6720,13 +6832,16 @@ THREE.EventDispatcher.prototype = { // Checking boundingSphere distance to ray matrixPosition.getPositionFromMatrix(object.matrixWorld); - sphere.set(matrixPosition, geometry.boundingSphere.radius * object.matrixWorld.getMaxScaleOnAxis()); + sphere.set( matrixPosition, geometry.boundingSphere.radius * object.matrixWorld.getMaxScaleOnAxis() ); - if(!raycaster.ray.isIntersectionSphere(sphere)) + if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) { + return intersects; + + } - inverseMatrix.getInverse(object.matrixWorld); - localRay.copy(raycaster.ray).applyMatrix4(inverseMatrix); + inverseMatrix.getInverse( object.matrixWorld ); + localRay.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); localRay.direction.normalize(); // for scale matrix var vertices = geometry.vertices; @@ -6735,16 +6850,17 @@ THREE.EventDispatcher.prototype = { var interLine = new THREE.Vector3(); var step = object.type === THREE.LineStrip ? 1 : 2; - for(var i = 0; i < nbVertices - 1; i=i+step) { + for ( var i = 0; i < nbVertices - 1; i = i + step ) { - localRay.distanceSqAndPointToSegment(vertices[i], vertices[i + 1], interLine, interSegment); - interSegment.applyMatrix4(object.matrixWorld); - interLine.applyMatrix4(object.matrixWorld); - if(interLine.distanceToSquared(interSegment) <= precisionSq) { + localRay.distanceSqAndPointToSegment( vertices[ i ], vertices[ i + 1 ], interLine, interSegment ); + interSegment.applyMatrix4( object.matrixWorld ); + interLine.applyMatrix4( object.matrixWorld ); - var distance = raycaster.ray.origin.distanceTo(interLine); + if ( interLine.distanceToSquared( interSegment ) <= precisionSq ) { - if(raycaster.near <= distance && distance <= raycaster.far) { + var distance = raycaster.ray.origin.distanceTo( interLine ); + + if ( raycaster.near <= distance && distance <= raycaster.far ) { intersects.push( { @@ -6755,9 +6871,13 @@ THREE.EventDispatcher.prototype = { object: object } ); + } + } + } + } }; @@ -6776,7 +6896,7 @@ THREE.EventDispatcher.prototype = { // THREE.Raycaster.prototype.precision = 0.0001; - THREE.Raycaster.prototype.linePrecision = -1; // if negative, we don't pick lines + THREE.Raycaster.prototype.linePrecision = 1; THREE.Raycaster.prototype.set = function ( origin, direction ) { @@ -6822,6 +6942,7 @@ THREE.EventDispatcher.prototype = { intersectDescendants( objects[ i ], this, intersects ); } + } intersects.sort( descSort ); diff --git a/build/three.min.js b/build/three.min.js index abd5052271..5763d16d4b 100644 --- a/build/three.min.js +++ b/build/three.min.js @@ -115,7 +115,8 @@ this.radius},intersectsSphere:function(a){var b=this.radius+a.radius;return a.ce this.radius*=a.getMaxScaleOnAxis();return this},translate:function(a){this.center.add(a);return this},equals:function(a){return a.center.equals(this.center)&&a.radius===this.radius},clone:function(){return(new THREE.Sphere).copy(this)}};THREE.Frustum=function(a,b,c,d,e,f){this.planes=[void 0!==a?a:new THREE.Plane,void 0!==b?b:new THREE.Plane,void 0!==c?c:new THREE.Plane,void 0!==d?d:new THREE.Plane,void 0!==e?e:new THREE.Plane,void 0!==f?f:new THREE.Plane]}; THREE.Frustum.prototype={constructor:THREE.Frustum,set:function(a,b,c,d,e,f){var h=this.planes;h[0].copy(a);h[1].copy(b);h[2].copy(c);h[3].copy(d);h[4].copy(e);h[5].copy(f);return this},copy:function(a){for(var b=this.planes,c=0;6>c;c++)b[c].copy(a.planes[c]);return this},setFromMatrix:function(a){var b=this.planes,c=a.elements,a=c[0],d=c[1],e=c[2],f=c[3],h=c[4],g=c[5],i=c[6],j=c[7],l=c[8],m=c[9],n=c[10],p=c[11],t=c[12],q=c[13],r=c[14],c=c[15];b[0].setComponents(f-a,j-h,p-l,c-t).normalize();b[1].setComponents(f+ a,j+h,p+l,c+t).normalize();b[2].setComponents(f+d,j+g,p+m,c+q).normalize();b[3].setComponents(f-d,j-g,p-m,c-q).normalize();b[4].setComponents(f-e,j-i,p-n,c-r).normalize();b[5].setComponents(f+e,j+i,p+n,c+r).normalize();return this},intersectsObject:function(){var a=new THREE.Vector3;return function(b){var c=b.geometry,b=b.matrixWorld;null===c.boundingSphere&&c.computeBoundingSphere();c=-c.boundingSphere.radius*b.getMaxScaleOnAxis();a.getPositionFromMatrix(b);for(var b=this.planes,d=0;6>d;d++)if(b[d].distanceToPoint(a)< -c)return!1;return!0}}(),intersectsSphere:function(a){for(var b=this.planes,c=a.center,a=-a.radius,d=0;6>d;d++)if(b[d].distanceToPoint(c)c;c++)if(0>b[c].distanceToPoint(a))return!1;return!0},clone:function(){return(new THREE.Frustum).copy(this)}};THREE.Plane=function(a,b){this.normal=void 0!==a?a:new THREE.Vector3(1,0,0);this.constant=void 0!==b?b:0}; +c)return!1;return!0}}(),intersectsSphere:function(a){for(var b=this.planes,c=a.center,a=-a.radius,d=0;6>d;d++)if(b[d].distanceToPoint(c)e;e++){var f=d[e];a.x=0h&&0>f)return!1}return!0}}(),containsPoint:function(a){for(var b=this.planes,c=0;6>c;c++)if(0>b[c].distanceToPoint(a))return!1;return!0},clone:function(){return(new THREE.Frustum).copy(this)}};THREE.Plane=function(a,b){this.normal=void 0!==a?a:new THREE.Vector3(1,0,0);this.constant=void 0!==b?b:0}; THREE.Plane.prototype={constructor:THREE.Plane,set:function(a,b){this.normal.copy(a);this.constant=b;return this},setComponents:function(a,b,c,d){this.normal.set(a,b,c);this.constant=d;return this},setFromNormalAndCoplanarPoint:function(a,b){this.normal.copy(a);this.constant=-b.dot(this.normal);return this},setFromCoplanarPoints:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c,d,e){d=a.subVectors(e,d).cross(b.subVectors(c,d)).normalize();this.setFromNormalAndCoplanarPoint(d, c);return this}}(),copy:function(a){this.normal.copy(a.normal);this.constant=a.constant;return this},normalize:function(){var a=1/this.normal.length();this.normal.multiplyScalar(a);this.constant*=a;return this},negate:function(){this.constant*=-1;this.normal.negate();return this},distanceToPoint:function(a){return this.normal.dot(a)+this.constant},distanceToSphere:function(a){return this.distanceToPoint(a.center)-a.radius},projectPoint:function(a,b){return this.orthoPoint(a,b).sub(a).negate()},orthoPoint:function(a, b){var c=this.distanceToPoint(a);return(b||new THREE.Vector3).copy(this.normal).multiplyScalar(c)},isIntersectionLine:function(a){var b=this.distanceToPoint(a.start),a=this.distanceToPoint(a.end);return 0>b&&0a&&0f||1g.scale.x)return n;n.push({distance:p,point:g.position,face:null,object:g})}else if(g instanceof -a.LOD)f.getPositionFromMatrix(g.matrixWorld),p=j.ray.origin.distanceTo(f),i(g.getObjectForDistance(p),j,n);else if(g instanceof a.Mesh){p=g.geometry;f.getPositionFromMatrix(g.matrixWorld);null===p.boundingSphere&&p.computeBoundingSphere();b.set(f,p.boundingSphere.radius*g.matrixWorld.getMaxScaleOnAxis());if(!1===j.ray.isIntersectionSphere(b))return n;var t=p.vertices;if(p instanceof a.BufferGeometry){var q=g.material;if(void 0===q||!p.dynamic)return n;var r=g.material instanceof a.MeshFaceMaterial, +a.LOD)f.getPositionFromMatrix(g.matrixWorld),p=j.ray.origin.distanceTo(f),i(g.getObjectForDistance(p),j,n);else if(g instanceof a.Mesh){p=g.geometry;f.getPositionFromMatrix(g.matrixWorld);null===p.boundingSphere&&p.computeBoundingSphere();b.set(f,p.boundingSphere.radius*g.matrixWorld.getMaxScaleOnAxis());if(!1===j.ray.isIntersectionSphere(b))return n;var t=p.vertices;if(p instanceof a.BufferGeometry){var q=g.material;if(void 0===q||!1===p.dynamic)return n;var r=g.material instanceof a.MeshFaceMaterial, s=!0===r?g.material.materials:null,v=g.material.side,z,C,F=j.precision;h.getInverse(g.matrixWorld);c.copy(j.ray).applyMatrix4(h);var H,t=!1;p.attributes.index&&(t=!0);s=new a.Vector3;H=new a.Vector3;var I=new a.Vector3;new a.Vector3;new a.Vector3;for(var G=0;GA)){v=q.side;if(v!==a.DoubleSide&&(z=c.direction.dot(d.normal),!(v===a.FrontSide?0>z:0j.far||(e=c.at(A,e), -a.Triangle.containsPoint(e,s,H,I)&&n.push({distance:A,point:j.ray.at(A),face:null,faceIndex:null,object:g}))}}else if(p instanceof a.Geometry){r=g.material instanceof a.MeshFaceMaterial;s=!0===r?g.material.materials:null;F=j.precision;h.getInverse(g.matrixWorld);c.copy(j.ray).applyMatrix4(h);I=0;for(H=p.faces.length;IA))){v=q.side; -if(v!==a.DoubleSide&&(z=c.direction.dot(d.normal),!(v===a.FrontSide?0>z:0j.far)){e=c.at(A,e);if(G instanceof a.Face3){if(v=t[G.a],z=t[G.b],C=t[G.c],!a.Triangle.containsPoint(e,v,z,C))continue}else if(G instanceof a.Face4){if(v=t[G.a],z=t[G.b],C=t[G.c],q=t[G.d],!a.Triangle.containsPoint(e,v,z,q)&&!a.Triangle.containsPoint(e,z,C,q))continue}else throw Error("face type not supported");n.push({distance:A,point:j.ray.at(A),face:G,faceIndex:I,object:g})}}}}else if(g instanceof -a.Line){F=j.linePrecision;if(0>F)return n;F*=F;p=g.geometry;null===p.boundingSphere&&p.computeBoundingSphere();f.getPositionFromMatrix(g.matrixWorld);b.set(f,p.boundingSphere.radius*g.matrixWorld.getMaxScaleOnAxis());if(!j.ray.isIntersectionSphere(b))return n;h.getInverse(g.matrixWorld);c.copy(j.ray).applyMatrix4(h);c.direction.normalize();t=p.vertices;q=t.length;A=new a.Vector3;v=new a.Vector3;z=g.type===a.LineStrip?1:2;for(r=0;rA))){v=q.side; +if(v!==a.DoubleSide&&(z=c.direction.dot(d.normal),!(v===a.FrontSide?0>z:0j.far)){e=c.at(A,e);if(G instanceof a.Face3){if(v=t[G.a],z=t[G.b],C=t[G.c],!1===a.Triangle.containsPoint(e,v,z,C))continue}else if(G instanceof a.Face4){if(v=t[G.a],z=t[G.b],C=t[G.c],q=t[G.d],!1===a.Triangle.containsPoint(e,v,z,q)&&!1===a.Triangle.containsPoint(e,z,C,q))continue}else throw Error("face type not supported");n.push({distance:A,point:j.ray.at(A),face:G,faceIndex:I,object:g})}}}}else if(g instanceof +a.Line){F=j.linePrecision;F*=F;p=g.geometry;null===p.boundingSphere&&p.computeBoundingSphere();f.getPositionFromMatrix(g.matrixWorld);b.set(f,p.boundingSphere.radius*g.matrixWorld.getMaxScaleOnAxis());if(!1===j.ray.isIntersectionSphere(b))return n;h.getInverse(g.matrixWorld);c.copy(j.ray).applyMatrix4(h);c.direction.normalize();t=p.vertices;q=t.length;A=new a.Vector3;v=new a.Vector3;z=g.type===a.LineStrip?1:2;for(r=0;r