{"version":3,"sources":["jsdelivr-header.js","/npm/citygml-to-obj@0.1.27/index.js"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA,ACNA,IAcI,WAKA,WAnBA,EAAI,QAAQ,UACZ,aAAe,QAAQ,iBACvB,GAAK,QAAQ,YACb,IAAM,QAAQ,OACd,QAAU,QAAQ,WAClB,QAAS,EAET,QAAU,QAAQ,MAAM,OAAO,OAE/B,UAAW,EAGX,WAAa,QAAQ,eAIrB,QAAU,CAAC,EACX,aAAe,GACf,SAAW,GAKX,cAAgB,WAElB,IAAK,IAAI,EAAI,EAAG,EAAI,QAAS,IAAK,CAChC,IAAI,EAAS,aAAa,KAAK,UAAY,WAE3C,QAAQ,EAAO,KAAO,CACpB,QAAS,EACT,OAAO,EACP,OAAO,GAIT,EAAO,GAAG,QAAQ,WAChB,QAAQ,KAAK,KAAK,OAAQ,CAC5B,IAGA,EAAO,GAAG,WAAW,SAAS,GACxB,EAAI,WACF,EAAI,KACN,QAAQ,MAAM,EAAI,KAGhB,UACF,KAAK,KAAK,UAGZ,QAAQ,KAAK,KAAK,OAAQ,EAE9B,GACF,CACF,EAEI,mBAAqB,WACvB,IAAI,GAAQ,EASZ,OAPA,EAAE,KAAK,SAAS,SAAS,GACvB,GAAI,EAAO,MAET,OADA,GAAQ,GACD,CAEX,KAEI,CAKN,EAEI,iBAAkB,EAElB,YAAc,WACZ,kBAIJ,iBAAkB,EAClB,iBACA,iBAAkB,EACpB,EAEI,eAAiB,WACnB,EAAE,KAAK,SAAS,SAAS,EAAQ,GAC/B,GAA4B,IAAxB,aAAa,OACf,OAAO,EAGT,GAAI,EAAO,MAAO,CAChB,EAAO,OAAQ,EAEf,IAAI,EAAO,aAAa,QACxB,EAAO,QAAQ,KAAK,GAGhB,aAAa,OAAS,UAAY,WAAW,aAC/C,QAAQ,IAAI,kBACZ,WAAW,SAEf,CACF,GACF,EAEI,aAAe,SAAS,EAAS,GAC9B,IACH,EAAU,CAAC,GAUb,GAFA,EAAE,SAAS,EALI,CACb,WAAW,IAMR,EAAQ,YAKb,GAAK,EAAQ,QAKb,GAAK,EAAQ,SAAb,CAMI,EAAE,QAAQ,WACZ,gBACA,WAAa,YAAY,YAAa,KAGxC,IAAI,EAAY,IAAI,aAAa,OAAQ,CACvC,OAAO,IAYT,EAAU,GAAG,SATY,SAAU,GACjC,QAAQ,MAAM,SAAU,GAIxB,KAAK,QAAQ,MAAQ,KACrB,KAAK,QAAQ,QACf,IAmBA,IAAI,EAAY,IAAI,QAAQ,QAAQ,EAAW,mBAE/C,EAAU,GAAG,SAAS,SAAS,GAC7B,aAAa,KAAK,CAChB,IAAK,EACL,SAAU,EAAQ,SAClB,QAAS,EAAQ,QACjB,UAAW,EAAQ,UACnB,YAAa,EAAQ,cAInB,aAAa,QAAU,WAAa,WAAW,aACjD,QAAQ,IAAI,iBACZ,WAAW,QAEf,IAEA,EAAU,GAAG,OAAO,WAClB,QAAQ,IAAI,iBACZ,QAAQ,IAAI,eAAgB,aAAa,QAGzC,IAAI,EAAiB,aAAY,WAC/B,KAAI,aAAa,OAAS,GAA1B,CAKA,cAAc,GAEd,UAAW,EAGX,cAAc,YAOd,EAAE,KAAK,SAAS,SAAS,GACnB,EAAO,OACT,EAAO,QAAQ,KAAK,SAExB,IAEA,QAAQ,IAAI,uBAIZ,IAAI,EAAa,aAAY,WACT,uBAGhB,QAAQ,IAAI,eAAgB,aAAa,QACzC,cAAc,GACd,EAAS,MAEb,GAAG,IAjCH,CAkCF,GAAG,IACL,KAEA,WAAa,GAAG,iBAAiB,EAAQ,cAC9B,KAAK,EAtGhB,MAFE,EAAS,IAAI,MAAM,iCAAkC,mBALrD,EAAS,IAAI,MAAM,yBAA0B,mBAL7C,EAAS,IAAI,MAAM,4BAmHvB,EAEA,OAAO,QAAU","file":"/npm/citygml-to-obj@0.1.27/index.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.19.2.\n * Original file: /npm/citygml-to-obj@0.1.27/index.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","var _ = require(\"lodash\");\nvar childProcess = require(\"child_process\");\nvar fs = require(\"fs-extra\");\nvar sax = require(\"sax\");\nvar saxpath = require(\"saxpath\");\nvar strict = true;\n\nvar numCPUs = require(\"os\").cpus().length;\n\nvar shutdown = false;\n\n// CityGML helpers\nvar citygmlSRS = require(\"citygml-srs\");\n\nvar readStream;\n\nvar workers = {};\nvar processQueue = [];\nvar maxQueue = 30;\nvar queueCheck;\n\n// TODO: Look into batching and threads to improve reliability and performance\n\nvar createWorkers = function() {\n  // Create a new worker for each CPU\n  for (var i = 0; i < numCPUs; i++) {\n    var worker = childProcess.fork(__dirname + \"/worker\");\n\n    workers[worker.pid] = {\n      process: worker,\n      ready: true,\n      alive: true\n    };\n\n    // Be notified when worker processes die.\n    worker.on(\"exit\", function() {\n      workers[this.pid].alive = false;\n    });\n\n    // Receive messages from this worker and handle them in the master process.\n    worker.on(\"message\", function(msg) {\n      if (msg.finished) {\n        if (msg.err) {\n          console.error(msg.err);\n        }\n\n        if (shutdown) {\n          this.kill(\"SIGINT\");\n        }\n\n        workers[this.pid].ready = true;\n      }\n    });\n  }\n};\n\nvar areWorkersShutdown = function() {\n  var alive = false;\n\n  _.each(workers, function(worker) {\n    if (worker.alive) {\n      alive = true;\n      return false;\n    }\n  });\n\n  if (alive) {\n    return false;\n  } else {\n    return true;\n  }\n}\n\nvar processingQueue = false;\n\nvar updateQueue = function() {\n  if (processingQueue) {\n    return;\n  }\n\n  processingQueue = true;\n  processWorkers();\n  processingQueue = false;\n};\n\nvar processWorkers = function() {\n  _.each(workers, function(worker, pid) {\n    if (processQueue.length === 0) {\n      return false;\n    }\n\n    if (worker.ready) {\n      worker.ready = false;\n\n      var item = processQueue.shift();\n      worker.process.send(item);\n\n      // Resume queue when space is available\n      if (processQueue.length < maxQueue && readStream.isPaused()) {\n        console.log(\"Resuming queue\");\n        readStream.resume();\n      }\n    }\n  });\n};\n\nvar citygmlToObj = function(options, callback) {\n  if (!options) {\n    options = {};\n  }\n\n  var defaults = {\n    overwrite: false\n  };\n\n  // Set defaults\n  _.defaults(options, defaults);\n\n  if (!options.citygmlPath) {\n    callback(new Error(\"CityGML path is required\"));\n    return;\n  }\n\n  if (!options.objPath) {\n    callback(new Error(\"OBJ path is required: \", citygmlPath));\n    return;\n  }\n\n  if (!options.proj4def) {\n    callback(new Error(\"Proj4 definition is required: \", citygmlPath));\n    return;\n  }\n\n  // Set up workers\n  if (_.isEmpty(workers)) {\n    createWorkers();\n    queueCheck = setInterval(updateQueue, 50);\n  }\n\n  var saxParser = sax.createStream(strict, {\n    xmlns: true\n  });\n\n  var streamErrorHandler = function (e) {\n    console.error(\"Error:\", e);\n\n    // Clear the error\n    // TODO: Check this is how sax-js recommends error handling\n    this._parser.error = null;\n    this._parser.resume();\n  };\n\n  saxParser.on(\"error\", streamErrorHandler);\n\n  // REMOVED: SRS logic replaced with user-defined proj4 definition\n  //\n  // var saxStreamEnvelope = new saxpath.SaXPath(saxParser, \"//gml:Envelope\");\n  //\n  // saxStreamEnvelope.on(\"match\", function(xml) {\n  //   var srs = citygmlSRS(xml);\n  //\n  //   if (srs) {\n  //     envelopeSRS = srs;\n  //   }\n  //\n  //   // No need to kill the stream as it's still used to find buildings\n  //   // readStream.destroy();\n  // });\n\n  var saxStream = new saxpath.SaXPath(saxParser, \"//bldg:Building\");\n\n  saxStream.on(\"match\", function(xml) {\n    processQueue.push({\n      xml: xml,\n      proj4def: options.proj4def,\n      objPath: options.objPath,\n      overwrite: options.overwrite,\n      valhallaKey: options.valhallaKey\n    });\n\n    // Pause stream if queue is too large\n    if (processQueue.length >= maxQueue && !readStream.isPaused()) {\n      console.log(\"Pausing queue\");\n      readStream.pause();\n    }\n  });\n\n  saxStream.on(\"end\", function() {\n    console.log(\"Shutting down\");\n    console.log(\"Queue count:\", processQueue.length);\n\n    // Wait for queue to empty\n    var queueWaitTimer = setInterval(function() {\n      if (processQueue.length > 0) {\n        return;\n      }\n\n      // Stop queue wait timer\n      clearInterval(queueWaitTimer);\n\n      shutdown = true;\n\n      // Stop update check\n      clearInterval(queueCheck);\n\n      // Update queue one last time\n      // updateQueue();\n\n      // Clean up unused workers\n      // Keep the currently active worker open until it's finished\n      _.each(workers, function(worker) {\n        if (worker.ready) {\n          worker.process.kill(\"SIGINT\");\n        }\n      });\n\n      console.log(\"Waiting for workers\");\n\n      // Wait for all workers to finish before callback\n      // TODO: Don't let this go on forever\n      var aliveTimer = setInterval(function() {\n        var areShutdown = areWorkersShutdown();\n\n        if (areShutdown) {\n          console.log(\"Queue count:\", processQueue.length);\n          clearInterval(aliveTimer);\n          callback(null);\n        }\n      }, 500);\n    }, 500);\n  });\n\n  readStream = fs.createReadStream(options.citygmlPath);\n  readStream.pipe(saxParser);\n};\n\nmodule.exports = citygmlToObj;\n"]}