public function writeStl($ps_stl) { // truncate file if (@file_put_contents($ps_stl, "") === false) { return false; // probably permission error } if (sizeof($this->opa_faces) < 1 || sizeof($this->opa_vertices) < 1) { return false; // invalid ply or not parsed yet } $vo_handle = @fopen($ps_stl, "w"); fwrite($vo_handle, "solid collectiveaccess_generated_stl\n"); foreach ($this->opa_faces as $vs_face) { // calculate normal (the 'right hand rule') // have to unpack from strings first $pa_unpack = unpack("I*", $vs_face); $p1 = array_values(unpack("f*", $this->opa_vertices[$pa_unpack[1]])); $p2 = array_values(unpack("f*", $this->opa_vertices[$pa_unpack[2]])); $p3 = array_values(unpack("f*", $this->opa_vertices[$pa_unpack[3]])); $u = PlyToStl::vec_sub($p2, $p1); $w = PlyToStl::vec_sub($p3, $p1); $n = PlyToStl::vec_crossprod($u, $w); // add triangle fprintf($vo_handle, "facet normal %f %f %f\n", $n[0], $n[1], $n[2]); fwrite($vo_handle, " outer loop\n"); fprintf($vo_handle, " vertex %f %f %f\n", $p1[0], $p1[1], $p1[2]); fprintf($vo_handle, " vertex %f %f %f\n", $p2[0], $p2[1], $p2[2]); fprintf($vo_handle, " vertex %f %f %f\n", $p3[0], $p3[1], $p3[2]); fwrite($vo_handle, " endloop\n"); fwrite($vo_handle, "endfacet\n"); } file_put_contents($ps_stl, "endsolid collectiveaccess_generated_stl\n", FILE_APPEND); return true; }