[Tex/LaTex] Render stl files in asymptote

3dasymptote

I want to draw a propeller in 3D for my fluid dynamics lecture. I found a 3D model of a propeller that can be downloaded as a stl file.

I found a python library numpy-stl that can read and draw, with the help of matplotlib, the propeller.

enter image description here

My question is: how can I do to import and draw the polygons in asymptote (a python intermediate step is not a problem: no need to implement a stl parser in asymptote!).

Best Answer

Actually, an ascii stl file is so simple it's easy to write an Asymptote script to read it directly. Note, however, that the code below is too simple to offer useful feedback in case the stl file has errors.

settings.outformat = "png";
settings.render = 8;
import three;
size(20cm);

struct stringpointer { string s; }

surface readstlfile(string filename, stringpointer returnsurfacename=null, bool ascii=true) {
  assert(ascii, "Reading binary stl files not implemented.");
  file stlfile = input(filename).word();  // Set up a file to read whitespace-delimited items.
  string nextword;
  real x, y, z;
  
  nextword = stlfile;  // Reading from a file is done by assignment in Asymptote.
  assert(nextword == "solid", filename + " is not a well-formed stl file.");
  
  string name = stlfile;
  if (returnsurfacename != null) returnsurfacename.s = name;

  surface toreturn;

  while (!eof(stlfile)) {
    nextword = stlfile;
    if (nextword == "endsolid") break;
    else if (nextword == "facet") {

      nextword = stlfile;
      assert(nextword == "normal");

      x = stlfile; y = stlfile; z = stlfile;
      triple normal = (x, y, z);

      nextword = stlfile; assert(nextword == "outer");
      nextword = stlfile; assert(nextword == "loop");
      triple[] vertices = new triple[3];
      for (int i = 0; i < 3; ++i) {
        nextword = stlfile; assert(nextword == "vertex");
        x = stlfile; y = stlfile; z = stlfile;
        vertices[i] = (x,y,z);
      }
      nextword = stlfile; assert(nextword == "endloop");
      nextword = stlfile; assert(nextword == "endfacet");

      patch triangle = patch(vertices[0] -- vertices[1] -- vertices[2] -- cycle);
      triangle.normals = array(4, value=normal);
      toreturn.s.push(triangle);
      
    } else assert(false, filename + " is not a well-formed stl file.");
  }
  assert(nextword == "endsolid", filename + " does not end correctly.");
  nextword = stlfile;
  assert(nextword == name, filename + " does not end with the solid's correct name " + name);
  return toreturn;
}

currentprojection = perspective(-30, 10, 60);
surface propeller = readstlfile("propellerbetter.stl");
draw(propeller, blue);

propeller

Related Question