forked from frxstrem/map-object-partitioner
-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.js.map
1 lines (1 loc) · 22.3 KB
/
index.js.map
1
{"version":3,"sources":["webpack:///webpack/bootstrap 3a415176cb0dca54aded","webpack:///./js/index.js","webpack:///./js/map.js","webpack:///./js/utils.js","webpack:///./js/code.js"],"names":[],"mappings":";AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,uBAAe;AACf;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;;;;;;ACtCA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,IAAG;AACH;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAC;;AAED;AACA;AACA;AACA,EAAC;AACD;AACA;AACA,EAAC;AACD;AACA;AACA,qBAAoB;;AAEpB;AACA;AACA;AACA;AACA;AACA;AACA,IAAG;AACH,qBAAoB;AACpB;AACA;AACA,QAAO;AACP;AACA;AACA,MAAK,OAAO;AACZ;AACA;AACA,4BAA2B;AAC3B,uBAAsB,gCAAgC;AACtD;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAC;AACD;AACA;;AAEA;AACA,qBAAoB;;AAEpB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,EAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAC;AACD;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,IAAG;AACH;AACA;AACA,EAAC;AACD;AACA;AACA,EAAC;;AAED;AACA;AACA;AACA;AACA;AACA,EAAC;;AAED;AACA;AACA,EAAC;;AAED;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,MAAK;AACL;AACA;AACA,MAAK;AACL,EAAC;;AAED;AACA;AACA,EAAC;;AAED;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,MAAK;AACL;AACA;AACA,MAAK;AACL,EAAC;;AAED;AACA;AACA;;AAEA;AACA;AACA;AACA,MAAK;AACL;AACA;AACA,MAAK;AACL,EAAC;;AAED;AACA;AACA;AACA,EAAC;;;;;;;AC3ND;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAgB,oBAAoB;AACpC;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,iBAAgB,kBAAkB;AAClC;;AAEA;AACA;AACA;AACA;AACA,mBAAkB,iBAAiB;AACnC;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAkB,wBAAwB;AAC1C;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,iBAAgB;AAChB;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;;;;;ACtMA;;AAEA;AACA;AACA;AACA,iBAAgB,oBAAoB;AACpC;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,iBAAgB,oBAAoB;AACpC;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;;;;;;AC5FA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,IAAG;AACH;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA,MAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA,mBAAkB,oBAAoB;AACtC;;AAEA;AACA,qBAAoB,kBAAkB;AACtC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,IAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA,qBAAoB;;AAEpB,mBAAkB,oBAAoB;AACtC;;AAEA;AACA;AACA;AACA,QAAO;AACP;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,qBAAoB,yBAAyB;AAC7C;AACA,iCAAgC;AAChC;;AAEA;AACA;AACA;;AAEA;AACA;AACA,mBAAkB,iBAAiB;AACnC;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA,qBAAoB,iBAAiB;AACrC;AACA,iCAAgC;AAChC;;AAEA;AACA;AACA;;AAEA;;AAEA,kDAAiD,qBAAqB;AACtE;AACA,IAAG;AACH","file":"index.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(0);\n\n\n\n/** WEBPACK FOOTER **\n ** webpack/bootstrap 3a415176cb0dca54aded\n **/","'use strict';\nconst map = require('./map');\nconst code = require('./code');\n\nconst MODE_NONE = 0;\nconst MODE_DOWN = 1;\nconst MODE_DRAG_MAP = 2;\n\nlet nextAreaId = 0;\n\nconst updateCoordinates = function(mx, my) {\n if(mx == null || my == null) {\n document.getElementById('coordinates').textContent = '???';\n } else {\n const p = map.at(mx, my);\n document.getElementById('coordinates').textContent = p[0].toFixed(1) + ',' + p[1].toFixed(1);\n\n if(map.currentArea.length > 1) {\n map.currentArea[map.currentArea.length - 1] = p;\n map.updateView();\n }\n }\n};\n\nwindow.addEventListener('keydown', function(e) {\n switch(e.keyCode) {\n case 27: // ESC\n // cancel current polygon\n e.preventDefault();\n map.currentArea.length = 0;\n map.updateView();\n break;\n }\n});\n\nlet lastX, lastY, dragMode, ignoreDrag = null;\nmap.canvas.addEventListener('mouseenter', function(e) {\n updateCoordinates(e.offsetX, e.offsetY);\n});\nmap.canvas.addEventListener('mouseleave', function(e) {\n updateCoordinates(null, null);\n});\nmap.canvas.addEventListener('mousedown', function(e) {\n updateCoordinates(e.offsetX, e.offsetY);\n lastX = e.offsetX; lastY = e.offsetY;\n\n e.preventDefault();\n if(e.buttons === 1) {\n if(ignoreDrag != null)\n clearTimeout(ignoreDrag);\n ignoreDrag = setTimeout(() => (ignoreDrag = null), 25);\n dragMode = MODE_DOWN;\n } else if(e.buttons === 2) {\n if(e.shiftKey) { // cancel last point\n if(map.currentArea.length <= 2) {\n map.currentArea.length = 0;\n } else {\n map.currentArea.splice(map.currentArea.length - 2, 1);\n }\n } else { // cancel polygon\n if(map.currentArea.length > 3) {\n const newArea = [];\n let x0, x1, y0, y1; // bounds\n for(let i = 0; i < map.currentArea.length - 1; i++) {\n const pt = map.currentArea[i];\n newArea.push(pt);\n\n if(x0 == null || pt[0] < x0)\n x0 = pt[0];\n if(x1 == null || pt[0] > x1)\n x1 = pt[0];\n if(y0 == null || pt[1] < y0)\n y0 = pt[1];\n if(y1 == null || pt[1] > y1)\n y1 = pt[1];\n }\n\n const id = nextAreaId++;\n newArea.id = id;\n map.areas.push(newArea);\n\n // add element to polygon list\n const li = document.createElement('li');\n\n const link = document.createElement('a');\n link.href = '#';\n link.onclick = function(e) {\n e.preventDefault();\n map.zoomRect(x0, x1, y0, y1);\n };\n link.textContent = 'Polygon #' + id;\n\n const deleteLink = document.createElement('a');\n deleteLink.href = '#';\n deleteLink.onclick = function(e) {\n e.preventDefault();\n li.parentNode.removeChild(li);\n\n const index = map.areas.indexOf(newArea);\n if(index >= 0) {\n map.areas.splice(index, 1);\n map.updateView();\n }\n };\n deleteLink.textContent = '(X)';\n\n li.appendChild(link);\n li.appendChild(document.createTextNode(' '));\n li.appendChild(deleteLink);\n document.getElementById('polygon-list').appendChild(li);\n }\n map.currentArea.length = 0;\n }\n }\n});\nmap.canvas.addEventListener('mousemove', function(e) {\n updateCoordinates(e.offsetX, e.offsetY);\n\n const dx = e.offsetX - lastX, dy = e.offsetY - lastY;\n lastX = e.offsetX; lastY = e.offsetY;\n\n if(ignoreDrag != null)\n return;\n switch(dragMode) {\n case MODE_DOWN:\n dragMode = MODE_DRAG_MAP;\n map.move(dx, dy);\n break;\n\n case MODE_DRAG_MAP:\n map.move(dx, dy);\n break;\n }\n});\nmap.canvas.addEventListener('mouseup', function(e) {\n updateCoordinates(e.offsetX, e.offsetY);\n if(ignoreDrag != null) {\n clearTimeout(ignoreDrag);\n ignoreDrag = null;\n }\n dragMode = MODE_NONE;\n});\nmap.canvas.addEventListener('dblclick', function(e) {\n updateCoordinates(e.offsetX, e.offsetY);\n\n const p = map.at(e.offsetX, e.offsetY);\n if(map.currentArea.length <= 1) {\n map.currentArea.length = 0;\n map.currentArea[0] = p;\n map.currentArea[1] = p;\n map.updateView();\n } else {\n map.currentArea.push(p);\n }\n});\nmap.canvas.addEventListener('contextmenu', function(e) {\n e.preventDefault();\n});\n\nmap.canvas.addEventListener('wheel', function(e) {\n e.preventDefault();\n const scale = Math.pow(2, e.deltaY / 200);\n const mp = map.at(e.offsetX, e.offsetY);\n map.zoom(scale, mp[0], mp[1]);\n});\n\ndocument.getElementById('load-btn').addEventListener('click', function(e) {\n document.getElementById('file-input').click();\n});\n\ndocument.getElementById('file-input').addEventListener('change', function(e) {\n const file = e.target.files[0];\n if(file == null) return;\n\n // parse file\n code.parseFile(file)\n .then((objects) => {\n map.updateObjects(objects);\n })\n .catch((error) => {\n console.error(error.stack || error);\n });\n});\n\ndocument.getElementById('zoom-out-btn').addEventListener('click', function(e) {\n map.zoomRect(-3000, 3000, -3000, 3000);\n});\n\ndocument.getElementById('update-btn').addEventListener('click', function(e) {\n // get objects and polygons\n const objects = map.objects;\n const areas = map.areas;\n\n // sort objects\n code.sortObjects(objects, areas)\n .then((result) => {\n map.updateView();\n })\n .catch((error) => {\n console.error(error.stack || error);\n });\n});\n\ndocument.getElementById('save-btn').addEventListener('click', function(e) {\n // get objects and polygons\n const objects = map.objects;\n\n // save objects to file\n code.saveObjects(objects)\n .then((result) => {\n })\n .catch((error) => {\n console.error(error.stack || error);\n });\n});\n\ndocument.getElementById('hide-valid').addEventListener('change', function(e) {\n map.hideValid = e.target.checked;\n map.updateView();\n});\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./js/index.js\n ** module id = 0\n ** module chunks = 0\n **/","'use strict';\n\nconst utils = require('./utils');\n\nconst ZOOM_MAX = 4;\n\n// get map canvas\nconst map = exports.canvas = document.getElementById('map');\nconst ctx = map.getContext('2d');\n\n// TODO: ensure that (ctx != null)\n\n// map image\nconst mapImage = new Image();\n\n// should hide objects in valid polygon?\n\n// in-world objects\nlet objects = exports.objects = [ ];\n\n// areas\nlet areas = exports.areas = [ ];\nlet currentArea = exports.currentArea = [];\n\n// center of view\nconst view = {\n // center of view\n x: 0,\n y: 0,\n // zoom level\n z: 0.1,\n};\n\n// update world objects\nconst updateObjects = exports.updateObjects = function(newObjects) {\n objects = exports.objects = newObjects;\n updateView();\n};\n\nlet nextUpdate = null;\nconst doUpdate = function() {\n nextUpdate = null;\n\n // for convenience, define WIDTH/2 and HEIGHT/2\n const w = map.width / 2;\n const h = map.height / 2;\n\n // calculate bounds\n const x0 = view.x - w / view.z;\n const x1 = view.x + w / view.z;\n const y0 = view.y - h / view.z;\n const y1 = view.y + h / view.z;\n\n // draw map image\n ctx.clearRect(0, 0, map.width, map.height);\n ctx.drawImage(mapImage, 3000 + x0, 3000 - y1, x1 - x0, y1 - y0, 0, 0, map.width, map.height);\n\n // draw objects\n const styles = {\n 'AddStaticVehicle': 'rgba(255,0,0,1)',\n 'AddStaticVehicleEx': 'rgba(0,255,0,1)',\n 'CreateObject': 'rgba(255,128,0,1)',\n 'CreateDynamicObject': 'rgba(255,255,0,1)',\n 'undefined': 'gray',\n 'undefined:hide': 'gray',\n };\n for(let i = 0; i < objects.length; i++) {\n const obj = objects[i];\n\n if(obj.x < x0 || obj.x > x1 || obj.y < y0 || obj.y > y1)\n continue;\n\n const p = where(obj.x, obj.y);\n\n let dotSize = 4 * Math.sqrt(view.z);\n let hide = false;\n if(obj.areas != null && obj.areas.length === 1) {\n dotSize = 2 * Math.sqrt(view.z);\n hide = true;\n }\n\n if(hide && exports.hideValid)\n continue;\n\n ctx.fillStyle = styles[obj.type + (hide ? ':hide' : '')];\n ctx.beginPath();\n ctx.arc(p[0], p[1], dotSize, 0, 2 * Math.PI);\n ctx.fill();\n }\n\n // draw areas\n for(let j = 0; j < areas.length; j++) {\n const area = areas[j];\n\n ctx.fillStyle = 'rgba(0,0,255,0.1)';\n ctx.strokeStyle = 'rgb(0,0,255)';\n ctx.lineWidth = 1;\n ctx.beginPath();\n for(let i = 0; i < area.length; i++) {\n const mp = area[i];\n const pt = where(mp[0], mp[1]);\n\n if(i === 0)\n ctx.moveTo(pt[0], pt[1]);\n else\n ctx.lineTo(pt[0], pt[1]);\n }\n ctx.closePath();\n ctx.fill();\n ctx.stroke();\n\n // find center of mass and area\n const C = utils.findCOM(area);\n const pt = where(C[0], C[1]);\n\n const fontSize = Math.sqrt(C[2]) / 5 * view.z;\n ctx.font = (fontSize | 0) + 'px sans-serif';\n ctx.fillStyle = 'rgb(0,128,255)';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'center';\n ctx.fillText(area.id, pt[0], pt[1]);\n }\n\n // draw current area\n if(currentArea.length > 1) {\n ctx.fillStyle = 'rgba(0,0,255,0.1)';\n ctx.strokeStyle = 'rgb(0,0,255)';\n ctx.lineWidth = 3;\n ctx.beginPath();\n for(let i = 0; i < currentArea.length; i++) {\n const mp = currentArea[i];\n const pt = where(mp[0], mp[1]);\n\n if(i === 0)\n ctx.moveTo(pt[0], pt[1]);\n else\n ctx.lineTo(pt[0], pt[1]);\n }\n ctx.fill();\n ctx.stroke();\n }\n};\n\n// update map view\nconst updateView = exports.updateView = function() {\n if(nextUpdate == null)\n nextUpdate = requestAnimationFrame(doUpdate);\n};\n\n// get coordinates of position on canvas\nconst at = exports.at = function(mx, my) {\n const px = (mx - map.width / 2) / view.z + view.x;\n const py = -(my - map.height / 2) / view.z + view.y;\n return [ px, py ];\n};\n\n// get canvas position of coordinate\nconst where = exports.where = function(px, py) {\n const cx = (px - view.x) * view.z + map.width / 2;\n const cy = -(py - view.y) * view.z + map.height / 2;\n return [ cx, cy ];\n};\n\n// zoom, optionally fixing a point\nconst zoom = exports.zoom = function(scale, fx, fy) {\n if(fx == null || fy == null) {\n fx = view.x; fy = view.y;\n }\n\n if(view.z / scale > ZOOM_MAX)\n scale = view.z / ZOOM_MAX;\n\n view.x = (view.x - fx) * scale + fx;\n view.y = (view.y - fy) * scale + fy;\n view.z /= scale;\n\n updateView();\n};\n\n// zoom rectangle into view\nconst zoomRect = exports.zoomRect = function(x0, x1, y0, y1) {\n view.x = (x0 + x1) / 2;\n view.y = (y0 + y1) / 2;\n view.z = 1 / Math.max((x1 - x0) / map.width, (y1 - y0) / map.height);\n\n updateView();\n};\n\n// move map\nconst move = exports.move = function(dx, dy) {\n view.x -= dx / view.z;\n view.y += dy / view.z;\n\n updateView();\n};\n\n// load map image\nmapImage.onload = () => updateView();\nmapImage.src = 'SanAndreas-TerrainMap.jpg';\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./js/map.js\n ** module id = 1\n ** module chunks = 0\n **/","'use strict';\n\n// find center of mass and area\nexports.findCOM = function(polygon) {\n let Cx = 0, Cy = 0, A = 0;\n for(let j = 0; j < polygon.length; j++) {\n const i = (j === 0 ? polygon.length - 1 : j - 1);\n const a = polygon[i], b = polygon[j];\n\n const k = (a[0] * b[1] - a[1] * b[0]);\n A += k;\n Cx += (a[0] + b[0]) * k;\n Cy += (a[1] + b[1]) * k;\n }\n\n A /= 2;\n Cx /= 6 * A;\n Cy /= 6 * A;\n\n // 0 = center X\n // 1 = center Y\n // 2 = unsigned area\n // 3 = signed area\n return [ Cx, Cy, Math.abs(A), A ];\n};\n\n// figure out if a point is contained in a polygon\nexports.containsPoint = function(polygon, x, y) {\n // pick a random line\n const lang = 2 * Math.PI * Math.random();\n const lx = Math.cos(lang), ly = Math.sin(lang);\n\n let c = [ 0, 0 ];\n\n // count how many times each edge of the polygon intersets the line,\n // on the positive and negative side relative to the point in question\n for(let j = 0; j < polygon.length; j++) {\n const i = (j === 0 ? polygon.length - 1 : j - 1);\n const a = polygon[i], b = polygon[j];\n\n // we need these constants for calcuation\n const rx = b[0] - a[0], ry = b[1] - a[1];\n const kx = a[0] - x, ky = a[1] - y;\n\n // ensure that the lines aren't parallel\n const d = rx * ly - ry * lx;\n if(d === 0) {\n console.warn('Parallel line occurred');\n continue;\n }\n\n const s = -ry / d * kx + rx / d * ky;\n const t = -ly / d * kx + lx / d * ky;\n\n if(t < 0 || t > 1) // not intersecting\n continue;\n\n if(s < 0)\n c[0]++;\n else\n c[1]++;\n }\n\n // contained if c[0] and c[1] are both odd\n if(c[0] % 2 === 1 && c[1] % 2 === 1) {\n return true;\n }\n\n return false;\n};\n\n// log various messages\nexports.log = function(message) {\n const logEl = document.getElementById('log-output');\n logEl.value += message + '\\n';\n logEl.scrollTop = logEl.scrollHeight;\n};\nexports.clearLog = function() {\n const logEl = document.getElementById('log-output');\n logEl.value = '';\n};\n\n// save file\nexports.saveFile = function(file, filename) {\n const url = URL.createObjectURL(file);\n\n const a = document.createElement('a');\n a.href = url;\n a.download = filename;\n a.click();\n\n URL.revokeObjectURL(url);\n};\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./js/utils.js\n ** module id = 2\n ** module chunks = 0\n **/","'use strict';\nconst utils = require('./utils');\n\n// read code from file\nexports.parseFile = function(file) {\n return new Promise(function(resolve, reject) {\n const reader = new FileReader();\n\n reader.onerror = function(e) {\n reject(e);\n };\n\n reader.onload = function() {\n resolve(reader.result);\n };\n utils.log('Reading file...');\n reader.readAsText(file);\n })\n .then((text) => {\n utils.log('Parsing file...');\n\n const pattern = new RegExp('(AddStaticVehicle(?:Ex)?|Create(?:Dynamic)?Object)\\\\(([0-9., +-]*)\\\\)', 'gm');\n let m;\n\n const objects = [];\n while((m = pattern.exec(text)) != null) {\n const func = m[1];\n const args = m[2].split(',').map((x) => parseFloat(x));\n\n const obj = {\n line: m[0], type: func };\n switch(func) {\n case 'AddStaticVehicle':\n case 'AddStaticVehicleEx':\n case 'CreateObject':\n case 'CreateDynamicObject':\n obj.id = args[0];\n obj.x = args[1];\n obj.y = args[2];\n break;\n }\n\n objects.push(obj);\n }\n\n utils.log('Loaded ' + objects.length + ' objects');\n\n return objects;\n });\n};\n\n// sort objects by area\nexports.sortObjects = function(objects, areas) {\n // TODO: maybe do this in own thread?\n return new Promise(function(resolve, reject) {\n utils.log('Sorting objects...');\n\n let noPolygon = 0, overlappingPolygons = 0;\n\n for(let i = 0; i < objects.length; i++) {\n const obj = objects[i];\n\n obj.areas = [];\n for(let j = 0; j < areas.length; j++) {\n if(utils.containsPoint(areas[j], obj.x, obj.y)) {\n obj.areas.push(areas[j].id);\n }\n }\n\n if(obj.areas.length === 0)\n noPolygon++;\n else if(obj.areas.length > 1)\n overlappingPolygons++;\n }\n\n utils.log('Done!');\n utils.log('Total objects: ' + objects.length);\n utils.log(' Covered by no polygon: ' + noPolygon);\n utils.log(' Covered by two or more: ' + overlappingPolygons);\n\n resolve();\n });\n};\n\n// save objects\nconst sortXY = function(a, b) {\n if(a.x < b.x) return -1;\n if(a.x > b.x) return 1;\n if(a.y < b.y) return -1;\n if(a.y > b.y) return 1;\n if(a.z < b.z) return -1;\n if(a.z > b.z) return 1;\n return 0;\n};\nexports.saveObjects = function(objects) {\n return new Promise(function(resolve, reject) {\n utils.log('Generating file...');\n\n const NONE = Symbol('NONE');\n\n const sorted = { [NONE]: [] };\n\n for(let i = 0; i < objects.length; i++) {\n const obj = objects[i];\n\n let key;\n if(obj.areas == null || obj.areas.length === 0) {\n key = NONE;\n } else {\n key = obj.areas[0];\n }\n\n if(!Object.prototype.hasOwnProperty.call(sorted, key))\n sorted[key] = [];\n sorted[key].push(obj);\n }\n\n const lines = [];\n\n // sort and write out uncategorized objects\n if(sorted[NONE].length > 0) {\n sorted[NONE].sort(sortXY);\n\n lines.push('/**');\n lines.push(' * Uncategorized: ' + sorted[NONE].length);\n lines.push('**/');\n lines.push('');\n\n for(let i = 0; i < sorted[NONE].length; i++) {\n const obj = sorted[NONE][i];\n lines.push(obj.line + ';');\n }\n\n lines.push('');\n lines.push('');\n }\n\n // sort areas\n const keys = Object.getOwnPropertyNames(sorted);\n for(let j = 0; j < keys.length; j++) {\n const key = keys[j];\n const list = sorted[key];\n\n list.sort(sortXY);\n\n lines.push('/**');\n lines.push(' * Area #' + key + ': ' + list.length);\n lines.push('**/');\n lines.push('');\n\n for(let i = 0; i < list.length; i++) {\n const obj = list[i];\n lines.push(obj.line + ';');\n }\n\n lines.push('');\n lines.push('');\n }\n\n utils.log('Done, downloading in browser');\n\n const blob = new Blob([ lines.join('\\n') ], { type: 'text/plain' });\n utils.saveFile(blob, 'sorted.txt');\n });\n};\n\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./js/code.js\n ** module id = 3\n ** module chunks = 0\n **/"],"sourceRoot":""}