Exemplo n.º 1
0
  def __init__(self, dialog, parent=None):
    PropertyPage.__init__(self, PAGE_CONTROLS, dialog, parent)
    Ui_ControlsPropertiesWidget.setupUi(self, self)

    self.controlsDir = os.path.join(tools.pluginDir(), "js", "threejs", "controls")

    self.initControlsList()
    self.registerPropertyWidgets([self.comboBox_Controls])

    self.comboBox_Controls.currentIndexChanged.connect(self.controlsChanged)
Exemplo n.º 2
0
    def __init__(self, dialog, parent=None):
        PropertyPage.__init__(self, PAGE_CONTROLS, dialog, parent)
        Ui_ControlsPropertiesWidget.setupUi(self, self)

        self.controlsDir = os.path.join(tools.pluginDir(), "js", "threejs",
                                        "controls")

        self.initControlsList()
        self.registerPropertyWidgets([self.comboBox_Controls])

        self.comboBox_Controls.currentIndexChanged.connect(
            self.controlsChanged)
Exemplo n.º 3
0
    def __init__(self,
                 iface,
                 objectTypeManager,
                 pluginManager,
                 exportSettings=None,
                 lastTreeItemData=None):
        QDialog.__init__(self, iface.mainWindow())
        self.iface = iface
        self.objectTypeManager = objectTypeManager
        self.pluginManager = pluginManager
        self._settings = exportSettings or {}
        self.lastTreeItemData = lastTreeItemData
        self.localBrowsingMode = True

        self.rb_quads = self.rb_point = None

        self.templateType = None
        self.currentItem = None
        self.currentPage = None

        # Set up the user interface from Designer.
        self.ui = ui = Ui_Qgis2threejsDialog()
        ui.setupUi(self)

        self.setWindowFlags(self.windowFlags() | Qt.WindowMinimizeButtonHint)

        # output html filename
        ui.lineEdit_OutputFilename.setText(
            self._settings.get("OutputFilename", ""))
        ui.lineEdit_OutputFilename.setPlaceholderText("[Temporary file]")

        # settings button
        icon = QIcon(os.path.join(tools.pluginDir(), "icons", "settings.png"))
        ui.toolButton_Settings.setIcon(icon)

        # popup menu displayed when settings button is pressed
        items = [["Load Settings...", self.loadSettings],
                 ["Save Settings As...", self.saveSettings], [None, None],
                 ["Clear Settings", self.clearSettings], [None, None],
                 ["Plugin Settings...", self.pluginSettings]]

        self.menu = QMenu()
        self.menu_actions = []
        for text, slot in items:
            if text:
                action = QAction(text, iface.mainWindow())
                action.triggered.connect(slot)
                self.menu.addAction(action)
                self.menu_actions.append(action)
            else:
                self.menu.addSeparator()

        ui.toolButton_Settings.setMenu(self.menu)
        ui.toolButton_Settings.setPopupMode(QToolButton.InstantPopup)

        # progress bar and message label
        ui.progressBar.setVisible(False)
        ui.label_MessageIcon.setVisible(False)

        # buttons
        ui.pushButton_Run.clicked.connect(self.run)
        ui.pushButton_Close.clicked.connect(self.reject)
        ui.pushButton_Help.clicked.connect(self.help)

        # set up map tool
        self.previousMapTool = None
        self.mapTool = RectangleMapTool(iface.mapCanvas())
        #self.mapTool = PointMapTool(iface.mapCanvas())

        # set up the template combo box
        self.initTemplateList()
        self.ui.comboBox_Template.currentIndexChanged.connect(
            self.currentTemplateChanged)

        # set up the properties pages
        self.pages = {}
        self.pages[ppages.PAGE_WORLD] = ppages.WorldPropertyPage(self)
        self.pages[ppages.PAGE_CONTROLS] = ppages.ControlsPropertyPage(self)
        self.pages[ppages.PAGE_DEM] = ppages.DEMPropertyPage(self)
        self.pages[ppages.PAGE_VECTOR] = ppages.VectorPropertyPage(self)
        container = ui.propertyPagesContainer
        for page in self.pages.itervalues():
            page.hide()
            container.addWidget(page)

        # build object tree
        self.topItemPages = {
            ObjectTreeItem.ITEM_WORLD: ppages.PAGE_WORLD,
            ObjectTreeItem.ITEM_CONTROLS: ppages.PAGE_CONTROLS,
            ObjectTreeItem.ITEM_DEM: ppages.PAGE_DEM
        }
        self.initObjectTree()
        self.ui.treeWidget.currentItemChanged.connect(
            self.currentObjectChanged)
        self.ui.treeWidget.itemChanged.connect(self.objectItemChanged)
        self.currentTemplateChanged()  # update item visibility

        ui.toolButton_Browse.clicked.connect(self.browseClicked)
Exemplo n.º 4
0
def runAdvanced(htmlfilename, context, dialog, progress=None):
  mapTo3d = context.mapTo3d
  canvas = context.canvas
  if progress is None:
    progress = dummyProgress
  demlayer = QgsMapLayerRegistry().instance().mapLayer(context.demlayerid)
  temp_dir = QDir.tempPath()
  timestamp = datetime.datetime.today().strftime("%Y%m%d%H%M%S")

  if htmlfilename == "":
    htmlfilename = tools.temporaryOutputDir() + "/%s.html" % timestamp
  out_dir, filename = os.path.split(htmlfilename)
  if not QDir(out_dir).exists():
    QDir().mkpath(out_dir)
  filetitle = os.path.splitext(filename)[0]

  # create quad tree
  quadtree = dialog.createQuadTree()
  if quadtree is None:
    QMessageBox.warning(None, "Qgis2threejs", "Focus point/area is not selected.")
    return
  quads = quadtree.quads()

  # create quads and a point on map canvas with rubber bands
  dialog.createRubberBands(quads, quadtree.focusRect.center())

  # create an image for texture
  image_basesize = 128
  hpw = canvas.extent().height() / canvas.extent().width()
  if hpw < 1:
    image_width = image_basesize
    image_height = round(image_width * hpw)
  else:
    image_height = image_basesize
    image_width = round(image_height * hpw)
  image = QImage(image_width, image_height, QImage.Format_ARGB32_Premultiplied)
  #qDebug("Created image size: %d, %d" % (image_width, image_height))

  layerids = []
  for layer in canvas.layers():
    layerids.append(unicode(layer.id()))

  # set up a renderer
  labeling = QgsPalLabeling()
  renderer = QgsMapRenderer()
  renderer.setOutputSize(image.size(), image.logicalDpiX())
  renderer.setDestinationCrs(context.crs)
  renderer.setProjectionsEnabled(True)
  renderer.setLabelingEngine(labeling)
  renderer.setLayerSet(layerids)

  painter = QPainter()
  antialias = True
  fillColor = canvas.canvasColor()
  if float(".".join(QT_VERSION_STR.split(".")[0:2])) < 4.8:
    fillColor = qRgb(fillColor.red(), fillColor.green(), fillColor.blue())

  # (currently) dem size should be 2 ^ quadtree.height * a + 1, where a is larger integer than 0
  # with smooth resolution change, this is not necessary
  dem_width = dem_height = max(64, 2 ** quadtree.height) + 1

  warp_dem = tools.MemoryWarpRaster(demlayer.source().encode("UTF-8"))
  wkt = str(context.crs.toWkt())

  # create JavaScript writer object
  context.setWarpDem(warp_dem)
  writer = JSWriter(htmlfilename, context)

  unites_center = True
  centerQuads = DEMQuadList(dem_width, dem_height)
  scripts = []
  plane_index = 0
  for i, quad in enumerate(quads):
    progress(50 * i / len(quads))
    extent = quad.extent

    if quad.height < quadtree.height or unites_center == False:
      renderer.setExtent(extent)
      # render map image
      image.fill(fillColor)
      painter.begin(image)
      if antialias:
        painter.setRenderHint(QPainter.Antialiasing)
      renderer.render(painter)
      painter.end()

      if context.localBrowsingMode:
        tex = tools.base64image(image)
      else:
        texfilename = os.path.splitext(htmlfilename)[0] + "_%d.png" % plane_index
        image.save(texfilename)
        tex = os.path.split(texfilename)[1]

    # calculate extent. output dem should be handled as points.
    xres = extent.width() / (dem_width - 1)
    yres = extent.height() / (dem_height - 1)
    geotransform = [extent.xMinimum() - xres / 2, xres, 0, extent.yMaximum() + yres / 2, 0, -yres]

    # warp dem
    dem_values = warp_dem.read(dem_width, dem_height, wkt, geotransform)
    if mapTo3d.multiplierZ != 1:
      dem_values = map(lambda x: x * mapTo3d.multiplierZ, dem_values)
    if debug_mode:
      qDebug("Warped DEM: %d x %d, extent %s" % (dem_width, dem_height, str(geotransform)))

    # generate javascript data file
    planeWidth = mapTo3d.planeWidth * extent.width() / canvas.extent().width()
    planeHeight = mapTo3d.planeHeight * extent.height() / canvas.extent().height()
    offsetX = mapTo3d.planeWidth * (extent.xMinimum() - canvas.extent().xMinimum()) / canvas.extent().width() + planeWidth / 2 - mapTo3d.planeWidth / 2
    offsetY = mapTo3d.planeHeight * (extent.yMinimum() - canvas.extent().yMinimum()) / canvas.extent().height() + planeHeight / 2 - mapTo3d.planeHeight / 2

    # value resampling on edges for combination with different resolution DEM
    neighbors = quadtree.neighbors(quad)
    #qDebug("Output quad (%d %s): height=%d" % (i, str(quad), quad.height))
    for direction, neighbor in enumerate(neighbors):
      if neighbor is None:
        continue
      #qDebug(" neighbor %d %s: height=%d" % (direction, str(neighbor), neighbor.height))
      interval = 2 ** (quad.height - neighbor.height)
      if interval > 1:
        if direction == QuadTree.UP or direction == QuadTree.DOWN:
          y = 0 if direction == QuadTree.UP else dem_height - 1
          for x1 in range(interval, dem_width, interval):
            x0 = x1 - interval
            z0 = dem_values[x0 + dem_width * y]
            z1 = dem_values[x1 + dem_width * y]
            for xx in range(1, interval):
              z = (z0 * (interval - xx) + z1 * xx) / interval
              dem_values[x0 + xx + dem_width * y] = z
        else:   # LEFT or RIGHT
          x = 0 if direction == QuadTree.LEFT else dem_width - 1
          for y1 in range(interval, dem_height, interval):
            y0 = y1 - interval
            z0 = dem_values[x + dem_width * y0]
            z1 = dem_values[x + dem_width * y1]
            for yy in range(1, interval):
              z = (z0 * (interval - yy) + z1 * yy) / interval
              dem_values[x + dem_width * (y0 + yy)] = z

    if quad.height < quadtree.height or unites_center == False:
      writer.openFile(True)
      opt = "{width:%f,height:%f,offsetX:%f,offsetY:%f}" % (planeWidth, planeHeight, offsetX, offsetY)
      writer.write('dem[%d] = {width:%d,height:%d,plane:%s,data:[%s]};\n' % (plane_index, dem_width, dem_height, opt, ",".join(map(gdal2threejs.formatValue, dem_values))))
      writer.write('tex[%d] = "%s";\n' % (plane_index, tex))
      plane_index += 1
    else:
      centerQuads.addQuad(quad, dem_values)

  if unites_center:
    extent = centerQuads.extent()
    if hpw < 1:
      image_width = image_basesize * centerQuads.width()
      image_height = round(image_width * hpw)
    else:
      image_height = image_basesize * centerQuads.height()
      image_width = round(image_height * hpw)
    image = QImage(image_width, image_height, QImage.Format_ARGB32_Premultiplied)
    #qDebug("Created image size: %d, %d" % (image_width, image_height))

    renderer.setOutputSize(image.size(), image.logicalDpiX())
    renderer.setExtent(extent)
    # render map image
    image.fill(fillColor)
    painter.begin(image)
    if antialias:
      painter.setRenderHint(QPainter.Antialiasing)
    renderer.render(painter)
    painter.end()

    if context.localBrowsingMode:
      tex = tools.base64image(image)
    else:
      texfilename = os.path.splitext(htmlfilename)[0] + "_%d.png" % plane_index
      image.save(texfilename)
      tex = os.path.split(texfilename)[1]

    dem_values = centerQuads.unitedDEM()
    planeWidth = mapTo3d.planeWidth * extent.width() / canvas.extent().width()
    planeHeight = mapTo3d.planeHeight * extent.height() / canvas.extent().height()
    offsetX = mapTo3d.planeWidth * (extent.xMinimum() - canvas.extent().xMinimum()) / canvas.extent().width() + planeWidth / 2 - mapTo3d.planeWidth / 2
    offsetY = mapTo3d.planeHeight * (extent.yMinimum() - canvas.extent().yMinimum()) / canvas.extent().height() + planeHeight / 2 - mapTo3d.planeHeight / 2

    dem_width = (dem_width - 1) * centerQuads.width() + 1
    dem_height = (dem_height - 1) * centerQuads.height() + 1

    writer.openFile(True)
    opt = "{width:%f,height:%f,offsetX:%f,offsetY:%f}" % (planeWidth, planeHeight, offsetX, offsetY)
    writer.write('dem[%d] = {width:%d,height:%d,plane:%s,data:[%s]};\n' % (plane_index, dem_width, dem_height, opt, ",".join(map(gdal2threejs.formatValue, dem_values))))
    writer.write('tex[%d] = "%s";\n' % (plane_index, tex))
    plane_index += 1
  progress(50)

  # vector data output
  writer.prepareNext()
  writeVectors(writer)
  progress(80)

  # copy files from template
  tools.copyThreejsFiles(out_dir)

  # generate html file
  with codecs.open(tools.pluginDir() + "/template.html", "r", "UTF-8") as f:
    html = f.read()

  with codecs.open(htmlfilename, "w", "UTF-8") as f:
    f.write(html.replace("${title}", filetitle).replace("${scripts}", writer.scripts()))

  return htmlfilename
Exemplo n.º 5
0
def runSimple(htmlfilename, context, progress=None):
  mapTo3d = context.mapTo3d
  canvas = context.canvas
  extent = canvas.extent()
  demlayer = QgsMapLayerRegistry().instance().mapLayer(context.demlayerid)
  if progress is None:
    progress = dummyProgress
  temp_dir = QDir.tempPath()
  timestamp = datetime.datetime.today().strftime("%Y%m%d%H%M%S")

  if htmlfilename == "":
    htmlfilename = tools.temporaryOutputDir() + "/%s.html" % timestamp
  out_dir, filename = os.path.split(htmlfilename)
  if not QDir(out_dir).exists():
    QDir().mkpath(out_dir)

  filetitle = os.path.splitext(filename)[0]

  # save map canvas image
  if context.localBrowsingMode:
    texfilename = os.path.join(temp_dir, "tex%s.png" % (timestamp))
    canvas.saveAsImage(texfilename)
    tex = gdal2threejs.base64image(texfilename)
    tools.removeTemporaryFiles([texfilename, texfilename + "w"])
  else:
    texfilename = os.path.splitext(htmlfilename)[0] + ".png"
    canvas.saveAsImage(texfilename)
    tex = os.path.split(texfilename)[1]
    tools.removeTemporaryFiles([texfilename + "w"])
  progress(20)

  # warp dem
  # calculate extent. output dem should be handled as points.
  xres = extent.width() / (context.dem_width - 1)
  yres = extent.height() / (context.dem_height - 1)
  geotransform = [extent.xMinimum() - xres / 2, xres, 0, extent.yMaximum() + yres / 2, 0, -yres]
  wkt = str(context.crs.toWkt())

  warp_dem = tools.MemoryWarpRaster(demlayer.source().encode("UTF-8"))
  dem_values = warp_dem.read(context.dem_width, context.dem_height, wkt, geotransform)
  if mapTo3d.multiplierZ != 1:
    dem_values = map(lambda x: x * mapTo3d.multiplierZ, dem_values)
  if debug_mode:
    qDebug("Warped DEM: %d x %d, extent %s" % (context.dem_width, context.dem_height, str(geotransform)))

  # create JavaScript writer object
  context.setWarpDem(warp_dem)
  writer = JSWriter(htmlfilename, context)
  writer.openFile()

  # write dem data
  offsetX = offsetY = 0
  opt = "{width:%f,height:%f,offsetX:%f,offsetY:%f}" % (mapTo3d.planeWidth, mapTo3d.planeHeight, offsetX, offsetY)
  writer.write('dem[0] = {width:%d,height:%d,plane:%s,data:[%s]};\n' % (context.dem_width, context.dem_height, opt, ",".join(map(gdal2threejs.formatValue, dem_values))))
  writer.write('tex[0] = "%s";\n' % tex)
  progress(50)

  # write vector data
  writeVectors(writer)
  progress(80)

  # copy files from template
  tools.copyThreejsFiles(out_dir)

  # generate html file
  with codecs.open(tools.pluginDir() + "/template.html", "r", "UTF-8") as f:
    html = f.read()

  with codecs.open(htmlfilename, "w", "UTF-8") as f:
    f.write(html.replace("${title}", filetitle).replace("${scripts}", writer.scripts()))

  return htmlfilename
Exemplo n.º 6
0
  def __init__(self, iface, objectTypeManager, pluginManager, exportSettings=None, lastTreeItemData=None):
    QDialog.__init__(self, iface.mainWindow())
    self.iface = iface
    self.objectTypeManager = objectTypeManager
    self.pluginManager = pluginManager
    self._settings = exportSettings or {}
    self.lastTreeItemData = lastTreeItemData
    self.localBrowsingMode = True

    self.rb_quads = self.rb_point = None

    self.templateType = None
    self.currentItem = None
    self.currentPage = None

    # Set up the user interface from Designer.
    self.ui = ui = Ui_Qgis2threejsDialog()
    ui.setupUi(self)

    self.setWindowFlags(self.windowFlags() | Qt.WindowMinimizeButtonHint)

    # output html filename
    ui.lineEdit_OutputFilename.setText(self._settings.get("OutputFilename", ""))
    ui.lineEdit_OutputFilename.setPlaceholderText("[Temporary file]")

    # settings button
    icon = QIcon(os.path.join(tools.pluginDir(), "icons", "settings.png"))
    ui.toolButton_Settings.setIcon(icon)

    # popup menu displayed when settings button is pressed
    items = [["Load Settings...", self.loadSettings],
             ["Save Settings As...", self.saveSettings],
             [None, None],
             ["Clear Settings", self.clearSettings],
             [None, None],
             ["Plugin Settings...", self.pluginSettings]]

    self.menu = QMenu()
    self.menu_actions = []
    for text, slot in items:
      if text:
        action = QAction(text, iface.mainWindow())
        action.triggered.connect(slot)
        self.menu.addAction(action)
        self.menu_actions.append(action)
      else:
        self.menu.addSeparator()

    ui.toolButton_Settings.setMenu(self.menu)
    ui.toolButton_Settings.setPopupMode(QToolButton.InstantPopup)

    # progress bar and message label
    ui.progressBar.setVisible(False)
    ui.label_MessageIcon.setVisible(False)

    # buttons
    ui.pushButton_Run.clicked.connect(self.run)
    ui.pushButton_Close.clicked.connect(self.reject)
    ui.pushButton_Help.clicked.connect(self.help)

    # set up map tool
    self.previousMapTool = None
    self.mapTool = RectangleMapTool(iface.mapCanvas())
    #self.mapTool = PointMapTool(iface.mapCanvas())

    # set up the template combo box
    self.initTemplateList()
    self.ui.comboBox_Template.currentIndexChanged.connect(self.currentTemplateChanged)

    # set up the properties pages
    self.pages = {}
    self.pages[ppages.PAGE_WORLD] = ppages.WorldPropertyPage(self)
    self.pages[ppages.PAGE_CONTROLS] = ppages.ControlsPropertyPage(self)
    self.pages[ppages.PAGE_DEM] = ppages.DEMPropertyPage(self)
    self.pages[ppages.PAGE_VECTOR] = ppages.VectorPropertyPage(self)
    container = ui.propertyPagesContainer
    for page in self.pages.itervalues():
      page.hide()
      container.addWidget(page)

    # build object tree
    self.topItemPages = {ObjectTreeItem.ITEM_WORLD: ppages.PAGE_WORLD, ObjectTreeItem.ITEM_CONTROLS: ppages.PAGE_CONTROLS, ObjectTreeItem.ITEM_DEM: ppages.PAGE_DEM}
    self.initObjectTree()
    self.ui.treeWidget.currentItemChanged.connect(self.currentObjectChanged)
    self.ui.treeWidget.itemChanged.connect(self.objectItemChanged)
    self.currentTemplateChanged()   # update item visibility

    ui.toolButton_Browse.clicked.connect(self.browseClicked)
def runAdvanced(htmlfilename, context, dialog, progress=None):
    mapTo3d = context.mapTo3d
    canvas = context.canvas
    if progress is None:
        progress = dummyProgress
    demlayer = QgsMapLayerRegistry().instance().mapLayer(context.demlayerid)
    temp_dir = QDir.tempPath()
    timestamp = datetime.datetime.today().strftime("%Y%m%d%H%M%S")

    if htmlfilename == "":
        htmlfilename = tools.temporaryOutputDir() + "/%s.html" % timestamp
    out_dir, filename = os.path.split(htmlfilename)
    if not QDir(out_dir).exists():
        QDir().mkpath(out_dir)
    filetitle = os.path.splitext(filename)[0]

    # create quad tree
    quadtree = dialog.createQuadTree()
    if quadtree is None:
        QMessageBox.warning(None, "Qgis2threejs",
                            "Focus point/area is not selected.")
        return
    quads = quadtree.quads()

    # create quads and a point on map canvas with rubber bands
    dialog.createRubberBands(quads, quadtree.focusRect.center())

    # create an image for texture
    image_basesize = 128
    hpw = canvas.extent().height() / canvas.extent().width()
    if hpw < 1:
        image_width = image_basesize
        image_height = round(image_width * hpw)
    else:
        image_height = image_basesize
        image_width = round(image_height * hpw)
    image = QImage(image_width, image_height,
                   QImage.Format_ARGB32_Premultiplied)
    #qDebug("Created image size: %d, %d" % (image_width, image_height))

    layerids = []
    for layer in canvas.layers():
        layerids.append(unicode(layer.id()))

    # set up a renderer
    labeling = QgsPalLabeling()
    renderer = QgsMapRenderer()
    renderer.setOutputSize(image.size(), image.logicalDpiX())
    renderer.setDestinationCrs(context.crs)
    renderer.setProjectionsEnabled(True)
    renderer.setLabelingEngine(labeling)
    renderer.setLayerSet(layerids)

    painter = QPainter()
    antialias = True
    fillColor = canvas.canvasColor()
    if float(".".join(QT_VERSION_STR.split(".")[0:2])) < 4.8:
        fillColor = qRgb(fillColor.red(), fillColor.green(), fillColor.blue())

    # (currently) dem size should be 2 ^ quadtree.height * a + 1, where a is larger integer than 0
    # with smooth resolution change, this is not necessary
    dem_width = dem_height = max(64, 2**quadtree.height) + 1

    warp_dem = tools.MemoryWarpRaster(demlayer.source().encode("UTF-8"))
    wkt = str(context.crs.toWkt())

    # create JavaScript writer object
    context.setWarpDem(warp_dem)
    writer = JSWriter(htmlfilename, context)

    unites_center = True
    centerQuads = DEMQuadList(dem_width, dem_height)
    scripts = []
    plane_index = 0
    for i, quad in enumerate(quads):
        progress(50 * i / len(quads))
        extent = quad.extent

        if quad.height < quadtree.height or unites_center == False:
            renderer.setExtent(extent)
            # render map image
            image.fill(fillColor)
            painter.begin(image)
            if antialias:
                painter.setRenderHint(QPainter.Antialiasing)
            renderer.render(painter)
            painter.end()

            if context.localBrowsingMode:
                tex = tools.base64image(image)
            else:
                texfilename = os.path.splitext(
                    htmlfilename)[0] + "_%d.png" % plane_index
                image.save(texfilename)
                tex = os.path.split(texfilename)[1]

        # calculate extent. output dem should be handled as points.
        xres = extent.width() / (dem_width - 1)
        yres = extent.height() / (dem_height - 1)
        geotransform = [
            extent.xMinimum() - xres / 2, xres, 0,
            extent.yMaximum() + yres / 2, 0, -yres
        ]

        # warp dem
        dem_values = warp_dem.read(dem_width, dem_height, wkt, geotransform)
        if mapTo3d.multiplierZ != 1:
            dem_values = map(lambda x: x * mapTo3d.multiplierZ, dem_values)
        if debug_mode:
            qDebug("Warped DEM: %d x %d, extent %s" %
                   (dem_width, dem_height, str(geotransform)))

        # generate javascript data file
        planeWidth = mapTo3d.planeWidth * extent.width() / canvas.extent(
        ).width()
        planeHeight = mapTo3d.planeHeight * extent.height() / canvas.extent(
        ).height()
        offsetX = mapTo3d.planeWidth * (
            extent.xMinimum() - canvas.extent().xMinimum()
        ) / canvas.extent().width() + planeWidth / 2 - mapTo3d.planeWidth / 2
        offsetY = mapTo3d.planeHeight * (
            extent.yMinimum() - canvas.extent().yMinimum()) / canvas.extent(
            ).height() + planeHeight / 2 - mapTo3d.planeHeight / 2

        # value resampling on edges for combination with different resolution DEM
        neighbors = quadtree.neighbors(quad)
        #qDebug("Output quad (%d %s): height=%d" % (i, str(quad), quad.height))
        for direction, neighbor in enumerate(neighbors):
            if neighbor is None:
                continue
            #qDebug(" neighbor %d %s: height=%d" % (direction, str(neighbor), neighbor.height))
            interval = 2**(quad.height - neighbor.height)
            if interval > 1:
                if direction == QuadTree.UP or direction == QuadTree.DOWN:
                    y = 0 if direction == QuadTree.UP else dem_height - 1
                    for x1 in range(interval, dem_width, interval):
                        x0 = x1 - interval
                        z0 = dem_values[x0 + dem_width * y]
                        z1 = dem_values[x1 + dem_width * y]
                        for xx in range(1, interval):
                            z = (z0 * (interval - xx) + z1 * xx) / interval
                            dem_values[x0 + xx + dem_width * y] = z
                else:  # LEFT or RIGHT
                    x = 0 if direction == QuadTree.LEFT else dem_width - 1
                    for y1 in range(interval, dem_height, interval):
                        y0 = y1 - interval
                        z0 = dem_values[x + dem_width * y0]
                        z1 = dem_values[x + dem_width * y1]
                        for yy in range(1, interval):
                            z = (z0 * (interval - yy) + z1 * yy) / interval
                            dem_values[x + dem_width * (y0 + yy)] = z

        if quad.height < quadtree.height or unites_center == False:
            writer.openFile(True)
            opt = "{width:%f,height:%f,offsetX:%f,offsetY:%f}" % (
                planeWidth, planeHeight, offsetX, offsetY)
            writer.write(
                'dem[%d] = {width:%d,height:%d,plane:%s,data:[%s]};\n' %
                (plane_index, dem_width, dem_height, opt, ",".join(
                    map(gdal2threejs.formatValue, dem_values))))
            writer.write('tex[%d] = "%s";\n' % (plane_index, tex))
            plane_index += 1
        else:
            centerQuads.addQuad(quad, dem_values)

    if unites_center:
        extent = centerQuads.extent()
        if hpw < 1:
            image_width = image_basesize * centerQuads.width()
            image_height = round(image_width * hpw)
        else:
            image_height = image_basesize * centerQuads.height()
            image_width = round(image_height * hpw)
        image = QImage(image_width, image_height,
                       QImage.Format_ARGB32_Premultiplied)
        #qDebug("Created image size: %d, %d" % (image_width, image_height))

        renderer.setOutputSize(image.size(), image.logicalDpiX())
        renderer.setExtent(extent)
        # render map image
        image.fill(fillColor)
        painter.begin(image)
        if antialias:
            painter.setRenderHint(QPainter.Antialiasing)
        renderer.render(painter)
        painter.end()

        if context.localBrowsingMode:
            tex = tools.base64image(image)
        else:
            texfilename = os.path.splitext(
                htmlfilename)[0] + "_%d.png" % plane_index
            image.save(texfilename)
            tex = os.path.split(texfilename)[1]

        dem_values = centerQuads.unitedDEM()
        planeWidth = mapTo3d.planeWidth * extent.width() / canvas.extent(
        ).width()
        planeHeight = mapTo3d.planeHeight * extent.height() / canvas.extent(
        ).height()
        offsetX = mapTo3d.planeWidth * (
            extent.xMinimum() - canvas.extent().xMinimum()
        ) / canvas.extent().width() + planeWidth / 2 - mapTo3d.planeWidth / 2
        offsetY = mapTo3d.planeHeight * (
            extent.yMinimum() - canvas.extent().yMinimum()) / canvas.extent(
            ).height() + planeHeight / 2 - mapTo3d.planeHeight / 2

        dem_width = (dem_width - 1) * centerQuads.width() + 1
        dem_height = (dem_height - 1) * centerQuads.height() + 1

        writer.openFile(True)
        opt = "{width:%f,height:%f,offsetX:%f,offsetY:%f}" % (
            planeWidth, planeHeight, offsetX, offsetY)
        writer.write('dem[%d] = {width:%d,height:%d,plane:%s,data:[%s]};\n' %
                     (plane_index, dem_width, dem_height, opt, ",".join(
                         map(gdal2threejs.formatValue, dem_values))))
        writer.write('tex[%d] = "%s";\n' % (plane_index, tex))
        plane_index += 1
    progress(50)

    # vector data output
    writer.prepareNext()
    writeVectors(writer)
    progress(80)

    # copy files from template
    tools.copyThreejsFiles(out_dir)

    # generate html file
    with codecs.open(tools.pluginDir() + "/template.html", "r", "UTF-8") as f:
        html = f.read()

    with codecs.open(htmlfilename, "w", "UTF-8") as f:
        f.write(
            html.replace("${title}",
                         filetitle).replace("${scripts}", writer.scripts()))

    return htmlfilename
def runSimple(htmlfilename, context, progress=None):
    mapTo3d = context.mapTo3d
    canvas = context.canvas
    extent = canvas.extent()
    demlayer = QgsMapLayerRegistry().instance().mapLayer(context.demlayerid)
    if progress is None:
        progress = dummyProgress
    temp_dir = QDir.tempPath()
    timestamp = datetime.datetime.today().strftime("%Y%m%d%H%M%S")

    if htmlfilename == "":
        htmlfilename = tools.temporaryOutputDir() + "/%s.html" % timestamp
    out_dir, filename = os.path.split(htmlfilename)
    if not QDir(out_dir).exists():
        QDir().mkpath(out_dir)

    filetitle = os.path.splitext(filename)[0]

    # save map canvas image
    if context.localBrowsingMode:
        texfilename = os.path.join(temp_dir, "tex%s.png" % (timestamp))
        canvas.saveAsImage(texfilename)
        tex = gdal2threejs.base64image(texfilename)
        tools.removeTemporaryFiles([texfilename, texfilename + "w"])
    else:
        texfilename = os.path.splitext(htmlfilename)[0] + ".png"
        canvas.saveAsImage(texfilename)
        tex = os.path.split(texfilename)[1]
        tools.removeTemporaryFiles([texfilename + "w"])
    progress(20)

    # warp dem
    # calculate extent. output dem should be handled as points.
    xres = extent.width() / (context.dem_width - 1)
    yres = extent.height() / (context.dem_height - 1)
    geotransform = [
        extent.xMinimum() - xres / 2, xres, 0,
        extent.yMaximum() + yres / 2, 0, -yres
    ]
    wkt = str(context.crs.toWkt())

    warp_dem = tools.MemoryWarpRaster(demlayer.source().encode("UTF-8"))
    dem_values = warp_dem.read(context.dem_width, context.dem_height, wkt,
                               geotransform)
    if mapTo3d.multiplierZ != 1:
        dem_values = map(lambda x: x * mapTo3d.multiplierZ, dem_values)
    if debug_mode:
        qDebug("Warped DEM: %d x %d, extent %s" %
               (context.dem_width, context.dem_height, str(geotransform)))

    # create JavaScript writer object
    context.setWarpDem(warp_dem)
    writer = JSWriter(htmlfilename, context)
    writer.openFile()

    # write dem data
    offsetX = offsetY = 0
    opt = "{width:%f,height:%f,offsetX:%f,offsetY:%f}" % (
        mapTo3d.planeWidth, mapTo3d.planeHeight, offsetX, offsetY)
    writer.write('dem[0] = {width:%d,height:%d,plane:%s,data:[%s]};\n' %
                 (context.dem_width, context.dem_height, opt, ",".join(
                     map(gdal2threejs.formatValue, dem_values))))
    writer.write('tex[0] = "%s";\n' % tex)
    progress(50)

    # write vector data
    writeVectors(writer)
    progress(80)

    # copy files from template
    tools.copyThreejsFiles(out_dir)

    # generate html file
    with codecs.open(tools.pluginDir() + "/template.html", "r", "UTF-8") as f:
        html = f.read()

    with codecs.open(htmlfilename, "w", "UTF-8") as f:
        f.write(
            html.replace("${title}",
                         filetitle).replace("${scripts}", writer.scripts()))

    return htmlfilename