// Digital Material Cube 006 // FabLab Japan // Hiroya Tanaka import java.awt.event.*; // Import Mesh Library import toxi.geom.*; import toxi.geom.mesh.*; import toxi.geom.mesh.subdiv.*; import toxi.processing.*; import toxi.util.*; import toxi.volume.*; ToxiclibsSupport gfx; WETriangleMesh mesh; boolean mesh_display = true; boolean voxel_display = true; boolean wire_display = true; // Import import processing.opengl.*; import javax.media.opengl.*; import controlP5.*; import javax.swing.*; import SpringGUI.*; SpringGUI gui; // File IO String getFile; String setFile; String ssetFile; String [] txtarray = null; String txt = null; // Field int FIELD_SIZE = 50; int FIELD_STEP = 10; // Pointer int mx = 1; int my = 1; int mz = 1; // Camera float expo = 1; float rotx, roty; float rate = 0.01; // Resolution of Box int resolution = 16; int scan = 1; int transparency = 100; // ControlP5 ControlP5 controlP5; Textfield tfUserName; // テキストフィールド String txts = ""; // Text PFont font; long time; // Unlekker import unlekker.data.*; import unlekker.geom.*; STL stl; FaceList poly; int faces; // メッシュの数 // Array int[][] xyarrays = new int[48][48]; int[][] yzarrays = new int[48][48]; int[][] zxarrays = new int[48][48]; int[][][] xyzarrays = new int[48][48][48]; //Filling Out Queue int pixelQueuex[] = new int[48*48*48]; int pixelQueuey[] = new int[48*48*48]; int pixelQueuez[] = new int[48*48*48]; int pixelQueueSize = 0; void setup() { addMouseWheelListener(new MouseWheelListener() { public void mouseWheelMoved(MouseWheelEvent mwe) { mouseWheel(mwe.getWheelRotation()); }}); setFile = ""; getFile = ""; // Array初期化 for(int k = 0; k<48; k = k + 1){ for(int j = 0; j<48; j = j + 1){ for(int i = 0; i<48; i = i + 1){ xyzarrays[k][j][i] = 0; } } } size(640, 480, OPENGL); gfx=new ToxiclibsSupport(this); controlP5 = new ControlP5(this); controlP5.addButton("loadfile",1,10,45,80,19); controlP5.addButton("savefile",1,100,45,80,19); controlP5.addButton("voxelize",1,190,45,80,19); controlP5.addSlider("resolution",1,48,10,70,200,20); controlP5.addSlider("scan",1,100,10,425,200,20); controlP5.addSlider("transparency",0,100,10,400,200,20); controlP5.addToggle("mesh_display",true,300,45,20,10).setMode(ControlP5.SWITCH); controlP5.addToggle("voxel_display",true,400,45,20,10).setMode(ControlP5.SWITCH); controlP5.addToggle("wire_display",true,500,45,20,10).setMode(ControlP5.SWITCH); } void draw() { background(0); PGraphicsOpenGL pgl = (PGraphicsOpenGL)g; // Lighting ambientLight(150, 150, 150); directionalLight(255,255,255,-1,0,0); pointLight(160, 160, 160, 0, 0, 200); spotLight(100, 100, 100, 0, 0, 200, 0, 0, -1, PI, 2); // FileIO if(getFile != ""){ //ファイルを取り込む fileLoader(); } //Text font = createFont("Meiryo", 12); textFont(font); fill(255,255,255); text("17 3D Filling - 6 Neibors - Transparency ", 10, 25); // 中心を合わせる pushMatrix(); translate(320,240,200); rotateX(rotx); rotateY(roty); scale(expo); // STL書き出し if(setFile != ""){ beginRaw("unlekker.data.STL",setFile+".stl"); println("start :"+setFile); } pushStyle(); // フレームの描画 if (wire_display == true){ FIELD_STEP = FIELD_SIZE*2/resolution; for(int k = 1; k<=resolution; k = k + 1){ for(int j = 1; j<=resolution; j = j + 1){ for(int i = 1; i<=resolution; i = i + 1){ // x float x = -FIELD_SIZE + FIELD_STEP*(i - 1); float xx = -FIELD_SIZE + FIELD_STEP*(i); float realx = (x + xx)/2; // y float y = -FIELD_SIZE + FIELD_STEP*(j - 1); float yy = -FIELD_SIZE + FIELD_STEP*(j); float realy = (y + yy)/2; // z float z = -FIELD_SIZE + FIELD_STEP*(k - 1); float zz = -FIELD_SIZE + FIELD_STEP*(k); float realz = (z + zz)/2; pushMatrix(); translate(realx,realy,realz); noFill(); if (k < int((resolution-1)*scan/100)+1) { stroke(0, 0, 50); } else { stroke(50, 50, 50); } box(FIELD_STEP ,FIELD_STEP ,FIELD_STEP ); popMatrix(); } } } } popStyle(); // メッシュの描画 if(poly!=null && mesh_display == true) { fill(255,255,255); noStroke(); poly.draw(this); } // ボクセルの描画 if ( voxel_display == true ) { noStroke(); noFill(); int len = txts.length(); int l = 0; FIELD_STEP = FIELD_SIZE*2/resolution; for(int k = int((resolution-1)*scan/100)+1; k<=resolution; k = k + 1){ for(int j = 1; j<=resolution; j = j + 1){ for(int i = 1; i<=resolution; i = i + 1){ //x float x = -FIELD_SIZE + FIELD_STEP*(i - 1); float xx = -FIELD_SIZE + FIELD_STEP*(i); float realx = (x + xx)/2; //y float y = -FIELD_SIZE + FIELD_STEP*(j - 1); float yy = -FIELD_SIZE + FIELD_STEP*(j); float realy = (y + yy)/2; //z float z = -FIELD_SIZE + FIELD_STEP*(k - 1); float zz = -FIELD_SIZE + FIELD_STEP*(k); float realz = (z + zz)/2; pushMatrix(); translate(realx,realy,realz); if( xyzarrays[i-1][j-1][k-1] == -1 ) { xyzarrays[i-1][j-1][k-1] = 1; } if ( xyzarrays[i-1][j-1][k-1] == 1 ) { l = l + transparency; if ( l>=100 ) { fill(255,00,00); box(FIELD_STEP,FIELD_STEP,FIELD_STEP); l = l - 100; } } //pointer mz = int((resolution-1)*scan/100)+1; if (mx == i && my == j && mz == k) { fill(255,255,0); box(FIELD_STEP ,FIELD_STEP ,FIELD_STEP ); } popMatrix(); } } } } popMatrix(); // STL書き出し終了 if(setFile != "") { endRaw(); setFile = ""; println("end"); } // α合成を有効にする GL gl = pgl.beginGL(); gl.glEnable(GL.GL_BLEND); gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); gl.glDisable(GL.GL_DEPTH_TEST); pgl.endGL(); // GUI コンポーネント描画のための設定 camera(); gl = pgl.beginGL(); gl.glDisable(GL.GL_DEPTH_TEST); // 深度テストを無効化 gl.glEnable(GL.GL_BLEND); gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); pgl.endGL(); // 3次元フィル while (pixelQueueSize > 0){ pixelQueueSize--; filling3d ( pixelQueuex[pixelQueueSize+1] ,pixelQueuey[pixelQueueSize+1], pixelQueuez[pixelQueueSize+1]); } } // テキストが入力された際にコールバックされるメソッド public synchronized void textfield(String txt) { txts = txt; } public void loadfile(int theValue) { getFile = getFileName(); } public void savefile(int theValue) { setFile = setFileName(); } public void voxelize(int theValue) { // メッシュの数:int faces   // AABB * AABBの衝突判定をつかってみる FIELD_STEP = FIELD_SIZE*2/resolution; for(int k = 1; k<=resolution; k = k + 1){ for(int j = 1; j<=resolution; j = j + 1){ for(int i = 1; i<=resolution; i = i + 1){ // x float x = -FIELD_SIZE + FIELD_STEP*(i - 1); float xx = -FIELD_SIZE + FIELD_STEP*(i); float realx = (x+xx)/2; // y float y = -FIELD_SIZE + FIELD_STEP*(j - 1); float yy = -FIELD_SIZE + FIELD_STEP*(j); float realy = (y+yy)/2; //z float z = -FIELD_SIZE + FIELD_STEP*(k - 1); float zz = -FIELD_SIZE + FIELD_STEP*(k); float realz = (z+zz)/2; for(int q = 0; q< poly.f.length; q= q + 1){ PVector pv1 = new PVector (poly.f[q].v[3],poly.f[q].v[4],poly.f[q].v[5] ); PVector pv2 = new PVector (poly.f[q].v[6],poly.f[q].v[7],poly.f[q].v[8]); PVector pv3 = new PVector (poly.f[q].v[9],poly.f[q].v[10],poly.f[q].v[11]); PVector bmin = new PVector (x,y,z); PVector bmax = new PVector (xx,yy,zz); boolean preresult = preAABB(x,y,z,xx,yy,zz, min(poly.f[q].v[3],poly.f[q].v[6],poly.f[q].v[9]),min(poly.f[q].v[4],poly.f[q].v[7],poly.f[q].v[10]),min(poly.f[q].v[5],poly.f[q].v[8],poly.f[q].v[11]), max(poly.f[q].v[3],poly.f[q].v[6],poly.f[q].v[9]),max(poly.f[q].v[4],poly.f[q].v[7],poly.f[q].v[10]),max(poly.f[q].v[5],poly.f[q].v[8],poly.f[q].v[11])); boolean result; if (preresult == true) { result= SPETestTriangleAABB(pv1 ,pv2, pv3, bmin, bmax); } else { result =false; } boolean result2 = AABB(x,y,z,xx,yy,zz, min(poly.f[q].v[3],poly.f[q].v[6],poly.f[q].v[9]),min(poly.f[q].v[4],poly.f[q].v[7],poly.f[q].v[10]),min(poly.f[q].v[5],poly.f[q].v[8],poly.f[q].v[11]), max(poly.f[q].v[3],poly.f[q].v[6],poly.f[q].v[9]),max(poly.f[q].v[4],poly.f[q].v[7],poly.f[q].v[10]),max(poly.f[q].v[5],poly.f[q].v[8],poly.f[q].v[11])); if (result == true || result2 == true ) { xyzarrays[i-1][j-1][k-1] = 1; break; } else { xyzarrays[i-1][j-1][k-1] = 0; } } } } } } // AABBどうちの接触を調べる public boolean preAABB(float aminx,float aminy,float aminz, float amaxx,float amaxy, float amaxz, float bminx, float bminy, float bminz, float bmaxx, float bmaxy, float bmaxz) { // 衝突 if( aminx < bmaxx && amaxx > bminx && aminy < bmaxy && amaxy > bminy && aminz < bmaxz && amaxz > bminz) { //println("1a"); return(true); } if( bminx < amaxx && bmaxx > aminx && bminy < amaxy && bmaxy > aminy && bminz < amaxz && bmaxz > aminz) { // println("1b"); return(true); } return(false); } public boolean AABB(float aminx,float aminy,float aminz, float amaxx,float amaxy, float amaxz, float bminx, float bminy, float bminz, float bmaxx, float bmaxy, float bmaxz) { // 包含 if( aminx < bminx && bmaxx < amaxx && aminy < bminy && bmaxy < amaxy && aminz < bminz && bmaxz < amaxz) { //println("2"); return(true); } return(false); } public float distance(float x1, float y1, float x2, float y2){ return(sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))); } // 座標 p1,p2 を通る直線と座標 p3,p4 を結ぶ線分が交差しているかを調べる public boolean intersection(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4){ if (((x1 - x2) * (y3 - y1) + (y1 - y2) * (x1 - x3)) * ((x1 - x2) * (y4 - y1) + (y1 - y2) * (x1 - x4)) <= 0 && ((x3 - x4) * (y1 - y3) + (y3 - y4) * (x3 - x1)) * ((x3 - x4) * (y2 - y3) + (y3 - y4) * (x3 - x2)) <= 0 ) { return(true); //交差する } return(false); //交差しない } void mouseDragged() { // Camera if (getFile == "" && setFile == "") { rotx = rotx + (mouseY - pmouseY) * rate; roty = roty + (mouseX - pmouseX) * rate; } } void mouseWheel(float delta) { expo = expo + delta*0.1; } void keyPressed() { // Mouse Pointer Move if (keyCode==DOWN && my1) { my--; } if ( keyCode==RIGHT && mx1) { mx--; } if ( keyCode==ENTER) { filling3d(mx,my,mz); } } private void filling3d (int x,int y, int z) { /* 塗りつぶし */ xyzarrays[x][y][z]=-1; /* ー1を置く */ if (y>0){ if (xyzarrays[x][y-1][z]==0) { pixelQueueSize++; pixelQueuex[pixelQueueSize] = x; pixelQueuey[pixelQueueSize] = y-1; pixelQueuez[pixelQueueSize] = z; } } if (x0) { if (xyzarrays[x-1][y][z]==0) { /* 左 */ pixelQueueSize++; pixelQueuex[pixelQueueSize] = x-1; pixelQueuey[pixelQueueSize] = y; pixelQueuez[pixelQueueSize] = z; } } if (z0) { if (xyzarrays[x][y][z-1]==0) { /* 手前 */ pixelQueueSize++; pixelQueuex[pixelQueueSize] = x; pixelQueuey[pixelQueueSize] = y; pixelQueuez[pixelQueueSize] = z-1; } } }