//----------------------- Quick SVG LIBRARY -------------------------------------------------- //----------------------- V1.0 Licence MIT --------------------------------------------------- //----------------------- Author : Patrick RASPINO-------------------------------------------- //----------------------- 11/08/16 ----------------------------------------------------------- // 'use strict'; var qSVG = { create: function(id, shape, attrs) { var shape = $(document.createElementNS("http://www.w3.org/2000/svg", shape)); for (var k in attrs) { shape.attr(k, attrs[k]); } if (id != 'none') { $("#" + id).append(shape); } return shape; }, angleDeg: function(cx, cy, ex, ey) { var dy = ey - cy; var dx = ex - cx; var theta = Math.atan2(dy, dx); // range (-PI, PI] theta *= 180 / Math.PI; // rads to degs, range (-180, 180] if (theta < 0) theta = 360 + theta; // range [0, 360) return theta; }, angle: function(x1, y1, x2, y2, x3, y3) { var x1 = parseInt(x1); var y1 = parseInt(y1); var x2 = parseInt(x2); var y2 = parseInt(y2); var anglerad; if (!x3) { if (x1 - x2 == 0) anglerad = Math.PI / 2; else { anglerad = Math.atan((y1 - y2) / (x1 - x2)); } var angledeg = anglerad * 180 / Math.PI; } else { var x3 = parseInt(x3); var y3 = parseInt(y3); var a = Math.sqrt(Math.pow(Math.abs(x2 - x1), 2) + Math.pow(Math.abs(y2 - y1), 2)); var b = Math.sqrt(Math.pow(Math.abs(x2 - x3), 2) + Math.pow(Math.abs(y2 - y3), 2)); var c = Math.sqrt(Math.pow(Math.abs(x3 - x1), 2) + Math.pow(Math.abs(y3 - y1), 2)); if (a == 0 || b == 0) anglerad = Math.PI / 2; else { anglerad = Math.acos((Math.pow(a, 2) + Math.pow(b, 2) - Math.pow(c, 2)) / (2 * a * b)); } angledeg = (360 * anglerad) / (2*Math.PI); } return ({ rad: anglerad, deg: angledeg }); }, getAngle: function(el1, el2) { return ({ rad: Math.atan2(el2.y - el1.y, el2.x - el1.x), deg: Math.atan2(el2.y - el1.y, el2.x - el1.x)* 180 / Math.PI }); }, middle: function(xo, yo, xd, yd) { var x1 = parseInt(xo); var y1 = parseInt(yo); var x2 = parseInt(xd); var y2 = parseInt(yd); var middleX = Math.abs(x1 + x2) / 2; var middleY = Math.abs(y1 + y2) / 2; return ({ x: middleX, y: middleY }); }, triangleArea: function(fp, sp, tp) { var A = 0; var B = 0; var C = 0; var p = 0; A = qSVG.measure(fp, sp); B = qSVG.measure(sp, tp); C = qSVG.measure(tp, fp); p = (A + B + C) / 2; return (Math.sqrt(p*(p-A)*(p-B)*(p-C))); }, measure: function(po, pt) { return Math.sqrt(Math.pow(po.x - pt.x, 2) + Math.pow(po.y - pt.y, 2)); }, gap: function(po, pt) { return Math.pow(po.x - pt.x, 2) + Math.pow(po.y - pt.y, 2); }, pDistance(point, pointA, pointB) { var x = point.x; var y = point.y; var x1 = pointA.x; var y1 = pointA.y; var x2 = pointB.x; var y2 = pointB.y; var A = x - x1; var B = y - y1; var C = x2 - x1; var D = y2 - y1; var dot = A * C + B * D; var len_sq = C * C + D * D; var param = -1; if (len_sq != 0) //in case of 0 length line param = dot / len_sq; var xx, yy; if (param < 0) { xx = x1; yy = y1; } else if (param > 1) { xx = x2; yy = y2; } else { xx = x1 + param * C; yy = y1 + param * D; } var dx = x - xx; var dy = y - yy; return ({ x: xx, y: yy, distance: Math.sqrt(dx * dx + dy * dy) }); }, nearPointOnEquation: function(equation, point) { // Y = Ax + B ---- equation {A:val, B:val} var pointA = {}; var pointB = {}; if (equation.A == 'h') { return ({ x: point.x, y: equation.B, distance: Math.abs(equation.B - point.y) }); } else if (equation.A == 'v') { return ({ x: equation.B, y: point.y, distance: Math.abs(equation.B - point.x) }); } else { pointA.x = point.x; pointA.y = (equation.A * point.x) + equation.B; pointB.x = (point.y - equation.B)/equation.A; pointB.y = point.y; return qSVG.pDistance(point, pointA, pointB); } }, circlePath: function(cx, cy, r){ return 'M '+cx+' '+cy+' m -'+r+', 0 a '+r+','+r+' 0 1,0 '+(r*2)+',0 a '+r+','+r+' 0 1,0 -'+(r*2)+',0'; }, createEquation: function(x0, y0, x1, y1) { if (x1 - x0 == 0) { return ({ A: 'v', B: x0 });} else if (y1 - y0 == 0) { return ({ A: 'h', B: y0 });} else { return ({ A: (y1 - y0) / (x1 - x0), B: y1 - (x1 * ((y1 - y0) / (x1 - x0))) });} }, perpendicularEquation: function(equation, x1, y1) { if (typeof(equation.A) != "string") { return ({ A: (-1 / equation.A), B: y1 - ((-1 / equation.A) * x1) });} if (equation.A == 'h') { return ({ A: 'v', B: x1 });} if (equation.A == 'v') { return ({ A: 'h', B: y1 });} }, angleBetweenEquations: function(m1, m2) { if (m1 == 'h') m1 = 0; if (m2 == 'h') m2 = 0; if (m1 == 'v') m1 = 10000; if (m2 == 'v') m2 = 10000; var angleRad = Math.atan(Math.abs((m2 - m1) / (1 + (m1 * m2)))); return (360 * angleRad) / (2*Math.PI); }, // type array return [x,y] ---- type object return {x:x, y:y} intersectionOfEquations: function(equation1, equation2, type = "array", message = false) { var retArray; var retObj; if (equation1.A == equation2.A) { retArray = false; retObj = false; } if (equation1.A == 'v' && equation2.A == 'h') { retArray = [equation1.B, equation2.B]; retObj = {x: equation1.B, y: equation2.B}; } if (equation1.A == 'h' && equation2.A == 'v') { retArray = [equation2.B, equation1.B]; retObj = {x: equation2.B, y: equation1.B}; } if (equation1.A == 'h' && equation2.A != 'v' && equation2.A != 'h') { retArray = [(equation1.B - equation2.B)/equation2.A, equation1.B]; retObj = {x: (equation1.B - equation2.B)/equation2.A, y: equation1.B}; } if (equation1.A == 'v' && equation2.A != 'v' && equation2.A != 'h') { retArray = [equation1.B, (equation2.A * equation1.B) + equation2.B]; retObj = {x: equation1.B, y: (equation2.A * equation1.B) + equation2.B}; } if (equation2.A == 'h' && equation1.A != 'v' && equation1.A != 'h') { retArray = [(equation2.B - equation1.B)/equation1.A, equation2.B]; retObj = {x: (equation2.B - equation1.B)/equation1.A, y: equation2.B}; } if (equation2.A == 'v' && equation1.A != 'v' && equation1.A != 'h') { retArray = [equation2.B, (equation1.A * equation2.B) + equation1.B]; retObj = {x: equation2.B, y: (equation1.A * equation2.B) + equation1.B}; } if (equation1.A != 'h' && equation1.A != 'v' && equation2.A != 'v' && equation2.A != 'h') { var xT = (equation2.B - equation1.B) / (equation1.A - equation2.A); var yT = (equation1.A * xT) + equation1.B; retArray = [xT, yT]; retObj = {x: xT, y: yT}; } if (type == "array") return retArray; else return retObj; }, vectorXY: function(obj1, obj2) { return ({ x: obj2.x - obj1.x, y: obj2.y - obj1.y }); }, vectorAngle: function(v1, v2) { return (Math.atan2((v2.y-v1.y),(v2.x-v1.x))+Math.PI/2) * (180/Math.PI); }, vectorDeter: function(v1, v2) { return (v1.x * v2.y)-(v1.y * v2.x); }, btwn: function(a, b1, b2, round = false) { if (round) { a = Math.round(a); b1 = Math.round(b1); b2 = Math.round(b2); } if ((a >= b1) && (a <= b2)) { return true; } if ((a >= b2) && (a <= b1)) { return true; } return false; }, nearPointFromPath: function(Pathsvg, point, range = Infinity) { var pathLength = Pathsvg.getTotalLength(); if (pathLength>0) { var precision = 40; var best; var bestLength; var bestDistance = Infinity; for (var scan, scanLength = 0, scanDistance; scanLength <= pathLength; scanLength += precision) { scan = Pathsvg.getPointAtLength(scanLength); scanDistance = qSVG.gap(scan, point); if (scanDistance < bestDistance) { best = scan, bestLength = scanLength, bestDistance = scanDistance; } } // binary search for precise estimate precision /= 2; while (precision > 1) { var before, after, beforeLength, afterLength, beforeDistance, afterDistance; if ((beforeLength = bestLength - precision) >= 0 && (beforeDistance = qSVG.gap(before = Pathsvg.getPointAtLength(beforeLength), point)) < bestDistance) { best = before, bestLength = beforeLength, bestDistance = beforeDistance; } else if ((afterLength = bestLength + precision) <= pathLength && (afterDistance = qSVG.gap(after = Pathsvg.getPointAtLength(afterLength), point)) < bestDistance) { best = after, bestLength = afterLength, bestDistance = afterDistance; } else { precision /= 2; } } if (bestDistance <= (range*range)) { return ({ x: best.x, y: best.y, length: bestLength, distance: bestDistance, seg: Pathsvg.getPathSegAtLength(bestLength) }); } else { return false; } }else { return false; } }, // ON PATH RETURN FALSE IF 0 NODE ON PATHSVG WITH POINT coords // RETURN INDEX ARRAY OF NODEs onPoint getNodeFromPath: function(Pathsvg, point, except = ['']) { var nodeList = Pathsvg.getPathData(); var k = 0; var nodes = []; var countNode = 0; for (k = 0; k < nodeList.length; k++) { if (nodeList[k].values[0] == point.x && nodeList[k].values[1] == point.y && nodeList[k].type != 'Z') { if (except.indexOf(k) == -1) { countNode++; nodes.push(k); } } } if (countNode == 0) return false; else return nodes; }, // RETURN ARRAY [{x,y}, {x,y}, ...] OF REAL COORDS POLYGON INTO WALLS, THICKNESS PARAM polygonIntoWalls: function(vertex, surface) { var vertexArray = surface; var wall = []; var polygon = []; for (var rr = 0; rr < vertexArray.length; rr++) { polygon.push({x: vertex[vertexArray[rr]].x, y: vertex[vertexArray[rr]].y}); } // FIND EDGE (WALLS HERE) OF THESE TWO VERTEX for (var i = 0 ; i < vertexArray.length-1; i++) { for (var segStart = 0; segStart < vertex[vertexArray[i+1]].segment.length; segStart++) { for (var segEnd = 0; segEnd < vertex[vertexArray[i]].segment.length; segEnd++) { if (vertex[vertexArray[i+1]].segment[segStart] == vertex[vertexArray[i]].segment[segEnd]) { wall.push({x1: vertex[vertexArray[i]].x, y1: vertex[vertexArray[i]].y, x2: vertex[vertexArray[i+1]].x, y2: vertex[vertexArray[i+1]].y, segment: vertex[vertexArray[i+1]].segment[segStart]}); } } } } // CALC INTERSECS OF EQ PATHS OF THESE TWO WALLS. var inside = []; var outside = []; for (var i = 0; i < wall.length; i++) { var inter = []; var edge = wall[i]; if (i < wall.length - 1) var nextEdge = wall[i+1]; else var nextEdge = wall[0]; var angleEdge = Math.atan2(edge.y2 - edge.y1, edge.x2 - edge.x1); var angleNextEdge = Math.atan2(nextEdge.y2 - nextEdge.y1, nextEdge.x2 - nextEdge.x1); var edgeThicknessX = (WALLS[edge.segment].thick/2) * Math.sin(angleEdge); var edgeThicknessY = (WALLS[edge.segment].thick/2) * Math.cos(angleEdge); var nextEdgeThicknessX = (WALLS[nextEdge.segment].thick/2) * Math.sin(angleNextEdge); var nextEdgeThicknessY = (WALLS[nextEdge.segment].thick/2) * Math.cos(angleNextEdge); var eqEdgeUp = qSVG.createEquation(edge.x1 + edgeThicknessX, edge.y1 - edgeThicknessY, edge.x2 + edgeThicknessX, edge.y2 - edgeThicknessY); var eqEdgeDw = qSVG.createEquation(edge.x1 - edgeThicknessX, edge.y1 + edgeThicknessY, edge.x2 - edgeThicknessX, edge.y2 + edgeThicknessY); var eqNextEdgeUp = qSVG.createEquation(nextEdge.x1 + nextEdgeThicknessX, nextEdge.y1 - nextEdgeThicknessY, nextEdge.x2 + nextEdgeThicknessX, nextEdge.y2 - nextEdgeThicknessY); var eqNextEdgeDw = qSVG.createEquation(nextEdge.x1 - nextEdgeThicknessX, nextEdge.y1 + nextEdgeThicknessY, nextEdge.x2 - nextEdgeThicknessX, nextEdge.y2 + nextEdgeThicknessY); angleEdge = angleEdge * (180 / Math.PI); angleNextEdge = angleNextEdge * (180 / Math.PI); if (eqEdgeUp.A != eqNextEdgeUp.A) { inter.push(qSVG.intersectionOfEquations(eqEdgeUp, eqNextEdgeUp, "object")); inter.push(qSVG.intersectionOfEquations(eqEdgeDw, eqNextEdgeDw, "object")); } else { inter.push({x: edge.x2 + edgeThicknessX, y: edge.y2 - edgeThicknessY}); inter.push({x: edge.x2 - edgeThicknessX, y: edge.y2 + edgeThicknessY}); } for (var ii = 0;ii < inter.length; ii++) { if (qSVG.rayCasting(inter[ii], polygon)) inside.push(inter[ii]); else outside.push(inter[ii]); } } inside.push(inside[0]); outside.push(outside[0]); return {inside: inside, outside: outside}; }, area: function(coordss) { if (coordss.length < 2) return false; var realArea = 0; var j = (coordss.length)-1; for (var i = 0; i < coordss.length; i++) { realArea = realArea + ((coordss[j].x + coordss[i].x) * (coordss[j].y - coordss[i].y)); j = i; } realArea = realArea / 2; return Math.abs(realArea.toFixed(2)); }, areaRoom: function (vertex, coords, digit = 2) { var vertexArray = coords; var roughArea = 0; var j = (vertexArray.length)-2; for (var i = 0; i < vertexArray.length-1; i++) { roughArea = roughArea + ((vertex[vertexArray[j]].x + vertex[vertexArray[i]].x) * (vertex[vertexArray[j]].y - vertex[vertexArray[i]].y)); j = i; } roughArea = roughArea / 2; return Math.abs(roughArea.toFixed(digit)); }, perimeterRoom: function (coords, digit = 2) { var vertexArray = coords; var roughRoom = 0; for (i = 0; i < vertexArray.length-1; i++) { added = qSVG.measure(vertex[vertexArray[i]], vertex[vertexArray[i+1]]); roughRoom = roughRoom + added; } return roughRoom.toFixed(digit); }, // H && V PROBLEM WHEN TWO SEGMENT ARE v/-> == I/-> junctionList: function(WALLS) { var junction = []; var segmentJunction = []; var junctionChild = []; // JUNCTION ARRAY LIST ALL SEGMENT INTERSECTIONS for (var i = 0; i < WALLS.length; i++) { var equation1 = qSVG.createEquation(WALLS[i].start.x, WALLS[i].start.y, WALLS[i].end.x, WALLS[i].end.y); for (var v = 0; v < WALLS.length; v++) { if (v != i) { var equation2 = qSVG.createEquation(WALLS[v].start.x, WALLS[v].start.y, WALLS[v].end.x, WALLS[v].end.y); var intersec; if (intersec = qSVG.intersectionOfEquations(equation1, equation2)) { if (WALLS[i].end.x == WALLS[v].start.x && WALLS[i].end.y == WALLS[v].start.y || WALLS[i].start.x == WALLS[v].end.x && WALLS[i].start.y == WALLS[v].end.y) { if (WALLS[i].end.x == WALLS[v].start.x && WALLS[i].end.y == WALLS[v].start.y) { junction.push({segment:i, child: v, values: [WALLS[v].start.x, WALLS[v].start.y], type: "natural"}); } if (WALLS[i].start.x == WALLS[v].end.x && WALLS[i].start.y == WALLS[v].end.y) { junction.push({segment:i, child: v, values: [WALLS[i].start.x, WALLS[i].start.y], type: "natural"}); } } else { if (qSVG.btwn(intersec[0], WALLS[i].start.x, WALLS[i].end.x, 'round') && qSVG.btwn(intersec[1], WALLS[i].start.y, WALLS[i].end.y, 'round') && qSVG.btwn(intersec[0], WALLS[v].start.x, WALLS[v].end.x, 'round') && qSVG.btwn(intersec[1], WALLS[v].start.y, WALLS[v].end.y, 'round')) { intersec[0] = intersec[0]; intersec[1] = intersec[1]; junction.push({segment:i, child: v, values: [intersec[0], intersec[1]], type: "intersection"}); } } } // IF EQ1 == EQ 2 FIND IF START OF SECOND SEG == END OF FIRST seg (eq.A maybe values H ou V) if ((Math.abs(equation1.A) == Math.abs(equation2.A) || equation1.A == equation2.A) && equation1.B == equation2.B) { if (WALLS[i].end.x == WALLS[v].start.x && WALLS[i].end.y == WALLS[v].start.y) { junction.push({segment:i, child: v, values: [WALLS[v].start.x, WALLS[v].start.y], type: "natural"}); } if (WALLS[i].start.x == WALLS[v].end.x && WALLS[i].start.y == WALLS[v].end.y) { junction.push({segment:i, child: v, values: [WALLS[i].start.x, WALLS[i].start.y], type: "natural"}); } } } } } return junction; }, vertexList: function(junction, segment) { var vertex = []; var vertextest = []; for (var jj = 0; jj < junction.length; jj++) { var found = true; for (var vv = 0; vv < vertex.length; vv++) { if ((Math.round(junction[jj].values[0]) == Math.round(vertex[vv].x)) && (Math.round(junction[jj].values[1]) == Math.round(vertex[vv].y))) { found = false; vertex[vv].segment.push(junction[jj].segment); break; } else { found = true; } } if (found) { vertex.push({x: Math.round(junction[jj].values[0]), y: Math.round(junction[jj].values[1]), segment: [junction[jj].segment], bypass:0, type: junction[jj].type}); } } var toClean = []; for (var ss = 0; ss < vertex.length; ss++) { vertex[ss].child = []; vertex[ss].removed = []; for (var sg = 0; sg < vertex[ss].segment.length; sg++) { for (var sc = 0; sc < vertex.length; sc++) { if (sc != ss) { for (var scg = 0; scg < vertex[sc].segment.length; scg++) { if (vertex[sc].segment[scg] == vertex[ss].segment[sg]) { vertex[ss].child.push({id: sc, angle: Math.floor(qSVG.getAngle(vertex[ss], vertex[sc]).deg)}); } } } } } toClean = []; for (var fr = 0; fr < vertex[ss].child.length-1; fr++) { for (var ft = fr+1; ft < vertex[ss].child.length; ft++) { if (fr != ft && typeof(vertex[ss].child[fr])!='undefined') { found = true; if (qSVG.btwn(vertex[ss].child[ft].angle, vertex[ss].child[fr].angle+3, vertex[ss].child[fr].angle-3, 'round') && found) { var dOne = qSVG.gap(vertex[ss], vertex[vertex[ss].child[ft].id]); var dTwo = qSVG.gap(vertex[ss], vertex[vertex[ss].child[fr].id]); if (dOne > dTwo) { toClean.push(ft); } else { toClean.push(fr); } } } } } toClean.sort(function(a, b) { return b-a; }); toClean.push(-1); for (var cc = 0; cc < toClean.length-1; cc++) { if (toClean[cc] > toClean[(cc+1)]) { vertex[ss].removed.push(vertex[ss].child[toClean[cc]].id); vertex[ss].child.splice(toClean[cc], 1); } } } vertexTest = vertex; return vertex; }, //******************************************************* //* @arr1, arr2 = Array to compare * //* @app = add function pop() or shift() to @arr1, arr2 * //* False if arr1.length != arr2.length * //* False if value into arr1[] != arr2[] - no order * //* ***************************************************** arrayCompare: function(arr1, arr2, app) { // if (arr1.length != arr2.length) return false; var minus = 0; var start = 0; if (app == 'pop') { minus = 1; } if (app == 'shift') { start = 1; } var coordCounter = arr1.length - minus - start; for (var iFirst = start; iFirst < arr1.length-minus; iFirst++) { for (var iSecond = start; iSecond < arr2.length-minus; iSecond++) { if (arr1[iFirst] == arr2[iSecond]) { coordCounter--; } } } if (coordCounter == 0) return true; else return false; }, vectorVertex: function(vex1, vex2, vex3) { var vCurr = qSVG.vectorXY(vex1, vex2); var vNext = qSVG.vectorXY(vex2, vex3); var Na = Math.sqrt((vCurr.x * vCurr.x) + (vCurr.y * vCurr.y)); var Nb = Math.sqrt((vNext.x * vNext.x) + (vNext.y * vNext.y)); var C = ((vCurr.x * vNext.x) + (vCurr.y * vNext.y)) / (Na * Nb); var S = ((vCurr.x * vNext.y) - (vCurr.y * vNext.x)); var BAC = Math.sign(S) * Math.acos(C); return BAC*(180 / Math.PI ); }, segmentTree: function(VERTEX_NUMBER, vertex) { var TREELIST = [VERTEX_NUMBER]; WAY = []; var COUNT = vertex.length; var ORIGIN = VERTEX_NUMBER; tree(TREELIST, ORIGIN, COUNT); return WAY; function tree(TREELIST, ORIGIN, COUNT) { if (TREELIST.length == 0) return; var TREETEMP = []; COUNT--; for (var k = 0;k < TREELIST.length; k++) { var found = true; var WRO = TREELIST[k]; var WRO_ARRAY = WRO.toString().split('-'); var WR = WRO_ARRAY[WRO_ARRAY.length - 1]; for (var v = 0; v < vertex[WR].child.length; v++) { if (vertex[WR].child[v].id == ORIGIN && COUNT < (vertex.length - 1) && WRO_ARRAY.length > 2) { // WAYS HYPER WAY.push(WRO+"-"+ORIGIN); // WAYS found = false; break; } } if (found) { var bestToAdd; var bestDet = 0; var nextVertex = -1; // var nextVertexValue = 360; var nextDeterValue = Infinity; var nextDeterVal = 0; var nextFlag = 0; if (vertex[WR].child.length == 1) { if (WR == ORIGIN && COUNT == (vertex.length - 1)) { TREETEMP.push(WRO+'-'+vertex[WR].child[0].id); } if (WR != ORIGIN && COUNT < (vertex.length - 1)) { TREETEMP.push(WRO+'-'+vertex[WR].child[0].id); } } else { for (var v = 0; v < vertex[WR].child.length && vertex[WR].child.length > 0; v++) { if (WR == ORIGIN && COUNT == (vertex.length - 1)) { // TO INIT FUNCTION -> // CLOCKWISE Research var vDet = qSVG.vectorVertex({x: 0, y: -1}, vertex[WR], vertex[vertex[WR].child[v].id]); if (vDet >= nextDeterVal ) { nextFlag = 1; nextDeterVal = vDet; nextVertex = vertex[WR].child[v].id; } if (Math.sign(vDet) == -1 && nextFlag == 0) { if (vDet < nextDeterValue && Math.sign(nextDeterValue) > -1) { nextDeterValue = vDet; nextVertex = vertex[WR].child[v].id; } if (vDet > nextDeterValue && Math.sign(nextDeterValue) == -1) { nextDeterValue = vDet; nextVertex = vertex[WR].child[v].id; } } } if (WR != ORIGIN && WRO_ARRAY[WRO_ARRAY.length-2] != vertex[WR].child[v].id && COUNT < (vertex.length - 1)) { // COUNTERCLOCKWISE Research var vDet = qSVG.vectorVertex(vertex[WRO_ARRAY[WRO_ARRAY.length-2]], vertex[WR], vertex[vertex[WR].child[v].id]); if (vDet < nextDeterValue && nextFlag == 0) { nextDeterValue = vDet; nextVertex = vertex[WR].child[v].id; } if (Math.sign(vDet) == -1) { nextFlag = 1; if (vDet <= nextDeterValue) { nextDeterValue = vDet; nextVertex = vertex[WR].child[v].id; } } } } if (nextVertex != -1) TREETEMP.push(WRO+'-'+nextVertex); } } } if (COUNT > 0) tree(TREETEMP, ORIGIN, COUNT); } }, polygonize: function(segment) { junction = qSVG.junctionList(segment); vertex = qSVG.vertexList(junction, segment); var vertexCopy = qSVG.vertexList(junction, segment); var edgesChild = []; for (var j = 0; j < vertex.length; j++) { for (var vv = 0; vv < vertex[j].child.length; vv++) { edgesChild.push([j, vertex[j].child[vv].id]); } } var polygons = []; var WAYS; for (var jc = 0; jc < edgesChild.length; jc++) { var bestVertex = 0; var bestVertexValue = Infinity; for (var j = 0; j < vertex.length; j++) { if (vertex[j].x < bestVertexValue && vertex[j].child.length > 1 && vertex[j].bypass == 0) { bestVertexValue = vertex[j].x; bestVertex = j; } if (vertex[j].x == bestVertexValue && vertex[j].child.length > 1 && vertex[j].bypass == 0) { if (vertex[j].y > vertex[bestVertex].y) { bestVertexValue = vertex[j].x; bestVertex = j; } } } // console.log("%c%s", "background: yellow; font-size: 14px;","RESEARCH WAY FOR STARTING VERTEX "+bestVertex); WAYS = qSVG.segmentTree(bestVertex, vertex); if (WAYS.length == 0) { vertex[bestVertex].bypass = 1; } if (WAYS.length > 0) { var tempSurface = WAYS[0].split('-'); var lengthRoom = qSVG.areaRoom(vertex, tempSurface); var bestArea = parseInt(lengthRoom); var found = true; for (var sss = 0; sss < polygons.length; sss++) { if (qSVG.arrayCompare(polygons[sss].way, tempSurface, 'pop') ) { found = false; vertex[bestVertex].bypass = 1; break; } } if (bestArea < 360) { vertex[bestVertex].bypass = 1; } if (vertex[bestVertex].bypass == 0) { // <-------- TO REVISE IMPORTANT !!!!!!!! bestArea Control ??? var realCoords = qSVG.polygonIntoWalls(vertex, tempSurface); var realArea = qSVG.area(realCoords.inside); var outsideArea = qSVG.area(realCoords.outside); var coords = []; for (var rr = 0; rr < tempSurface.length; rr++) { coords.push({x: vertex[tempSurface[rr]].x, y: vertex[tempSurface[rr]].y}); } // WARNING -> FAKE if (realCoords.inside.length != realCoords.outside) { polygons.push({way: tempSurface, coords: coords, coordsOutside: realCoords.outside, coordsInside: realCoords.inside, area: realArea, outsideArea: outsideArea, realArea: bestArea}); } else { // REAL INSIDE POLYGONE -> ROOM polygons.push({way: tempSurface, coords: realCoords.inside, coordsOutside: realCoords.outside, area: realArea, outsideArea: outsideArea, realArea: bestArea}); } // REMOVE FIRST POINT OF WAY ON CHILDS FIRST VERTEX for (var aa = 0; aa < vertex[bestVertex].child.length; aa++) { if (vertex[bestVertex].child[aa].id == tempSurface[1]) { vertex[bestVertex].child.splice(aa, 1); } } // REMOVE FIRST VERTEX OF WAY ON CHILDS SECOND VERTEX for (var aa = 0; aa < vertex[tempSurface[1]].child.length; aa++) { if (vertex[tempSurface[1]].child[aa].id == bestVertex) { vertex[tempSurface[1]].child.splice(aa, 1); } } //REMOVE FILAMENTS ????? do { var looping = 0; for (var aa = 0; aa < vertex.length; aa++) { if (vertex[aa].child.length == 1) { looping = 1; vertex[aa].child = []; for (var ab = 0; ab < vertex.length; ab++) { // OR MAKE ONLY ON THE WAY tempSurface ?? BETTER ?? for (var ac = 0; ac < vertex[ab].child.length; ac++) { if (vertex[ab].child[ac].id == aa) { vertex[ab].child.splice(ac, 1); } } } } } } while (looping == 1); } } } //SUB AREA(s) ON POLYGON CONTAINS OTHERS FREE POLYGONS (polygon without commonSideEdge) for (var pp = 0; pp < polygons.length; pp++) { var inside = []; for (var free = 0; free < polygons.length; free++) { if (pp != free) { var polygonFree = polygons[free].coords; var countCoords = polygonFree.length; var found = true; for (pf = 0; pf < countCoords; pf++) { found = qSVG.rayCasting(polygonFree[pf], polygons[pp].coords); if (!found) { break; } } if (found) { inside.push(free); polygons[pp].area = polygons[pp].area - polygons[free].outsideArea; } } } polygons[pp].inside = inside; } return {polygons : polygons, vertex : vertex}; }, diffArray : function(arr1, arr2) { return arr1.concat(arr2).filter(function (val) { if (!(arr1.includes(val) && arr2.includes(val))) return val; }); }, diffObjIntoArray : function(arr1, arr2) { var count = 0; for (var k =0; k y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); if (intersect) inside = !inside; } return inside; }, //polygon = [{x1,y1}, {x2,y2}, ...] polygonVisualCenter: function(room) { var polygon = room.coords; var insideArray = room.inside; var sample = 80; var grid = []; //BOUNDING BOX OF POLYGON var minX, minY, maxX, maxY; for (var i = 0; i < polygon.length; i++) { var p = polygon[i]; if (!i || p.x < minX) minX = p.x; if (!i || p.y < minY) minY = p.y; if (!i || p.x > maxX) maxX = p.x; if (!i || p.y > maxY) maxY = p.y; } var width = maxX - minX; var height = maxY - minY; //INIT GRID var sampleWidth = Math.floor(width / sample); var sampleHeight = Math.floor(height / sample); for (var hh = 0; hh < sample; hh++) { for (var ww = 0; ww < sample; ww++) { var posX = minX + (ww * sampleWidth); var posY = minY + (hh * sampleHeight); if (qSVG.rayCasting({x: posX, y: posY}, polygon)) { var found = true; for (var ii = 0; ii < insideArray.length; ii++) { if (qSVG.rayCasting({x: posX, y: posY}, ROOM[insideArray[ii]].coordsOutside)) { found = false; break; } } if (found) { grid.push({x: posX, y: posY}); } } } } var bestRange = 0; var bestMatrix; for (var matrix = 0; matrix < grid.length; matrix++) { var minDistance = Infinity; for (var pp = 0; pp < polygon.length-1; pp++) { var scanDistance = qSVG.pDistance(grid[matrix], polygon[pp], polygon[pp+1]); if (scanDistance.distance < minDistance) { minDistance = scanDistance.distance; } } if (minDistance > bestRange) { bestMatrix = matrix; bestRange = minDistance; } } return grid[bestMatrix]; }, textOnDiv: function(label, pos, styled, div) { if (typeof(pos) != 'undefined') { var text = document.createElementNS('http://www.w3.org/2000/svg', 'text'); text.setAttributeNS(null, 'x', pos.x); text.setAttributeNS(null, 'y', pos.y); text.setAttribute("style","fill:"+styled.color+";font-weight:"+styled.fontWeight+";font-size:"+styled.fontSize); text.setAttributeNS(null, 'text-anchor', 'middle'); text.textContent = label; document.getElementById(div).appendChild(text); } } }; //----------------------- END Quick SVG LIBRARY --------------------------------------------------s