package com.akjava.gwt.three.client.java.geometry; import java.util.List; import com.akjava.gwt.lib.client.JavaScriptUtils; import com.akjava.gwt.lib.client.LogUtils; import com.akjava.gwt.three.client.java.ThreeLog; import com.akjava.gwt.three.client.js.THREE; import com.akjava.gwt.three.client.js.core.Face3; import com.akjava.gwt.three.client.js.core.Geometry; import com.akjava.gwt.three.client.js.math.Vector2; import com.akjava.gwt.three.client.js.math.Vector3; import com.google.gwt.core.client.JsArray; /** * basically designed doubleside and connected * @author aki * */ public class PointsToGeometry { double tickUv=0.01;//Texture area /* * left-top is center area.bottom edge is top.right edge is left * */ //double tickUv=0.25;//for debug /* * hand make geometry * * UV is totall broken so far */ private double uBase=1.0; private int slicesPlus; double vBase; int stacks; private Vector3 normal; private boolean debug=false; private boolean reverseFirstSurface;//if true looks like box private boolean edge=false;//testing edge not so good than expected public Vector3 getVertexNormal() { return normal; } public void setVertexNormal(Vector3 normal) { this.normal = normal; } public PointsToGeometry vertexNormal(Vector3 normal){ this.normal = normal; return this; } /* * on default this geometry front & back normal is same * * if value is true flip baskside normal as basic-box * */ public PointsToGeometry reverseFirstSurface(boolean value){ this.reverseFirstSurface=value; return this; } private boolean flipNormal; public PointsToGeometry flipNormal(boolean value){ this.flipNormal=value; return this; } public PointsToGeometry debug(boolean value){ this.debug=value; return this; } private Vector2 getUv(int u,int v){ return THREE.Vector2( (double)u / slicesPlus*uBase, (double)v / stacks *vBase); } /* * not thread safe */ public Geometry createGeometry(List<Vector3> points,int slices,double thick,boolean connectHorizontal){ if(thick==0){ LogUtils.log("0 thick not support yet"); } Geometry geometry=THREE.Geometry(); stacks=(points.size()/(slices+1))-1; //stacks is face count.not vertex count vBase=1.0-tickUv*2; for(int i=0;i<=stacks;i++){ for(int j=0;j<=slices;j++){ int index=i*(slices+1)+j; geometry.getVertices().push(points.get(index).clone()); } } int sliceCount=slices+1; slicesPlus=connectHorizontal?slices+1:slices; if(!connectHorizontal){ uBase-=tickUv*2; } JsArray<JsArray<Vector2>> uvs=geometry.getFaceVertexUvs().get(0).cast(); for ( double i = 0; i < stacks; i ++ ) { for ( double j = 0; j < slices; j ++ ) { int a = (int)(i * sliceCount + j); int b = (int)(i * sliceCount + j + 1); int c = (int)(( i + 1 ) * sliceCount + j + 1); int d = (int)(( i + 1 ) * sliceCount + j); Vector2 uva = getUv((int)j,(int)i); Vector2 uvb = getUv((int)j+1,(int)i); Vector2 uvc = getUv((int)j+1,(int)i+1); Vector2 uvd = getUv((int)j,(int)i+1); if(debug){ LogUtils.log("first-surface:"+a+","+b+","+c+","+d); } boolean reverse=flipNormal; if(reverseFirstSurface){ reverse=!reverse; } if(reverse){ geometry.getFaces().push( THREE.Face3( d, b, a ) ); pushUv(uvs,uvd ,uva, uvb ); geometry.getFaces().push(THREE.Face3( d, c, b ) ); pushUv(uvs, uvd.clone(),uvb.clone(), uvc ); }else{ geometry.getFaces().push( THREE.Face3( a, b, d ) ); pushUv(uvs,uva, uvb, uvd ); geometry.getFaces().push(THREE.Face3( b, c, d ) ); pushUv(uvs, uvb.clone(), uvc, uvd.clone() ); } } } int frontGeometrySize=geometry.getVertices().length(); if(debug){ LogUtils.log("first-surface-vertex:"+frontGeometrySize); } geometry.computeFaceNormals(); geometry.computeVertexNormals(); //create second one //TODO option to reverse. //calcurate normals JsArray<Vector3> normals=JsArray.createArray().cast(); for(int i=0;i<geometry.getFaces().length();i++){ Face3 face=geometry.getFaces().get(i); for(int j=0;j<3;j++){ int vindex=face.gwtGet(j); Vector3 normalValue=normals.get(vindex); if(normalValue==null){ normalValue=THREE.Vector3(); normals.set(vindex, normalValue); } normalValue.add(face.getVertexNormals().get(j)); } } if(normal!=null){ normal.normalize(); } if(debug){ for(int i=0;i<normals.length();i++){ ThreeLog.log("normal"+i,normals.get(i)); } } //second one for(int i=0;i<=stacks;i++){ for(int j=0;j<=slices;j++){ int index=i*(slices+1)+j; Vector3 v=points.get(index).clone(); //ThreeLog.log("normal:",normals.get(index)); Vector3 vertexNormal=normal; if(vertexNormal==null){ vertexNormal=normals.get(index).normalize(); } if(reverseFirstSurface){ vertexNormal.multiplyScalar(-1); } //ThreeLog.log("upNormal",vertexNormal.clone().multiplyScalar(thick)); v.add(vertexNormal.clone().multiplyScalar(thick)); geometry.getVertices().push(v); } } for ( double i = 0; i < stacks; i ++ ) { for ( double j = 0; j < slices; j ++ ) { int a = (int)(i * sliceCount + j)+frontGeometrySize; int b = (int)(i * sliceCount + j + 1)+frontGeometrySize; int c = (int)(( i + 1 ) * sliceCount + j + 1)+frontGeometrySize; int d = (int)(( i + 1 ) * sliceCount + j)+frontGeometrySize; Vector2 uva = getUv((int)j,(int)i); Vector2 uvb = getUv((int)j+1,(int)i); Vector2 uvc = getUv((int)j+1,(int)i+1); Vector2 uvd = getUv((int)j,(int)i+1); if(debug){ LogUtils.log("second-surface:"+a+","+b+","+c+","+d); } boolean reverse=flipNormal; if(reverse){ geometry.getFaces().push( THREE.Face3( d, b, a ) ); pushUv(uvs,uvd ,uva, uvb ); geometry.getFaces().push(THREE.Face3( d, c, b ) ); pushUv(uvs, uvd.clone(),uvb.clone(), uvc ); }else{ geometry.getFaces().push( THREE.Face3( a, b, d ) ); pushUv(uvs,uva, uvb, uvd ); geometry.getFaces().push(THREE.Face3( b, c, d ) ); pushUv(uvs, uvb.clone(), uvc, uvd.clone() ); } } } //top if(thick!=0){ for ( double j = 0; j < slices; j ++ ) { int i=0; int a = (int)(i * sliceCount + j); int b = (int)(i * sliceCount + j +1); int c = (int)(i * sliceCount + j+1)+frontGeometrySize; int d = (int)(i * sliceCount + j)+frontGeometrySize; //TODO modify uv Vector2 uva = getUv((int)j,(int)i); Vector2 uvb = getUv((int)j+1,(int)i); Vector2 uvc = getUv((int)j+1,(int)i); Vector2 uvd = getUv((int)j,(int)i); uva.setY(vBase+tickUv); uvb.setY(vBase+tickUv); uvc.setY(1); uvd.setY(1); if(debug){ LogUtils.log("top:"+a+","+b+","+c+","+d+" abd bcd"); } if(flipNormal){ geometry.getFaces().push( THREE.Face3( d, b, a ) ); pushUv(uvs, uvd, uvb, uva ); geometry.getFaces().push(THREE.Face3( d, c, b ) ); pushUv(uvs, uvd.clone(), uvc, uvb.clone()); }else{ geometry.getFaces().push( THREE.Face3( a, b, d ) ); pushUv(uvs, uva, uvb, uvd ); geometry.getFaces().push(THREE.Face3( b, c, d ) ); pushUv(uvs, uvb.clone(), uvc, uvd.clone()); } } //bottom for ( double j = 0; j < slices; j ++ ) { int i=stacks; int a = (int)(i * sliceCount + j); int b = (int)(i * sliceCount + j +1); int c = (int)(i * sliceCount + j+1)+frontGeometrySize; int d = (int)(i * sliceCount + j)+frontGeometrySize; Vector2 uva = getUv((int)j,(int)i); Vector2 uvb = getUv((int)j+1,(int)i); Vector2 uvc = getUv((int)j+1,(int)i); Vector2 uvd = getUv((int)j,(int)i); uva.setY(vBase); uvb.setY(vBase); uvc.setY(vBase+tickUv); uvd.setY(vBase+tickUv); if(debug){ LogUtils.log("bottom:"+a+","+b+","+c+","+d+" dba dcb"); } if(flipNormal){ geometry.getFaces().push( THREE.Face3( a, b, d ) ); pushUv(uvs, uva, uvb, uvd ); geometry.getFaces().push(THREE.Face3( b, c, d ) ); pushUv(uvs, uvb.clone(), uvc, uvd.clone()); }else{ geometry.getFaces().push( THREE.Face3( d, b, a ) ); pushUv(uvs, uvd, uvb, uva ); geometry.getFaces().push(THREE.Face3( d, c, b ) ); pushUv(uvs, uvd.clone(), uvc, uvb.clone()); } } } if(connectHorizontal){ int primaryFirstTop=0; int primaryLastTop=0; int secondaryFirstTop=0; int secondaryLastTop=0; int primaryFirstBottom=0; int primaryLastBottom=0; int secondaryFirstBottom=0; int secondaryLastBottom=0; for ( double i = 0; i < stacks; i ++ ) { int j=0; int j2=slices; int a = (int)(i * sliceCount + j); int b = (int)(( i + 1 ) * sliceCount + j); int d = (int)(i * sliceCount + j2); int c = (int)(( i + 1 ) * sliceCount + j2); Vector2 uva = getUv(slices,(int)i); Vector2 uvb = getUv(slices+1,(int)i); Vector2 uvc = getUv(slices+1,(int)i+1); Vector2 uvd = getUv(slices,(int)i+1); boolean reverse=flipNormal; if(reverseFirstSurface){ reverse=!reverse; } if(reverse){ geometry.getFaces().push( THREE.Face3( d, b, a ) ); pushUv(uvs,uvd ,uva, uvb ); geometry.getFaces().push(THREE.Face3( d, c, b ) ); pushUv(uvs, uvd.clone(),uvb.clone(), uvc ); if(i==0){ primaryFirstTop=a; primaryLastTop=d; } if(i==stacks-1){ primaryFirstBottom=b; primaryLastBottom=c; } }else{ geometry.getFaces().push( THREE.Face3( a, b, d ) ); pushUv(uvs,uva, uvb, uvd ); geometry.getFaces().push(THREE.Face3( b, c, d ) ); pushUv(uvs, uvb.clone(), uvc, uvd.clone() ); if(i==0){ primaryFirstTop=a; primaryLastTop=d; } if(i==stacks-1){ primaryFirstBottom=b; primaryLastBottom=c; } } } for ( double i = 0; i < stacks; i ++ ) { int j=0; int j2=slices; int a = (int)(i * sliceCount + j)+frontGeometrySize; int b = (int)(( i + 1 ) * sliceCount + j)+frontGeometrySize; int d = (int)(i * sliceCount + j2)+frontGeometrySize; int c = (int)(( i + 1 ) * sliceCount + j2)+frontGeometrySize; Vector2 uva = getUv(slices,(int)i); Vector2 uvb = getUv(slices+1,(int)i); Vector2 uvc = getUv(slices+1,(int)i+1); Vector2 uvd = getUv(slices,(int)i+1); if(flipNormal){ geometry.getFaces().push( THREE.Face3( d, b, a ) ); pushUv(uvs,uvd ,uva, uvb ); geometry.getFaces().push(THREE.Face3( d, c, b ) ); pushUv(uvs, uvd.clone(),uvb.clone(), uvc ); if(i==0){ secondaryFirstTop=a; secondaryLastTop=d; } if(i==stacks-1){ secondaryFirstBottom=b; secondaryLastBottom=c; } }else{ geometry.getFaces().push( THREE.Face3( a, b, d ) ); pushUv(uvs,uva, uvb, uvd ); geometry.getFaces().push(THREE.Face3( b, c, d ) ); pushUv(uvs, uvb.clone(), uvc, uvd.clone() ); if(i==0){ secondaryFirstTop=a; secondaryLastTop=d; } if(i==stacks-1){ secondaryFirstBottom=b; secondaryLastBottom=c; } } } if(thick!=0 ){ Vector2 uva = getUv(slices,0); Vector2 uvb = getUv(slices+1,0); Vector2 uvc = getUv(slices+1,0); Vector2 uvd = getUv(slices,0); //LogUtils.log("top:"+primaryFirstTop+","+primaryLastTop+","+secondaryFirstTop+","+secondaryLastTop); //set first uva.setY(vBase+tickUv); uvb.setY(vBase+tickUv); uvc.setY(1); uvd.setY(1); int a=primaryLastTop; int b=primaryFirstTop; int c=secondaryFirstTop; int d=secondaryLastTop; if(flipNormal){ //LogUtils.log("flip-top "+a+","+b+","+c+","+d); geometry.getFaces().push( THREE.Face3( d, b, a ) ); pushUv(uvs, uvd, uvb, uva ); geometry.getFaces().push(THREE.Face3( d, c, b ) ); pushUv(uvs, uvd.clone(), uvc, uvb.clone()); /* ThreeLog.log("a",geometry.getVertices().get(a)); ThreeLog.log("b",geometry.getVertices().get(b)); ThreeLog.log("c",geometry.getVertices().get(c)); ThreeLog.log("d",geometry.getVertices().get(d)); ThreeLog.log("a",uva); ThreeLog.log("b",uvb); ThreeLog.log("c",uvc); ThreeLog.log("d",uvd); */ }else{ LogUtils.log("top "+a+","+b+","+c+","+d); geometry.getFaces().push( THREE.Face3(a, b,d ) ); pushUv(uvs, uva, uvb, uvd ); geometry.getFaces().push( THREE.Face3( b ,c,d) ); pushUv(uvs, uvb.clone(), uvc, uvd.clone()); } uva = getUv(slices,0); uvb = getUv(slices+1,0); uvc = getUv(slices+1,0); uvd = getUv(slices,0); //LogUtils.log("bottom:"+primaryFirstBottom+","+primaryLastBottom+","+secondaryFirstBottom+","+secondaryLastBottom); //set bottom uva.setY(vBase); uvb.setY(vBase); uvc.setY(vBase+tickUv); uvd.setY(vBase+tickUv); a=primaryLastBottom; b=primaryFirstBottom; c=secondaryFirstBottom; d=secondaryLastBottom; if(flipNormal){ //LogUtils.log("flip-bottom "+a+","+b+","+c+","+d); geometry.getFaces().push( THREE.Face3(a, b,d ) ); pushUv(uvs, uva, uvb, uvd ); geometry.getFaces().push( THREE.Face3( b ,c,d) ); pushUv(uvs, uvb.clone(), uvc, uvd.clone()); }else{ //LogUtils.log("bottom "+a+","+b+","+c+","+d); geometry.getFaces().push( THREE.Face3( d, b, a ) ); pushUv(uvs, uvd, uvb, uva ); geometry.getFaces().push(THREE.Face3( d, c, b ) ); pushUv(uvs, uvd.clone(), uvc, uvb.clone()); } } /* if(thick!=0){ for ( double j = slices; j <= slices; j ++ ) { int i=0; int a = (int)(i * sliceCount + j); int b = (int)(i * sliceCount + j +1); int c = (int)(i * sliceCount + j+1)+frontGeometrySize; int d = (int)(i * sliceCount + j)+frontGeometrySize; //TODO modify uv Vector2 uva = getUv((int)j,(int)i); Vector2 uvb = getUv((int)j+1,(int)i); Vector2 uvc = getUv((int)j+1,(int)i); Vector2 uvd = getUv((int)j,(int)i); uva.setY(vBase+tickUv); uvb.setY(vBase+tickUv); uvc.setY(1); uvd.setY(1); geometry.getFaces().push( THREE.Face3( a, b, d ) ); pushUv(uvs, uva, uvb, uvd ); geometry.getFaces().push(THREE.Face3( b, c, d ) ); pushUv(uvs, uvb.clone(), uvc, uvd.clone()); } //bottom for ( double j = slices; j <= slices; j ++ ) { int i=stacks; int a = (int)(i * sliceCount + j); int b = (int)(i * sliceCount + j +1); int c = (int)(i * sliceCount + j+1)+frontGeometrySize; int d = (int)(i * sliceCount + j)+frontGeometrySize; Vector2 uva = getUv((int)j,(int)i); Vector2 uvb = getUv((int)j+1,(int)i); Vector2 uvc = getUv((int)j+1,(int)i); Vector2 uvd = getUv((int)j,(int)i); uva.setY(vBase); uvb.setY(vBase); uvc.setY(vBase+tickUv); uvd.setY(vBase+tickUv); geometry.getFaces().push( THREE.Face3( d, b, a ) ); pushUv(uvs, uvd, uvb, uva ); geometry.getFaces().push(THREE.Face3( d, c, b ) ); pushUv(uvs, uvd.clone(), uvc, uvb.clone()); } } */ }else{//create side if(thick!=0){ for ( double i = 0; i < stacks; i ++ ) { int j=0; int a = (int)(i * sliceCount + j); int b = (int)(( i + 1 ) * sliceCount + j); int c = (int)(( i + 1 ) * sliceCount + j)+frontGeometrySize; int d = (int)(i * sliceCount + j)+frontGeometrySize; //TODO modify uv Vector2 uva = getUv(0,(int)i); Vector2 uvb = getUv(0,(int)i); Vector2 uvc = getUv(0,(int)i+1); Vector2 uvd = getUv(0,(int)i+1); uva.setX(1); uvb.setX(1.0-tickUv); uvc.setX(1.0-tickUv); uvd.setX(1); if(debug){ LogUtils.log("left:"+a+","+b+","+c+","+d+" dba dcb"); } if(flipNormal){ geometry.getFaces().push( THREE.Face3( a, b, d ) ); pushUv(uvs, uva, uvb, uvd ); geometry.getFaces().push(THREE.Face3( b, c, d ) ); pushUv(uvs, uvb.clone(), uvc, uvd.clone()); }else{ geometry.getFaces().push( THREE.Face3( d, b, a ) ); pushUv(uvs, uvd, uvb, uva ); geometry.getFaces().push(THREE.Face3( d, c, b ) ); pushUv(uvs, uvd.clone(), uvc, uvb.clone()); } } for ( double i = 0; i < stacks; i ++ ) { int j=slices; int a = (int)(i * sliceCount + j); int b = (int)(( i + 1 ) * sliceCount + j); int c = (int)(( i + 1 ) * sliceCount + j)+frontGeometrySize; int d = (int)(i * sliceCount + j)+frontGeometrySize; Vector2 uva = getUv(0,(int)i); Vector2 uvb = getUv(0,(int)i); Vector2 uvc = getUv(0,(int)i+1); Vector2 uvd = getUv(0,(int)i+1); uva.setX(1-tickUv); uvb.setX(1.0-tickUv*2); uvc.setX(1.0-tickUv*2); uvd.setX(1-tickUv); if(debug){ LogUtils.log("right:"+a+","+b+","+c+","+d+" abd bcd"); } if(flipNormal){ geometry.getFaces().push( THREE.Face3( d, b, a ) ); pushUv(uvs, uvd, uvb, uva ); geometry.getFaces().push(THREE.Face3( d, c, b ) ); pushUv(uvs, uvd.clone(), uvc, uvb.clone()); }else{ geometry.getFaces().push( THREE.Face3( a, b, d ) ); pushUv(uvs, uva, uvb, uvd ); geometry.getFaces().push(THREE.Face3( b, c, d ) ); pushUv(uvs, uvb.clone(), uvc, uvd.clone()); } } } } if(edge){ for ( double j = 0; j < slices; j ++ ) { int i=stacks; int pre=stacks-1; int prea = (int)(pre * sliceCount + j); int preb = (int)(pre * sliceCount + j +1); int prec = (int)(pre * sliceCount + j+1)+frontGeometrySize; int pred = (int)(pre * sliceCount + j)+frontGeometrySize; int a = (int)(i * sliceCount + j); int b = (int)(i * sliceCount + j +1); int c = (int)(i * sliceCount + j+1)+frontGeometrySize; int d = (int)(i * sliceCount + j)+frontGeometrySize; Vector3 prePos=THREE.Vector3() .add(geometry.vertices().get(prea)) .add(geometry.vertices().get(preb)) .add(geometry.vertices().get(prec)) .add(geometry.vertices().get(prea)) .divideScalar(4); Vector3 newPos=THREE.Vector3() .add(geometry.vertices().get(a)) .add(geometry.vertices().get(b)) .add(geometry.vertices().get(c)) .add(geometry.vertices().get(d)) .divideScalar(4); Vector3 diff=newPos.clone().sub(prePos); newPos.add(diff); geometry.getVertices().push(newPos); int newPosIndex=geometry.getVertices().length()-1; Vector2 uva = getUv((int)j,(int)i); Vector2 uvb = getUv((int)j+1,(int)i); Vector2 uvc = getUv((int)j+1,(int)i); Vector2 uvd = getUv((int)j,(int)i); uva.setY(vBase); uvb.setY(vBase); uvc.setY(vBase+tickUv); uvd.setY(vBase+tickUv); Vector2 uvCenter=THREE.Vector2().add(uvc).add(uvd).divideScalar(2); if(debug){ LogUtils.log("bottom:"+a+","+b+","+c+","+d+" dba dcb"); } geometry.getFaces().push( THREE.Face3( a, b, newPosIndex ) ); pushUv(uvs, uva.clone(), uvb.clone(), uvCenter.clone()); geometry.getFaces().push( THREE.Face3( b, c, newPosIndex ) ); pushUv(uvs, uva.clone(), uvb.clone(), uvCenter.clone()); geometry.getFaces().push( THREE.Face3( c, d, newPosIndex ) ); pushUv(uvs, uva.clone(), uvb.clone(), uvCenter.clone()); geometry.getFaces().push( THREE.Face3( d, a, newPosIndex ) ); pushUv(uvs, uva.clone(), uvb.clone(), uvCenter.clone()); //TODO if(flipNormal){ }else{ } } } geometry.mergeVertices();//this means almost impossible to know each vertex position(merged) geometry.computeFaceNormals(); geometry.computeVertexNormals(); return geometry; } @SuppressWarnings({ "unused", "unchecked" }) private void pushUv(JsArray<JsArray<Vector2>> target,Vector2 uv1,Vector2 uv2,Vector2 uv3){ Vector2 uv1Flipped=uv1.clone(); Vector2 uv2Flipped=uv2.clone(); Vector2 uv3Flipped=uv3.clone(); uv1Flipped.setY(1-uv1.getY()); uv2Flipped.setY(1-uv2.getY()); uv3Flipped.setY(1-uv3.getY()); target.push(JavaScriptUtils.createJSArray(uv1Flipped,uv2Flipped,uv3Flipped)); } }