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