diff --git a/index.html b/index.html index 976a58d..8ba3449 100644 --- a/index.html +++ b/index.html @@ -8,7 +8,7 @@ - + @@ -45,47 +45,24 @@
diff --git a/js/main.js b/js/main.js index 7b771db..60f9e6e 100644 --- a/js/main.js +++ b/js/main.js @@ -16,20 +16,26 @@ var main = new function () { document.addEventListener("mousemove", sketch1.mouseMoveHandle, false); document.addEventListener("mousedown", sketch1.mouseDownHandle, false); - //document.addEventListener("mouseup", sketch.mouseUpHandle, false); - document.addEventListener("mouseup",function(){ + document.addEventListener("mouseup",function( event ){ sketchToMesh(event, sketch1); } , false); - canvas3d.addEventListener("mouseout", sketch1.mouseOutHandle, false); + //document.addEventListener("mouseup", sketch1.mouseUpHandle, false); + document.addEventListener("mouseout", sketch1.mouseOutHandle, false); + //canvas3d.addEventListener("mouseout", sketch1.mouseOutHandle, false); }; //Function to be called on sketching mouseup to create mesh function sketchToMesh (e,sketch) { - sketch.mouseUpHandle(e); + try{ + sketch.mouseUpHandle(e); + } catch (err) { + alert("Invalid sketch."); + } + if(world.canvas3d.style.display == 'none') { - if(sketch.proportion.y) { - world.proportion = {y: sketch.proportion.y, h:sketch.h, w: sketch.w}; - } + if(sketch.proportion.y) { + world.proportion = {y: sketch.proportion.y, h:sketch.h, w: sketch.w}; + } world.buildObject(sketch.contour, sketch.steiner, sketch.arrayDistance, sketch.triangles); displaying = sketch.canvas2d.style.display; sketch.canvas2d.style.display = "none"; @@ -44,7 +50,10 @@ $(document).ready(function () { var canvas3d = document.getElementById('3dcanvas'); $('#edit').on('click', function() { - console.log("asdasdasdf"); + document.removeEventListener('mousemove', world.onMouseMove, false); + document.removeEventListener('mousedown',world.onMouseDown,false); + document.removeEventListener('mouseup',world.onMouseUp,false); + document.removeEventListener('click', world.onDelete, false); if(canvas2d.style.display == "none") { canvas2d.style.display = 'block'; canvas3d.style.display = 'none'; @@ -59,16 +68,41 @@ $(document).ready(function () { }); $('#translate').on('click', function() { + world.isRotating = false; + var canvas2d = document.getElementById('2dcanvas'); + var canvas3d = document.getElementById('3dcanvas'); + canvas2d.style.display == 'none'; + canvas3d.style.display = 'block'; + document.addEventListener('mousemove', world.onMouseMove, false); + + document.removeEventListener('mousedown',world.onMouseDownRotate,false); + document.addEventListener('mousedown',world.onMouseDownTranslate,false); + document.addEventListener('mouseup',world.onMouseUp,false); + document.removeEventListener('click', world.onDelete, false); + + + }); + + $('#rotate').on('click', function() { + world.isTranslating = false; var canvas2d = document.getElementById('2dcanvas'); var canvas3d = document.getElementById('3dcanvas'); canvas2d.style.display == 'none'; canvas3d.style.display = 'block'; - console.log(world.isDragging); document.addEventListener('mousemove', world.onMouseMove, false); - document.addEventListener('mousedown',world.onMouseDown,false); + document.removeEventListener('mousedown', world.onMouseDownTranslate, false); + document.addEventListener('mousedown',world.onMouseDownRotate,false); document.addEventListener('mouseup',world.onMouseUp,false); + document.removeEventListener('click', world.onDelete, false); + + }); + $('#delete').on('click', function(){ + document.addEventListener('mousemove', world.onMouseMove, false); + document.removeEventListener('mousedown',world.onMouseDown,false); + document.removeEventListener('mouseup',world.onMouseUp,false); + document.addEventListener('click', world.onDelete, false); }); }) diff --git a/js/sketchSingleton.js b/js/sketchSingleton.js index 09892a4..b2f8abb 100644 --- a/js/sketchSingleton.js +++ b/js/sketchSingleton.js @@ -18,34 +18,35 @@ var sketch = function () { this.minY = 0; this.dot_flag = false; this.borderVertices = []; - this.pointDistance = 400; - this.pointDistance1 = Math.sqrt(this.pointDistance); + this.pointDistance = 100; + this.pointDistance1 = Math.sqrt(self.pointDistance); //mesh points. this.borderPoints = []; this.contour = []; this.steiner = []; this.triangles = []; - this.arrayDistance = null; this.x = "black"; this.y = 2; this.proportion = {x: 0, y: 0}; this.init2d = function (p, canvas) { parent = p; - this.canvas2d = canvas;//document.getElementById('2dcanvas'); - this.ctx = this.canvas2d.getContext("2d"); - fullCanvas(this.canvas2d); - this.w = this.canvas2d.width; - this.h = this.canvas2d.height; + self.canvas2d = canvas;//document.getElementById('2dcanvas'); + self.ctx = self.canvas2d.getContext("2d"); + fullCanvas(self.canvas2d); + self.w = self.canvas2d.width; + self.h = self.canvas2d.height; - this.ctx.clearRect(0, 0, this.w, this.h); + self.ctx.clearRect(0, 0, self.w, self.h); self.borderPoints = []; self.contour = []; self.steiner = []; self.triangles = []; self.arrayDistance = null; self.borderVertices = []; - //console.log("init", this.w, this.h); + self.arrayDistance = null; + self.arrayMaxima = []; + //console.log("init", self.w, self.h); }; this.mouseMoveHandle = function (e) { @@ -61,10 +62,9 @@ var sketch = function () { }; this.mouseUpHandle = function (e) { - console.log(self.canvas2d.style.display); if(self.canvas2d.style.display != 'none') { findxy('up', e); - fillBorderBruteForce(self.maxX, self.minX, self.maxY, self.minY, self.borderVertices); + fillBorderHex(self.maxX, self.minX, self.maxY, self.minY, self.borderVertices); getMesh(); self.proportion = {x: (self.maxX - self.minX)/self.w, y: (self.maxY - self.minY)/self.h}; } @@ -75,119 +75,214 @@ var sketch = function () { }; this.draw = function () { - this.ctx.strokeStyle = "red"; - this.ctx.lineWidth = 1; - this.ctx.beginPath(); - this.ctx.moveTo(this.prevX, this.prevY); - this.ctx.lineTo(this.currX, this.currY); - this.ctx.stroke(); - this.ctx.closePath(); - this.ctx.strokeStyle = this.x; - this.ctx.lineWidth = this.y; - var distance = distance2(this.lastX, this.lastY, this.currX, this.currY); - - if (distance == this.pointDistance ) { + self.ctx.strokeStyle = "red"; + self.ctx.lineWidth = 1; + self.ctx.beginPath(); + self.ctx.moveTo(self.prevX, self.prevY); + self.ctx.lineTo(self.currX, self.currY); + self.ctx.stroke(); + self.ctx.closePath(); + self.ctx.strokeStyle = self.x; + self.ctx.lineWidth = self.y; + var distance = distance2(self.lastX, self.lastY, self.currX, self.currY); + + if (distance == self.pointDistance ) { //console.log("distance = " + distance); - this.createVertex(this.currX,this.currY); - }else if(distance > this.pointDistance){ + self.createVertex(self.currX,self.currY); + }else if(distance > self.pointDistance){ //console.log("distance > " + distance); - t = Math.sqrt(this.pointDistance / distance); - var cX = this.lastX + t*(this.currX - this.lastX); - var cY = this.lastY + t*(this.currY - this.lastY); + t = Math.sqrt(self.pointDistance / distance); + var cX = self.lastX + t*(self.currX - self.lastX); + var cY = self.lastY + t*(self.currY - self.lastY); //console.log(distance2(lastX,lastY,cX,cY)); - this.createVertex(cX, cY); + self.createVertex(cX, cY); } }; this.createVertex = function (valueX, valueY) { - this.lastX = this.currX; - this.lastY = this.currY; - if (this.lastX > this.maxX) this.maxX = this.lastX; - if (this.lastX < this.minX) this.minX = this.lastX; - if (this.lastY > this.maxY) this.maxY = this.lastY; - if (this.lastY < this.minY) this.minY = this.lastY; - var style = this.ctx.fillStyle; - this.ctx.fillStyle = "#02E020"; - this.ctx.beginPath(); - this.ctx.arc(valueX,valueY,2,0,2*Math.PI); - this.ctx.fill(); - this.ctx.fillStyle = style; + self.lastX = self.currX; + self.lastY = self.currY; + if (self.lastX > self.maxX) self.maxX = self.lastX; + if (self.lastX < self.minX) self.minX = self.lastX; + if (self.lastY > self.maxY) self.maxY = self.lastY; + if (self.lastY < self.minY) self.minY = self.lastY; + var style = self.ctx.fillStyle; + self.ctx.fillStyle = "#02E020"; + self.ctx.beginPath(); + self.ctx.arc(valueX,valueY,2,0,2*Math.PI); + self.ctx.fill(); + self.ctx.fillStyle = style; var point = [valueX,valueY]; - this.borderVertices.push(point); - this.contour.push({x:valueX, y:valueY, id:(this.contour.length+1)}); + self.borderVertices.push(point); + self.contour.push({x:valueX, y:valueY, id:(self.contour.length+1)}); }; this.getDistanceVector = function () { - //console.log("Is it here?",this.steiner, this.contour); - this.arrayDistance = new Array(this.steiner.length); - this.arrayDistance.fill(-1); - - //calculate the distance of every steiner point to all he segments on the border - for (var j = 0; j < this.steiner.length; j++) { - for (var i = 0; i < this.contour.length; i++) { - var index = (i == (this.contour.length-1)) ? 0 : i+1; - //console.log(i, index); - var distance = pointToSegment(this.contour[i], this.contour[index], this.steiner[j]); - //var distance = distance2(steiner[j].x, steiner[j].y, contour[i].x, contour[i].y) - if (this.arrayDistance[j] == - 1 || this.arrayDistance[j] > distance) { - this.arrayDistance[j] = distance; + self.arrayDistance = new Array(self.steiner.length); + + + //calculate the distance of every steiner point to all the segments on the border + for (var j = 0; j < self.steiner.length; j++) { + self.arrayDistance[j] = {d: -1, v: {x:-1, y:-1}}; + for (var i = 0; i < self.contour.length; i++) { + var index = (i == (self.contour.length-1)) ? 0 : i+1; + var distance = pointToSegmentHope(self.contour[i], self.contour[index], self.steiner[j]); + if (self.arrayDistance[j].d == - 1 || self.arrayDistance[j].d > distance.d) { + self.arrayDistance[j].d = distance.d; + self.arrayDistance[j].v = distance.vector; } }; }; //for all pS: if arrayDistance[pS.id] < pointDistance: remove pS - /**/ - this.steiner = this.steiner.filter( function (p) { - if (self.arrayDistance[p.id - 1] >= self.pointDistance) { + self.steiner = self.steiner.filter( function (point) { + if (self.arrayDistance[point.id - 1].d >= (self.pointDistance/4.0)) { return true; } else { - self.arrayDistance[p.id - 1] = -1; + self.arrayDistance[point.id - 1].d = -1; return false; } }); - for (var i = 0; i < this.steiner.length; i++) { - this.steiner[i].id = i+1+this.contour.length; + //re-index steiner points + for (var i = 0; i < self.steiner.length; i++) { + self.steiner[i].id = i+1+self.contour.length; }; - this.arrayDistance = this.arrayDistance.filter( function (d) { - return d != -1; + //remove distances belonging to removed steiner points + self.arrayDistance = self.arrayDistance.filter( function (element) { + return element.d != -1; }); + + //take the root of all distances + self.arrayDistance = self.arrayDistance.map( function (element) { + return {d: Math.sqrt(element.d), v: element.v}; + } ); + + /**/ + + for (var j = 0; j < self.steiner.length; j++) { + for (var i = 0; i < self.contour.length; i++) { + var index = (i == (self.contour.length-1)) ? 0 : i+1; + var distance = pointToSegmentHope(self.contour[i], self.contour[index], self.steiner[j]); + if (Math.abs(self.arrayDistance[j].d-Math.sqrt(distance.d)) <= 1.0*(Number.EPSILON+self.pointDistance1)) { + if (dot(self.arrayDistance[j].v.x, self.arrayDistance[j].v.y, distance.vector.x, distance.vector.y)<0.0) { + self.arrayMaxima.push(j); + break; + }; + } + }; + }; + /**/ + + //Smooth each maximum with its neighbouring maximum (that lie inside its radius of distance) + var smoothHeight = new Array(self.arrayMaxima.length); + //var tempRadius = 0; + var accumWeight = 0; + var tempWeight = 0; + var tempDist = 0; + for (var i = 0; i < self.arrayMaxima.length; i++) { + + //self height has weight 1 + accumWeight = 1.0; + smoothHeight[i] = 1.0*self.arrayDistance[self.arrayMaxima[i]].d; + //set up radius with margin of error + //tempRadius = (self.arrayDistance[self.arrayMaxima[i]].d+Number.EPSILON+self.pointDistance1); + //check neighbours + for (var j = 0; j < self.arrayMaxima.length; j++) { + //console.log("j", j); + tempDist = distance1(self.steiner[self.arrayMaxima[i]].x, self.steiner[self.arrayMaxima[i]].y, self.steiner[self.arrayMaxima[j]].x, self.steiner[self.arrayMaxima[j]].y); + if(i != j && tempDist < self.arrayDistance[self.arrayMaxima[i]].d ) {//tempRadius ) { + tempWeight = (Math.sqrt((self.arrayDistance[self.arrayMaxima[i]].d*self.arrayDistance[self.arrayMaxima[i]].d)-(tempDist*tempDist)))/self.arrayDistance[self.arrayMaxima[i]].d; + accumWeight += tempWeight; + smoothHeight[i] += tempWeight*self.arrayDistance[self.arrayMaxima[j]].d; + } + + }; + + smoothHeight[i] = smoothHeight[i]/accumWeight; + + }; + /**/ + + var smoothAll = new Array(self.arrayDistance); + var weightAll = new Array(self.arrayDistance); + for (var i = 0; i < self.arrayDistance.length; i++) { + smoothAll[i] = self.arrayDistance[i].d; + weightAll[i] = 1.0; + } + + //Now, replace maxima distances on arrayDistance by smoothed distances + for (var i = self.arrayMaxima.length - 1; i >= 0; i--) { + //console.log(self.arrayDistance[self.arrayMaxima[i]].d,"-->",smoothHeight[i]) + self.arrayDistance[self.arrayMaxima[i]].d = smoothHeight[i]; + + for (var j = 0; j < self.arrayDistance.length; j++) { + var distance = distance2(self.steiner[j].x, self.steiner[j].y, self.steiner[self.arrayMaxima[i]].x, self.steiner[self.arrayMaxima[i]].y); + if (j != self.arrayMaxima[i] && distance < (self.arrayDistance[self.arrayMaxima[i]].d*self.arrayDistance[self.arrayMaxima[i]].d) ) { + + if (self.arrayDistance[j].d < self.arrayDistance[self.arrayMaxima[i]].d) { + smoothAll[j] += Math.sqrt((2.0*self.arrayDistance[self.arrayMaxima[i]].d*self.arrayDistance[j].d)-(self.arrayDistance[j].d*self.arrayDistance[j].d)); + weightAll[j] += 1.0; + } else{ + smoothAll[j] += self.arrayDistance[self.arrayMaxima[i]].d; + weightAll[j] += 1.0; + }; + + } + }; + + }; + /**/ + + //inflation smoothing + for (var i = 0; i < self.arrayDistance.length; i++) { + self.arrayDistance[i].d = smoothAll[i]/weightAll[i]; + if (Number.isNaN(self.arrayDistance[i].d)) { + self.arrayDistance[i].d = 0.0; + }; + }; /**/ - var aD1 = this.arrayDistance.map (function (p) { - return p; - }); - //console.log("ArrayDistance1:",aD1); }; - this.debugInflate = function () { + self.debugInflate = function () { var maxDistance = 0; var minDistance = -1; - this.arrayDistance.map( function (d) { - if (d > maxDistance) { - maxDistance = d; + self.arrayDistance.map( function (d) { + if (d.d > maxDistance) { + maxDistance = d.d; }; - if (minDistance == -1 || minDistance > d) { - minDistance = d; + if (minDistance == -1 || minDistance > d.d) { + minDistance = d.d; }; }); maxDistance = maxDistance - minDistance; - var normalArrayDistance = this.arrayDistance.map( function (d) { - return (d - minDistance) / maxDistance; + var normalArrayDistance = self.arrayDistance.map( function (d) { + return (d.d - minDistance) / maxDistance; }); //console.log(normalArrayDistance); - var style = this.ctx.fillStyle; + var style = self.ctx.fillStyle; normalArrayDistance.map( function (d, i) { var value = parseInt(d*255); //console.log(value); self.ctx.beginPath(); self.ctx.arc( self.steiner[i].x, self.steiner[i].y, self.pointDistance1/2.0, 0, 2*Math.PI); + //self.ctx.arc( self.steiner[i].x, self.steiner[i].y, 2.0, 0, 2*Math.PI); self.ctx.fillStyle = "rgb("+value+","+value+","+value+")"; self.ctx.fill(); } ); + + for (var i = 0; i < self.arrayMaxima.length; i++) { + var style = self.ctx.fillStyle; + self.ctx.fillStyle = "#FF00FF"; + self.ctx.beginPath(); + self.ctx.arc(self.steiner[self.arrayMaxima[i]].x,self.steiner[self.arrayMaxima[i]].y,6,0,2*Math.PI); + self.ctx.fill(); + self.ctx.fillStyle = style; + }; }; function findxy (res, e) { @@ -259,12 +354,75 @@ var sketch = function () { if (odd) { fillPoints.push(point); self.steiner.push({x: i, y: j, id: (self.steiner.length + 1)}); - var style = self.ctx.fillStyle; - self.ctx.fillStyle = "#00F0A0"; + } + } + } + + return fillPoints; + }; + + function fillBorderHex (maxPointX,minPointX, maxPointY,minPointY , borderVertices) { + + smoothContour(); + + var odd = false; + var fillPoints = []; + var upMove = Math.sqrt(3)*self.pointDistance1; + for (var i = minPointX - self.pointDistance1; i < maxPointX; i+= self.pointDistance1) { + var style = self.ctx.fillStyle; + self.ctx.fillStyle = "#E0A000"; + self.ctx.beginPath(); + self.ctx.arc(i,minPointY-2*self.pointDistance1,2,0,2*Math.PI); + self.ctx.fill(); + self.ctx.fillStyle = style; + for (var j = minPointY - self.pointDistance1; j < maxPointY; j+= upMove) { + odd = false;//test number os crossings with edge for the segment tha goes: + var point = [i,j];//from the current point... + var lastpoint = [i,minPointY-2*self.pointDistance1];//to the first one on self column. + + for (var k = 0; k < borderVertices.length ; k ++){ + var a = (k+1) % borderVertices.length; + var intersected = intersect(borderVertices[k][0],borderVertices[k][1], + borderVertices[a][0],borderVertices[a][1], + lastpoint[0],lastpoint[1], + point[0],point[1]); + if(intersected) { + odd = !odd; + } + } + + if (odd) { + fillPoints.push(point); + self.steiner.push({x: i, y: j, id: (self.steiner.length + 1)}); + } + } + } + for (var i = minPointX - (self.pointDistance1/2.0); i < maxPointX; i+= self.pointDistance1) { + var style = self.ctx.fillStyle; + self.ctx.fillStyle = "#E0A000"; self.ctx.beginPath(); - self.ctx.arc(point[0],point[1],2,0,2*Math.PI); + self.ctx.arc(i,minPointY-2*self.pointDistance1,2,0,2*Math.PI); self.ctx.fill(); self.ctx.fillStyle = style; + for (var j = minPointY - self.pointDistance1 + (upMove/2.0); j < maxPointY; j+= upMove) { + odd = false;//test number os crossings with edge for the segment tha goes: + var point = [i,j];//from the current point... + var lastpoint = [i,minPointY-2*self.pointDistance1];//to the first one on self column. + + for (var k = 0; k < borderVertices.length ; k ++){ + var a = (k+1) % borderVertices.length; + var intersected = intersect(borderVertices[k][0],borderVertices[k][1], + borderVertices[a][0],borderVertices[a][1], + lastpoint[0],lastpoint[1], + point[0],point[1]); + if(intersected) { + odd = !odd; + } + } + + if (odd) { + fillPoints.push(point); + self.steiner.push({x: i, y: j, id: (self.steiner.length + 1)}); } } } @@ -272,53 +430,161 @@ var sketch = function () { return fillPoints; }; + function smoothContour() { + var smoothContour = new Array(self.contour.length); + var next = 0; + var prev = 0; + for (var i = 0; i < self.contour.length; i++) { + next = (i == (self.contour.length-1)) ? 0 : i+1; + prev = (i == 0) ? (self.contour.length-1) : i-1; + smoothContour[i] = (self.contour[i]+self.contour[next]+self.contour[prev])/3.0; + }; + } + + function smoothSteiner() { + //smooth mesh with neighbour structures + var smoothSteiner = new Array(self.steiner); + var weightSteiner = new Array(self.steiner); + for (var i = 0; i < self.arrayDistance.length; i++) { + smoothSteiner[i] = self.arrayDistance[i].d; + weightSteiner[i] = 1.0; + }; + + var cl = self.contour.length; + var sl = self.steiner.length; + + for (var i = 0; i < self.triangles.length; i++) { + var verts = self.triangles[i].getPoints(); + if (verts[0].id > cl) { + smoothSteiner[verts[0].id-cl-1] += (verts[1].id > cl) ? self.arrayDistance[verts[1].id-cl-1].d : 0.0; + smoothSteiner[verts[0].id-cl-1] += (verts[2].id > cl) ? self.arrayDistance[verts[2].id-cl-1].d : 0.0; + weightSteiner[verts[0].id-cl-1] += 2.0; + }; + if (verts[1].id > cl) { + smoothSteiner[verts[1].id-cl-1] += (verts[0].id > cl) ? self.arrayDistance[verts[0].id-cl-1].d : 0.0; + smoothSteiner[verts[1].id-cl-1] += (verts[2].id > cl) ? self.arrayDistance[verts[2].id-cl-1].d : 0.0; + weightSteiner[verts[1].id-cl-1] += 2.0; + }; + if (verts[2].id > cl) { + smoothSteiner[verts[2].id-cl-1] += (verts[1].id > cl) ? self.arrayDistance[verts[1].id-cl-1].d : 0.0; + smoothSteiner[verts[2].id-cl-1] += (verts[0].id > cl) ? self.arrayDistance[verts[0].id-cl-1].d : 0.0; + weightSteiner[verts[2].id-cl-1] += 2.0; + }; + }; + + for (var i = 0; i < self.arrayDistance.length; i++) { + self.arrayDistance[i].d = smoothSteiner[i]/weightSteiner[i]; + if (Number.isNaN(self.arrayDistance[i].d)) { + self.arrayDistance[i].d = 0.0; + }; + }; + + //console.log("arrayDistance: ", self.arrayDistance) + //console.log(smoothSteiner, weightSteiner); + }; + + function smoothMesh() { + //smooth mesh with neighbour structures + var smoothSteiner = new Array(self.steiner); + var weightSteiner = new Array(self.steiner); + for (var i = 0; i < self.arrayDistance.length; i++) { + smoothSteiner[i] = self.arrayDistance[i].d; + weightSteiner[i] = 1.0; + }; + + var smoothContour = new Array(self.contour.length); + var weightContour = new Array(self.contour.length); + for (var i = 0; i < self.contour.length; i++) { + smoothContour[i] = {x: self.contour[i].x, y: self.contour[i].y}; + weightContour[i] = 1.0; + }; + + var cl = self.contour.length; + var sl = self.steiner.length; + + for (var i = 0; i < self.triangles.length; i++) { + var verts = self.triangles[i].getPoints(); + if (verts[0].id > cl) { + smoothSteiner[verts[0].id-cl-1] += (verts[1].id > cl) ? self.arrayDistance[verts[1].id-cl-1].d : 0.0; + smoothSteiner[verts[0].id-cl-1] += (verts[2].id > cl) ? self.arrayDistance[verts[2].id-cl-1].d : 0.0; + weightSteiner[verts[0].id-cl-1] += 2.0; + } else { + smoothContour[verts[0].id-1].x += (verts[1].id > cl) ? self.steiner[verts[1].id-cl-1].x : self.contour[verts[1].id-1].x; + smoothContour[verts[0].id-1].y += (verts[1].id > cl) ? self.steiner[verts[1].id-cl-1].y : self.contour[verts[1].id-1].y; + smoothContour[verts[0].id-1].x += (verts[2].id > cl) ? self.steiner[verts[2].id-cl-1].x : self.contour[verts[2].id-1].x; + smoothContour[verts[0].id-1].y += (verts[2].id > cl) ? self.steiner[verts[2].id-cl-1].y : self.contour[verts[2].id-1].y; + weightContour += 2.0; + }; + if (verts[1].id > cl) { + smoothSteiner[verts[1].id-cl-1] += (verts[0].id > cl) ? self.arrayDistance[verts[0].id-cl-1].d : 0.0; + smoothSteiner[verts[1].id-cl-1] += (verts[2].id > cl) ? self.arrayDistance[verts[2].id-cl-1].d : 0.0; + weightSteiner[verts[1].id-cl-1] += 2.0; + } else { + smoothContour[verts[1].id-1].x += (verts[0].id > cl) ? self.steiner[verts[0].id-cl-1].x : self.contour[verts[0].id-1].x; + smoothContour[verts[1].id-1].y += (verts[0].id > cl) ? self.steiner[verts[0].id-cl-1].y : self.contour[verts[0].id-1].y; + smoothContour[verts[1].id-1].x += (verts[2].id > cl) ? self.steiner[verts[2].id-cl-1].x : self.contour[verts[2].id-1].x; + smoothContour[verts[1].id-1].y += (verts[2].id > cl) ? self.steiner[verts[2].id-cl-1].y : self.contour[verts[2].id-1].y; + weightContour += 2.0; + }; + if (verts[2].id > cl) { + smoothSteiner[verts[2].id-cl-1] += (verts[1].id > cl) ? self.arrayDistance[verts[1].id-cl-1].d : 0.0; + smoothSteiner[verts[2].id-cl-1] += (verts[0].id > cl) ? self.arrayDistance[verts[0].id-cl-1].d : 0.0; + weightSteiner[verts[2].id-cl-1] += 2.0; + + } else { + smoothContour[verts[2].id-1].x += (verts[0].id > cl) ? self.steiner[verts[0].id-cl-1].x : self.contour[verts[0].id-1].x; + smoothContour[verts[2].id-1].y += (verts[0].id > cl) ? self.steiner[verts[0].id-cl-1].y : self.contour[verts[0].id-1].y; + smoothContour[verts[2].id-1].x += (verts[1].id > cl) ? self.steiner[verts[1].id-cl-1].x : self.contour[verts[1].id-1].x; + smoothContour[verts[2].id-1].y += (verts[1].id > cl) ? self.steiner[verts[1].id-cl-1].y : self.contour[verts[1].id-1].y; + weightContour += 2.0; + }; + }; + + for (var i = 0; i < self.arrayDistance.length; i++) { + self.arrayDistance[i].d = smoothSteiner[i]/weightSteiner[i]; + if (Number.isNaN(self.arrayDistance[i].d)) { + self.arrayDistance[i].d = 0.0; + }; + }; + + for (var i = 0; i < self.contour.length; i++) { + var tempX = self.contour[i].x; + var tempY = self.contour[i].y; + self.contour[i].x = smoothContour[i].x/weightContour[i]; + self.contour[i].y = smoothContour[i].y/weightContour[i]; + if (Number.isNaN(self.contour[i].x) || !Number.isFinite(self.contour[i].x)) { + if (Number.isNaN(tempX) || !Number.isFinite(tempY)) { + self.contour[i].x = 0.0; + } else { + self.contour[i].x = tempX; + } + }; + if (Number.isNaN(self.contour[i].y) || !Number.isFinite(self.contour[i].y)) { + if (Number.isNaN(tempY) || !Number.isFinite(tempY)) { + self.contour[i].y = 0.0; + } else { + self.contour[i].y = tempY; + } + }; + }; + }; + function getMesh () { self.getDistanceVector(); + var swctx = new poly2tri.SweepContext(self.contour); swctx.addPoints(self.steiner); swctx.triangulate(); self.triangles = swctx.getTriangles(); - self.triangles.forEach(function(t) { - //console.log("Triangle: "); - t.getPoints().forEach(function(p) { - //console.log(p.x,p.y,p.id); - }); - //console.log("X"); - //draw tri - self.ctx.beginPath(); - self.ctx.moveTo(t.getPoint(0).x, t.getPoint(0).y); - self.ctx.lineTo(t.getPoint(1).x, t.getPoint(1).y); - self.ctx.lineTo(t.getPoint(2).x, t.getPoint(2).y); - self.ctx.closePath(); - self.ctx.stroke(); - }); - //DEBUG START - /**/ - var allPoints = new Array(self.contour.length+self.steiner.length); - allPoints.fill(-1); - self.triangles.forEach(function(t) { - t.getPoints().forEach(function(p) { - allPoints[p.id-1] = {x: p.x, y:p.y, id:p.id}; - }); - }); - //console.log("All Points:"); - for (var i = 0; i < allPoints.length; i++) { - //console.log(allPoints[i].x, allPoints[i].y, allPoints[i].id); - }; - //console.log("Contour"); - for (var i = 0; i < self.contour.length; i++) { - //console.log(self.contour[i].x, self.contour[i].y, self.contour[i].id); - }; - //console.log("Steiner"); - for (var i = 0; i < self.steiner.length; i++) { - //console.log(self.steiner[i].x, self.steiner[i].y, self.steiner[i].id); - }; - /**/ - //DEBUG END - - self.debugInflate(); + smoothSteiner(); + smoothContour(); + smoothSteiner(); + smoothContour(); + smoothSteiner(); + smoothContour(); + }; } diff --git a/js/utils.js b/js/utils.js index 749bf3b..c06d29a 100644 --- a/js/utils.js +++ b/js/utils.js @@ -16,6 +16,10 @@ function distance2 (aX, aY, bX, bY){ return (aX - bX)*(aX - bX) + (aY - bY)*(aY - bY); } +function distance1 (aX, aY, bX, bY){ + return Math.sqrt(distance2(aX, aY, bX, bY)); +} + function ccw (aX, aY, bX, bY, cX, cY) { return (cY-aY)*(bX-aX) > (bY-aY)*(cX-aX); } @@ -27,9 +31,13 @@ function intersect (aX, aY, bX, bY, cX, cY,dX, dY) { } function pointToSegment (a, b, p) { + //vector from p to a var vecP = [p.x-a.x, p.y-a.y]; + //vector from p to b var vecR = [b.x-a.x, b.y-a.y]; + //Length of vecR var lenVecR = Math.sqrt(vecR[0]*vecR[0]+vecR[1]*vecR[1]); + //Length of vecP projection onto vecR var lenProj = vecP[0]*(vecR[0]/lenVecR) + vecP[1]*(vecR[1]/lenVecR); if (lenProj <= 0) { //closer to a return distance2(p.x,p.y,a.x,a.y); @@ -40,6 +48,32 @@ function pointToSegment (a, b, p) { } } +function pointToSegmentHope (a, b, p) { + var vecP = [p.x-a.x, p.y-a.y]; + var vecR = [b.x-a.x, b.y-a.y]; + var lenVecR = Math.sqrt(vecR[0]*vecR[0]+vecR[1]*vecR[1]); + var lenProj = vecP[0]*(vecR[0]/lenVecR) + vecP[1]*(vecR[1]/lenVecR); + if (lenProj <= 0) { //closer to a + return {d: distance2(p.x,p.y,a.x,a.y), vector: {x: a.x-p.x, y: a.y-p.y}}; + } else if (lenProj >= lenVecR) { //closer to b + return {d: distance2(p.x,p.y,b.x,b.y), vector: {x: b.x-p.x, y: b.y-p.y}}; + } else {//projection lies inside projection + return {d: distance2(p.x, p.y, a.x+(lenProj*vecR[0]/lenVecR), a.y+(lenProj*vecR[1]/lenVecR)), + vector: { + x: a.x+(lenProj*vecR[0]/lenVecR)-p.x, + y: a.y+(lenProj*vecR[1]/lenVecR)-p.y + } + }; + } +} + +function normalizedProjectionLength (ax,ay,bx,by) { + var p = dot(ax,ay,bx,by); + p = p/distance1(ax,ay,0,0); + p = p/distance1(bx,by,0,0); + return p; +} + function findIntersection (aX, aY, bX, bY, cX, cY,dX, dY) { var a1 = aX - bX; var b1 = aY - bY; @@ -54,4 +88,37 @@ function findIntersection (aX, aY, bX, bY, cX, cY,dX, dY) { var y = (c1*b2 - b1*c2)/det; return [x, y] +} + +function dot (ax, ay, bx, by) { + return (ax*bx)+(ay*by); +} + +function bSearch (array, value) { + var l = array.length; + if (array[0] > value || array[l] < value) { + return false; + } + else if (array[0] == value || array[l] == value) + { + return true; + } + var curr = Math.floor(array.length/2.0); + var down = 0; + var up = l; + var prev = -1; + while(curr != prev) { + if (array[curr] == value) { + return true; + } else if (array[curr] < value){ + prev = curr; + down = curr; + curr = Math.floor((curr+up)/2.0); + } else if (array[curr] > value) { + prev = curr; + up = curr; + curr = Math.floor((curr+down)/2.0); + } + } + return false; } \ No newline at end of file diff --git a/js/world.js b/js/world.js index 9a06756..68cd113 100644 --- a/js/world.js +++ b/js/world.js @@ -1,5 +1,5 @@ var world = new function() { - var scene, camera, renderer, parent, plane; + var scene, camera, renderer, parent, plane, obj; var objects = new Array(); var raycaster = new THREE.Raycaster(); var mouse = new THREE.Vector2(); @@ -7,55 +7,69 @@ var world = new function() { var size = { w: window.innerWidth, h:window.innerHeight}; var self = this; this.isDragging = false; + this.isRotating = false; this.canvas3d = null; + var initialRotationVector = new THREE.Vector3(); + var finalRotationVector = new THREE.Vector3(); var intersects = null; - var offset = new THREE.Vector3(); + var cameraOffset = new THREE.Vector3(0,0,2); + var translateOffset = new THREE.Vector3(); var selected = {obj: null, p: null}; this.proportion = {y : 0, w: 0, h: 0}; + this.init3d = function (p, canvas) { parent = p; - this.canvas3d = canvas;//document.getElementById('3dcanvas'); + this.canvas3d = canvas; + fullCanvas(this.canvas3d); - console.log(this.canvas3d.width); this.canvas3d.width -= $('#3dcanvas').offset().left; - console.log(this.canvas3d.width); + size = { w: this.canvas3d.width, h:this.canvas3d.height}; + scene = new THREE.Scene(); + obj = new THREE.Object3D; + scene.add(obj); + camera = new THREE.PerspectiveCamera( 75, this.canvas3d.width/this.canvas3d.height, 0.1, 1000 ); - //camera = new THREE.OrthographicCamera( this.canvas3d.width / - 2, this.canvas3d.width / 2, this.canvas3d.height / 2, this.canvas3d.height / - 2, 1, 1000 ); renderer = new THREE.WebGLRenderer({canvas: this.canvas3d}); renderer.setSize( this.canvas3d.width, this.canvas3d.height ); - camera.position.x = 0; - camera.position.y = 0; - camera.position.z = 2; + camera.position.copy(cameraOffset); + camera.lookAt(new THREE.Vector3(0,0,0)); //create lighting - var light1 = new THREE.PointLight( 0xffefef, 1, 100 ); + var light1 = new THREE.PointLight( 0xffefef, 0.5, 100 ); light1.position.set( 15, 15, 15 ); scene.add( light1 ); - var light2 = new THREE.PointLight( 0xefefff, 1, 100 ); + var light2 = new THREE.PointLight( 0xefefff, 0.5, 100 ); light2.position.set( -15, 15, 15 ); scene.add( light2 ); - plane = new THREE.Mesh(new THREE.PlaneBufferGeometry(2, 2,8,8), new THREE.MeshBasicMaterial({color: 0xffffff, + //Plane used for translation + plane = new THREE.Mesh(new THREE.PlaneBufferGeometry(this.canvas3d.width, this.canvas3d.height,8,8), new THREE.MeshBasicMaterial({color: 0xff0000, transparent: true, opacity: 0})); + //plane = new THREE.Mesh(new THREE.PlaneBufferGeometry(1.0, 1.0,8,8), new THREE.MeshBasicMaterial({color: 0xff0000, + // transparent: true, opacity: 0.5})); scene.add(plane); plane.position.set(size.w,size.h,0); plane.visible = true; + //control state variables + self.isDragging = false; + self.isRotating = false; + render(); } this.buildObject = function (contour, steiner, arrayDistance, triangles) { + //var material = new THREE.MeshDepthMaterial(); + //var material = new THREE.MeshBasicMaterial({ color: 0xdddddd, wireframe: true, side: THREE.DoubleSide}); var material = new THREE.MeshPhongMaterial( { color: 0xdddddd, specular: 0xffffff, shininess: 10, shading: THREE.SmoothShading, side: THREE.DoubleSide } ); var geometry = new THREE.Geometry(); //create common contour - //console.log("Vertices:"); for (var i = 0; i < contour.length; i++) { - //console.log(contour[i].x, contour[i].y, 0); geometry.vertices.push( new THREE.Vector3( contour[i].x, contour[i].y, 0 ) ); @@ -63,87 +77,80 @@ var world = new function() { //create front vertices for (var i = 0; i < steiner.length; i++) { - //console.log(steiner[i].x, steiner[i].y, arrayDistance[i]); geometry.vertices.push( - new THREE.Vector3( steiner[i].x, steiner[i].y, Math.sqrt(arrayDistance[i]) ) + new THREE.Vector3( steiner[i].x, steiner[i].y,arrayDistance[i].d ) ); }; //create back vertices for (var i = 0; i < steiner.length; i++) { - //console.log(steiner[i].x, steiner[i].y, arrayDistance[i]); geometry.vertices.push( - new THREE.Vector3( steiner[i].x, steiner[i].y, -1.0*Math.sqrt(arrayDistance[i]) ) + new THREE.Vector3( steiner[i].x, steiner[i].y, -1.0*arrayDistance[i].d ) ); }; - //console.log("Faces"); + //create faces var cl = contour.length; var sl = steiner.length; for (var i = 0; i < triangles.length; i++) { - //console.log(triangles[i].getPoint(0).id, triangles[i].getPoint(1).id, triangles[i].getPoint(2).id); //create front faces geometry.faces.push( new THREE.Face3( triangles[i].getPoint(0).id-1, triangles[i].getPoint(1).id-1, triangles[i].getPoint(2).id-1 ) ); //create back faces - var a = ((triangles[i].getPoint(0).id-1)>=cl)?(triangles[i].getPoint(0).id-1+sl):(triangles[i].getPoint(0).id-1); + //var a = ((triangles[i].getPoint(0).id-1)>=cl)?(triangles[i].getPoint(0).id-1+sl):(triangles[i].getPoint(0).id-1); + //var b = ((triangles[i].getPoint(1).id-1)>=cl)?(triangles[i].getPoint(1).id-1+sl):(triangles[i].getPoint(1).id-1); + //var c = ((triangles[i].getPoint(2).id-1)>=cl)?(triangles[i].getPoint(2).id-1+sl):(triangles[i].getPoint(2).id-1); + var a = ((triangles[i].getPoint(2).id-1)>=cl)?(triangles[i].getPoint(2).id-1+sl):(triangles[i].getPoint(2).id-1); var b = ((triangles[i].getPoint(1).id-1)>=cl)?(triangles[i].getPoint(1).id-1+sl):(triangles[i].getPoint(1).id-1); - var c = ((triangles[i].getPoint(2).id-1)>=cl)?(triangles[i].getPoint(2).id-1+sl):(triangles[i].getPoint(2).id-1); - //console.log(a, b, c); + var c = ((triangles[i].getPoint(0).id-1)>=cl)?(triangles[i].getPoint(0).id-1+sl):(triangles[i].getPoint(0).id-1); + geometry.faces.push( new THREE.Face3( a, b, c ) ); }; - //To set model in [-1,1] sphere - //geometry.normalize(); - var rad = 75.0 * Math.PI/180; - var width_scene = 2 * ((1.0/Math.abs(Math.tan(rad/2.0)))+ 0.1)/(1.0/Math.abs(Math.tan(rad/2.0))); - console.log(width_scene, Math.tan(rad/2.0)); - /*var scale_y = self.proportion.y * width_scene;*/ - var scale_y = width_scene/self.proportion.h; - geometry.translate(- self.proportion.w/2.0, -self.proportion.h/2.0, 0); - geometry.scale(scale_y, -scale_y, scale_y); - var plane2 = new THREE.Mesh(new THREE.PlaneBufferGeometry(width_scene*this.canvas3d.width/this.canvas3d.height, this.canvas3d.width/this.canvas3d.height), new THREE.MeshBasicMaterial({color: 0xff0000, - transparent: false, opacity: 1})); - objects.push(plane2); - //geometry.normalize(); - //console.log("Normalized"); - //for (var i = 0; i < geometry.vertices.length; i++) { - // console.log(geometry.vertices[i]); - //}; - - //correct - //geometry.scale(1.0,-1.0,1.0); - + //Add sketches proportional to their size + geometry.normalize(); + geometry.scale(self.proportion.y, -self.proportion.y, self.proportion.y); + + geometry = dumbSmoothGeometry(geometry); + geometry = dumbSmoothGeometry(geometry); + geometry = dumbSmoothGeometry(geometry); + + //dumbSmoothGeometry(geometry); + //dumbSmoothGeometry(geometry); + //dumbSmoothGeometry(geometry); + + geometry.verticesNeedUpdate = true; + //So as to allow smooth shading + geometry.computeFaceNormals(); geometry.computeVertexNormals(); - //Dunno + //Bounding sphere geometry.computeBoundingSphere(); var object = new THREE.Mesh( geometry, material ); - //scene.add( object ); objects.push(object); - }; var render = function () { requestAnimationFrame( render ); - if (objects) { for (var i = objects.length - 1; i >= 0; i--) { - //objects[i].rotation.y += 0.05; scene.add(objects[i]); } - //object.rotation.y = 0.05; } - - //cube.rotation.x += 0.1; - //cube.rotation.y += 0.1; - + //var axis = new THREE.Vector3(1,0,0); + //scene.rotateOnAxis(axis, 0.01); + //cameraOffset.normalize().applyAxisAngle(axis, 0.01).setLength(cameraOffset.length()); + //camera.up.applyAxisAngle(axis, 0.01); + //camera.position.copy(cameraOffset); + //camera.lookAt(new THREE.Vector3(0,0,0)); + //console.log("Camera: ", cameraOffset); + renderer.render(scene, camera); }; @@ -152,52 +159,175 @@ var world = new function() { mouse.y = -((e.clientY - self.canvas3d.offsetTop) / size.h) * 2 + 1; var deltaMove = {x: e.clientX - previousMousePosition.x, y: e.clientY - previousMousePosition.y}; + + raycaster.setFromCamera(mouse,camera); + if(self.isDragging) { - raycaster.setFromCamera(mouse,camera); - var intersect = raycaster.intersectObject(plane); - var translateVector = new THREE.Vector3(); - translateVector.subVectors(intersect[0].point, selected.p); - selected.obj.translateX(translateVector.x).translateY(translateVector.y).translateZ(translateVector.z); - selected.p = intersect[0].point; - console.log(translateVector,intersect[0].point, selected.p); + // Intersect with plane + var intersectPlane = raycaster.intersectObject(plane); + // Based on offset calculated on onMouseDownTranslate, change object position + selected.obj.position.copy(intersectPlane[0].point.sub(translateOffset)); + } else { + //If not translating, keep updating plane to first hit object center, facing camera + var intersects = raycaster.intersectObjects(objects); + if (intersects.length > 0) { + plane.position.copy(intersects[0].object.position); + var at = new THREE.Vector3(); + //this three version implements a .lookAt that looks at a direction + //from the object's origin (o) to the parameter passed (p): p - o + //so, we add the object's position (o) to make lookAt look at p + at.copy(camera.position).add(plane.position); + //var rot = new THREE.Matrix4(); + //rot.getInverse(rot.clone().makeRotationFromQuaternion(scene.quaternion.clone())); + //at.applyMatrix4(rot); + plane.lookAt(at); + } } - if(!self.isDragging) { - var deltaRotationQuaternion = new THREE.Quaternion() - .setFromEuler(new THREE.Euler( - toRadians(deltaMove.y * 1), - toRadians(deltaMove.x * 1), - 0, - 'XYZ' - )); - var object = intersects[0]; - object.quaternion.multiplyQuaternions(deltaRotationQuaternion, object.quaternion); + if(self.isRotating) { + //trackball rotation + finalRotationVector = projectOnSphere(mouse.x, mouse.y, 1.0); + var dot = initialRotationVector.dot(finalRotationVector); + var angle = ( dot <=1 ) ? Math.acos(dot) : 0.0; + var axis = initialRotationVector.clone(); + axis.cross(finalRotationVector); + if (axis.length() != 0) { + axis.normalize(); + }; + axis.transformDirection(new THREE.Matrix4().getInverse( + new THREE.Matrix4().multiplyMatrices( + camera.matrixWorldInverse, scene.matrix + ) + )); + //scene.rotateOnAxis(axis, 0.01); + + var offsetLength = cameraOffset.length(); + cameraOffset.normalize().applyAxisAngle(axis.negate(), angle).setLength(offsetLength); + camera.position.copy(cameraOffset); + camera.lookAt(new THREE.Vector3(0,0,0)); + + initialRotationVector = finalRotationVector.clone(); } - previousMousePosition = { x: event.clientX, y: event.clientY}; + previousMousePosition = { x: e.clientX, y: e.clientY}; } - this.onMouseDown = function(e) { - console.log('entrei'); - + this.onMouseDownTranslate = function(e) { raycaster.setFromCamera(mouse,camera); - var abelha = raycaster.intersectObjects(objects); - //{ distance, point, face, faceIndex, indices, object } - selected.obj = abelha[0].object; - selected.p = abelha[0].point; + var intersection = raycaster.intersectObjects(objects); + if (intersection.length > 0) { + //{ distance, point, face, faceIndex, indices, object } + selected.obj = intersection[0].object; + selected.p = intersection[0].point; - console.log( abelha, selected.obj, camera, mouse); - - var vector = new THREE.Vector3(0,0,20); - plane.position.copy(selected.p); - plane.lookAt(plane.position.x, plane.position.y, 100); - self.isDragging = true; + var intersectPlane = raycaster.intersectObject(plane); + translateOffset.copy(intersectPlane[0].point).sub(plane.position); + self.isDragging = true; + }; + } + + this.onMouseDownRotate = function(e) { + initialRotationVector = projectOnSphere(mouse.x, mouse.y, 1.0); + console.log("init Rot ", initialRotationVector); + self.isRotating = true; + } + + function projectOnSphere ( x, y, radius ) { + var projection = new THREE.Vector3(x,y,0); + var projectionLength = projection.length(); + if (projectionLength <= radius) { + projection.z = Math.sqrt(1 - projectionLength); + projection.normalize(); + } else{ + projection.normalize(); + } + return projection; } this.onMouseUp = function(e) { self.isDragging = false; - } + self.isRotating = false; + } + + this.onDelete = function(e) { + raycaster.setFromCamera(mouse,camera); + var intersec_delete = raycaster.intersectObjects(objects); + if(intersec_delete.length > 0) { + //console.log(intersec_delete); + for(var i = 0; i < objects.length; i++ ){ + if(intersec_delete[0].object.id == objects[i].id){ + //console.log('entrei'); + objects.splice(i,1); + scene.remove(intersec_delete[0].object); + } + } + //console.log(objects); + render(); + } + } + function toRadians (degrees) { return degrees * (Math.PI/180); } + function dumbSmoothGeometry (geom) { + var smoothing = new Array(geom.vertices.length); + /**/ + var weights = new Array(geom.vertices.length); + for (var i = 0; i < smoothing.length; i++) { + smoothing[i] = geom.vertices[i].clone(); + weights[i] = 1.0; + }; + + var tri = 0; + for (var i = 0; i < geom.faces.length; i++) { + tri = geom.faces[i].clone(); + + smoothing[tri.a].add(geom.vertices[tri.b]).add(geom.vertices[tri.c]); + smoothing[tri.b].add(geom.vertices[tri.a]).add(geom.vertices[tri.c]); + smoothing[tri.c].add(geom.vertices[tri.a]).add(geom.vertices[tri.b]); + + weights[tri.a] += 2.0; + weights[tri.b] += 2.0; + weights[tri.c] += 2.0; + }; + + for (var i = 0; i < smoothing.length; i++) { + //console.log(weights[i], " & ", smoothing[i]); + smoothing[i] = smoothing[i].divideScalar(weights[i]); + geom.vertices[i] = smoothing[i].clone(); + }; + + return geom; + /**/ + /** + for (var i = 0; i < geom.vertices.length; i++) { + smoothing[i] = geom.vertices[i].clone(); + }; + + + + for (var i = 0; i < smoothing.length; i++) { + geom.vertices[i] = smoothing[i].clone(); + }; + + return geom; + /**/ + } + + function catmullClarkSubdiv (geom) { + //face points + var faceP = new Array(geom.faces.length); + + var tri = 0; + for (var i = 0; i < geom.faces.length; i++) { + tri = geom.faces[i].clone(); + faceP[i] = geom.vertices[tri.a] + .clone() + .add(geom.vertices[tri.b]) + .add(geom.vertices[tri.c]) + .divideScalar(3.0); + + }; + } + }