4:processing final

今週やりたかったこと

先週の文字の3D出力が出来たので今度はそれにエフェクトを付けようと思った
が、課題にいろいろぶつかり結論から言うと断念した。

・openGLがテキスト対応していない

先週はフォントをボクセル化して出力していたのだが、
やはり元のフォントの形のまま使いたいと思いいろいろ調べていた結果
openGLがテキストに対応していない事がわかった。
ここら辺で前回open processingで参考にしたサンプルが
何故あんなに回りくどい方法で文字を立体化していたのかを納得した。

で、前回のpdeからやろうと試みるも自分で書いたものではないので理解が出来ず、断念

目標はドラゴンクエストのロゴのようなものをprocessingで打ち込んでつくること



とりあえず文字を二次元で曲線配置することはなんとかできそう。
(といってもとりあえず円上に配置)
だけどいろいろ調べていたら何となくやりたいことはこの方法ではない気がしている。
ここらへんでタイムアップ。

いろんなやり方がないかひたすらgoogleに検索をかけた一週間だった。

トップのイメージはopen processingでみつけた3Dのグリッド上に線が描けるプログラム。
休憩がてら見つけて面白かったのでいろいろいじってみた。



キャンバスサイズの変更、メッシュ化、線の太さが変えられる。
オリジナルのiPadスタンドを作ろうと思い、processingの実行画面上で作ってみた。
"export"を押してプリントしてみようとファイルを開いてみたら、
何故かphotoshopが起動。
よく見るとobjであった。

3D printできない…。
明日以降コードを読んでstl出力出来るように改変してみたい。





3:stl export(processing) part2

3D word print





3d_word_stl.pde
  1. //controlP5
  2. import controlP5.*;
  3. ControlP5 controlP5;
  4. Textfield tfUserName;
  5. String txts = "";
  6. int sliderA;


  7. // Import
  8. import javax.swing.*;

  9. // Unlekker
  10. import unlekker.data.*;
  11. import unlekker.geom.*;
  12. public STL stl;
  13. public FaceList poly;

  14. // File IO
  15. String getFile; 
  16. String setFile;
  17. String [] txtarray = null;
  18. String txt = null;

  19. // Field 
  20. int FIELD_SIZE = 50;
  21. int FIELD_STEP =  10;

  22. //import peasy.org.apache.commons.math.*;
  23. //import peasy.*;
  24. //import peasy.org.apache.commons.math.geometry.*;
  25. PFont ff;
  26. PImage ww;
  27. ArrayList positions = new ArrayList();
  28. //PeasyCam cam;
  29. String sentence;

  30. public void setup()
  31. {
  32.   size(400, 250, P3D);
  33.   //cam = new PeasyCam(this, 80);
  34.   //cam.setRotations( -0.73, -0.27, 0.30); 
  35.   ff = loadFont("HelveticaNeue-UltraLight-48.vlw");
  36.   sentence = "";
  37.   ww = crImage();
  38.   scan();
  39.   colorMode(RGB, 255);
  40.   frameRate(60);
  41.   fill(0, 0);
  42.   
  43.   controlP5 = new ControlP5(this);
  44.   controlP5.addButton("savefile", 1, 180, 150, 40, 10);
  45.   controlP5.addSlider("sliderA", -10, 10,0, 100, 100, 200, 10);
  46.   
  47.   smooth();
  48. }

  49. public void draw()
  50. {
  51.   background(0);
  52.   lights();
  53.    fill(255);
  54.   text("press any one word → slide bar → save file", 80, 200); // 表示するテキスト, x座標, y座標
  55.   pushMatrix();
  56.   translate(-200, -8, 0);  
  57.     // STL書き出し
  58.   if (setFile != null) {
  59.     beginRaw("unlekker.data.STL", setFile+".stl");
  60.     println("start :"+setFile);
  61.   }
  62.   for(int i = 0; i < positions.size()-1; i++)
  63.   {
  64.     PVector ps = (PVector) positions.get(i);
  65.     translate(ps.x+200, ps.y+50, 0);
  66.     noStroke();
  67.     fill(200);
  68.     box(1, 1, sliderA);
  69.     translate(-(ps.x+200), -(ps.y+50), 0);
  70.   }
  71.     // STL書き出し終了
  72.   if (setFile !=null) {
  73.     endRaw();   
  74.     setFile = null;
  75.     println("end");
  76.   }
  77.   popMatrix();

  78.   controlP5.draw();
  79. }

  80. PImage crImage()
  81. {
  82.   PGraphics pg = createGraphics(400,20,JAVA2D);
  83.   pg.beginDraw();
  84.   pg.background(255);
  85.   pg.fill(250);
  86.   pg.textAlign(CENTER);
  87.   pg.textFont(ff, 16);
  88.   pg.text(sentence, 0, 0, 400, 20);
  89.   pg.endDraw();
  90.   PImage w = createImage(400,20,RGB);
  91.   copy(pg, 0, 0, 400, 20, 0, 0, 400, 20);
  92.   return w;
  93. }

  94. public void scan()
  95. {
  96.   positions.clear(); 
  97.   for(int x = 0; x < ww.width; x++) {
  98.     for(int y = 0; y < ww.height; y++) {
  99.       if(get(x,y) != -65794){
  100.         positions.add(new PVector(x,y,0));     
  101.       }
  102.     }
  103.    }
  104. }

  105. public void keyPressed() {
  106.   if(textWidth(sentence) <= 210){
  107.      sentence += key;
  108.      crImage();
  109.      scan();
  110.      } 
  111.      else
  112.      sentence = "";
  113. }

  114. public void savefile(int theValue) {
  115.   setFile = setFileName();
  116. }

  117. public void sliderA(int v) {
  118.   sliderA = v;
  119. }


file_io.pde
  1. //ファイルを取り込むファンクション 
  2. void fileLoader() {
  3.   //選択ファイルパスのドット以降の文字列を取得
  4.   String ext = getFile.substring(getFile.lastIndexOf('.') + 1);
  5.   //その文字列を小文字にする
  6.   ext.toLowerCase();
  7.   //文字列末尾がstlであれば 
  8.   if (ext.equals("stl")) {
  9.     println(ext);
  10.     stl=new STL(this, getFile);
  11.     // Get polygon data
  12.     poly=stl.getPolyData();
  13.     poly.normalize(FIELD_SIZE*2); // normalize object to 400 radius
  14.     poly.calcBounds();
  15.     poly.center(); // center it around world origin
  16.   }

  17.   //選択ファイルパスを空に戻す
  18.   getFile = null;
  19. }



  20. //ファイル選択画面、選択ファイルパス取得の処理 
  21. String getFileName() {
  22.   //処理タイミングの設定 
  23.   SwingUtilities.invokeLater(new Runnable() { 
  24.     public void run() {
  25.       try {
  26.         //ファイル選択画面表示 
  27.         JFileChooser fc = new JFileChooser(); 
  28.         int returnVal = fc.showOpenDialog(null);
  29.         //「開く」ボタンが押された場合
  30.         if (returnVal == JFileChooser.APPROVE_OPTION) {
  31.           //選択ファイル取得 
  32.           File file = fc.getSelectedFile();
  33.           //選択ファイルのパス取得 
  34.           getFile = file.getPath();
  35.         }
  36.       }
  37.       //上記以外の場合 
  38.       catch (Exception e) {
  39.         //エラー出力 
  40.         e.printStackTrace();
  41.       }
  42.     }
  43.   } 
  44.   );
  45.   //選択ファイルパス取得
  46.   return getFile;
  47. }


  48. //ファイル選択画面、選択ファイルパス取得の処理 
  49. String setFileName() {
  50.   //処理タイミングの設定 
  51.   SwingUtilities.invokeLater(new Runnable() { 
  52.     public void run() {
  53.       try {
  54.         //ファイル選択画面表示 
  55.         JFileChooser fc = new JFileChooser(); 
  56.         int returnVal = fc.showSaveDialog(null);
  57.         //「開く」ボタンが押された場合
  58.         if (returnVal == JFileChooser.APPROVE_OPTION) {
  59.           //選択ファイル取得 
  60.           File file = fc.getSelectedFile();
  61.           //選択ファイルのパス取得 
  62.           setFile = file.getPath();
  63.         }
  64.       }
  65.       //上記以外の場合 
  66.       catch (Exception e) {
  67.         //エラー出力 
  68.         e.printStackTrace();
  69.       }
  70.     }
  71.   } 
  72.   );
  73.   //選択ファイルパス取得
  74.   return setFile;
  75. }


2:stl export(processing)

今週はとにかくいろいろ調べたり先輩方に聞いたりして現状やっと課題に取り組める状態でタイムアウトしてしまった。

結論から言えばprocessingのバージョンの違いでstlのexportが動かなかった様であるが、いろいろ自分で調べたり試行錯誤してみてとにかく大変だった。
pappletのエラーみたいなもので延々時間がとられていて、調べても自力ではよくわからなかった。

なので、今週分の課題は
processingだけでも今日中に作って、明日にでも出力したいと思う。
完成時点でこのlogに追記する。

反省点として、sampleが動かなかった時点でsampleが正常に動くことに時間をかけずに3dのobjectだけでも先に作っておけば良かったと思う。

途中先生がprocessingで作られたgeo formingのシミュレーターを使ってstl出力をしてみたが、データに厚みがないため全部サポート構造のような物体ができた。

2:Processing -> PDF -> Fabrication


curtain by ball point pen drawing
(PILOT HI-TEC-C)




第2回課題:processingからlineデータをpdfにexportして物質化すること。
カッティングマシンしか現状使えないからカッティングマシンの使用を考えたが、カットを実際にすると複雑なものが物質か出来ない。なので例のごとくカッティングマシンのアタッチメントをボールペンに取り替えて取り替えて手描きでは描けないようなイラストのペインティングを行った。コードはサンプルコードをOpen Processingより引用してメッシュのカーテンをがなびいている状態をボールペンで描いてみた。一番上の画像が実際に紙に描写されたカーテンで、その次の画像がprocessing上での動作である。

下は間違えて3Dデータをpdf exportしようとして失敗したときの例。lineデータではないので失敗した。




ソースコード
--------------------------------------------------------------------------------------



import processing.pdf.*;

boolean EXPORT = false;

ArrayList particles;

// every particle within this many pixels will be influenced by the cursor
float mouseInfluenceSize = 30; 
// minimum distance for tearing when user is right clicking
float mouseTearSize = 8;

// force of gravity is really 9.8, but because of scaling, we use 9.8 * 40 (392)
// (9.8 is too small for a 1 second timestep)
float gravity = 392; 

// Dimensions for our curtain. These are number of particles for each direction, not actual widths and heights
// the true width and height can be calculated by multiplying restingDistances by the curtain dimensions
final int curtainHeight = 56;
final int curtainWidth = 80;
final int yStart = 25; // where will the curtain start on the y axis?
final float restingDistances = 5;
final float stiffnesses = 1;
final int curtainTearSensitivity = 50; // distance the particles have to go before ripping

// These variables are used to keep track of how much time is elapsed between each frame
// they're used in the physics to maintain a certain level of accuracy and consistency
// this program should run the at the same rate whether it's running at 30 FPS or 300,000 FPS
long previousTime;
long currentTime;
// Delta means change. It's actually a triangular symbol, to label variables in equations
// some programmers like to call it elapsedTime, or changeInTime. It's all a matter of preference
// To keep the simulation accurate, we use a fixed time step.
final int fixedDeltaTime = 15;
float fixedDeltaTimeSeconds = (float)fixedDeltaTime / 1000;

// the leftOverDeltaTime carries over change in time that isn't accounted for over to the next frame
int leftOverDeltaTime = 0;

// How many times are the constraints solved for per frame:
int constraintAccuracy = 3;

// instructional stuffs:
PFont font;
final int instructionLength = 3000;
final int instructionFade = 300;
void setup () {
  // I find that P2D is the fastest renderer for 2D graphics
  // OPENGL may be faster for some people
  // The default renderer is JAVA2D
  size(640,480, P2D);
  
  // we square the mouseInfluenceSize and mouseTearSize so we don't have to use squareRoot when comparing distances with this.
  mouseInfluenceSize *= mouseInfluenceSize; 
  mouseTearSize *= mouseTearSize;
  
  // create the curtain
  createCurtain();
  
  font = loadFont("LucidaBright-Demi-16.vlw");
  textFont(font);
}

void draw () {
  
  if(EXPORT == true) {
    beginRecord(PDF, "Line.pdf"); //この関数が呼ばれるとその時点での画像がPDF出力され                //る。
  }
  
  background(255);
  
  /******** Physics ********/
  // time related stuff
  currentTime = millis();
  // deltaTimeMS: change in time in milliseconds since last frame
  long deltaTimeMS = currentTime - previousTime;
  previousTime = currentTime; // reset previousTime
  // timeStepAmt will be how many of our fixedDeltaTime's can fit in the physics for this frame. 
  int timeStepAmt = (int)((float)(deltaTimeMS + leftOverDeltaTime) / (float)fixedDeltaTime);
  leftOverDeltaTime += (int)deltaTimeMS - (timeStepAmt * fixedDeltaTime); // reset leftOverDeltaTime.
  
  // update physics
  for (int iteration = 1; iteration <= timeStepAmt; iteration++) {
    // solve the constraints multiple times
    // the more it's solved, the more accurate.
    for (int x = 0; x < constraintAccuracy; x++) {
      for (int i = 0; i < particles.size(); i++) {
        Particle particle = (Particle) particles.get(i);
        particle.solveConstraints();
      }
    }
    
    // update each particle's position
    for (int i = 0; i < particles.size(); i++) {
      Particle particle = (Particle) particles.get(i);
      particle.updateInteractions();
      particle.updatePhysics(fixedDeltaTimeSeconds);
      
      // Draw the particle only on the very last iteration
      if (iteration == timeStepAmt)
        particle.draw();
    }
  }

  if (millis() < instructionLength)
    drawInstructions();

  if (frameCount % 60 == 0)
    println("Frame rate is " + frameRate);
    
      if(EXPORT == true) {
    endRecord();//PDF出力終わり
    EXPORT = false; 
  }  
}
void createCurtain () {
  // We use an ArrayList instead of an array so we could add or remove particles at will.
  // not that it isn't possible using an array, it's just more convenient this way
  particles = new ArrayList();
  
  // midWidth: amount to translate the curtain along x-axis for it to be centered
  // (curtainWidth * restingDistances) = curtain's pixel width
  int midWidth = (int) (width/2 - (curtainWidth * restingDistances)/2);
  // Since this our fabric is basically a grid of points, we have two loops
  for (int y = 0; y <= curtainHeight; y++) { // due to the way particles are attached, we need the y loop on the outside
    for (int x = 0; x <= curtainWidth; x++) { 
      Particle particle = new Particle(new PVector(midWidth + x * restingDistances, y * restingDistances + yStart));
      
      // attach to 
      // x - 1  and
      // y - 1  
      // particle attachTo parameters: Particle particle, float restingDistance, float stiffness
      // try disabling the next 2 lines (the if statement and attachTo part) to create a hairy effect
      if (x != 0) 
        particle.attachTo((Particle)(particles.get(particles.size()-1)), restingDistances, stiffnesses);
      // the index for the particles are one dimensions, 
      // so we convert x,y coordinates to 1 dimension using the formula y*width+x  
      if (y != 0)
        particle.attachTo((Particle)(particles.get((y - 1) * (curtainWidth+1) + x)), restingDistances, stiffnesses);
        
/*
      // shearing, presumably. Attaching invisible links diagonally between points can give our cloth stiffness.
      // the stiffer these are, the more our cloth acts like jello. 
      // these are unnecessary for me, so I keep them disabled.
      if ((x != 0) && (y != 0)) 
        particle.attachTo((Particle)(particles.get((y - 1) * (curtainWidth+1) + (x-1))), restingDistances * sqrt(2), 0.1, false);
      if ((x != curtainWidth) && (y != 0))
        particle.attachTo((Particle)(particles.get((y - 1) * (curtainWidth+1) + (x+1))), restingDistances * sqrt(2), 1, true);
*/
      
      // we pin the very top particles to where they are
      if (y == 0)
        particle.pinTo(particle.position);
        
      // add to particle array  
      particles.add(particle);
    }
  }
}

// Controls. The r key resets the curtain, g toggles gravity
void keyPressed() {
  if ((key == 'r') || (key == 'R'))
    createCurtain();
  if ((key == 'g') || (key == 'G'))
    toggleGravity();
}
void toggleGravity () {
  if (gravity != 0)
    gravity = 0;
  else
    gravity = 392;
}

void drawInstructions () {
  float fade = 255 - (((float)millis()-(instructionLength - instructionFade)) / instructionFade) * 255;
  stroke(0, fade);
  fill(255, fade);
  rect(0,0, 200,45);
  fill(0, fade);
  text("'r' : reset", 10, 20);
  text("'g' : toggle gravity", 10, 35);
}

// Credit to: http://www.codeguru.com/forum/showpost.php?p=1913101&postcount=16
float distPointToSegmentSquared (float lineX1, float lineY1, float lineX2, float lineY2, float pointX, float pointY) {
  float vx = lineX1 - pointX;
  float vy = lineY1 - pointY;
  float ux = lineX2 - lineX1;
  float uy = lineY2 - lineY1;
  
  float len = ux*ux + uy*uy;
  float det = (-vx * ux) + (-vy * uy);
  if ((det < 0) || (det > len)) {
    ux = lineX2 - pointX;
    uy = lineY2 - pointY;
    return min(vx*vx+vy*vy, ux*ux+uy*uy);
  }
  
  det = ux*vy - uy*vx;
  return (det*det) / len;
}

void mousePressed() {
 if(mouseButton == RIGHT){
   EXPORT = true; 
 }
}


--------------------------------------------------------------------------------------