Browse Source

Merge pull request #414 from jbousquie/feature.CreateTube

Feature.create tube
David Catuhe 10 years ago
parent
commit
bb5dc8e6c2
2 changed files with 120 additions and 0 deletions
  1. 89 0
      Babylon/Math/babylon.math.ts
  2. 31 0
      Babylon/Mesh/babylon.mesh.ts

+ 89 - 0
Babylon/Math/babylon.math.ts

@@ -3005,4 +3005,93 @@
             return new Path2(x, y);
         }
     }
+
+    export class Path3D {
+        private _curve: Vector3[] = [];
+        private _distances: number[] = [];
+        private _tangents: Vector3[] = [];
+        private _normals: Vector3[] = [];
+        private _binormals: Vector3[] = [];
+
+        constructor(public path: Vector3[]) {
+            this._curve = path.slice();   // copy array         
+            var l: number = this._curve.length;
+            // first and last tangents
+            this._tangents[0] = this._curve[1].subtract(this._curve[0]);
+            this._tangents[0].normalize();
+            this._tangents[l-1] = this._curve[l-1].subtract(this._curve[l-2]);
+            this._tangents[l-1].normalize();
+            // normals and binormals at first point : arbitrary vector with _normalVector()
+            var tg0: Vector3 = this._tangents[0];
+            var pp0: Vector3 = this._normalVector(this._curve[0], tg0);
+            this._normals[0] = pp0;
+            this._normals[0].normalize();
+            this._binormals[0] = BABYLON.Vector3.Cross(tg0, this._normals[0]);
+            this._normals[0].normalize();
+            this._distances[0] = 0;
+            // normals and binormals : next points
+            var prev: Vector3;        // previous vector (segment)
+            var cur: Vector3;         // current vector (segment)
+            var curTang: Vector3;     // current tangent
+            var prevNorm: Vector3;    // previous normal
+            var prevBinor: Vector3;   // previous binormal
+            for(var i: number = 1; i < l; i++) {
+                // tangents
+                prev = this._curve[i].subtract(this._curve[i-1]);
+                if (i < l-1) {
+                    cur = this._curve[i+1].subtract(this._curve[i]);
+                    this._tangents[i] = prev.add(cur);
+                    this._tangents[i].normalize();               
+                }
+                this._distances[i] = this._distances[i-1] + prev.length();         
+                // normals and binormals
+                // http://www.cs.cmu.edu/afs/andrew/scs/cs/15-462/web/old/asst2camera.html
+                curTang = this._tangents[i];
+                prevNorm = this._normals[i-1];
+                prevBinor = this._binormals[i-1];
+                this._normals[i] = BABYLON.Vector3.Cross(prevBinor, curTang);
+                this._normals[i].normalize();
+                this._binormals[i] = BABYLON.Vector3.Cross(curTang, this._normals[i]);
+                this._binormals[i].normalize();
+            }
+        }
+
+        public getCurve(): Vector3[] {
+            return this._curve;
+        }
+
+        public getTangents(): Vector3[] {
+            return this._tangents;
+        }
+
+        public getNormals(): Vector3[] {
+            return this._normals;
+        }
+
+        public getBinormals(): Vector3[] {
+            return this._binormals;
+        }
+
+        public getDistances(): number[] {
+            return this._distances;
+        }
+
+        // private function normalVector(v0, vt) :
+        // returns an arbitrary point in the plane defined by the point v0 and the vector vt orthogonal to this plane
+        private _normalVector(v0: Vector3, vt: Vector3): Vector3 {
+            var point: Vector3; 
+            if (vt.x != 1) {     // search for a point in the plane
+                point = new BABYLON.Vector3(1, 0, 0);   
+            }
+            else if (vt.y != 1) {
+                point = new BABYLON.Vector3(0, 1, 0);  
+            }
+            else if (vt.z != 1) {
+                point = new BABYLON.Vector3(0, 0, 1);  
+            }
+            var normal0: Vector3 = BABYLON.Vector3.Cross(vt, point);
+            normal0.normalize();
+            return normal0;        
+        }
+    }
 }

+ 31 - 0
Babylon/Mesh/babylon.mesh.ts

@@ -1265,6 +1265,37 @@
             return ground;
         }
 
+        public static CreateTube(name: string, path: Vector3[], radius: number, tesselation: number, radiusFunction: { (i: number, distance: number): number; }, scene: Scene, updatable?: boolean, sideOrientation: number = Mesh.DEFAULTSIDE): Mesh {
+            var tube: Mesh;
+            var path3D: Path3D = new BABYLON.Path3D(path);
+            var tangents: Vector3[] = path3D.getTangents();
+            var normals: Vector3[] = path3D.getNormals();
+            var distances: number[] = path3D.getDistances();
+            var pi2: number = Math.PI * 2;
+            var step: number = pi2 / tesselation;
+            var returnRadius: { (i: number, distance: number): number; } = function(i, distance) { return radius };
+            var radiusFunction: { (i: number, distance: number): number; } = radiusFunction || returnRadius; 
+            var circlePaths: Vector3[][] = [];
+            var circlePath: Vector3[];
+            var rad: number;
+            var normal: Vector3;
+            var rotated: Vector3;
+            var rotationMatrix: Matrix;
+            for (var i: number = 0; i < path.length; i++) {
+                rad = radiusFunction(i, distances[i]);      // current radius
+                circlePath = [];                            // current circle array
+                normal =  normals[i]                        // current normal  
+                for( var ang: number = 0; ang < pi2; ang += step) {
+                    rotationMatrix = BABYLON.Matrix.RotationAxis(tangents[i], ang);
+                    rotated = BABYLON.Vector3.TransformCoordinates(normal, rotationMatrix).scaleInPlace(rad).add(path[i]);
+                    circlePath.push(rotated);
+                }
+                circlePaths.push(circlePath);
+            }
+            tube = BABYLON.Mesh.CreateRibbon(name, circlePaths, false, true, 0, scene, updatable, sideOrientation);
+            return tube;
+        }
+
         // Tools
         public static MinMax(meshes: AbstractMesh[]): { min: Vector3; max: Vector3 } {
             var minVector: Vector3 = null;