// php working! /* //TODO: Check Si tol < increm (sinon => prop ajust tol ou ajust nbtot points) //TODO: settings !!! //TODO: maxx-minx => grain / tol recommendation! //TODO: webworker! */ // ------------------------------------------------------------------------------- // UTILITIES // ------------------------------------------------------------------------------- // General // ------- function sqr(a) { return a * a; } // ------------------------------------------------------------------------------- // PATH 2 POINTS // ------------------------------------------------------------------------------- // Setting variables // ----------------- var precisionOut = 1000; var precision = 1000; var totPoints = 10000; var TOL = 0.2; var reduc = 50; var xOffset = 0; var yOffset = 120; // Specific utilities // ------------------ function distPt(pt1, pt2){ return Math.sqrt(sqr(pt1.x - pt2.x) + sqr(pt1.y - pt2.y)); } function longPath(path) { return path.getTotalLength(); } function longTotal(pathCollec) { var tot = 0; for (var i = 0; i < pathCollec.length; ++i) { tot += longPath(pathCollec[i]); } return tot; } // Specific utilities for points function cpPt(pt){ var np = []; np.x = pt.x; np.y = pt.y; return np; } function plus(a, b){ var r = {}; r.x = a.x + b.x; r.y = a.y + b.y; return r; } function moins(a, b){ var r = {}; r.x = a.x - b.x; r.y = a.y - b.y; return r; } function plusN(a, b, n){ var r = {}; r.x = a.x + n*b.x; r.y = a.y + n*b.y; return r; } // Main specific functions // ----------------------- /** * @brief Transforms a SVG path into a points array * * @param [in] path The path to transform * @param [in] increm the incrementation (relative to length used for the points * @return The point array */ function path2points(path, increm) { var ptList = []; for (var i = 0; i < path.getTotalLength(); i += increm ) { pt = path.getPointAtLength(Math.round(i * precision) / precision); ptList.push(pt); } pt = path.getPointAtLength(path.getTotalLength()); ptList.push(pt); return ptList; } /** * @brief Finds all "jumps" in a path (a.k.a. when it goes from one openning to another). * * @param [in] ptList The initial points list * @param [in] increm The increment used to transform from path (a.k.a. the "normal" distance between points) * @return A list of indices (in ptList) of points adjacent to jumps (that is every point just before and just after a jump) */ function findJumps(ptList, increm){ var jumpList = []; for(var i = 1; i < ptList.length; ++i){ if(distPt(ptList[i-1], ptList[i]) > ( 1.5 * ( increm ) ) ){ // Jump detected jumpList.push(i-1); jumpList.push(i); } } return jumpList; } /** * @brief Corrects the jumps in a list of points (to correctly close the shape) * * @param [in, out] ptList The list of points to be corrected * @param [in] increm The increment used to transform from path (a.k.a. the "normal" distance between points) * @return Returns the corrected list of points * * @details In facts it adds all points corresponding to jumps at the end ... in reverse order regarding their first appearance in the list */ function correctJumps(ptList, increm){ var corList = findJumps(ptList, increm); for(var i = corList.length-1; i >= 0; --i){ ptList.push(cpPt(ptList[corList[i]])); } } /** * @brief Get rid of points judged "not needed" * * @param [in] ptList Initial point list * @param [in] tol distance under which the error is judged acceptable (that is the max individual positionning we'll max by dropping a point) * @param [in] protectedIndex Indexes that should be protected should appear in here as (ex: index 6 should be protected) : protectedIndex["_"+6] => true * @return return the simplified list */ function simplifyPath(ptList, tol, protectedIndex){ var simplified = []; if(ptList.length > 1){ simplified[0] = ptList[0]; simplified[1] = ptList[1]; }else{ return ptList; } var i = 2; var skip = 0; while(i < ptList.length){ if(ptList.length - i > 2 && ! protectedIndex["_"+(i)] && simplified.length >=2 ){ var ptC = ptList[i]; var dernOk = simplified[simplified.length-1]; var vect = moins(dernOk, simplified[simplified.length-2]); var ptNC = plusN(dernOk, vect, skip + 1); if(distPt(ptC, ptNC) < tol) { // current point is ~aligned var ptN = ptList[i+1]; if(distPt(ptN, plus(ptNC, vect)) < tol){ // next is also ~aligned => we can get rid of next // Do nothing (that is do not add to simplified!) ++skip; }else{ simplified.push(ptList[i]); // Yeah ... repetitions ... but I want it to only do tests when required skip = 0; } }else{ simplified.push(ptList[i]); skip = 0; } }else{ simplified.push(ptList[i]); skip = 0; } ++i; } return simplified; } //function simplifyPath2 /** * @brief Gets all path from SVG and turns it into an array of coordinates * * @return Array of Array of Array of Point of coordinates * | | | | | * | | | | --> unformated number * | | | | * | | | --> 2 element: * | | | x : x coord * | | | y : y coord * | | | * | | --> one full path : * | | 0 : coord_0 (x,y) [Point] * | | 1 : coord_1 (x,y) [Point] * | | ... * | | * | --> A path and its name : * | name : path_name [path ID] * | path : path_ [(x,y), (x,y), ...] * | * --> All paths: * 0 : [path0_name, path0_[] ] * 1 : [path1_name, path1_[] ] * ... * * @details Transforms all SVG path to coordinates lists, then corrects those lists for jumps and return an array of those corrected lists of points */ function getPts() { var objects = document.getElementsByTagName("path"); var objTrans = []; var increm = longTotal(objects) / totPoints; if(confirm("Trouvé : " + objects.length + " objet(s), increm = " + increm)){ var tab = []; for (var i = 0; i < objects.length; ++i) { var ptList = path2points(objects[i], increm); correctJumps(ptList, increm); var path_w_name = []; path_w_name.name = objects[i].id; path_w_name.path = simplifyPath(ptList, TOL, tab); objTrans.push(path_w_name); } zeroish(objTrans); } return objTrans; } // The 3 functions below take something like is output by getPts function getMinMax_x_y(tab){ var extr = []; extr.MinX = Infinity; extr.MaxX = -Infinity; extr.MinY = Infinity; extr.MaxY = -Infinity; for(var i = 0; i < tab.length; ++i){ var onePath = tab[i]; for(var j = 0; j < onePath.path.length; ++j){ var onePoint = onePath.path[j]; if(onePoint.x < extr.MinX) extr.MinX = onePoint.x; if(onePoint.x > extr.MaxX) extr.MaxX = onePoint.x; if(onePoint.y < extr.MinY) extr.MinY = onePoint.y; if(onePoint.y > extr.MaxY) extr.MaxY = onePoint.y; } } return extr; } function translate(tab, x, y){ for(var i = 0; i < tab.length; ++i){ for(var j = 0; j < tab[i].path.length; ++j){ tab[i].path[j].x += x; tab[i].path[j].y += y; } } } function zeroish(objTrans){ var extr = getMinMax_x_y(objTrans); translate(objTrans, -extr.MinX, -extr.MinY); } // ------------------------------------------------------------------------------- // LIST OF POINTS 2 TEXT // ------------------------------------------------------------------------------- // Specific utilities // ------------------ function prpVal(val, offset) { return Math.round((val / reduc + offset) * precisionOut) / precisionOut; } function singleObjTrans2String(objTrans) { var str = ""; for (var i_pt = 0; i_pt < objTrans.length; ++i_pt) { str += prpVal(objTrans[i_pt].x, xOffset) + "mm\t" + prpVal(objTrans[i_pt].y, yOffset) + "mm\n"; } return str; } // ------------------------------------------------------------------------------- // TEXT 2 FILES // ------------------------------------------------------------------------------- function txt2file(txt, filename) { var link = document.getElementById("downloadFile"); link.download = filename + '.txt'; var blob = new Blob([txt], { type: 'text/plain' }); link.href = window.URL.createObjectURL(blob); link.click(); } function all2File() { alert("Gathering data"); var objTrans = getPts(); for (var i = 0; i < objTrans.length; ++i) { alert("Preparing File " + objTrans[i].name); txt2file(singleObjTrans2String(objTrans[i].path), objTrans[i].name); } alert("terminé!"); } // ------------------------------------------------------------------------------- // INTERFACE // ------------------------------------------------------------------------------- function startTransform() { all2File(); }