/*
This file is a part of "Papier" a paper-crafting tool
Copyright (C) 2018 Saint Pierre Thomas ( s1pierro@protonmail.fr )
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
'use strict';
/**
@function getwavefrontproperties
@param {object} o - the mesh to analisys
*/
function getwavefrontproperties (o)
{
var xmax = obj.vertices[0][0];
var xmin = obj.vertices[0][0];
var ymax = obj.vertices[0][1];
var ymin = obj.vertices[0][1];
var zmax = obj.vertices[0][2];
var zmin = obj.vertices[0][2];
for ( var i = 0 ; i < obj.vertices.length ; i++)
{
if ( obj.vertices[i][0] > xmax ) xmax = obj.vertices[i][0]
if ( obj.vertices[i][0] < xmin ) xmin = obj.vertices[i][0]
if ( obj.vertices[i][1] > ymax ) ymax = obj.vertices[i][1]
if ( obj.vertices[i][1] < ymin ) ymin = obj.vertices[i][1]
if ( obj.vertices[i][2] > zmax ) zmax = obj.vertices[i][2]
if ( obj.vertices[i][2] < zmin ) zmin = obj.vertices[i][2]
}
o.sx = xmax-xmin;
o.sy = ymax-ymin;
o.sz = zmax-zmin;
}
/**
@function parsewavefront
@param {object} objText - a string containing the mesh defined
@param {text} id - the id to attibute to the created mesh object
@returns {object} an object that store mesh define in a format
suitable to the app
*/
function printWavefront (o)
{
var po = '# o '+o.nme;
var tmp = '\n#frz';
for ( var i = 0 ; i < o.edges.length ; i++ )
if (edgestate(o, i) == "freeze" ) tmp+=' '+i;
po = po+tmp;
tmp = '';
for ( var i = 0 ; i < o.vertices.length ; i++ )
tmp+='\nv '+o.vertices[i][0]+' '+o.vertices[i][1]+' '+o.vertices[i][2];
po = po+tmp;
tmp = '';
for ( var i = 0 ; i < o.triangles.length ; i++ )
tmp+='\nf '+(o.triangles[i][0]+1)+' '+(o.triangles[i][1]+1)+' '+(o.triangles[i][2]+1);
po = po+tmp;
return po;
}
function parsewavefront(objText, id) {
console.clear();
var nv = 0;
var nt = 0;
var ng = 0;
var obj = {};
var vertexMatches = objText.match(/^v( -?\d+(\.\d+)?){3}$/gm);
// var triMatches = objText.match(/^f( \d+){3}$/gm);
var triMatches = objText.match(/^f( \d+){3,4}$/gm);
var gMatches = objText.match(/^f( \d+){3,4}$|^usemtl (.+)$/gm);
var positionMatches = objText.match(/^position( -?\d+(\.\d+)?){3}$/gm);
var frzMatches = objText.match(/^#frz( \d+){1,}$/gm);
var nameMatches = objText.match(/^# o( .+){1,}/gm);
if (nameMatches) {
var name = nameMatches[0].split(" ");
name.shift();
var tmpname = "";
for ( var g = 1 ; g < name.length ; g++ )
tmpname+=' '+name[g];
obj.nme = tmpname;
}
else obj.nme ='unnamed';
if (vertexMatches) {
obj.vertices = vertexMatches.map(function(vertex) {
nv++;
var vertices = vertex.split(" ");
vertices.shift();
return Float64Array.from(vertices);;
});
}
if (positionMatches) {
console.log (positionMatches );
}
if (frzMatches) {
var frozen = frzMatches[0];//.map(function(frz) {
frozen = frozen.split(" ");
frozen.shift();
obj.prefreeze = Uint16Array.from(frozen);
// });
}
if (triMatches) {
obj.triangles = triMatches.map(function(tri) {
nt++;
var triangle = tri.split(" ");
triangle.shift();
// l(triangles);
var t = Uint16Array.from(triangle);
t[0] = t[0]-1;
t[1] = t[1]-1;
t[2] = t[2]-1;
// l(t);
return t;
});
}
var mat = 'mat';
if (gMatches) {
gMatches.map(function(g) {
var inc = true;
var gMatch = g.split(" ");
if (gMatch[0] === 'usemtl')
{
gMatch.shift();
inc = false;
mat = gMatch[0];
} else if (gMatch[0] === 'f')
{
obj.triangles[ng].state="visible";
obj.triangles[ng].mat = mat;
ng++;
}
});
}
for (var i = 0 ; i < obj.triangles.length ; i++ )
obj.triangles[i].id = id;
obj.edges = [];
genEdge (obj );
rotateWavefront (obj, 21.4, 43.3, 66.3);
/*
rotateWavefront (obj, getRandomArbitrary(0, 1),
getRandomArbitrary(0, 1),
getRandomArbitrary(0, 1));
**/
syncTriangleSomOrder (obj);
genNormales(obj);
obj.nv = nv;
obj.nt = nt;
obj.ng = ng;
var xmax = obj.vertices[0][0];
var xmin = obj.vertices[0][0];
var ymax = obj.vertices[0][1];
var ymin = obj.vertices[0][1];
var zmax = obj.vertices[0][2];
var zmin = obj.vertices[0][2];
for ( var i = 0 ; i < obj.vertices.length ; i++)
{
if ( obj.vertices[i][0] > xmax ) xmax = obj.vertices[i][0]
if ( obj.vertices[i][0] < xmin ) xmin = obj.vertices[i][0]
if ( obj.vertices[i][1] > ymax ) ymax = obj.vertices[i][1]
if ( obj.vertices[i][1] < ymin ) ymin = obj.vertices[i][1]
if ( obj.vertices[i][2] > zmax ) zmax = obj.vertices[i][2]
if ( obj.vertices[i][2] < zmin ) zmin = obj.vertices[i][2]
}
var sx = (xmax-xmin);
var sy = (ymax-ymin);
var sz = (zmax-zmin);
var mx = xmax-sx/2;
var my = ymax-sy/2;
var mz = zmax-sz/2;
var height = sx;
if ( height < sy ) height = sy;
if ( height < sz ) height = sz;
obj.height = height*1.5;
translateWavefront (obj, -mx, -my, -mz);
obj.sx = xmax-xmin;
obj.sy = ymax-ymin;
obj.sz = zmax-zmin;
$('.sizeX').text((obj.sx/10).toFixed(2));
$('.sizeY').text((obj.sy/10).toFixed(2));
$('.sizeZ').text((obj.sz/10).toFixed(2));
$('#p-title-content').text(obj.nme);
return obj;
}
window['parsewavefront'] = parsewavefront;
function genEdge (obj )
{
var edgeOverBurdedError = false;
for ( var i = 0 ; i < obj.triangles.length ; i++)
{
addEdge (obj, obj.triangles[i][obj.triangles[i].length-1], obj.triangles[i][0], i );
for ( var j = 0 ; j < obj.triangles[i].length-1 ; j++ )
addEdge (obj, obj.triangles[i][j], obj.triangles[i][j+1], i );
}
obj.ne = obj.edges.length;
for ( var i = 0 ; i < obj.edges.length ; i++)
if ( obj.edges[i].tri.length > 2 )
edgeOverBurdedError = true;
if (edgeOverBurdedError)
alert ( 'Error, the mesh contains edges that are shared by more than'+
' two triangles. Some pattern flattening will be corrupted');
}
window['genEdge'] = genEdge;
function addEdge (obj, es1, es2, t)
{
var e = gotEdge (obj, es1, es2 );
if (e == -1)
{
var tmp = { som : [es1, es2], tri : [t], state : "hide", id : obj.edges.length };
obj.edges.push (tmp);
}
else
{
if( gotTriangleEdge (obj, es1, es2, t ) == -1 ) obj.edges[e].tri.push (t);
}
}
window.addEdge = addEdge;
function gotEdge (obj, es1, es2 )
{
for ( var i = 0 ; i < obj.edges.length ; i++)
if ( ( obj.edges[i].som[0] == es1 && obj.edges[i].som[1] == es2 ) |
( obj.edges[i].som[0] == es2 && obj.edges[i].som[1] == es1 ) )
return i;
return -1;
}
function gotTriangleEdge (obj, es1, es2, t )
{
var e = gotEdge (obj, es1, es2 );
if ( e != -1 )
{
for ( var j = 0 ; j < obj.edges[e].tri.length ; j++ )
{
if ( obj.edges[e].tri[j] == t )
return e;
}
}
return -1;
}
function loadWavefrontFromHTLM(object, id) {
var contents = $(object).text();
var obj = parsewavefront(contents, id);
return obj;
}
window['loadWavefrontFromHTLM'] = loadWavefrontFromHTLM;
function setWavefrontId(w, id) {
for ( var j = 0 ; j < w.nt ; j++)
w.triangles[ j ].id = id;
}
window['setWavefrontId'] = setWavefrontId;
function genNormales(obj) {
obj.trianglesnorm = [];
for (var i = 0; i < obj.triangles.length ; i += 1) {
var norm = normalisevertex(
vectorproduct(
vectfromvertices(
obj.vertices[obj.triangles[i][0]],
obj.vertices[obj.triangles[i][2]] ).s,
vectfromvertices(
obj.vertices[obj.triangles[i][0]],
obj.vertices[obj.triangles[i][1]] ).s
)
);
obj.trianglesnorm.push (norm);
}
}
window['genNormales'] = genNormales;
function translateWavefront (wavefront, x, y, z)
{
for ( var i = 0 ; i < wavefront.vertices.length ; i ++ )
{
wavefront.vertices[i][0] = parseFloat(wavefront.vertices[i][0])+x;
wavefront.vertices[i][1] = parseFloat(wavefront.vertices[i][1])+y;
wavefront.vertices[i][2] = parseFloat(wavefront.vertices[i][2])+z;
}
}
window['translateWavefront'] = translateWavefront;
function scaleWavefront (wavefront, scale)
{
fl( 'scaling '+scale);
for ( var i = 0 ; i < wavefront.vertices.length ; i ++ )
{
wavefront.vertices[i][0] = parseFloat(wavefront.vertices[i][0])*scale;
wavefront.vertices[i][1] = parseFloat(wavefront.vertices[i][1])*scale;
wavefront.vertices[i][2] = parseFloat(wavefront.vertices[i][2])*scale;
}
var xmax = wavefront.vertices[0][0];
var xmin = wavefront.vertices[0][0];
var ymax = wavefront.vertices[0][1];
var ymin = wavefront.vertices[0][1];
var zmax = wavefront.vertices[0][2];
var zmin = wavefront.vertices[0][2];
for ( var i = 0 ; i < wavefront.vertices.length ; i++)
{
if ( wavefront.vertices[i][0] > xmax ) xmax = wavefront.vertices[i][0]
if ( wavefront.vertices[i][0] < xmin ) xmin = wavefront.vertices[i][0]
if ( wavefront.vertices[i][1] > ymax ) ymax = wavefront.vertices[i][1]
if ( wavefront.vertices[i][1] < ymin ) ymin = wavefront.vertices[i][1]
if ( wavefront.vertices[i][2] > zmax ) zmax = wavefront.vertices[i][2]
if ( wavefront.vertices[i][2] < zmin ) zmin = wavefront.vertices[i][2]
}
wavefront.sx = xmax-xmin;
wavefront.sy = ymax-ymin;
wavefront.sz = zmax-zmin;
$('.sizeX').text((wavefront.sx/10).toFixed(2));
$('.sizeY').text((wavefront.sy/10).toFixed(2));
$('.sizeZ').text((wavefront.sz/10).toFixed(2));
}
function rotateWavefront (wavefront, x, y, z)
{
var tmpmat = genrmat(x, y, z);
var tmp = wavefront;
for (var i = 0; i < wavefront.vertices.length; i++)
wavefront.vertices[i] = applymat(tmpmat, wavefront.vertices[i]);
genNormales(wavefront);
}
window['rotateWavefront'] = rotateWavefront;
function readWavefrontFile(evt) {
toggleDview ();
$('#main-app-dialog-title').text( 'loading ...');//+' body : '+$( window ).width()+' '+$( window ).height() );
$('#main-app-dialog-info').text( 'please wait');//+' body : '+$( window ).width()+' '+$( window ).height() );
blankscene ();
var f = evt.target.files[0];
if (f)
{
var r = new FileReader();
r.onload = function(e)
{
var contents = e.target.result;
var obj = parsewavefront(e.target.result, 0);
pobj = $.extend(true, {}, obj);
patterns = new Patterns(pobj);
feedscene();
if (pobj.prefreeze != undefined )
{
for ( var i = 0 ; i < pobj.prefreeze.length ; i++)
setedgestate (pobj, pobj.prefreeze[i], "freeze");
patterns.rebuild();
}
activeshape1 = -1;
toggleDview ();
}
r.readAsText(f);
} else {
alert("Failed to load file");
}
}
function loadWavefrontExample(file) {
toggleDview ();
$('#main-app-dialog-title').text( 'loading');//+' body : '+$( window ).width()+' '+$( window ).height() );
console.log('Loading ...')
jQuery.get(file, function(data)
{
var obj = parsewavefront(data, 0);
pobj = $.extend(true, {}, obj);
//l(wavefront);
patterns = new Patterns(pobj);
blankscene ();
feedscene();
if (pobj.prefreeze != undefined )
{
for ( var i = 0 ; i < pobj.prefreeze.length ; i++)
setedgestate (pobj, pobj.prefreeze[i], "freeze");
patterns.rebuild();
}
activeshape1 = -1;
toggleDview ();
});
}
function getEdgeId (o, s1, s2)
{
if ( s1 == s2 ) return -2;
if ( s1 == -1 | -1 == s2 ) return -3;
for (var i = 0 ; i < o.edges.length ; i++ )
{
var ok1 = false;
var ok2 = false;
for ( var j = 0 ; j < o.edges[i].som.length ; j++ )
{
if ( o.edges[i].som[j] == s1 ) ok1 = true;
if ( o.edges[i].som[j] == s2 ) ok2 = true;
}
if ( ok1 && ok2 ) return i;
}
return -1;
}
function sharededge ( o, triangle_1, triangle_2)
{
if ( triangle_1 == triangle_2 ) return -2;
if ( triangle_1 == -1 | -1 == triangle_2 ) return -3;
for (var i = 0 ; i < o.edges.length ; i++ )
{
var ok1 = false;
var ok2 = false;
for ( var j = 0 ; j < o.edges[i].tri.length ; j++ )
{
if ( o.edges[i].tri[j] == triangle_1 ) ok1 = true;
if ( o.edges[i].tri[j] == triangle_2 ) ok2 = true;
}
if ( ok1 && ok2 ) return i;
}
return -1;
}
function syncTriangleSomOrder (o)
{
var td = new ToDo ();
td.add(0);
var flipCnt = 0;
var dnl = new processedelements ();
var cnt = 0;
while (td.isEmpty() == false)
{
var crtTri = td.next();
// fl('\nLoop ('+cnt+') start, triangle : '+crtTri+'\n##################');
dnl.add (crtTri);
var tmp = findJoinedTriangles (o, crtTri );
// we need to elimanate triangles that have already by checked
for (let i = tmp.length - 1; i >= 0; i--)
if (true == dnl.is(tmp[i]))
tmp.splice(i, 1);
// fl(tmp.length+' triangle to check');
// fl(tmp);
for (var i = 0 ; i < tmp.length ; i++)
{
//TODO test each triange with crtTri
//fl('is done '+tmp[i]+' : '+dnl.is(tmp[i]));
if (dnl.is(tmp[i]) == false )
{
if ( doesTrianleNeedFlip (o, tmp[i], crtTri) == true )
{
flipTriangle (o, tmp[i]);
flipCnt++;
}
td.add(tmp[i]);
dnl.add (tmp[i]);
}
}
td.done(crtTri);
cnt++;
}
if ( cnt != o.triangles.length ) alert('WARNING,the mesh is not monobloc, flattening errors could occur.')
// fl (dnl.pe);
//fl(flipCnt+' triangle(s) fliped')
//if ( dnl.is(tmp[i]) == false ) td.add(tmp[i]);
}
function doesTrianleNeedFlip (o, t, ref)
{
//TODO Emergency, Very important.
var s1 = o.edges[sharededge ( o, t, ref )].som[0];
var s2 = o.edges[sharededge ( o, t, ref )].som[1];
var st1 = -1;
var st2 = -1;
if ( o.triangles[t][0] == s1 && o.triangles[t][1] == s2 ) st1 = 1;
if ( o.triangles[t][1] == s1 && o.triangles[t][2] == s2 ) st1 = 1;
if ( o.triangles[t][2] == s1 && o.triangles[t][0] == s2 ) st1 = 1;
if ( o.triangles[ref][0] == s1 && o.triangles[ref][1] == s2 ) st2 = 1;
if ( o.triangles[ref][1] == s1 && o.triangles[ref][2] == s2 ) st2 = 1;
if ( o.triangles[ref][2] == s1 && o.triangles[ref][0] == s2 ) st2 = 1;
if (st1 == st2 )
return true;
return false;
}
function findJoinedTriangles (o, t)
{
var tmp = TRIANGLEgetedges (o, t);
var tmp2 = [];
for ( var i = 0 ; i < tmp.length ; i ++ )
for ( var j = 0 ; j < o.edges[tmp[i]].tri.length ; j++ )
if ( o.edges[tmp[i]].tri[j] != t )
tmp2.push(o.edges[tmp[i]].tri[j])
return tmp2;
}
function flipTriangle (o, t)
{
var tmp = $.extend(true, {}, o.triangles[t]);
o.triangles[t][0] = tmp[1];
o.triangles[t][1] = tmp[0];
}
function TRIANGLEgetedges (o, t)
{
var tmp = [];
for( var i = 0 ; i < o.edges.length ; i++ )
{
if ( JUNCTIONgottriangle (o.edges[i], t) != -1 ) tmp.push(i);
}
return tmp;
}
function JUNCTIONgottriangle (j, t)
{
for( var i = 0 ; i < j.tri.length ; i++ )
if ( j.tri[i] == t ) return i;
return -1;
}
function edgestate (o, e)
{
return o.edges[e].state;
}
function setedgestate (o, e, s)
{
scene.children[(2+e)].visible = true;
o.edges[e].state = s;
if( s == "visible")
scene.children[(2+e)].material = materialFrontier;
if( s == "freeze")
{
scene.children[(2+e)].visible = false;
}
if( s == "highlight")
scene.children[(2+e)].material = materialFrontier;
if( s == "hide")
{
scene.children[(2+e)].visible = false;
}
}
function shapestate (o, t)
{
l('## shape('+t+').state : '+o.triangles[t].state);
return o.triangles[t].state;
}
function setshapestate (o, t, s)
{
if ( s == undefined )
fl('-#- ERROR unable to set shape ( '+t+' ) state to '+s+' leaving function "setshapestate"', 'lr');
o.triangles[t].state = s;
if( s == "visible")
{
scene.children[(2+t+o.ne)].material = materialVisible;
scene.children[(2+t+o.ne)].visible = true;
}
if( s == "solid")
{
scene.children[(2+t+o.ne)].material = materialSolid;
scene.children[(2+t+o.ne)].visible = true;
}
if( s == "highlight")
{
scene.children[(2+t+o.ne)].visible = true;
scene.children[(2+t+o.ne)].material = materialHighlighted;
}
}
function download(filename, text) {
var element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
/*
this file is a part of
papier 0.4.1
Author : Saint Pierre Thomas
If you got interest in such kind of app
feel free to contact me at spierro@protonmail.fr
Licenced under the termes of the GNU GPL v3
*/