3

Stackoverflowers,

I am doing a simple project using Android smartphones to create 3D forms. I am using Android Processing to make a simple App.

My code makes a 3D shape and saves it as an .STL file. It works on my laptop and saves the .STL file, but in the App. version, I need it to save to the External storage/SD Card of my phone (HTC Sensation). It does not, because of the way the “save” function (writeSTL) in the Processing library I am using has been written.

I have posted for help here (my code more complete code is here too):

http://forum.processing.org/two/discussion/4809/exporting-geometry-stl-obj-dfx-modelbuilder-and-android

...and Marius Watz who wrote the library says that the writeSTL() code is pretty much standalone and the only thing missing is (or should be) replacing the code creating the output stream, which needs to be modified to work with Android. Basically, this line:

FileOutputStream out=(FileOutputStream)UIO.getOutputStream(p.sketchPath(filename));

I am not a great programmer in that I can usually get Processing to do what I need to do but no more; this problem has me beaten. I am looking for ideas for the correct code to replace the line:...

FileOutputStream out=(FileOutputStream)UIO.getOutputStream(p.sketchPath(filename));

...with something “Android-friendly”. Calling getExternalStorageDirectory() should work but I am at a loss to find the correct structure.

The code for the writeSTL function is below.

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * Output binary STL file of mesh geometry.
 * @param p Reference to PApplet instance
 * @param filename Name of file to save to
 */

  public void customWriteSTL(UGeometry geo, PApplet p, String filename) {
  byte [] header;
  ByteBuffer buf;
  UFace f;

  try {
    if (!filename.toLowerCase().endsWith("stl")) filename+=".stl";
    FileOutputStream out=(FileOutputStream)UIO.getOutputStream(p.sketchPath(filename));

buf = ByteBuffer.allocate(200);
header=new byte[80];
buf.get(header, 0, 80);
out.write(header);
buf.rewind();

buf.order(ByteOrder.LITTLE_ENDIAN);
buf.putInt(geo.faceNum);
buf.rewind();
buf.get(header, 0, 4);
out.write(header, 0, 4);
buf.rewind();

UUtil.logDivider("Writing STL '"+filename+"' "+geo.faceNum);

buf.clear();
header=new byte[50];
if (geo.bb!=null) UUtil.log(geo.bb.toString());

for (int i=0; i<geo.faceNum; i++) {
  f=geo.face[i];
  if (f.n==null) f.calcNormal();

  buf.rewind();
  buf.putFloat(f.n.x);
  buf.putFloat(f.n.y);
  buf.putFloat(f.n.z);

  for (int j=0; j<3; j++) {
    buf.putFloat(f.v[j].x);
    buf.putFloat(f.v[j].y);
    buf.putFloat(f.v[j].z);
  }

  buf.rewind();
  buf.get(header);
  out.write(header);
}

out.flush();
out.close();
UUtil.log("Closing '"+filename+"'. "+geo.faceNum+" triangles written.\n");
  } 
  catch (Exception e) {
e.printStackTrace();
  }
}

Any suggestions are gratefully received.

Thank you in advance.

4

1 回答 1

1

有几种方法可以做到这一点 - 有些可以正常工作,有些是正确的......就像处理/Java的所有事情一样。它与普通 Java 并没有什么不同——唯一的怪癖是根 SD 路径,并检查它是否存在(请注意,有些手机具有“内部”而不是“外部”存储(即不可移动/可交换),但是Android 应该解释这些相同的 AFAIK。

以经典的 Java 方式,您真的应该事先检查 SD 卡是否存在......我使用以下结构,取自@kaolick这个答案

    String state = Environment.getExternalStorageState();
    if (state.equals(Environment.MEDIA_MOUNTED)) {
        // Storage is available and writeable - ALL GOOD  
    } else if (state.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) {
        // Storage is only readable - RUH ROH
    } else {
        // Storage is neither readable nor writeable - ABORT    
    }

请注意,他提供了一个完整的类供您使用,这很棒,并且有一些方便的功能。

您可能要查看的第二件事是在设备的 SD 卡上创建一个自定义目录,可能在 setup() 中 - 如下所示:

  try{
    String dirName = "//sdcard//MyAppName";
    File newFile = new File(dirName);

    if(newFile.exists() && newFile.isDirectory()) {
      println("Directory Exists... All Good");
    } 
    else {
      println("Directory Doesn't Exist... We're Making It");
      newFile.mkdirs();
    }
  }
  catch(Exception e) {
    e.printStacktrace();
  }

当然,而不是硬编码路径名称,你应该做类似的事情

String dirName = Environment.getExternalStorageDirectory().getAbsolutePath() + "/MyAppName";

反而...

另外,请注意,上面的 try/catch 应该放在“if (state.equals(Environment.MEDIA_MOUNTED))”的 case 语句中......或者应该包装在从那里调用的单独函数 anc 中。

然后,最后,保存它。如果你想使用 BufferedWriter,它看起来像这样:

  BufferedWriter writer = new BufferedWriter(new FileWriter(dirName, true));
  writer.write(STL_STUFF);
  writer.flush();
  writer.close();

我只在 BufferedOutput Stream 中使用了 FileOutputStream,它看起来像这样:

try {
    String fileName = "SOME_UNIQUE_NAME_PER_FILE";
    String localFile = dirName + "/" +filename;
    OutputStream output = new BufferedOutputStream(newFileOutputStream(localFile));
}
catch(Exception e) {
    e.printStackTrace();
}

最后,如果你和他交谈,请向马吕斯问好!;-)

于 2014-06-29T19:05:22.957 回答