Exemple #1
0
void NMEAGPS::updateEndPointUI(){

    if (boat.isMoving){

      ui->resultLabel->setText(QString::number(boat.boatSpeed, 'f', 2) + " knots");

      if (boat.latitude < 0)
          ui->southButton->setChecked(true);
      else
          ui->northButton->setChecked(true);

      if (boat.longnitude < 0) {
          ui->westButton->setChecked(true);
      } else {
          ui->eastButton->setChecked(true);
      }

      QString latstr = QString::fromStdString(DegreesMinutesSecondsLat(boat.latitude, 0));
      QString lngstr = QString::fromStdString(DegreesMinutesSecondsLng(boat.longnitude, 0));
      ui->latLineEdit->setText(latstr.left(8));
      ui->longLineEdit->setText(lngstr.left(9));
      coordinatesChanged();
      setBoatMapLocation(boat.latitude, boat.longnitude);

  }
}
void LocationInformationWidget::acceptChanges()
{
	emit stopFilterDiveSite();
	char *uiString;
	currentDs->latitude = displayed_dive_site.latitude;
	currentDs->longitude = displayed_dive_site.longitude;
	uiString = ui.diveSiteName->text().toUtf8().data();
	if (!same_string(uiString, currentDs->name)) {
		free(currentDs->name);
		currentDs->name = copy_string(uiString);
	}
	uiString = ui.diveSiteDescription->text().toUtf8().data();
	if (!same_string(uiString, currentDs->description)) {
		free(currentDs->description);
		currentDs->description = copy_string(uiString);
	}
	uiString = ui.diveSiteNotes->document()->toPlainText().toUtf8().data();
	if (!same_string(uiString, currentDs->notes)) {
		free(currentDs->notes);
		currentDs->notes = copy_string(uiString);
	}
	if (current_mode == CREATE_DIVE_SITE)
		displayed_dive.dive_site_uuid = currentDs->uuid;
	if (dive_site_is_empty(currentDs)) {
		LocationInformationModel::instance()->removeRow(get_divesite_idx(currentDs));
		displayed_dive.dive_site_uuid = 0;
	}

	mark_divelist_changed(true);
	resetState();
	emit informationManagementEnded();
	emit coordinatesChanged();
}
void LocationInformationWidget::acceptChanges()
{
	char *uiString;
	currentDs->latitude = displayed_dive_site.latitude;
	currentDs->longitude = displayed_dive_site.longitude;
	uiString = ui.diveSiteName->text().toUtf8().data();
	if (!same_string(uiString, currentDs->name)) {
		free(currentDs->name);
		currentDs->name = copy_string(uiString);
	}
	uiString = ui.diveSiteDescription->text().toUtf8().data();
	if (!same_string(uiString, currentDs->description)) {
		free(currentDs->description);
		currentDs->description = copy_string(uiString);
	}
	uiString = ui.diveSiteNotes->document()->toPlainText().toUtf8().data();
	if (!same_string(uiString, currentDs->notes)) {
		free(currentDs->notes);
		currentDs->notes = copy_string(uiString);
	}
	if (dive_site_is_empty(currentDs)) {
		delete_dive_site(currentDs->uuid);
		displayed_dive.dive_site_uuid = 0;
		setLocationId(0);
	} else {
		setLocationId(currentDs->uuid);
	}
	mark_divelist_changed(true);
	resetState();
	emit informationManagementEnded();
	emit coordinatesChanged();
}
void LocationInformationWidget::rejectChanges()
{
	resetState();
	emit stopFilterDiveSite();
	emit informationManagementEnded();
	emit coordinatesChanged();
}
void LocationInformationWidget::on_diveSiteName_textChanged(const QString& text)
{
	if (!same_string(qPrintable(text), currentDs->name)) {
		free(displayed_dive_site.name);
		displayed_dive_site.name = copy_string(qPrintable(text));
		markChangedWidget(ui.diveSiteName);
		emit coordinatesChanged();
	}
}
//------------------------------------------------------------------------------
void ctkCoordinatesWidget::updateCoordinates()
{
  Q_D(ctkCoordinatesWidget);
  for (int i = 0; i < d->Dimension; ++i)
    {
    d->Coordinates[i] = this->spinBox(i)->value();
    }
  emit coordinatesChanged(d->Coordinates);
}
void LocationInformationWidget::on_diveSiteCoordinates_textChanged(const QString& text)
{
	if (!currentDs || !same_string(qPrintable(text), printGPSCoords(currentDs->latitude.udeg, currentDs->longitude.udeg))) {
		double latitude, longitude;
		if (parseGpsText(text, &latitude, &longitude)) {
			displayed_dive_site.latitude.udeg = latitude * 1000000;
			displayed_dive_site.longitude.udeg = longitude * 1000000;
			markChangedWidget(ui.diveSiteCoordinates);
			emit coordinatesChanged();
		}
	}
}
void LocationInformationWidget::rejectChanges()
{
	Q_ASSERT(currentDs != NULL);
	if (dive_site_is_empty(currentDs)) {
		delete_dive_site(currentDs->uuid);
		displayed_dive.dive_site_uuid = 0;
		setLocationId(0);
	} else {
		setLocationId(currentDs->uuid);
	}
	resetState();
	emit informationManagementEnded();
	emit coordinatesChanged();
}
//------------------------------------------------------------------------------
void ctkCoordinatesWidget::updateCoordinates()
{
    for (int i = 0; i < this->Dimension; ++i)
    {
        QLayoutItem* item = this->layout()->itemAt(i);
        QDoubleSpinBox* spinBox =
            item ? qobject_cast<QDoubleSpinBox*>(item->widget()) : 0;
        if ( spinBox)
        {
            this->Coordinates[i] = spinBox->value();
        }
    }
    emit coordinatesChanged(this->Coordinates);
}
//------------------------------------------------------------------------------
void ctkCoordinatesWidget::updateCoordinate(double coordinate)
{
  for (int i = 0; i < this->Dimension; ++i)
    {
    QLayoutItem* item = this->layout()->itemAt(i);
    QDoubleSpinBox* spinBox = 
      item ? qobject_cast<QDoubleSpinBox*>(item->widget()) : 0;
    if ( spinBox && spinBox == this->sender())
      {
      this->Coordinates[i] = coordinate;
      break;
      }
    }
  emit coordinatesChanged(this->Coordinates);
}
Exemple #11
0
void NMEAGPS::setCoordinates() {

    if (validateCoordinates()){
        boat.latitude = Boat::latDecimal(ui->latLineEdit->text());
        if (ui->southButton->isChecked())
            boat.latitude = boat.latitude * -1;
        boat.longnitude = Boat::longDecimal(ui->longLineEdit->text());
        if (ui->westButton->isChecked())
            boat.longnitude = boat.longnitude * -1;
        coordinatesChanged();
        setBoatMapLocation(boat.latitude, boat.longnitude);

        ui->latLineEdit->setCursorPosition(latCursorPos);
        ui->longLineEdit->setCursorPosition(longCursorPos);
    }
}
MainWindow::MainWindow()
    : dcStream_(0)
    , desktopSelectionWindow_(new DesktopSelectionWindow())
    , x_(0)
    , y_(0)
    , width_(0)
    , height_(0)
    , deviceScale_(1.f)
{
    generateCursorImage();
    setupUI();

    // Receive changes from the selection rectangle
    connect(desktopSelectionWindow_->getDesktopSelectionView()->getDesktopSelectionRectangle(),
            SIGNAL(coordinatesChanged(QRect)), this, SLOT(setCoordinates(QRect)));

    connect(desktopSelectionWindow_, SIGNAL(windowVisible(bool)), showDesktopSelectionWindowAction_, SLOT(setChecked(bool)));
}
void LocationInformationWidget::on_diveSiteName_textChanged(const QString& text)
{
	if (currentDs && text != currentDs->name) {
		// This needs to be changed directly into the model so that
		// the changes are replyed on the ComboBox with the current selection.

		int i;
		struct dive_site *ds;
		for_each_dive_site(i,ds)
			if (ds->uuid == currentDs->uuid)
				break;

		displayed_dive_site.name = copy_string(qPrintable(text));
		QModelIndex idx = LocationInformationModel::instance()->index(i,0);
		LocationInformationModel::instance()->setData(idx, text, Qt::EditRole);
		markChangedWidget(ui.diveSiteName);
		emit coordinatesChanged();
	}
void LocationInformationWidget::rejectChanges()
{
	if (current_mode == CREATE_DIVE_SITE) {
		LocationInformationModel::instance()->removeRow(get_divesite_idx(currentDs));
		if (displayed_dive.dive_site_uuid) {
			displayed_dive_site = *get_dive_site_by_uuid(displayed_dive.dive_site_uuid);
		} else {
			displayed_dive_site.uuid = 0;
		}
	} else if ((currentDs && dive_site_is_empty(currentDs))) {
		LocationInformationModel::instance()->removeRow(get_divesite_idx(currentDs));
		displayed_dive_site.uuid = 0;
	}

	resetState();
	emit stopFilterDiveSite();
	emit informationManagementEnded();
	emit coordinatesChanged();
}
QgsMapToolNodeTool::QgsMapToolNodeTool( QgsMapCanvas* canvas ): QgsMapToolVertexEdit( canvas )
{
  mSelectionFeature = NULL;
  mQRubberBand = NULL;
  mSelectAnother = false;
  mCtrl = false;
  mMoving = true;
  mClicked = false;
  mChangingGeometry = false;
  mIsPoint = false;
  //signal handling change of layer structure
  connect( canvas, SIGNAL( layersChanged() ), this, SLOT( layersChanged() ) );
  //signal when destination srs changed to repaint coordinates
  connect( canvas->mapRenderer(), SIGNAL( destinationSrsChanged() ), this, SLOT( coordinatesChanged() ) );
  //signal changing of coordinate renderer changed to repaint markers
  connect( canvas->mapRenderer(), SIGNAL( hasCrsTransformEnabled( bool ) ), this, SLOT( coordinatesChanged( ) ) );
  //signal changing of current layer
  connect( QgisApp::instance()->legend(), SIGNAL( currentLayerChanged( QgsMapLayer* ) ),
           this, SLOT( currentLayerChanged( QgsMapLayer* ) ) );
}
Exemple #16
0
/*!
  \class MatrixModel
  \brief Model for the access to data of a Matrix-object.

	This is a model in the sense of Qt4 model/view framework which is used
	to access a Matrix object from any of Qt4s view classes, typically a QMatrixView.
	Its main purposes are translating Matrix signals into QAbstractItemModel signals
	and translating calls to the QAbstractItemModel read/write API into calls
	in the public API of Matrix.

	\ingroup backend
*/
MatrixModel::MatrixModel(Matrix* matrix) : QAbstractItemModel(0), m_matrix(matrix), m_suppressDataChangedSignal(false) {
	connect(m_matrix, SIGNAL(columnsAboutToBeInserted(int,int)),
			this, SLOT(handleColumnsAboutToBeInserted(int,int)));
	connect(m_matrix, SIGNAL(columnsInserted(int,int)),
			this, SLOT(handleColumnsInserted(int,int)));
	connect(m_matrix, SIGNAL(columnsAboutToBeRemoved(int,int)),
			this, SLOT(handleColumnsAboutToBeRemoved(int,int)));
	connect(m_matrix, SIGNAL(columnsRemoved(int,int)),
			this, SLOT(handleColumnsRemoved(int,int)));
	connect(m_matrix, SIGNAL(rowsAboutToBeInserted(int,int)),
			this, SLOT(handleRowsAboutToBeInserted(int,int)));
	connect(m_matrix, SIGNAL(rowsInserted(int,int)),
			this, SLOT(handleRowsInserted(int,int)));
	connect(m_matrix, SIGNAL(rowsAboutToBeRemoved(int,int)),
			this, SLOT(handleRowsAboutToBeRemoved(int,int)));
	connect(m_matrix, SIGNAL(rowsRemoved(int,int)),
			this, SLOT(handleRowsRemoved(int,int)));
	connect(m_matrix, SIGNAL(dataChanged(int,int,int,int)),
			this, SLOT(handleDataChanged(int,int,int,int)));
	connect(m_matrix, SIGNAL(coordinatesChanged()),
			this, SLOT(handleCoordinatesChanged()));
	connect(m_matrix, SIGNAL(numericFormatChanged(char)), this, SLOT(handleFormatChanged()));
	connect(m_matrix, SIGNAL(precisionChanged(int)), this, SLOT(handleFormatChanged()));
}
void DesktopSelectionRectangle::mouseMoveEvent(QGraphicsSceneMouseEvent * event)
{
    if(event->buttons().testFlag(Qt::LeftButton))
    {
        if(resizing_)
        {
            QRectF r = rect();
            QPointF eventPos = event->pos();

            r.setBottomRight(eventPos);

            setRect(r);
        }
        else
        {
            QPointF delta = event->pos() - event->lastPos();

            moveBy(delta.x(), delta.y());
        }

        updateCoordinates();
        emit coordinatesChanged(x_, y_, width_, height_);
    }
}
Exemple #18
0
MainWindow::MainWindow() : QMainWindow(),
	actionNextDive(0),
	actionPreviousDive(0),
	helpView(0),
	state(VIEWALL),
	survey(0)
{
	Q_ASSERT_X(m_Instance == NULL, "MainWindow", "MainWindow recreated!");
	m_Instance = this;
	ui.setupUi(this);
	read_hashes();
	// Define the States of the Application Here, Currently the states are situations where the different
	// widgets will change on the mainwindow.

	// for the "default" mode
	MainTab *mainTab = new MainTab();
	DiveListView *diveListView = new DiveListView();
	ProfileWidget2 *profileWidget = new ProfileWidget2();

#ifndef NO_MARBLE
	GlobeGPS *globeGps = new GlobeGPS();
#else
	QWidget *globeGps = NULL;
#endif

	PlannerSettingsWidget *plannerSettings = new PlannerSettingsWidget();
	DivePlannerWidget *plannerWidget = new DivePlannerWidget();
	PlannerDetails *plannerDetails = new PlannerDetails();
	LocationInformationWidget *locationInformation = new LocationInformationWidget();

	// what is a sane order for those icons? we should have the ones the user is
	// most likely to want towards the top so they are always visible
	// and the ones that someone likely sets and then never touches again towards the bottom
	profileToolbarActions << ui.profCalcCeiling << ui.profCalcAllTissues << // start with various ceilings
				 ui.profIncrement3m << ui.profDcCeiling <<
				 ui.profPhe << ui.profPn2 << ui.profPO2 << // partial pressure graphs
				 ui.profRuler << ui.profScaled << // measuring and scaling
				 ui.profTogglePicture << ui.profTankbar <<
				 ui.profMod << ui.profNdl_tts << // various values that a user is either interested in or not
				 ui.profEad << ui.profSAC <<
				 ui.profHR << // very few dive computers support this
				 ui.profTissues; // maybe less frequently used

	QToolBar *toolBar = new QToolBar();
	Q_FOREACH (QAction *a, profileToolbarActions)
		toolBar->addAction(a);
	toolBar->setOrientation(Qt::Vertical);
	toolBar->setIconSize(QSize(24,24));

	QWidget *profileContainer = new QWidget();
	QHBoxLayout *profLayout = new QHBoxLayout();
	profLayout->setSpacing(0);
	profLayout->setMargin(0);
	profLayout->setContentsMargins(0,0,0,0);
	profLayout->addWidget(toolBar);
	profLayout->addWidget(profileWidget);
	profileContainer->setLayout(profLayout);

	registerApplicationState("Default", mainTab, profileContainer, diveListView, globeGps );
	registerApplicationState("AddDive", mainTab, profileContainer, diveListView, globeGps );
	registerApplicationState("EditDive", mainTab, profileContainer, diveListView, globeGps );
	registerApplicationState("PlanDive", plannerWidget, profileContainer, plannerSettings, plannerDetails );
	registerApplicationState("EditPlannedDive", plannerWidget, profileContainer, diveListView, globeGps );
	registerApplicationState("EditDiveSite",locationInformation, profileContainer, diveListView, globeGps );

	setApplicationState("Default");

	ui.multiFilter->hide();

	setWindowIcon(QIcon(":subsurface-icon"));
	if (!QIcon::hasThemeIcon("window-close")) {
		QIcon::setThemeName("subsurface");
	}
	connect(dive_list(), SIGNAL(currentDiveChanged(int)), this, SLOT(current_dive_changed(int)));
	connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), this, SLOT(readSettings()));
	connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), diveListView, SLOT(update()));
	connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), diveListView, SLOT(reloadHeaderActions()));
	connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), information(), SLOT(updateDiveInfo()));
	connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), divePlannerWidget(), SLOT(settingsChanged()));
	connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), divePlannerSettingsWidget(), SLOT(settingsChanged()));
	connect(PreferencesDialog::instance(), SIGNAL(settingsChanged()), TankInfoModel::instance(), SLOT(update()));
	connect(ui.actionRecent1, SIGNAL(triggered(bool)), this, SLOT(recentFileTriggered(bool)));
	connect(ui.actionRecent2, SIGNAL(triggered(bool)), this, SLOT(recentFileTriggered(bool)));
	connect(ui.actionRecent3, SIGNAL(triggered(bool)), this, SLOT(recentFileTriggered(bool)));
	connect(ui.actionRecent4, SIGNAL(triggered(bool)), this, SLOT(recentFileTriggered(bool)));
	connect(information(), SIGNAL(addDiveFinished()), graphics(), SLOT(setProfileState()));
	connect(DivePlannerPointsModel::instance(), SIGNAL(planCreated()), this, SLOT(planCreated()));
	connect(DivePlannerPointsModel::instance(), SIGNAL(planCanceled()), this, SLOT(planCanceled()));
	connect(plannerDetails->printPlan(), SIGNAL(pressed()), divePlannerWidget(), SLOT(printDecoPlan()));
	connect(mainTab, SIGNAL(requestDiveSiteEdit(uint32_t)), this, SLOT(enableDiveSiteEdit(uint32_t)));
	connect(locationInformation, SIGNAL(informationManagementEnded()), this, SLOT(setDefaultState()));
	connect(locationInformation, SIGNAL(informationManagementEnded()), information(), SLOT(showLocation()));
	connect(locationInformation, SIGNAL(coordinatesChanged()), globe(), SLOT(repopulateLabels()));

#ifdef NO_PRINTING
	plannerDetails->printPlan()->hide();
	ui.menuFile->removeAction(ui.actionPrint);
#endif
#ifndef USE_LIBGIT23_API
	ui.menuFile->removeAction(ui.actionCloudstorageopen);
	ui.menuFile->removeAction(ui.actionCloudstoragesave);
	qDebug() << "disabled / made invisible the cloud storage stuff";
#endif

	ui.mainErrorMessage->hide();
	graphics()->setEmptyState();
	initialUiSetup();
	readSettings();
	diveListView->reload(DiveTripModel::TREE);
	diveListView->reloadHeaderActions();
	diveListView->setFocus();
	globe()->reload();
	diveListView->expand(dive_list()->model()->index(0, 0));
	diveListView->scrollTo(dive_list()->model()->index(0, 0), QAbstractItemView::PositionAtCenter);
	divePlannerWidget()->settingsChanged();
	divePlannerSettingsWidget()->settingsChanged();
#ifdef NO_MARBLE
	ui.menuView->removeAction(ui.actionViewGlobe);
#else
	connect(globe(), SIGNAL(coordinatesChanged()), locationInformation, SLOT(updateGpsCoordinates()));
#endif
#ifdef NO_USERMANUAL
	ui.menuHelp->removeAction(ui.actionUserManual);
#endif
	memset(&copyPasteDive, 0, sizeof(copyPasteDive));
	memset(&what, 0, sizeof(what));

	updateManager = new UpdateManager(this);
	undoStack = new QUndoStack(this);
	QAction *undoAction = undoStack->createUndoAction(this, tr("&Undo"));
	QAction *redoAction = undoStack->createRedoAction(this, tr("&Redo"));
	undoAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Z));
	redoAction->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Z));
	QList<QAction*>undoRedoActions;
	undoRedoActions.append(undoAction);
	undoRedoActions.append(redoAction);
	ui.menu_Edit->addActions(undoRedoActions);

	ReverseGeoLookupThread *geoLookup = ReverseGeoLookupThread::instance();
	connect(geoLookup, SIGNAL(started()),information(), SLOT(disableGeoLookupEdition()));
	connect(geoLookup, SIGNAL(finished()), information(), SLOT(enableGeoLookupEdition()));
}
//------------------------------------------------------------------------------
void ctkCoordinatesWidget::updateCoordinate(double coordinate)
{
  Q_D(ctkCoordinatesWidget);
  int element = -1;
  for (int i = 0; i < d->Dimension; ++i)
    {
    if ( this->spinBox(i) && this->spinBox(i) == this->sender())
      {
      d->Coordinates[i] = coordinate;
      element = i;
      }
    }
  Q_ASSERT(element != -1);
  // Update the last edited history by push first the element.
  for (int i = d->Dimension -1; i > 0; --i)
    {
    if (d->LastUserEditedCoordinates[i] == element)
      {
      d->LastUserEditedCoordinates.swap(i,i-1);
      }
    }
  // What is the oldest coordinate to be edited
  int oldestElement = d->LastUserEditedCoordinates.last();

  if (this->isNormalized())
    {
    // We have to ensure the coordinates are normalized.
    double den = 0.;
    double squaredNorm = this->squaredNorm();
    // Old Values xx + yy + zz = 1
    // New values: x'x' + y'y' + z'z' = 1
    // Say we are changing y into y':
    // x'x' + z'z' = 1 - y'y'
    if (oldestElement != -1 &&
        d->Coordinates[oldestElement] != 0.0 &&
        squaredNorm != 0.0)
      {
      // 1) Normalize only with the oldest user edited value
      // The oldest element is z, that means we try to have
      // x = x' (so that the user doesn't loose the edit he just made on the
      // element (x) he edited before this one (y).
      // Let's pose a the coef to multiply z into z' that keeps the norm to 1
      // xx + z'z' = 1 - y'y' (because x = x')
      // xx + azaz = 1 - y'y' (because z' = az)
      // aa*zz = 1 - y'y' - xx
      // a = sqrt( (1 - y'y' - xx) / zz )
      den = (1. - (squaredNorm -
             d->Coordinates[oldestElement] *
             d->Coordinates[oldestElement])) /
              (d->Coordinates[oldestElement] *
               d->Coordinates[oldestElement]);
      if (den > 0.)
        {
        den = sqrt(den);
        }
      }
    // Maybe 1) failed, then give 2) a chance.
    if (den <= 0)
      {
      oldestElement = -1;
      }
    bool mult = true;
    if (oldestElement == -1)
      {
      // 2) Normalize with all the coordinates
      // Let's pose a the coef to multiply x into x' and z into z' that keeps
      // the norm to 1:
      // axax + azaz = 1 - y'y'
      // aa(xx + zz) = 1 - y'y'
      // a = sqrt( (1 - y'y') / (xx + zz) )
      squaredNorm -= coordinate * coordinate;
      if (squaredNorm != 0.0)
        {
        den = sqrt( (1. - coordinate * coordinate) / squaredNorm);
        }
      else if (d->Dimension > 1)
        {
        mult = false;
        den = sqrt((1. - coordinate*coordinate) / (d->Dimension - 1));
        }
      }
    // Normalize coordinates
    double* normalizedCoordinates = new double[d->Dimension];
    for (int i = 0; i < d->Dimension; ++i)
      {
      if ((i != element && oldestElement == -1) ||
          (i == oldestElement && oldestElement != -1))
        {
        normalizedCoordinates[i] = mult ? d->Coordinates[i] * den : den;
        }
      else
        {
        normalizedCoordinates[i] = d->Coordinates[i];
        }
      }
    this->setCoordinates(normalizedCoordinates);
    delete [] normalizedCoordinates;
    }
  else
    {
    emit coordinatesChanged(d->Coordinates);
    }
}
Exemple #20
0
void MapView::redraw() {
  if (!this->isEnabled()) {
    // blank
    uchar *bits = image.bits();
    int imgstride = image.bytesPerLine();
    int imgoffset = 0;
    for (int y = 0; y < image.height(); y++, imgoffset += imgstride)
      memset(bits + imgoffset, 0xee, imgstride);
    update();
    return;
  }

  double chunksize = 16 * zoom;

  // first find the center block position
  int centerchunkx = floor(x / 16);
  int centerchunkz = floor(z / 16);
  // and the center of the screen
  int centerx = image.width() / 2;
  int centery = image.height() / 2;
  // and align for panning
  centerx -= (x - centerchunkx * 16) * zoom;
  centery -= (z - centerchunkz * 16) * zoom;
  // now calculate the topleft block on the screen
  int startx = centerchunkx - floor(centerx / chunksize) - 1;
  int startz = centerchunkz - floor(centery / chunksize) - 1;
  // and the dimensions of the screen in blocks
  int blockswide = image.width() / chunksize + 3;
  int blockstall = image.height() / chunksize + 3;

  for (int cz = startz; cz < startz + blockstall; cz++)
    for (int cx = startx; cx < startx + blockswide; cx++)
      drawChunk(cx, cz);

  // add on the entity layer
  QPainter canvas(&image);
  double halfviewwidth = image.width() / 2 / zoom;
  double halvviewheight = image.height() / 2 / zoom;
  double x1 = x - halfviewwidth;
  double z1 = z - halvviewheight;
  double x2 = x + halfviewwidth;
  double z2 = z + halvviewheight;

  // draw the entities
  for (int cz = startz; cz < startz + blockstall; cz++) {
    for (int cx = startx; cx < startx + blockswide; cx++) {
      for (auto &type : overlayItemTypes) {
        Chunk *chunk = cache.fetch(cx, cz);
        if (chunk) {
          auto range = chunk->entities.equal_range(type);
          for (auto it = range.first; it != range.second; ++it) {
            // don't show entities above our depth
            int entityY = (*it)->midpoint().y;
            // everything below the current block,
            // but also inside the current block
            if (entityY < depth + 1) {
              int entityX = static_cast<int>((*it)->midpoint().x) & 0x0f;
              int entityZ = static_cast<int>((*it)->midpoint().z) & 0x0f;
              int index = entityX + (entityZ << 4);
              int highY = chunk->depth[index];
              if ( (entityY+10 >= highY) ||
                   (entityY+10 >= depth) )
                (*it)->draw(x1, z1, zoom, &canvas);
            }
          }
        }
      }
    }
  }


  // draw the generated structures
  for (auto &type : overlayItemTypes) {
    for (auto &item : overlayItems[type]) {
      if (item->intersects(OverlayItem::Point(x1 - 1, 0, z1 - 1),
                           OverlayItem::Point(x2 + 1, depth, z2 + 1))) {
        item->draw(x1, z1, zoom, &canvas);
      }
    }
  }

  emit(coordinatesChanged(x, depth, z));

  update();
}
//------------------------------------------------------------------------------
void ctkCoordinatesWidget::updateCoordinate(double coordinate)
{
    double den = 0.;
    int element = -1;
    for (int i = 0; i < this->Dimension; ++i)
    {
        QLayoutItem* item = this->layout()->itemAt(i);
        QDoubleSpinBox* spinBox =
            item ? qobject_cast<QDoubleSpinBox*>(item->widget()) : 0;
        if ( spinBox && spinBox == this->sender())
        {
            this->Coordinates[i] = coordinate;
            element = i;
        }
        else
        {
            den += this->Coordinates[i]*this->Coordinates[i];
        }
    }
    Q_ASSERT(element != -1);
    if (this->isNormalized())
    {
        // Old Values xx + yy + zz = 1
        // New values: x'x' + y'y' + z'z' = 1
        // Say we are changing y into y':
        // x'x' + z'z' = 1 - y'y'
        // Let's pose a the coef to multiply x into x' that keeps the norm to 1:
        // axax + azaz = 1 - y'y'
        // aa(xx + zz) = 1 - y'y'
        // a = sqrt( (1 - y'y') / (xx + zz) )
        bool mult = true;
        if (den != 0.0)
        {
            mult = true;
            den = sqrt( (1. - coordinate * coordinate) / den);
        }
        else if (this->Dimension > 1)
        {
            mult = false;
            den = sqrt((1. - coordinate*coordinate) / (this->Dimension - 1));
        }
        double* normalizedCoordinates = new double[this->Dimension];
        for (int i = 0; i < this->Dimension; ++i)
        {
            if (i != element)
            {
                normalizedCoordinates[i] = mult ? this->Coordinates[i] * den : den;
            }
            else
            {
                normalizedCoordinates[i] = this->Coordinates[i];
            }
        }
        this->setCoordinates(normalizedCoordinates);
        delete [] normalizedCoordinates;
    }
    else
    {
        emit coordinatesChanged(this->Coordinates);
    }
}