waterish_os_rev3_public/libraries/bitluni_ESP32Lib/Utilities/StlConverter.html

256 lines
6.2 KiB
HTML
Raw Normal View History

2019-08-09 02:01:56 +00:00
<!--
Author: bitluni 2019
License:
Creative Commons Attribution ShareAlike 4.0
https://creativecommons.org/licenses/by-sa/4.0/
For further details check out:
https://youtube.com/bitlunislab
https://github.com/bitluni
http://bitluni.net
-->
<head>
<script>
function readStl(stl, removeDouble)
{
//digital high five to @tonylukasavage for his https://github.com/tonylukasavage/jsstl
var data = {
vertexCount: 0,
triangleCount: 0,
edgeCount: 0,
triangles: [],
edges: [],
vertices: [],
triangleNormals: []
}
var map = [];
var o = 80;
var dv = new DataView(stl);
var triangleCount = dv.getUint32(o, true);
o += 4;
for (var j = 0; j < triangleCount; j++)
{
var t = [];
data.triangleNormals.push([dv.getFloat32(o, true), dv.getFloat32(o + 4, true), dv.getFloat32(o + 8, true)]);
o += 12;
for (var i = 0; i < 3; i++)
{
var v = [dv.getFloat32(o, true), dv.getFloat32(o + 4, true), dv.getFloat32(o + 8, true)];
if(removeDouble)
{
var newv = false;
if(map["f"+v[0]] === undefined)
map["f"+v[0]] = [];
if(map["f"+v[0]]["f"+v[1]] === undefined)
map["f"+v[0]]["f"+v[1]] = [];
if(map["f"+v[0]]["f"+v[1]]["f"+v[2]] === undefined)
{
map["f"+v[0]]["f"+v[1]]["f"+v[2]] = data.vertices.length;
t.push(data.vertices.length);
data.vertices.push(v);
}
else
t.push(map["f"+v[0]]["f"+v[1]]["f"+v[2]]);
}
else
{
t.push(data.vertices.length);
data.vertices.push(v);
}
o += 12;
}
data.triangles.push(t);
o += 2;
}
return data;
};
function scaleMesh(mesh)
{
if(!mesh.vertices.length) return;
var min = [mesh.vertices[0][0], mesh.vertices[0][1], mesh.vertices[0][2]];
var max = [min[0], min[1], min[2]];
for(var i = 0; i < mesh.vertices.length; i++)
{
var v = mesh.vertices[i];
min[0] = Math.min(min[0], v[0]);
min[1] = Math.min(min[1], v[1]);
min[2] = Math.min(min[2], v[2]);
max[0] = Math.max(max[0], v[0]);
max[1] = Math.max(max[1], v[1]);
max[2] = Math.max(max[2], v[2]);
}
size = Math.max(Math.max(max[0] - min[0], max[1] - min[1]), max[2] - min[2]);
for(var i = 0; i < mesh.vertices.length; i++)
{
var v = mesh.vertices[i];
v[0] = (v[0] - (max[0] + min[0]) * 0.5) / size;
v[1] = (v[1] - (max[1] + min[1]) * 0.5) / size;
v[2] = (v[2] - (max[2] + min[2]) * 0.5) / size;
}
}
function createEdges(mesh)
{
var map = [];
mesh.edges = [];
for(var i = 0; i < mesh.triangles.length; i++)
{
var t = mesh.triangles[i];
for(var j = 0; j < 3; j++)
{
var v0 = t[j];
var v1 = t[(j + 1) % 3];
if(v0 > v1)
{
var v = v0; v0 = v1; v1 = v;
}
if(map["v" + v0] === undefined)
map["v" + v0] = [];
if(map["v" + v0]["v" + v1] === undefined)
{
mesh.edges.push([v0, v1]);
map["v" + v0]["v" + v1] = true;
}
}
}
}
function meshToText(mesh, digits, edges, triangles, normals, name)
{
var text = "namespace " + name + "\r\n{\r\n";
text += "const int vertexCount = " + mesh.vertices.length + ";\r\n";
if(edges)
text += "const int edgeCount = " + mesh.edges.length + ";\r\n";
if(triangles)
text += "const int triangleCount = " + mesh.triangles.length + ";\r\n";
text += "const float vertices[][3] = {"
for(var i = 0; i < mesh.vertices.length; i++)
{
if((i & 15) == 0) text += "\r\n";
text += mesh.vertices[i][0].toFixed(digits) + ", " + mesh.vertices[i][1].toFixed(digits) + ", " + mesh.vertices[i][2].toFixed(digits) + ", ";
}
text += "};\r\n";
if(triangles)
{
text += "const unsigned short triangles[][3] = {";
for(var i = 0; i < mesh.triangles.length; i++)
{
if((i & 15) == 0) text += "\r\n";
text += mesh.triangles[i][0] + ", " + mesh.triangles[i][1] + ", " + mesh.triangles[i][2] + ", ";
}
text += "};\r\n";
}
if(edges)
{
text += "const unsigned short edges[][2] = {";
for(var i = 0; i < mesh.edges.length; i++)
{
if((i & 15) == 0) text += "\r\n";
text += mesh.edges[i][0] + ", " + mesh.edges[i][1] + ", ";
}
text += "};\r\n";
}
if(normals)
{
text += "const float triangleNormals[][3] = {";
for(var i = 0; i < mesh.triangles.length; i++)
{
if((i & 15) == 0) text += "\r\n";
text += mesh.triangleNormals[i][0].toFixed(digits) + ", " + mesh.triangleNormals[i][1].toFixed(digits) + ", " + mesh.triangleNormals[i][2].toFixed(digits) + ", ";
}
text += "};\r\n";
}
text += "};\r\n";
return text;
}
function convert(event)
{
var reader = new FileReader();
var file = event.target.files[0];
reader.onload = function(){
mesh = readStl(reader.result, true);
scaleMesh(mesh);
createEdges(mesh);
var link = document.createElement("a");
var name = file.name.split('.', 1)[0];
link.download = name + ".h";
link.href = URL.createObjectURL(new Blob(
[meshToText(mesh, 4,
document.getElementById("edges").checked,
document.getElementById("tris").checked,
document.getElementById("triNorms").checked, name)], {type: "text/plain"}));
document.body.appendChild(document.createElement("br"));
document.body.appendChild(link);
link.innerHTML = link.download;
link.click();
//document.body.removeChild(link);
event.target.value = "";
}
reader.readAsArrayBuffer(file);
}
</script><style>
.menu
{
background-color: #eeeeee;
padding: 1px;
display: block;
margin: 3px;
padding: 5px;
border-radius: 3px;
}
h1
{
color: white;
background: #800000;
padding: 10px;
border-radius: 5px;
}
.file
{
background-color: #ffdddd;
margin-right: 5px;
}
h1
{
margin-bottom: 5px;
}
.block
{
padding: 5px;
display: inline-block;
border-radius: 3px;
}
.options
{
background-color: #aeeeee;
}
.fileselection
{
background-color: #eeeeae;
}
</style>
</head>
<body style="font-family: arial">
<h1>bitluni's STL Converter</h1>
<div style="max-width: 800px">
<div class="menu">
Choose data structures to export and open the binary STL file to convert it to a c++ header file.<br>
Normals are needed to calculate lighting.<br>
<span class="options block">
Export: <input id="edges" type="checkbox">edges <input id="tris" type="checkbox" checked>triangles <input id="triNorms" type="checkbox" checked>triangle normals<br>
</span>
<span class="fileselection block">
<input type="file" onchange="convert(event)" accept=".stl">
</span>
</div>
</body></html>