1. 程式人生 > >three.js 原始碼註釋(九十四)extras/core/Shape.js

three.js 原始碼註釋(九十四)extras/core/Shape.js


俺也是剛開始學,好多地兒肯定不對還請見諒.

以下程式碼是THREE.JS 原始碼檔案中extras/core/Shape.js檔案的註釋.


/**
 * @author zz85 / http://www.lab4games.net/zz85/blog
 * Defines a 2d shape plane using paths.
 **/

// STEP 1 Create a path.
// 1. 建立路徑
// STEP 2 Turn path into shape.
// 2. 將路徑變成截面
// STEP 3 ExtrudeGeometry takes in Shape/Shapes
// 3. 將截面拉伸成幾何體
// STEP 3a - Extract points from each shape, turn to vertices
// 3a. 匯出所有的截面頂點到vertices屬性中
// STEP 3b - Triangulate each shape, add faces.
// 3b. 組織所有的頂點為三角面.
/*
///Shape物件將二維平面生成圖形物件的抽象基類.
///
*/
///<summary>Shape</summary>
THREE.Shape = function () {

	THREE.Path.apply( this, arguments );	//呼叫Path物件的call方法,將原本屬於Path的方法交給當前物件Shape來使用.
	this.holes = [];	//將孔洞存放到holes陣列中.

};
/*************************************************
****下面是Shape物件的方法屬性定義,繼承自Path物件.
**************************************************/
THREE.Shape.prototype = Object.create( THREE.Path.prototype );

/*
///extrude生成拉伸幾何體的便利方法.
///
/// parameters = {
///
///  curveSegments: <int>, // number of points on the curves 曲線上的頂點數量
///  steps: <int>, // number of points for z-side extrusions / used for subdividing segements of extrude spline too 步數,曲線拉伸的細分線段數
///  amount: <int>, // Depth to extrude the shape 拉伸線段的厚度.
///
///  bevelEnabled: <bool>, // turn on bevel 是否啟用倒角
///  bevelThickness: <float>, // how deep into the original shape bevel goes 倒角的厚度
///  bevelSize: <float>, // how far from shape outline is bevel 從截面外輪廓倒角的尺寸.
///  bevelSegments: <int>, // number of bevel layers 倒角部分的細分線段數.
///
///  extrudePath: <THREE.CurvePath> // 3d spline path to extrude shape along. (creates Frames if .frames aren't defined) 截面拉伸的路徑,3d的spline物件.
///  frames: <THREE.TubeGeometry.FrenetFrames> // containing arrays of tangents, normals, binormals 包含三角形,法線,副法線陣列.
///
///  material: <int> // material index for front and back faces 正面和背面材質索引
///  extrudeMaterial: <int> // material index for extrusion and beveled faces 拉伸體和斜面的材質索引
///  uvGenerator: <Object> // object that provides UV generator functions UV座標生成函式.
///
/// }
*/
///<summary>extrude</summary>
///<param name ="options" type="String">引數選項</param>
///<returns type="THREE.ExtrudeGeometry">拉伸幾何體.</returns>
// Convenience method to return ExtrudeGeometry
// 生成拉伸幾何體的便利方法.
THREE.Shape.prototype.extrude = function ( options ) {

	var extruded = new THREE.ExtrudeGeometry( this, options );
	return extruded;

};
/*
///makeGeometry建立圖形幾何體的便利方法
///
/// parameters = {
///
///	curveSegments: <int>, // number of points on the curves. NOT USED AT THE MOMENT. 曲線上的頂點數量
///
///	material: <int> // material index for front and back faces 正面和背面材質索引
///	uvGenerator: <Object> // object that provides UV generator functions UV座標生成函式
///
/// }
*/
///<summary>makeGeometry</summary>
///<param name ="options" type="String">引數選項</param>
///<returns type="THREE.ShapeGeometry">拉伸幾何體.</returns>
// Convenience method to return ShapeGeometry
// 建立圖形幾何體的便利方法.
THREE.Shape.prototype.makeGeometry = function ( options ) {

	var geometry = new THREE.ShapeGeometry( this, options );
	return geometry;

};
/*
///getPointsHoles方法根據divisions將孔洞等分,獲得在孔洞物件上等分點的點序列.如果沒有設定引數divisions.返回對應等分孔洞頂點的座標陣列.
///定量等分孔洞
*/
///<summary>getPointsHoles</summary>
///<param name ="divisions" type="int">根據divisions將孔洞等分,獲得在孔洞物件上等分點的點序列.如果沒有設定引數divisions.</param>
///<returns type="Vector3Array">返回對應等分孔洞頂點的座標陣列.</returns>
// Get points of holes
// 定量等分,獲得所有孔洞的頂點
THREE.Shape.prototype.getPointsHoles = function ( divisions ) {

	var i, il = this.holes.length, holesPts = [];

	for ( i = 0; i < il; i ++ ) {

		holesPts[ i ] = this.holes[ i ].getTransformedPoints( divisions, this.bends );

	}

	return holesPts;	//返回對應等分孔洞頂點的座標陣列

};
/*
///getSpacedPointsHoles方法根據divisions將孔洞等分,獲得在孔洞物件上等分點的點序列.如果沒有設定引數divisions.返回對應等分孔洞頂點的座標陣列.
///定距等分孔洞
*/
///<summary>getSpacedPointsHoles</summary>
///<param name ="divisions" type="int">根據divisions將孔洞等分,獲得在孔洞物件上等分點的點序列.如果沒有設定引數divisions.</param>
///<returns type="Vector3Array">返回對應等分孔洞頂點的座標陣列.</returns>
// Get points of holes (spaced by regular distance)
// 定距等分,獲得所有孔洞的頂點.
THREE.Shape.prototype.getSpacedPointsHoles = function ( divisions ) {

	var i, il = this.holes.length, holesPts = [];

	for ( i = 0; i < il; i ++ ) {

		holesPts[ i ] = this.holes[ i ].getTransformedSpacedPoints( divisions, this.bends );

	}

	return holesPts;	//返回對應等分孔洞頂點的座標陣列

};

/*
///extractAllPoints方法根據divisions將孔洞等分,獲得在所有介面和孔洞物件上等分點的點序列.如果沒有設定引數divisions.返回所有介面和孔洞等分頂點的座標陣列.
///定量等分孔洞
*/
///<summary>extractAllPoints</summary>
///<param name ="divisions" type="int">根據divisions將所有介面和孔洞等分,獲得在所有介面和孔洞物件上等分點的點序列.如果沒有設定引數divisions.</param>
///<returns type="Vector3Array">返回所有介面和孔洞等分頂點的座標陣列.</returns>
// Get points of shape and holes (keypoints based on segments parameter)
// 定量等分,獲得所有介面和孔洞的頂點.
THREE.Shape.prototype.extractAllPoints = function ( divisions ) {

	return {

		shape: this.getTransformedPoints( divisions ),
		holes: this.getPointsHoles( divisions )

	};

};

/*
///extractPoints方法根據divisions將孔洞等分,獲得在所有介面和孔洞物件上等分點的點序列.如果沒有設定引數divisions.返回所有介面和孔洞等分頂點的座標陣列.
///
*/
///<summary>extractPoints</summary>
///<param name ="divisions" type="int">根據divisions將所有介面和孔洞等分,獲得在所有介面和孔洞物件上等分點的點序列.如果沒有設定引數divisions.</param>
///<returns type="Vector3Array">返回所有介面和孔洞等分頂點的座標陣列.</returns>
// 等分所有介面和孔洞,獲得的頂點
THREE.Shape.prototype.extractPoints = function ( divisions ) {

	if (this.useSpacedPoints) {
		return this.extractAllSpacedPoints(divisions);
	}

	return this.extractAllPoints(divisions);

};

//
// THREE.Shape.prototype.extractAllPointsWithBend = function ( divisions, bend ) {
//
// 	return {
//
// 		shape: this.transform( bend, divisions ),
// 		holes: this.getPointsHoles( divisions, bend )
//
// 	};
//
// };

/*
///extractAllSpacedPoints方法根據divisions將孔洞等分,獲得在所有介面和孔洞物件上等分點的點序列.如果沒有設定引數divisions.返回所有介面和孔洞等分頂點的座標陣列.
///定距等分孔洞
*/
///<summary>extractAllSpacedPoints</summary>
///<param name ="divisions" type="int">根據divisions將所有介面和孔洞等分,獲得在所有介面和孔洞物件上等分點的點序列.如果沒有設定引數divisions.</param>
///<returns type="Object">返回所有介面和孔洞等分頂點的座標陣列.</returns>
// Get points of shape and holes (spaced by regular distance)
// 定距等分,獲得所有介面和孔洞的頂點.
THREE.Shape.prototype.extractAllSpacedPoints = function ( divisions ) {

	return {

		shape: this.getTransformedSpacedPoints( divisions ),
		holes: this.getSpacedPointsHoles( divisions )

	};

};

/**************************************************************
 *	Utils shape物件的工具集
 **************************************************************/
THREE.Shape.Utils = {
	/*
	///triangulateShape方法將傳遞的頂點陣列(引數contour)和鏤空(孔洞)陣列(引數holes)三角化.
	*/
	///<summary>triangulateShape</summary>
	///<param name ="contour" type="Vector3Array">拉伸幾何體的頂點資料.</param>
	///<param name ="holes" type="Vector3Array">鏤空(孔洞)頂點資料.</param>
	///<returns type="Vector3Array">返回圍繞形狀的頂點索引.</returns>
	triangulateShape: function ( contour, holes ) {

		function point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) {
			// inOtherPt needs to be colinear to the inSegment
			if ( inSegPt1.x != inSegPt2.x ) {
				if ( inSegPt1.x < inSegPt2.x ) {
					return	( ( inSegPt1.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt2.x ) );
				} else {
					return	( ( inSegPt2.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt1.x ) );
				}
			} else {
				if ( inSegPt1.y < inSegPt2.y ) {
					return	( ( inSegPt1.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt2.y ) );
				} else {
					return	( ( inSegPt2.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt1.y ) );
				}
			}
		}

		/*
		///intersect_segments_2D方法返回兩條線段的交點.
		*/
		///<summary>intersect_segments_2D</summary>
		///<param name ="inSeg1Pt1" type="Vector2">要檢查交點的第一條線的起始點.</param>
		///<param name ="inSeg1Pt2" type="Vector2">要檢查交點的第一條線的結束點.</param>
		///<param name ="inSeg2Pt1" type="Vector2">要檢查交點的第二條線的起始點.</param>
		///<param name ="inSeg2Pt2" type="Vector2">要檢查交點的第二條線的結束點.</param>
		///<param name ="inExcludeAdjacentSegs" type="boolean">是否排除相鄰的線段.</param>
		///<returns type="Vector2Array">二維向量陣列.</returns>
		function intersect_segments_2D( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1, inSeg2Pt2, inExcludeAdjacentSegs ) {
			var EPSILON = 0.0000000001;

			var seg1dx = inSeg1Pt2.x - inSeg1Pt1.x,   seg1dy = inSeg1Pt2.y - inSeg1Pt1.y;
			var seg2dx = inSeg2Pt2.x - inSeg2Pt1.x,   seg2dy = inSeg2Pt2.y - inSeg2Pt1.y;

			var seg1seg2dx = inSeg1Pt1.x - inSeg2Pt1.x;
			var seg1seg2dy = inSeg1Pt1.y - inSeg2Pt1.y;

			var limit		= seg1dy * seg2dx - seg1dx * seg2dy;
			var perpSeg1	= seg1dy * seg1seg2dx - seg1dx * seg1seg2dy;

			if ( Math.abs(limit) > EPSILON ) {			// not parallel //兩條線不平行

				var perpSeg2;
				if ( limit > 0 ) {
					if ( ( perpSeg1 < 0 ) || ( perpSeg1 > limit ) ) 		return [];	//返回空陣列
					perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy;
					if ( ( perpSeg2 < 0 ) || ( perpSeg2 > limit ) ) 		return [];	//返回空陣列
				} else {
					if ( ( perpSeg1 > 0 ) || ( perpSeg1 < limit ) ) 		return [];	//返回空陣列
					perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy;
					if ( ( perpSeg2 > 0 ) || ( perpSeg2 < limit ) ) 		return [];	//返回空陣列
				}

				// i.e. to reduce rounding errors
				// intersection at endpoint of segment#1?
				// 交點位於第一條線的端點
				if ( perpSeg2 == 0 ) {
					if ( ( inExcludeAdjacentSegs ) &&
						 ( ( perpSeg1 == 0 ) || ( perpSeg1 == limit ) ) )		return [];	//返回空陣列
					return  [ inSeg1Pt1 ];
				}
				if ( perpSeg2 == limit ) {
					if ( ( inExcludeAdjacentSegs ) &&
						 ( ( perpSeg1 == 0 ) || ( perpSeg1 == limit ) ) )		return [];	//返回空陣列
					return  [ inSeg1Pt2 ];
				}
				// intersection at endpoint of segment#2?
				// 交點位於第二條線的端點
				if ( perpSeg1 == 0 )		return  [ inSeg2Pt1 ];
				if ( perpSeg1 == limit )	return  [ inSeg2Pt2 ];

				// return real intersection point
				// 返回真正的交點
				var factorSeg1 = perpSeg2 / limit;
				return	[ { x: inSeg1Pt1.x + factorSeg1 * seg1dx,
							y: inSeg1Pt1.y + factorSeg1 * seg1dy } ];

			} else {		// parallel or colinear 平行或共線
				if ( ( perpSeg1 != 0 ) ||
					 ( seg2dy * seg1seg2dx != seg2dx * seg1seg2dy ) ) 			return [];	//返回空陣列

				// they are collinear or degenerate 兩條線共線或則無效
				var seg1Pt = ( (seg1dx == 0) && (seg1dy == 0) );	// segment1 ist just a point? 第一條線只是一個點
				var seg2Pt = ( (seg2dx == 0) && (seg2dy == 0) );	// segment2 ist just a point? 第二條線只是一個點
				// both segments are points 兩條線都是點
				if ( seg1Pt && seg2Pt ) {
					if ( (inSeg1Pt1.x != inSeg2Pt1.x) ||
						 (inSeg1Pt1.y != inSeg2Pt1.y) )		return [];   	// they are distinct  points 兩個點不共點,返回空陣列
					return  [ inSeg1Pt1 ];                 					// they are the same point 共點
				}
				// segment#1  is a single point 第一條線段是一個點
				if ( seg1Pt ) {
					if (! point_in_segment_2D_colin( inSeg2Pt1, inSeg2Pt2, inSeg1Pt1 ) )		return [];		// but not in segment#2 不在第二條線段內,返回空陣列
					return  [ inSeg1Pt1 ];
				}
				// segment#2  is a single point 第二條線是一個點
				if ( seg2Pt ) {
					if (! point_in_segment_2D_colin( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1 ) )		return [];		// but not in segment#1 不在第一條線段內,返回空陣列
					return  [ inSeg2Pt1 ];
				}

				// they are collinear segments, which might overlap 兩條線共線,有可能重疊.
				var seg1min, seg1max, seg1minVal, seg1maxVal;
				var seg2min, seg2max, seg2minVal, seg2maxVal;
				if (seg1dx != 0) {		// the segments are NOT on a vertical line 線不是垂直線
					if ( inSeg1Pt1.x < inSeg1Pt2.x ) {
						seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.x;
						seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.x;
					} else {
						seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.x;
						seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.x;
					}
					if ( inSeg2Pt1.x < inSeg2Pt2.x ) {
						seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.x;
						seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.x;
					} else {
						seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.x;
						seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.x;
					}
				} else {				// the segments are on a vertical line 
					if ( inSeg1Pt1.y < inSeg1Pt2.y ) {
						seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.y;
						seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.y;
					} else {
						seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.y;
						seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.y;
					}
					if ( inSeg2Pt1.y < inSeg2Pt2.y ) {
						seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.y;
						seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.y;
					} else {
						seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.y;
						seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.y;
					}
				}
				if ( seg1minVal <= seg2minVal ) {
					if ( seg1maxVal <  seg2minVal )	return [];
					if ( seg1maxVal == seg2minVal )	{
						if ( inExcludeAdjacentSegs )		return [];
						return [ seg2min ];
					}
					if ( seg1maxVal <= seg2maxVal )	return [ seg2min, seg1max ];
					return	[ seg2min, seg2max ];
				} else {
					if ( seg1minVal >  seg2maxVal )	return [];
					if ( seg1minVal == seg2maxVal )	{
						if ( inExcludeAdjacentSegs )		return [];
						return [ seg1min ];
					}
					if ( seg1maxVal <= seg2maxVal )	return [ seg1min, seg1max ];
					return	[ seg1min, seg2max ];
				}
			}
		}

		/*
		///isPointInsideAngle方法判斷第四個引數是否在前三個引數組成的三角形內.
		*/
		///<summary>isPointInsideAngle</summary>
		///<param name ="inVertex" type="int">頂點索引.</param>
		///<param name ="inLegFromPt" type="int">上一個頂點索引.</param>
		///<param name ="inLegToPt" type="int">下一個頂點索引.</param>
		///<param name ="inOtherPt" type="int">孔洞頂點索引.</param>
		///<returns type="boolean">true 或者 false.</returns>
		function isPointInsideAngle( inVertex, inLegFromPt, inLegToPt, inOtherPt ) {
			// The order of legs is important	引數的排列順序非常重要.

			var EPSILON = 0.0000000001;

			// translation of all points, so that Vertex is at (0,0)
			var legFromPtX	= inLegFromPt.x - inVertex.x,  legFromPtY	= inLegFromPt.y - inVertex.y;
			var legToPtX	= inLegToPt.x	- inVertex.x,  legToPtY		= inLegToPt.y	- inVertex.y;
			var otherPtX	= inOtherPt.x	- inVertex.x,  otherPtY		= inOtherPt.y	- inVertex.y;

			// main angle >0: < 180 deg.; 0: 180 deg.; <0: > 180 deg.
			var from2toAngle	= legFromPtX * legToPtY - legFromPtY * legToPtX;
			var from2otherAngle	= legFromPtX * otherPtY - legFromPtY * otherPtX;

			if ( Math.abs(from2toAngle) > EPSILON ) {			// angle != 180 deg.

				var other2toAngle		= otherPtX * legToPtY - otherPtY * legToPtX;
				// console.log( "from2to: " + from2toAngle + ", from2other: " + from2otherAngle + ", other2to: " + other2toAngle );

				if ( from2toAngle > 0 ) {				// main angle < 180 deg.
					return	( ( from2otherAngle >= 0 ) && ( other2toAngle >= 0 ) );
				} else {								// main angle > 180 deg.
					return	( ( from2otherAngle >= 0 ) || ( other2toAngle >= 0 ) );
				}
			} else {										// angle == 180 deg.
				// console.log( "from2to: 180 deg., from2other: " + from2otherAngle  );
				return	( from2otherAngle > 0 );
			}
		}

		/*
		///removeHoles方法從拉伸幾何體中刪除孔洞.
		*/
		///<summary>removeHoles</summary>
		///<param name ="contour" type="Vector3Array">拉伸幾何體的頂點資料.</param>
		///<param name ="holes" type="Vector3Array">鏤空(孔洞)頂點資料.</param>
		///<returns type="Object">返回沒有鏤空(孔洞)的拉伸幾何體.</returns>
		function removeHoles( contour, holes ) {

			var shape = contour.concat(); // work on this shape
			var hole;

			/*
			///isCutLineInsideAngles方法返回當前索引所指的圖形頂點在鏤空頂點,以及前一個頂點,後一個頂點組成的三角形內.
			// 或者當前索引所指的鏤空頂點在圖形頂點,以及前一個頂點,後一個頂點組成的三角形內,true為真.
			*/
			///<summary>isCutLineInsideAngles</summary>
			///<param name ="inShapeIdx" type="int">拉伸幾何體的頂點資料.</param>
			///<param name ="inHoleIdx" type="int">鏤空(孔洞)頂點資料.</param>
			///<returns type="boolean">true 或者 false.</returns>
			function isCutLineInsideAngles( inShapeIdx, inHoleIdx ) {
				// Check if hole point lies within angle around shape point
				// 檢查鏤空(孔洞)的頂點在
				var lastShapeIdx = shape.length - 1;

				var prevShapeIdx = inShapeIdx - 1;
				if ( prevShapeIdx < 0 )			prevShapeIdx = lastShapeIdx;

				var nextShapeIdx = inShapeIdx + 1;
				if ( nextShapeIdx > lastShapeIdx )	nextShapeIdx = 0;

				var insideAngle = isPointInsideAngle( shape[inShapeIdx], shape[ prevShapeIdx ], shape[ nextShapeIdx ], hole[inHoleIdx] );
				if (! insideAngle ) {
					// console.log( "Vertex (Shape): " + inShapeIdx + ", Point: " + hole[inHoleIdx].x + "/" + hole[inHoleIdx].y );
					return	false;
				}

				// Check if shape point lies within angle around hole point
				// 檢查圖形頂點位於環繞鏤空(孔洞)的三角形內.
				var lastHoleIdx = hole.length - 1;

				var prevHoleIdx = inHoleIdx - 1;
				if ( prevHoleIdx < 0 )			prevHoleIdx = lastHoleIdx;

				var nextHoleIdx = inHoleIdx + 1;
				if ( nextHoleIdx > lastHoleIdx )	nextHoleIdx = 0;

				insideAngle = isPointInsideAngle( hole[inHoleIdx], hole[ prevHoleIdx ], hole[ nextHoleIdx ], shape[inShapeIdx] );
				if (! insideAngle ) {
					// console.log( "Vertex (Hole): " + inHoleIdx + ", Point: " + shape[inShapeIdx].x + "/" + shape[inShapeIdx].y );
					return	false;
				}

				return	true;	//
			}
			/*
			///intersectsShapeEdge方法檢查鏤空(孔洞)與形狀邊界是否有交點,true為真.
			*/
			///<summary>isCutLineInsideAngles</summary>
			///<param name ="inShapeIdx" type="int">拉伸幾何體的頂點資料.</param>
			///<param name ="inHoleIdx" type="int">鏤空(孔洞)頂點資料.</param>
			///<returns type="boolean">true 或者 false.</returns>
			function intersectsShapeEdge( inShapePt, inHolePt ) {
				// checks for intersections with shape edges
				// 檢查鏤空(孔洞)與形狀邊界是否有交點.
				var sIdx, nextIdx, intersection;
				for ( sIdx = 0; sIdx < shape.length; sIdx ++ ) {
					nextIdx = sIdx+1; nextIdx %= shape.length;
					intersection = intersect_segments_2D( inShapePt, inHolePt, shape[sIdx], shape[nextIdx], true );
					if ( intersection.length > 0 )		return	true;
				}

				return	false;
			}

			var indepHoles = [];
			/*
			///intersectsShapeEdge方法檢查當前的鏤空(孔洞)是否是否與其它鏤空(孔洞)邊界相交,true為真.
			*/
			///<summary>isCutLineInsideAngles</summary>
			///<param name ="inShapeIdx" type="int">拉伸幾何體的頂點資料.</param>
			///<param name ="inHoleIdx" type="int">鏤空(孔洞)頂點資料.</param>
			///<returns type="boolean">true 或者 false.</returns>
			function intersectsHoleEdge( inShapePt, inHolePt ) {
				// checks for intersections with hole edges
				// 檢查當前的鏤空(孔洞)是否是否與其它鏤空(孔洞)邊界相交.
				var ihIdx, chkHole,
					hIdx, nextIdx, intersection;
				for ( ihIdx = 0; ihIdx < indepHoles.length; ihIdx ++ ) {
					chkHole = holes[indepHoles[ihIdx]];
					for ( hIdx = 0; hIdx < chkHole.length; hIdx ++ ) {
						nextIdx = hIdx+1; nextIdx %= chkHole.length;
						intersection = intersect_segments_2D( inShapePt, inHolePt, chkHole[hIdx], chkHole[nextIdx], true );
						if ( intersection.length > 0 )		return	true;
					}
				}
				return	false;
			}

			var holeIndex, shapeIndex,
				shapePt, holePt,
				holeIdx, cutKey, failedCuts = [],
				tmpShape1, tmpShape2,
				tmpHole1, tmpHole2;

			for ( var h = 0, hl = holes.length; h < hl; h ++ ) {

				indepHoles.push( h );

			}

			var minShapeIndex = 0;
			var counter = indepHoles.length * 2;
			while ( indepHoles.length > 0 ) {
				counter --;
				if ( counter < 0 ) {
					console.log( "Infinite Loop! Holes left:" + indepHoles.length + ", Probably Hole outside Shape!" );
					break;
				}

				// search for shape-vertex and hole-vertex,
				// 搜尋形狀的頂點和鏤空(孔洞)頂點
				// which can be connected without intersections
				// 哪些可以連線並無交點.
				for ( shapeIndex = minShapeIndex; shapeIndex < shape.length; shapeIndex ++ ) {

					shapePt = shape[ shapeIndex ];
					holeIndex	= - 1;

					// search for hole which can be reached without intersections
					// 搜尋鏤空(孔洞)的頂點,哪些可以到達並沒有交點.
					for ( var h = 0; h < indepHoles.length; h ++ ) {
						holeIdx = indepHoles[h];

						// prevent multiple checks
						// 避免多次檢查
						cutKey = shapePt.x + ":" + shapePt.y + ":" + holeIdx;
						if ( failedCuts[cutKey] !== undefined )			continue;

						hole = holes[holeIdx];
						for ( var h2 = 0; h2 < hole.length; h2 ++ ) {
							holePt = hole[ h2 ];
							if (! isCutLineInsideAngles( shapeIndex, h2 ) )		continue;	//如果孔洞頂點不在切線內
							if ( intersectsShapeEdge( shapePt, holePt ) )		continue;	//如果與圖形的邊相交.
							if ( intersectsHoleEdge( shapePt, holePt ) )		continue;	//如果與鏤空(空洞)的邊相交.

							holeIndex = h2;
							indepHoles.splice(h,1);

							tmpShape1 = shape.slice( 0, shapeIndex+1 );
							tmpShape2 = shape.slice( shapeIndex );
							tmpHole1 = hole.slice( holeIndex );
							tmpHole2 = hole.slice( 0, holeIndex+1 );

							shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 );

							minShapeIndex = shapeIndex;

							// Debug only, to show the selected cuts
							// glob_CutLines.push( [ shapePt, holePt ] );

							break;
						}
						if ( holeIndex >= 0 )	break;		// hole-vertex found 找到鏤空頂點

						failedCuts[cutKey] = true;			// remember failure	//新增切割線頂點索引
					}
					if ( holeIndex >= 0 )	break;		// hole-vertex found	//找到鏤空(孔洞)頂點
				}
			}

			return shape; 			/* shape with no holes */ // 返回不包含鏤空(孔洞)的形狀.
		}


		var i, il, f, face,
			key, index,
			allPointsMap = {};

		// To maintain reference to old shape, one must match coordinates, or offset the indices from original arrays. It's probably easier to do the first.
		// 將孔洞的頂點按照圖形原來座標順序,偏移索引,這是首先能做的.

		var allpoints = contour.concat(); 	//宣告陣列,存放合併後的頂點陣列.

		for ( var h = 0, hl = holes.length; h < hl; h ++ ) {	//遍歷鏤空(孔洞)的頂點

			Array.prototype.push.apply( allpoints, holes[h] );	//將鏤空(孔洞)的頂點壓入所有頂點陣列中.

		}

		//console.log( "allpoints",allpoints, allpoints.length );

		// prepare all points map 準備所有的頂點的雜湊表.

		for ( i = 0, il = allpoints.length; i < il; i ++ ) {

			key = allpoints[ i ].x + ":" + allpoints[ i ].y;

			if ( allPointsMap[ key ] !== undefined ) {

				console.log( "Duplicate point", key );

			}

			allPointsMap[ key ] = i;

		}

		// remove holes by cutting paths to holes and adding them to the shape
		// 刪除鏤空(孔洞),並將孔洞的作為實體的一部分.
		var shapeWithoutHoles = removeHoles( contour, holes );	//呼叫removeHoles方法.

		var triangles = THREE.FontUtils.Triangulate( shapeWithoutHoles, false ); // True returns indices for points of spooled shape 真正返回圍繞形狀的頂點索引.
		//console.log( "triangles",triangles, triangles.length );

		// check all face vertices against all points map
		// 檢查所有的面頂點順序與所有頂點的雜湊表一致.

		for ( i = 0, il = triangles.length; i < il; i ++ ) {

			face = triangles[ i ];

			for ( f = 0; f < 3; f ++ ) {

				key = face[ f ].x + ":" + face[ f ].y;

				index = allPointsMap[ key ];

				if ( index !== undefined ) {

					face[ f ] = index;

				}

			}

		}

		return triangles.concat(); //返回圍繞形狀的頂點索引.

	},
	/*
	///isClockWise方法判斷頂點座標陣列的順序是否是順時針.
	*/
	///<summary>isClockWise</summary>
	///<param name ="pts" type="PointArray">頂點座標陣列</param>
	///<returns type="boolean">返回true 或者 false.</returns>
	isClockWise: function ( pts ) {

		return THREE.FontUtils.Triangulate.area( pts ) < 0;

	},

	// Bezier Curves formulas obtained from
	// http://en.wikipedia.org/wiki/B%C3%A9zier_curve

	// Quad Bezier Functions
	// 二次貝塞爾方程.

	b2p0: function ( t, p ) {

		var k = 1 - t;
		return k * k * p;

	},

	b2p1: function ( t, p ) {

		return 2 * ( 1 - t ) * t * p;

	},

	b2p2: function ( t, p ) {

		return t * t * p;

	},

	b2: function ( t, p0, p1, p2 ) {

		return this.b2p0( t, p0 ) + this.b2p1( t, p1 ) + this.b2p2( t, p2 );

	},

	// Cubic Bezier Functions
	// 三次貝塞爾取信方程.

	b3p0: function ( t, p ) {

		var k = 1 - t;
		return k * k * k * p;

	},

	b3p1: function ( t, p ) {

		var k = 1 - t;
		return 3 * k * k * t * p;

	},

	b3p2: function ( t, p ) {

		var k = 1 - t;
		return 3 * k * t * t * p;

	},

	b3p3: function ( t, p ) {

		return t * t * t * p;

	},

	b3: function ( t, p0, p1, p2, p3 ) {

		return this.b3p0( t, p0 ) + this.b3p1( t, p1 ) + this.b3p2( t, p2 ) +  this.b3p3( t, p3 );

	}

};



以下程式碼是THREE.JS 原始碼檔案中extras/core/Shape.js檔案的註釋.

相關推薦

three.js 原始碼註釋extras/core/Shape.js

俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中extras/core/Shape.js檔案的註釋. /** * @author zz85 / http://www.lab4games.net/zz85/blog * Def

three.js 原始碼註釋extras/geometries/ParametricGeometry.js

俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中extras/geometries/ParametricGeometry.js檔案的註釋. /** * @author zz85 / https://github.com/zz8

three.js 原始碼註釋extras/geometries/IcosahedronGeometry.js

俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中extras/geometries/IcosahedronGeometry.js檔案的註釋. /** * @author timothypratley / https://git

three.js 原始碼註釋Texture/Texture.js

俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中Texture/Texture.js檔案的註釋. /** * @author mrdoob / http://mrdoob.com/ * @author alteredq /

three.js 原始碼註釋Core/Object3D.js

俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中Core/Object3D.js檔案的註釋. /** * @author mrdoob / http://mrdoob.com/ * @author mikael emting

three.js 原始碼註釋Material /MeshDepthMaterial.js

俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中materials/MeshDepthMaterial.js檔案的註釋. /** * @author mrdoob / http://mrdoob.com/ * @author

three.js 原始碼註釋Core/BufferGeometry.js

俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中Core/BufferGeometry.js檔案的註釋. /** * @author alteredq / http://alteredqualia.com/ */ /* //

three.js 原始碼註釋objects/Mesh.js

俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中objects/Mesh.js檔案的註釋. /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / htt

three.js 原始碼註釋Material /MeshPhongMaterial.js

俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中materials/MeshPhongMaterial.js檔案的註釋. /** * @author mrdoob / http://mrdoob.com/ * @author

three.js 原始碼註釋objects/Line.js

俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中objects/Line.js檔案的註釋. /** * @author mrdoob / http://mrdoob.com/ */ /* ///Line物件,建立一條線,或者

Java程式設計師從笨鳥到菜鳥之深入java虛擬機器——類的生命週期 下類的初始化

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Android O 連線WiFi AP流程梳理續——連線網路

前言: 之前在(五十五)Android O 連線WiFi AP流程梳理 梳理連線流程梳理到SupplicantStaNetworkHal 然後沒梳理的下去,現在繼續梳理下。 相關梳理: 1)(九十三) Android O 連線WiFi AP流程梳理續——儲存網路 2)&nb

Redis原始碼分析--- redis.h服務端的實現分析1

       上次剛剛分析過了客戶端的結構體分析,思路比較簡答,清晰,最後學習的是服務端的實現,服務端在Redis可是重中之重,裡面基本上囊括了之前模組中涉及到的所有知識點,從redis的標頭檔案就可以看出了,redis.h程式碼量就已經破1000+行了,而且都還只是一些變

three.js 原始碼註釋Material /MeshNormalMaterial.js

俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中Material/MeshNormalMaterial.js檔案的註釋. /** * @author mrdoob / http://mrdoob.com/ * * para

three.js 原始碼註釋Math/Sphere.js

俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中Math/Sphere.js檔案的註釋. // File:src/math/Sphere.js /** * @author bhouston / http://exocorte

three.js 原始碼註釋Light/AreaLight.js

俺也是剛開始學,好多地兒肯定不對還請見諒. 以下程式碼是THREE.JS 原始碼檔案中Light/AreaLight.js檔案的註釋. /** * @author MPanknin / http://www.redplant.de/ * @author alte

three.js 原始碼註釋Math/Vector3.js

以下程式碼是THREE.JS 原始碼檔案中Math/Vector3.js檔案的註釋. // File:src/math/Vector3.js /** * @author mrdoob / http://mrdoob.com/ * @author *kil

three.js 原始碼註釋Math/Vector2.js

以下程式碼是THREE.JS 原始碼檔案中Math/Vector2.js檔案的註釋. // File:src/math/Vector2.js /** * @author mrdoob / http://mrdoob.com/ * @author philog

Vue.js框架--Ui框架的Element UI

主要操作技能:    1>去官網檢視http://element-cn.eleme.io/2.4/#/zh-CN/component/quickstart      2>安裝:  cnpm i element-u

Redis原始碼剖析和註釋--- Redis Cluster 的通訊流程深入剖析載入配置檔案、節點握手、分配槽

Redis Cluster 通訊流程深入剖析 1. Redis Cluster 介紹和搭建 這篇部落格會介紹Redis Cluster的資料分割槽理論和一個三主三從叢集的搭建。 2. Redis Cluster 和 Redis Sentin