<commit_before>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "WorldInfo.h"

/* common implementation headers */
#include "global.h"
#include "Pack.h"
#include "Protocol.h"

WorldInfo::WorldInfo() :
  maxHeight(0),
  database(NULL)
{
  size[0] = 400.0f;
  size[1] = 400.0f;
  gravity = -9.81f;
}

WorldInfo::~WorldInfo()
{
  delete[] database;
}

void WorldInfo::addWall(float x, float y, float z, float r, float w, float h)
{
  if ((z + h) > maxHeight)
    maxHeight = z+h;

  int i = walls.size();
  walls.resize(i+1);
  walls[i].pos[0] = x;
  walls[i].pos[1] = y;
  walls[i].pos[2] = z;
  walls[i].rotation = r;
  walls[i].size[0] = w;
  // no depth to walls
  walls[i].size[1] = 0.0f;
  walls[i].size[2] = h;
}

void WorldInfo::addBox(float x, float y, float z, float r, float w, float d, float h, bool drive, bool shoot)
{
  if ((z + h) > maxHeight)
    maxHeight = z+h;

  int i = boxes.size();
  boxes.resize(i+1);
  boxes[i].pos[0] = x;
  boxes[i].pos[1] = y;
  boxes[i].pos[2] = z;
  boxes[i].rotation = r;
  boxes[i].size[0] = w;
  boxes[i].size[1] = d;
  boxes[i].size[2] = h;
  boxes[i].driveThrough = drive;
  boxes[i].shootThrough = shoot;
}

void WorldInfo::addPyramid(float x, float y, float z, float r, float w, float d, float h, bool drive, bool shoot, bool flipZ)
{
  if ((z + h) > maxHeight)
    maxHeight = z+h;

  int i = pyramids.size();
  pyramids.resize(i+1);
  pyramids[i].pos[0] = x;
  pyramids[i].pos[1] = y;
  pyramids[i].pos[2] = z;
  pyramids[i].rotation = r;
  pyramids[i].size[0] = w;
  pyramids[i].size[1] = d;
  pyramids[i].size[2] = h;
  pyramids[i].driveThrough = drive;
  pyramids[i].shootThrough = shoot;
  pyramids[i].flipZ = flipZ;
}

void WorldInfo::addTeleporter(float x, float y, float z, float r, float w, float d, float h, float b, bool drive, bool shoot)
{
  if ((z + h) > maxHeight)
    maxHeight = z+h;

  int i = teleporters.size();
  teleporters.resize(i+1);
  teleporters[i].pos[0] = x;
  teleporters[i].pos[1] = y;
  teleporters[i].pos[2] = z;
  teleporters[i].rotation = r;
  teleporters[i].size[0] = w;
  teleporters[i].size[1] = d;
  teleporters[i].size[2] = h;
  teleporters[i].driveThrough = drive;
  teleporters[i].shootThrough = shoot;
  teleporters[i].border = b;
  // default link through
  teleporters[i].to[0] = i * 2 + 1;
  teleporters[i].to[1] = i * 2;
}

void WorldInfo::addBase(float x, float y, float z, float r, float w, float d, float h, bool drive, bool shoot)
{
  if ((z + h) > maxHeight)
    maxHeight = z+h;

  int i = bases.size();
  bases.resize(i+1);
  bases[i].pos[0] = x;
  bases[i].pos[1] = y;
  bases[i].pos[2] = z;
  bases[i].rotation = r;
  bases[i].size[0] = w;
  bases[i].size[1] = d;
  bases[i].size[2] = h;
  bases[i].driveThrough = drive;
  bases[i].shootThrough = shoot;
}

void WorldInfo::addLink(int from, int to)
{
  // silently discard links from teleporters that don't exist
  if (unsigned(from) <= teleporters.size() * 2 + 1) {
    teleporters[from / 2].to[from % 2] = to;
  }
}

void WorldInfo::addZone(const CustomZone *zone)
{
  entryZones.addZone( zone );
}

float WorldInfo::getMaxWorldHeight()
{
  return maxHeight;
}

bool WorldInfo::rectHitCirc(float dx, float dy, const float *p, float r) const
{
  // Algorithm from Graphics Gems, pp51-53.
  const float rr = r * r, rx = -p[0], ry = -p[1];
  if (rx + dx < 0.0f) // west of rect
    if (ry + dy < 0.0f) //  sw corner
      return (rx + dx) * (rx + dx) + (ry + dy) * (ry + dy) < rr;
    else if (ry - dy > 0.0f) //  nw corner
      return (rx + dx) * (rx + dx) + (ry - dy) * (ry - dy) < rr;
    else //  due west
      return rx + dx > -r;

  else if (rx - dx > 0.0f) // east of rect
    if (ry + dy < 0.0f) //  se corner
      return (rx - dx) * (rx - dx) + (ry + dy) * (ry + dy) < rr;
    else if (ry - dy > 0.0f) //  ne corner
      return (rx - dx) * (rx - dx) + (ry - dy) * (ry - dy) < rr;
    else //  due east
      return rx - dx < r;

  else if (ry + dy < 0.0f) // due south
    return ry + dy > -r;

  else if (ry - dy > 0.0f) // due north
    return ry - dy < r;

  // circle origin in rect
  return true;
}

bool WorldInfo::inRect(const float *p1, float angle, const float *size, float x, float y, float r) const
{
  // translate origin
  float pa[2];
  pa[0] = x - p1[0];
  pa[1] = y - p1[1];

  // rotate
  float pb[2];
  const float c = cosf(-angle), s = sinf(-angle);
  pb[0] = c * pa[0] - s * pa[1];
  pb[1] = c * pa[1] + s * pa[0];

  // do test
  return rectHitCirc(size[0], size[1], pb, r);
}

InBuildingType WorldInfo::inBuilding(ObstacleLocation **location,
				     float x, float y, float z, float r,
				     float height)
{
  ObstacleLocationList::iterator it;
  PyramidList::iterator pyrit;
  TeleporterList::iterator telit;

  for (it = bases.begin(); it != bases.end(); ++it) {
    ObstacleLocation &base = *it;
    if ((base.pos[2] < (z + height))
	&& ((base.pos[2] + base.size[2]) > z)
	&& (inRect(base.pos, base.rotation, base.size, x, y, r))) {
      if (location != NULL)
	*location = &base;
      return IN_BASE;
    }
  }
  for (it = boxes.begin(); it != boxes.end(); ++it) {
    ObstacleLocation &box = *it;
    if ((box.pos[2] < (z + height))
	&& ((box.pos[2] + box.size[2]) > z)
	&& (inRect(box.pos, box.rotation, box.size, x, y, r))) {
      if (location != NULL)
	*location = &box;
      if (box.driveThrough) return IN_BOX_DRIVETHROUGH;
      else return IN_BOX_NOTDRIVETHROUGH;
    }
  }
  for (pyrit = pyramids.begin(); pyrit != pyramids.end(); ++pyrit) {
    ObstacleLocation &pyr = *pyrit;
    if ((pyr.pos[2] < (z + height))
	&& ((pyr.pos[2] + pyr.size[2]) > z)
	&& (inRect(pyr.pos, pyr.rotation, pyr.size,x,y,r))) {
      if (location != NULL)
	*location = &pyr;
      return IN_PYRAMID;
    }
  }
  for (telit = teleporters.begin(); telit != teleporters.end(); ++telit) {
    Teleporter &tele = *telit;
    if ((tele.pos[2] < (z + height))
	&& ((tele.pos[2] + tele.size[2]) > z)
	&& (inRect(tele.pos, tele.rotation, tele.size, x, y, r))) {
      static ObstacleLocation __teleporter;
      __teleporter = tele;
      if (location != NULL)
	*location = &__teleporter;
      return IN_TELEPORTER;
    }
  }

  if (location != NULL)
    *location = (ObstacleLocation *)NULL;
  return NOT_IN_BUILDING;
}

bool WorldInfo::getZonePoint(const std::string &qualifier, float *pt)
{
  return entryZones.getZonePoint(qualifier, pt);
}

void WorldInfo::finishWorld()
{
  entryZones.calculateQualifierLists();
}

int WorldInfo::packDatabase()
{
  databaseSize =
    (2 + 2 + WorldCodeWallSize) * walls.size() +
    (2 + 2 + WorldCodeBoxSize) * boxes.size() +
    (2 + 2 + WorldCodePyramidSize) * pyramids.size() +
    (2 + 2 + WorldCodeTeleporterSize) * teleporters.size() +
    (2 + 2 + WorldCodeLinkSize) * 2 * teleporters.size();
  database = new char[databaseSize];
  void *databasePtr = database;

  // define i out here so we avoid the loop variable scope debates
  ObstacleLocationList::iterator it;
  unsigned char	bitMask;

  // add walls
  for (it = walls.begin(); it != walls.end(); ++it) {
    ObstacleLocation &wall = *it;
    databasePtr = nboPackUShort(databasePtr, WorldCodeWallSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodeWall);
    databasePtr = nboPackVector(databasePtr, wall.pos);
    databasePtr = nboPackFloat(databasePtr, wall.rotation);
    databasePtr = nboPackFloat(databasePtr, wall.size[0]);
    // walls have no depth
    databasePtr = nboPackFloat(databasePtr, wall.size[2]);
  }

  // add boxes
  for (it = boxes.begin(); it != boxes.end(); ++it) {
    ObstacleLocation &box = *it;
    databasePtr = nboPackUShort(databasePtr, WorldCodeBoxSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodeBox);
    databasePtr = nboPackVector(databasePtr, box.pos);
    databasePtr = nboPackFloat(databasePtr, box.rotation);
    databasePtr = nboPackVector(databasePtr, box.size);
    bitMask = 0;
    if (box.driveThrough)
      bitMask |= _DRIVE_THRU;
    if (box.shootThrough)
      bitMask |= _SHOOT_THRU;
    databasePtr = nboPackUByte(databasePtr, bitMask);
  }

  // add pyramids
  for (PyramidList::iterator pyr_it = pyramids.begin(); pyr_it != pyramids.end(); ++pyr_it) {
    Pyramid &pyr = *pyr_it;
    databasePtr = nboPackUShort(databasePtr, WorldCodePyramidSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodePyramid);
    databasePtr = nboPackVector(databasePtr, pyr.pos);
    databasePtr = nboPackFloat(databasePtr, pyr.rotation);
    databasePtr = nboPackVector(databasePtr, pyr.size);
    bitMask = 0;
    if (pyr.driveThrough)
      bitMask |= _DRIVE_THRU;
    if (pyr.shootThrough)
      bitMask |= _SHOOT_THRU;
    if (pyr.flipZ)
      bitMask |= _FLIP_Z;
    databasePtr = nboPackUByte(databasePtr, bitMask);
  }

  // add teleporters
  int i = 0;
  for (TeleporterList::iterator telit = teleporters.begin(); telit != teleporters.end(); ++telit, i++) {
    Teleporter &tele = *telit;
    databasePtr = nboPackUShort(databasePtr, WorldCodeTeleporterSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodeTeleporter);
    databasePtr = nboPackVector(databasePtr, tele.pos);
    databasePtr = nboPackFloat(databasePtr, tele.rotation);
    databasePtr = nboPackVector(databasePtr, tele.size);
    databasePtr = nboPackFloat(databasePtr, tele.border);
    bitMask = 0;
    if (tele.driveThrough)
      bitMask |= _DRIVE_THRU;
    if (tele.shootThrough)
      bitMask |= _SHOOT_THRU;
    databasePtr = nboPackUByte(databasePtr, bitMask);
    // and each link
    databasePtr = nboPackUShort(databasePtr, WorldCodeLinkSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodeLink);
    databasePtr = nboPackUShort(databasePtr, uint16_t(i * 2));
    databasePtr = nboPackUShort(databasePtr, uint16_t(tele.to[0]));
    databasePtr = nboPackUShort(databasePtr, WorldCodeLinkSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodeLink);
    databasePtr = nboPackUShort(databasePtr, uint16_t(i * 2 + 1));
    databasePtr = nboPackUShort(databasePtr, uint16_t(tele.to[1]));
  }

  return 1;
}

void *WorldInfo::getDatabase() const
{
  return database;
}

int WorldInfo::getDatabaseSize() const
{
  return databaseSize;
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>doc open bug<commit_after>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "WorldInfo.h"

/* common implementation headers */
#include "global.h"
#include "Pack.h"
#include "Protocol.h"

WorldInfo::WorldInfo() :
  maxHeight(0),
  database(NULL)
{
  size[0] = 400.0f;
  size[1] = 400.0f;
  gravity = -9.81f;
}

WorldInfo::~WorldInfo()
{
  delete[] database;
}

void WorldInfo::addWall(float x, float y, float z, float r, float w, float h)
{
  if ((z + h) > maxHeight)
    maxHeight = z+h;

  int i = walls.size();
  walls.resize(i+1);
  walls[i].pos[0] = x;
  walls[i].pos[1] = y;
  walls[i].pos[2] = z;
  walls[i].rotation = r;
  walls[i].size[0] = w;
  // no depth to walls
  walls[i].size[1] = 0.0f;
  walls[i].size[2] = h;
}

void WorldInfo::addBox(float x, float y, float z, float r, float w, float d, float h, bool drive, bool shoot)
{
  if ((z + h) > maxHeight)
    maxHeight = z+h;

  int i = boxes.size();
  boxes.resize(i+1);
  boxes[i].pos[0] = x;
  boxes[i].pos[1] = y;
  boxes[i].pos[2] = z;
  boxes[i].rotation = r;
  boxes[i].size[0] = w;
  boxes[i].size[1] = d;
  boxes[i].size[2] = h;
  boxes[i].driveThrough = drive;
  boxes[i].shootThrough = shoot;
}

void WorldInfo::addPyramid(float x, float y, float z, float r, float w, float d, float h, bool drive, bool shoot, bool flipZ)
{
  if ((z + h) > maxHeight)
    maxHeight = z+h;

  int i = pyramids.size();
  pyramids.resize(i+1);
  pyramids[i].pos[0] = x;
  pyramids[i].pos[1] = y;
  pyramids[i].pos[2] = z;
  pyramids[i].rotation = r;
  pyramids[i].size[0] = w;
  pyramids[i].size[1] = d;
  pyramids[i].size[2] = h;
  pyramids[i].driveThrough = drive;
  pyramids[i].shootThrough = shoot;
  pyramids[i].flipZ = flipZ;
}

void WorldInfo::addTeleporter(float x, float y, float z, float r, float w, float d, float h, float b, bool drive, bool shoot)
{
  if ((z + h) > maxHeight)
    maxHeight = z+h;

  int i = teleporters.size();
  teleporters.resize(i+1);
  teleporters[i].pos[0] = x;
  teleporters[i].pos[1] = y;
  teleporters[i].pos[2] = z;
  teleporters[i].rotation = r;
  teleporters[i].size[0] = w;
  teleporters[i].size[1] = d;
  teleporters[i].size[2] = h;
  teleporters[i].driveThrough = drive;
  teleporters[i].shootThrough = shoot;
  teleporters[i].border = b;
  // default link through
  teleporters[i].to[0] = i * 2 + 1;
  teleporters[i].to[1] = i * 2;
}

void WorldInfo::addBase(float x, float y, float z, float r, float w, float d, float h, bool drive, bool shoot)
{
  if ((z + h) > maxHeight)
    maxHeight = z+h;

  int i = bases.size();
  bases.resize(i+1);
  bases[i].pos[0] = x;
  bases[i].pos[1] = y;
  bases[i].pos[2] = z;
  bases[i].rotation = r;
  bases[i].size[0] = w;
  bases[i].size[1] = d;
  bases[i].size[2] = h;
  bases[i].driveThrough = drive;
  bases[i].shootThrough = shoot;
}

void WorldInfo::addLink(int from, int to)
{
  // silently discard links from teleporters that don't exist
  if (unsigned(from) <= teleporters.size() * 2 + 1) {
    teleporters[from / 2].to[from % 2] = to;
  }
}

void WorldInfo::addZone(const CustomZone *zone)
{
  entryZones.addZone( zone );
}

float WorldInfo::getMaxWorldHeight()
{
  return maxHeight;
}

bool WorldInfo::rectHitCirc(float dx, float dy, const float *p, float r) const
{
  // Algorithm from Graphics Gems, pp51-53.
  const float rr = r * r, rx = -p[0], ry = -p[1];
  if (rx + dx < 0.0f) // west of rect
    if (ry + dy < 0.0f) //  sw corner
      return (rx + dx) * (rx + dx) + (ry + dy) * (ry + dy) < rr;
    else if (ry - dy > 0.0f) //  nw corner
      return (rx + dx) * (rx + dx) + (ry - dy) * (ry - dy) < rr;
    else //  due west
      return rx + dx > -r;

  else if (rx - dx > 0.0f) // east of rect
    if (ry + dy < 0.0f) //  se corner
      return (rx - dx) * (rx - dx) + (ry + dy) * (ry + dy) < rr;
    else if (ry - dy > 0.0f) //  ne corner
      return (rx - dx) * (rx - dx) + (ry - dy) * (ry - dy) < rr;
    else //  due east
      return rx - dx < r;

  else if (ry + dy < 0.0f) // due south
    return ry + dy > -r;

  else if (ry - dy > 0.0f) // due north
    return ry - dy < r;

  // circle origin in rect
  return true;
}

bool WorldInfo::inRect(const float *p1, float angle, const float *size, float x, float y, float r) const
{
  // translate origin
  float pa[2];
  pa[0] = x - p1[0];
  pa[1] = y - p1[1];

  // rotate
  float pb[2];
  const float c = cosf(-angle), s = sinf(-angle);
  pb[0] = c * pa[0] - s * pa[1];
  pb[1] = c * pa[1] + s * pa[0];

  // do test
  return rectHitCirc(size[0], size[1], pb, r);
}

InBuildingType WorldInfo::inBuilding(ObstacleLocation **location,
				     float x, float y, float z, float r,
				     float height)
{
  ObstacleLocationList::iterator it;
  PyramidList::iterator pyrit;
  TeleporterList::iterator telit;

  for (it = bases.begin(); it != bases.end(); ++it) {
    ObstacleLocation &base = *it;
    if ((base.pos[2] < (z + height))
	&& ((base.pos[2] + base.size[2]) > z)
	&& (inRect(base.pos, base.rotation, base.size, x, y, r))) {
      if (location != NULL)
	*location = &base;
      return IN_BASE;
    }
  }
  for (it = boxes.begin(); it != boxes.end(); ++it) {
    ObstacleLocation &box = *it;
    if ((box.pos[2] < (z + height))
	&& ((box.pos[2] + box.size[2]) > z)
	&& (inRect(box.pos, box.rotation, box.size, x, y, r))) {
      if (location != NULL)
	*location = &box;
      if (box.driveThrough) return IN_BOX_DRIVETHROUGH;
      else return IN_BOX_NOTDRIVETHROUGH;
    }
  }
  for (pyrit = pyramids.begin(); pyrit != pyramids.end(); ++pyrit) {
    ObstacleLocation &pyr = *pyrit;
    if ((pyr.pos[2] < (z + height))
	&& ((pyr.pos[2] + pyr.size[2]) > z)
	&& (inRect(pyr.pos, pyr.rotation, pyr.size,x,y,r))) {
      if (location != NULL)
	*location = &pyr;
      return IN_PYRAMID;
    }
  }
  for (telit = teleporters.begin(); telit != teleporters.end(); ++telit) {
    Teleporter &tele = *telit;
    if ((tele.pos[2] < (z + height))
	&& ((tele.pos[2] + tele.size[2]) > z)
	&& (inRect(tele.pos, tele.rotation, tele.size, x, y, r))) {
      static ObstacleLocation __teleporter;
      __teleporter = tele;
      if (location != NULL)
	*location = &__teleporter;
      return IN_TELEPORTER;
    }
  }

  if (location != NULL)
    *location = (ObstacleLocation *)NULL;
  return NOT_IN_BUILDING;
}

bool WorldInfo::getZonePoint(const std::string &qualifier, float *pt)
{
  if (entryZones.getZonePoint(qualifier, pt))
  {
    //BUG: modify pt so that it is on a building
    return true;
  }

  return false;
}

void WorldInfo::finishWorld()
{
  entryZones.calculateQualifierLists();
}

int WorldInfo::packDatabase()
{
  databaseSize =
    (2 + 2 + WorldCodeWallSize) * walls.size() +
    (2 + 2 + WorldCodeBoxSize) * boxes.size() +
    (2 + 2 + WorldCodePyramidSize) * pyramids.size() +
    (2 + 2 + WorldCodeTeleporterSize) * teleporters.size() +
    (2 + 2 + WorldCodeLinkSize) * 2 * teleporters.size();
  database = new char[databaseSize];
  void *databasePtr = database;

  // define i out here so we avoid the loop variable scope debates
  ObstacleLocationList::iterator it;
  unsigned char	bitMask;

  // add walls
  for (it = walls.begin(); it != walls.end(); ++it) {
    ObstacleLocation &wall = *it;
    databasePtr = nboPackUShort(databasePtr, WorldCodeWallSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodeWall);
    databasePtr = nboPackVector(databasePtr, wall.pos);
    databasePtr = nboPackFloat(databasePtr, wall.rotation);
    databasePtr = nboPackFloat(databasePtr, wall.size[0]);
    // walls have no depth
    databasePtr = nboPackFloat(databasePtr, wall.size[2]);
  }

  // add boxes
  for (it = boxes.begin(); it != boxes.end(); ++it) {
    ObstacleLocation &box = *it;
    databasePtr = nboPackUShort(databasePtr, WorldCodeBoxSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodeBox);
    databasePtr = nboPackVector(databasePtr, box.pos);
    databasePtr = nboPackFloat(databasePtr, box.rotation);
    databasePtr = nboPackVector(databasePtr, box.size);
    bitMask = 0;
    if (box.driveThrough)
      bitMask |= _DRIVE_THRU;
    if (box.shootThrough)
      bitMask |= _SHOOT_THRU;
    databasePtr = nboPackUByte(databasePtr, bitMask);
  }

  // add pyramids
  for (PyramidList::iterator pyr_it = pyramids.begin(); pyr_it != pyramids.end(); ++pyr_it) {
    Pyramid &pyr = *pyr_it;
    databasePtr = nboPackUShort(databasePtr, WorldCodePyramidSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodePyramid);
    databasePtr = nboPackVector(databasePtr, pyr.pos);
    databasePtr = nboPackFloat(databasePtr, pyr.rotation);
    databasePtr = nboPackVector(databasePtr, pyr.size);
    bitMask = 0;
    if (pyr.driveThrough)
      bitMask |= _DRIVE_THRU;
    if (pyr.shootThrough)
      bitMask |= _SHOOT_THRU;
    if (pyr.flipZ)
      bitMask |= _FLIP_Z;
    databasePtr = nboPackUByte(databasePtr, bitMask);
  }

  // add teleporters
  int i = 0;
  for (TeleporterList::iterator telit = teleporters.begin(); telit != teleporters.end(); ++telit, i++) {
    Teleporter &tele = *telit;
    databasePtr = nboPackUShort(databasePtr, WorldCodeTeleporterSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodeTeleporter);
    databasePtr = nboPackVector(databasePtr, tele.pos);
    databasePtr = nboPackFloat(databasePtr, tele.rotation);
    databasePtr = nboPackVector(databasePtr, tele.size);
    databasePtr = nboPackFloat(databasePtr, tele.border);
    bitMask = 0;
    if (tele.driveThrough)
      bitMask |= _DRIVE_THRU;
    if (tele.shootThrough)
      bitMask |= _SHOOT_THRU;
    databasePtr = nboPackUByte(databasePtr, bitMask);
    // and each link
    databasePtr = nboPackUShort(databasePtr, WorldCodeLinkSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodeLink);
    databasePtr = nboPackUShort(databasePtr, uint16_t(i * 2));
    databasePtr = nboPackUShort(databasePtr, uint16_t(tele.to[0]));
    databasePtr = nboPackUShort(databasePtr, WorldCodeLinkSize);
    databasePtr = nboPackUShort(databasePtr, WorldCodeLink);
    databasePtr = nboPackUShort(databasePtr, uint16_t(i * 2 + 1));
    databasePtr = nboPackUShort(databasePtr, uint16_t(tele.to[1]));
  }

  return 1;
}

void *WorldInfo::getDatabase() const
{
  return database;
}

int WorldInfo::getDatabaseSize() const
{
  return databaseSize;
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>// -*- C++ -*-
//
// ----------------------------------------------------------------------
//
// Brad T. Aagaard, U.S. Geological Survey
//
// This code was developed as part of the Computational Infrastructure
// for Geodynamics (http://geodynamics.org).
//
// Copyright (c) 2010-2016 University of California, Davis
//
// See COPYING for license information.
//
// ----------------------------------------------------------------------
//

#include <portinfo>

#include "CSGeoProj.hh" // implementation of class methods

#include "Projector.hh" // USES Projector
#include "Converter.hh" // USES Converter

#include "spatialdata/utils/LineParser.hh" // USES LineParser

#include <math.h> // USES M_PI, sin(), cos()
#include <iostream> // USES std::istream, std::ostream

#include <stdexcept> // USES std::runtime_error, std::exception
#include <sstream> // USES std::ostringsgream
#include <strings.h> // USES strcasecmp()
#include <assert.h> // USES assert()

// ----------------------------------------------------------------------
// Default constructor
spatialdata::geocoords::CSGeoProj::CSGeoProj(void) :
  _originLon(0.0),
  _originLat(0.0),
  _originX(0.0),
  _originY(0.0),
  _rotAngle(0.0),
  _pProjector(0)
{ // constructor
} // constructor

// ----------------------------------------------------------------------
// Default destructor
spatialdata::geocoords::CSGeoProj::~CSGeoProj(void)
{ // destructor
  delete _pProjector; _pProjector = 0;
} // destructor

// ----------------------------------------------------------------------
// Copy constructor
spatialdata::geocoords::CSGeoProj::CSGeoProj(const CSGeoProj& cs) :
  CSGeo(cs),
  _originLon(cs._originLon),
  _originLat(cs._originLat),
  _originX(cs._originX),
  _originY(cs._originY),
  _rotAngle(cs._rotAngle),
  _pProjector(0)
{ // copy constructor
  if (0 != cs._pProjector)
    _pProjector = new Projector(*cs._pProjector);
} // copy constructor

// ----------------------------------------------------------------------
// Set projector.
void
spatialdata::geocoords::CSGeoProj::projector(const Projector& projector)
{ // projector
  _pProjector = new Projector(projector);
} // projector

// ----------------------------------------------------------------------
// Set origin of local projected coordinate system.
void
spatialdata::geocoords::CSGeoProj::origin(const double lon,
					  const double lat)
{ // origin
  if (lon < -360.0 || lon > 360.0 || lat < -360.0 || lat > 360.0) {
    std::ostringstream msg;
    msg << "Longitude (" << lon << ") and latitude (" << lat
	<< ") must be between in the range [-360.0, 360.0].";
    throw std::runtime_error(msg.str());
  } // if

  _originLon = lon;
  _originLat = lat;
  _originX = 0.0;
  _originY = 0.0;
} // origin

// ----------------------------------------------------------------------
// Get origin of local projected coordinate system.
void
spatialdata::geocoords::CSGeoProj::origin(double* pLon,
					  double* pLat)
{ // origin
  assert(pLon);
  assert(pLat);

  *pLon = _originLon;
  *pLat = _originLat;
} // origin

// ----------------------------------------------------------------------
// Set rotation angle (CCW from east) of local x axis.
void
spatialdata::geocoords::CSGeoProj::rotationAngle(const double angle)
{ // rotationAngle
  if (angle < -360.0 || angle > 360.0) {
    std::ostringstream msg;
    msg << "Rotation angle (" << angle
	<< ") must be between in the range [-360.0, 360.0].";
    throw std::runtime_error(msg.str());
  } // if

  _rotAngle = angle;
} // rotationAngle

// ----------------------------------------------------------------------
// Get rotation angle (CCW from east) of local x axis.
double
spatialdata::geocoords::CSGeoProj::rotationAngle(void) const
{ // rotationAngle
  return _rotAngle;
} // rotationAngle

// ----------------------------------------------------------------------
// Initialize the coordinate system.
void
spatialdata::geocoords::CSGeoProj::initialize(void)
{ // initialize
  CSGeo::initialize();

  assert(0 != _pProjector);
  _pProjector->initialize(*this);

  // Convert origin in lon/lat to projected coordinate system.
  _originX = 0.0;
  _originY = 0.0;
  if (_originLon != 0.0 || _originLat != 0.0) {
    CSGeo csSrc;
    csSrc.ellipsoid("WGS84");
    csSrc.datumHoriz("WGS84");
    csSrc.datumVert(this->datumVert());
    csSrc.toMeters(this->toMeters());
    csSrc.setSpaceDim(2);
    csSrc.initialize();

    CSGeoProj csDest;
    csDest.ellipsoid(this->ellipsoid());
    csDest.datumHoriz(this->datumHoriz());
    csDest.datumVert(this->datumVert());
    csDest.toMeters(this->toMeters());
    csDest.setSpaceDim(2);
    assert(_pProjector);
    csDest.projector(*_pProjector);
    csDest.initialize();

    double originCoords[2] = { _originLon, _originLat };
    Converter::convert(originCoords, 1, 2, &csDest, &csSrc);
    _originX = originCoords[0];
    _originY = originCoords[1];
  } // if
} // initialize

// ----------------------------------------------------------------------
// Convert coordinates to PROJ4 useable form.
void
spatialdata::geocoords::CSGeoProj::toProjForm(double* coords,
					      const int numLocs,
					      const int numDims) const
{ // toProjForm
  assert( (0 < numLocs && 0 != coords) ||
	  (0 == numLocs && 0 == coords));
  assert(0 != _pProjector);
  if (numDims != spaceDim()) {
    std::ostringstream msg;
    msg
      << "Number of spatial dimensions of coordinates ("
      << numDims << ") does not match number of spatial dimensions ("
      << spaceDim() << ") of coordinate system.";
    throw std::runtime_error(msg.str());
  } // if

  const double angleRad = M_PI * _rotAngle / 180.0;
  for (int i=0; i < numLocs; ++i) {
    const double xOld = coords[i*numDims  ];
    const double yOld = coords[i*numDims+1];

    coords[i*numDims  ] = _originX + cos(angleRad)*xOld - sin(angleRad)*yOld;
    coords[i*numDims+1] = _originY + sin(angleRad)*xOld + cos(angleRad)*yOld;
  } // for

  _pProjector->invproject(coords, numLocs, numDims);
  CSGeo::toProjForm(coords, numLocs, numDims);
} // toProjForm

// ----------------------------------------------------------------------
// Convert coordinates from PROJ4 form to form associated w/coordsys.
void
spatialdata::geocoords::CSGeoProj::fromProjForm(double* coords,
						const int numLocs,
						const int numDims) const
{ // fromProjForm
  assert( (0 < numLocs && 0 != coords) ||
	  (0 == numLocs && 0 == coords));
  assert(0 != _pProjector);
  if (numDims != spaceDim()) {
    std::ostringstream msg;
    msg
      << "Number of spatial dimensions of coordinates ("
      << numDims << ") does not match number of spatial dimensions ("
      << spaceDim() << ") of coordinate system.";
    throw std::runtime_error(msg.str());
  } // if

  CSGeo::fromProjForm(coords, numLocs, numDims);
  _pProjector->project(coords, numLocs, numDims);

  const double angleRad = M_PI * _rotAngle / 180.0;
  for (int i=0; i < numLocs; ++i) {
    const double xRel = coords[i*numDims  ] - _originX;
    const double yRel = coords[i*numDims+1] - _originY;

    coords[i*numDims  ] = cos(angleRad)*xRel + sin(angleRad)*yRel;
    coords[i*numDims+1] = -sin(angleRad)*xRel + cos(angleRad)*yRel;
  } // for
} // fromProjForm

// ----------------------------------------------------------------------
// Pickle coordinate system to ascii stream.
void
spatialdata::geocoords::CSGeoProj::pickle(std::ostream& s) const
{ // pickle
  s << "geo-projected {\n"
    << "  to-meters = " << toMeters() << "\n"
    << "  ellipsoid = " << ellipsoid() << "\n"
    << "  datum-horiz = " << datumHoriz() << "\n"
    << "  datum-vert = " << datumVert() << "\n"
    << "  origin-lon = " << _originLon << "\n"
    << "  origin-lat = " << _originLat << "\n"
    << "  rotation-angle = " << rotationAngle() << "\n"
    << "  projector = ";
  _pProjector->pickle(s);
  s << "}\n";
} // pickle

// ----------------------------------------------------------------------
// Unpickle coordinate system from ascii stream.
void
spatialdata::geocoords::CSGeoProj::unpickle(std::istream& s)
{ // unpickle
  utils::LineParser parser(s, "//");
  parser.eatwhitespace(true);

  std::string token;
  std::istringstream buffer;
  const int maxIgnore = 256;
  char cbuffer[maxIgnore];
  double val;
  std::string name;

  parser.ignore('{');
  buffer.str(parser.next());
  buffer.clear();
  buffer >> token;
  while (buffer.good() && token != "}") {
    buffer.ignore(maxIgnore, '=');
    if (0 == strcasecmp(token.c_str(), "to-meters")) {
      buffer >> val;
      toMeters(val);
    } else if (0 == strcasecmp(token.c_str(), "ellipsoid")) {
      buffer >> name;
      ellipsoid(name.c_str());
    } else if (0 == strcasecmp(token.c_str(), "datum-horiz")) {
      buffer >> std::ws;
      buffer.get(cbuffer, maxIgnore, '\n');
      datumHoriz(cbuffer);
    } else if (0 == strcasecmp(token.c_str(), "datum-vert")) {
      buffer >> std::ws;
      buffer.get(cbuffer, maxIgnore, '\n');
      datumVert(cbuffer);
    } else if (0 == strcasecmp(token.c_str(), "origin-lon")) {
      buffer >> _originLon;
    } else if (0 == strcasecmp(token.c_str(), "origin-lat")) {
      buffer >> _originLat;
    } else if (0 == strcasecmp(token.c_str(), "rotation-angle")) {
      buffer >> _rotAngle;
    } else if (0 == strcasecmp(token.c_str(), "projector")) {
      std::string rbuffer(buffer.str());
      int start = token.length();
      int end = rbuffer.length();
      for (int i=start; i < end; ++i)
	if ('=' == rbuffer[i])
	  start = i+1;
      for (int i=end-1; i >= start; --i) {
	s.putback(rbuffer[i]);
      } // for
      s.clear();
      if (0 == _pProjector)
	_pProjector = new Projector;
      _pProjector->unpickle(s);
    } else {
      std::ostringstream msg;
      msg << "Could not parse '" << token << "' into a CSGeoProj token.\n"
	  << "Known CSGeoProj token:\n"
	  << "  to-meters, ellipsoid, datum-horiz, datum-vert, projector\n";
      throw std::runtime_error(msg.str().c_str());
    } // else
    buffer.str(parser.next());
    buffer.clear();
    buffer >> token;
  } // while
  if (token != "}")
    throw std::runtime_error("I/O error while parsing CSGeoProj "
			     "settings.");
} // unpickle

// End of file
<commit_msg>Fixed bug in parsing projected coordinate system.<commit_after>// -*- C++ -*-
//
// ----------------------------------------------------------------------
//
// Brad T. Aagaard, U.S. Geological Survey
//
// This code was developed as part of the Computational Infrastructure
// for Geodynamics (http://geodynamics.org).
//
// Copyright (c) 2010-2016 University of California, Davis
//
// See COPYING for license information.
//
// ----------------------------------------------------------------------
//

#include <portinfo>

#include "CSGeoProj.hh" // implementation of class methods

#include "Projector.hh" // USES Projector
#include "Converter.hh" // USES Converter

#include "spatialdata/utils/LineParser.hh" // USES LineParser

#include <math.h> // USES M_PI, sin(), cos()
#include <iostream> // USES std::istream, std::ostream

#include <stdexcept> // USES std::runtime_error, std::exception
#include <sstream> // USES std::ostringsgream
#include <strings.h> // USES strcasecmp()
#include <assert.h> // USES assert()

// ----------------------------------------------------------------------
// Default constructor
spatialdata::geocoords::CSGeoProj::CSGeoProj(void) :
  _originLon(0.0),
  _originLat(0.0),
  _originX(0.0),
  _originY(0.0),
  _rotAngle(0.0),
  _pProjector(0)
{ // constructor
} // constructor

// ----------------------------------------------------------------------
// Default destructor
spatialdata::geocoords::CSGeoProj::~CSGeoProj(void)
{ // destructor
  delete _pProjector; _pProjector = 0;
} // destructor

// ----------------------------------------------------------------------
// Copy constructor
spatialdata::geocoords::CSGeoProj::CSGeoProj(const CSGeoProj& cs) :
  CSGeo(cs),
  _originLon(cs._originLon),
  _originLat(cs._originLat),
  _originX(cs._originX),
  _originY(cs._originY),
  _rotAngle(cs._rotAngle),
  _pProjector(0)
{ // copy constructor
  if (0 != cs._pProjector)
    _pProjector = new Projector(*cs._pProjector);
} // copy constructor

// ----------------------------------------------------------------------
// Set projector.
void
spatialdata::geocoords::CSGeoProj::projector(const Projector& projector)
{ // projector
  _pProjector = new Projector(projector);
} // projector

// ----------------------------------------------------------------------
// Set origin of local projected coordinate system.
void
spatialdata::geocoords::CSGeoProj::origin(const double lon,
					  const double lat)
{ // origin
  if (lon < -360.0 || lon > 360.0 || lat < -360.0 || lat > 360.0) {
    std::ostringstream msg;
    msg << "Longitude (" << lon << ") and latitude (" << lat
	<< ") must be between in the range [-360.0, 360.0].";
    throw std::runtime_error(msg.str());
  } // if

  _originLon = lon;
  _originLat = lat;
  _originX = 0.0;
  _originY = 0.0;
} // origin

// ----------------------------------------------------------------------
// Get origin of local projected coordinate system.
void
spatialdata::geocoords::CSGeoProj::origin(double* pLon,
					  double* pLat)
{ // origin
  assert(pLon);
  assert(pLat);

  *pLon = _originLon;
  *pLat = _originLat;
} // origin

// ----------------------------------------------------------------------
// Set rotation angle (CCW from east) of local x axis.
void
spatialdata::geocoords::CSGeoProj::rotationAngle(const double angle)
{ // rotationAngle
  if (angle < -360.0 || angle > 360.0) {
    std::ostringstream msg;
    msg << "Rotation angle (" << angle
	<< ") must be between in the range [-360.0, 360.0].";
    throw std::runtime_error(msg.str());
  } // if

  _rotAngle = angle;
} // rotationAngle

// ----------------------------------------------------------------------
// Get rotation angle (CCW from east) of local x axis.
double
spatialdata::geocoords::CSGeoProj::rotationAngle(void) const
{ // rotationAngle
  return _rotAngle;
} // rotationAngle

// ----------------------------------------------------------------------
// Initialize the coordinate system.
void
spatialdata::geocoords::CSGeoProj::initialize(void)
{ // initialize
  CSGeo::initialize();

  assert(0 != _pProjector);
  _pProjector->initialize(*this);

  // Convert origin in lon/lat to projected coordinate system.
  _originX = 0.0;
  _originY = 0.0;
  if (_originLon != 0.0 || _originLat != 0.0) {
    CSGeo csSrc;
    csSrc.ellipsoid("WGS84");
    csSrc.datumHoriz("WGS84");
    csSrc.datumVert(this->datumVert());
    csSrc.toMeters(this->toMeters());
    csSrc.setSpaceDim(2);
    csSrc.initialize();

    CSGeoProj csDest;
    csDest.ellipsoid(this->ellipsoid());
    csDest.datumHoriz(this->datumHoriz());
    csDest.datumVert(this->datumVert());
    csDest.toMeters(this->toMeters());
    csDest.setSpaceDim(2);
    assert(_pProjector);
    csDest.projector(*_pProjector);
    csDest.initialize();

    double originCoords[2] = { _originLon, _originLat };
    Converter::convert(originCoords, 1, 2, &csDest, &csSrc);
    _originX = originCoords[0];
    _originY = originCoords[1];
  } // if
} // initialize

// ----------------------------------------------------------------------
// Convert coordinates to PROJ4 useable form.
void
spatialdata::geocoords::CSGeoProj::toProjForm(double* coords,
					      const int numLocs,
					      const int numDims) const
{ // toProjForm
  assert( (0 < numLocs && 0 != coords) ||
	  (0 == numLocs && 0 == coords));
  assert(0 != _pProjector);
  if (numDims != spaceDim()) {
    std::ostringstream msg;
    msg
      << "Number of spatial dimensions of coordinates ("
      << numDims << ") does not match number of spatial dimensions ("
      << spaceDim() << ") of coordinate system.";
    throw std::runtime_error(msg.str());
  } // if

  const double angleRad = M_PI * _rotAngle / 180.0;
  for (int i=0; i < numLocs; ++i) {
    const double xOld = coords[i*numDims  ];
    const double yOld = coords[i*numDims+1];

    coords[i*numDims  ] = _originX + cos(angleRad)*xOld - sin(angleRad)*yOld;
    coords[i*numDims+1] = _originY + sin(angleRad)*xOld + cos(angleRad)*yOld;
  } // for

  _pProjector->invproject(coords, numLocs, numDims);
  CSGeo::toProjForm(coords, numLocs, numDims);
} // toProjForm

// ----------------------------------------------------------------------
// Convert coordinates from PROJ4 form to form associated w/coordsys.
void
spatialdata::geocoords::CSGeoProj::fromProjForm(double* coords,
						const int numLocs,
						const int numDims) const
{ // fromProjForm
  assert( (0 < numLocs && 0 != coords) ||
	  (0 == numLocs && 0 == coords));
  assert(0 != _pProjector);
  if (numDims != spaceDim()) {
    std::ostringstream msg;
    msg
      << "Number of spatial dimensions of coordinates ("
      << numDims << ") does not match number of spatial dimensions ("
      << spaceDim() << ") of coordinate system.";
    throw std::runtime_error(msg.str());
  } // if

  CSGeo::fromProjForm(coords, numLocs, numDims);
  _pProjector->project(coords, numLocs, numDims);

  const double angleRad = M_PI * _rotAngle / 180.0;
  for (int i=0; i < numLocs; ++i) {
    const double xRel = coords[i*numDims  ] - _originX;
    const double yRel = coords[i*numDims+1] - _originY;

    coords[i*numDims  ] = cos(angleRad)*xRel + sin(angleRad)*yRel;
    coords[i*numDims+1] = -sin(angleRad)*xRel + cos(angleRad)*yRel;
  } // for
} // fromProjForm

// ----------------------------------------------------------------------
// Pickle coordinate system to ascii stream.
void
spatialdata::geocoords::CSGeoProj::pickle(std::ostream& s) const
{ // pickle
  s << "geo-projected {\n"
    << "  to-meters = " << toMeters() << "\n"
    << "  ellipsoid = " << ellipsoid() << "\n"
    << "  datum-horiz = " << datumHoriz() << "\n"
    << "  datum-vert = " << datumVert() << "\n"
    << "  origin-lon = " << _originLon << "\n"
    << "  origin-lat = " << _originLat << "\n"
    << "  rotation-angle = " << rotationAngle() << "\n"
    << "  projector = ";
  _pProjector->pickle(s);
  s << "}\n";
} // pickle

// ----------------------------------------------------------------------
// Unpickle coordinate system from ascii stream.
void
spatialdata::geocoords::CSGeoProj::unpickle(std::istream& s)
{ // unpickle
  utils::LineParser parser(s, "//");
  parser.eatwhitespace(true);

  std::string token;
  std::istringstream buffer;
  const int maxIgnore = 256;
  char cbuffer[maxIgnore];
  double val;
  std::string name;

  parser.ignore('{');
  buffer.str(parser.next());
  buffer.clear();
  buffer >> token;
  while (buffer.good() && token != "}") {
    buffer.ignore(maxIgnore, '=');
    if (0 == strcasecmp(token.c_str(), "to-meters")) {
      buffer >> val;
      toMeters(val);
    } else if (0 == strcasecmp(token.c_str(), "ellipsoid")) {
      buffer >> name;
      ellipsoid(name.c_str());
    } else if (0 == strcasecmp(token.c_str(), "datum-horiz")) {
      buffer >> std::ws;
      buffer.get(cbuffer, maxIgnore, '\n');
      datumHoriz(cbuffer);
    } else if (0 == strcasecmp(token.c_str(), "datum-vert")) {
      buffer >> std::ws;
      buffer.get(cbuffer, maxIgnore, '\n');
      datumVert(cbuffer);
    } else if (0 == strcasecmp(token.c_str(), "origin-lon")) {
      buffer >> _originLon;
    } else if (0 == strcasecmp(token.c_str(), "origin-lat")) {
      buffer >> _originLat;
    } else if (0 == strcasecmp(token.c_str(), "rotation-angle")) {
      buffer >> _rotAngle;
    } else if (0 == strcasecmp(token.c_str(), "projector")) {
      std::string rbuffer(buffer.str());
      s.putback('\n');
      s.clear();
      int i = rbuffer.length()-1;
      while (i >= 0) {
	s.putback(rbuffer[i]);
	if ('=' == rbuffer[i--])
	  break;
      } // while
      s.clear();
      if (0 == _pProjector)
	_pProjector = new Projector;
      _pProjector->unpickle(s);
    } else {
      std::ostringstream msg;
      msg << "Could not parse '" << token << "' into a CSGeoProj token.\n"
	  << "Known CSGeoProj token:\n"
	  << "  to-meters, ellipsoid, datum-horiz, datum-vert, projector\n";
      throw std::runtime_error(msg.str().c_str());
    } // else
    buffer.str(parser.next());
    buffer.clear();
    buffer >> token;
  } // while
  if (token != "}")
    throw std::runtime_error("I/O error while parsing CSGeoProj "
			     "settings.");
} // unpickle

// End of file
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the demonstration applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qdeclarativeengine.h"
#include "qdeclarativecontext.h"
#include "qdeclarative.h"
#include <qdeclarativeitem.h>
#include <qdeclarativeview.h>

#include <QWidget>
#include <QApplication>
#include <QFile>
#include <QTime>
#include <QTimer>
#include <QVBoxLayout>
#include <QFileInfo>

QString fileName = "minehunt.qml";

class Tile : public QObject
{
    Q_OBJECT
public:
    Tile() : _hasFlag(false), _hasMine(false), _hint(-1), _flipped(false) {}

    Q_PROPERTY(bool hasFlag READ hasFlag WRITE setHasFlag NOTIFY hasFlagChanged);
    bool hasFlag() const { return _hasFlag; }

    Q_PROPERTY(bool hasMine READ hasMine NOTIFY hasMineChanged);
    bool hasMine() const { return _hasMine; }

    Q_PROPERTY(int hint READ hint NOTIFY hintChanged);
    int hint() const { return _hint; }

    Q_PROPERTY(bool flipped READ flipped NOTIFY flippedChanged());
    bool flipped() const { return _flipped; }

    void setHasFlag(bool flag) {if(flag==_hasFlag) return; _hasFlag = flag; emit hasFlagChanged();}
    void setHasMine(bool mine) {if(mine==_hasMine) return; _hasMine = mine; emit hasMineChanged();}
    void setHint(int hint) { if(hint == _hint) return; _hint = hint; emit hintChanged(); }
    void flip() { if (_flipped) return; _flipped = true; emit flippedChanged(); }
    void unflip() { if(!_flipped) return; _flipped = false; emit flippedChanged(); }

signals:
    void flippedChanged();
    void hasFlagChanged();
    void hintChanged();
    void hasMineChanged();

private:
    bool _hasFlag;
    bool _hasMine;
    int _hint;
    bool _flipped;
};

QML_DECLARE_TYPE(Tile);

class MyWidget : public QWidget
{
Q_OBJECT
public:
    MyWidget(int = 370, int = 480, QWidget *parent=0, Qt::WindowFlags flags=0);
    ~MyWidget();

    Q_PROPERTY(QList<Tile *> *tiles READ tiles CONSTANT);
    QList<Tile *> *tiles() { return &_tiles; }

    Q_PROPERTY(bool isPlaying READ isPlaying NOTIFY isPlayingChanged);
    bool isPlaying() {return playing;}

    Q_PROPERTY(bool hasWon READ hasWon NOTIFY hasWonChanged);
    bool hasWon() {return won;}

    Q_PROPERTY(int numMines READ numMines NOTIFY numMinesChanged);
    int numMines() const{return nMines;}

    Q_PROPERTY(int numFlags READ numFlags NOTIFY numFlagsChanged);
    int numFlags() const{return nFlags;}

public slots:
    Q_INVOKABLE void flip(int row, int col);
    Q_INVOKABLE void flag(int row, int col);
    void setBoard();
    void reset();

signals:
    void isPlayingChanged();
    void hasWonChanged();
    void numMinesChanged();
    void numFlagsChanged();

private:
    bool onBoard( int r, int c ) const { return r >= 0 && r < numRows && c >= 0 && c < numCols; }
    Tile *tile( int row, int col ) { return onBoard(row, col) ? _tiles[col+numRows*row] : 0; }
    int getHint(int row, int col);
    void setPlaying(bool b){if(b==playing) return; playing=b; emit isPlayingChanged();}

    QDeclarativeView *canvas;

    QList<Tile *> _tiles;
    int numCols;
    int numRows;
    bool playing;
    bool won;
    int remaining;
    int nMines;
    int nFlags;
};

MyWidget::MyWidget(int width, int height, QWidget *parent, Qt::WindowFlags flags)
: QWidget(parent, flags), canvas(0), numCols(9), numRows(9), playing(true), won(false)
{
    setObjectName("mainWidget");
    srand(QTime(0,0,0).secsTo(QTime::currentTime()));

    //initialize array
    for(int ii = 0; ii < numRows * numCols; ++ii) {
        _tiles << new Tile;
    }

    reset();

    QVBoxLayout *vbox = new QVBoxLayout;
    vbox->setMargin(0);
    setLayout(vbox);

    canvas = new QDeclarativeView(this);
    canvas->setFixedSize(width, height);
    vbox->addWidget(canvas);

    QDeclarativeContext *ctxt = canvas->rootContext();
    ctxt->addDefaultObject(this);
    ctxt->setContextProperty("tiles", QVariant::fromValue<QList<Tile*>*>(&_tiles));//QTBUG-5675

    canvas->setSource(QUrl::fromLocalFile(fileName));
}

MyWidget::~MyWidget()
{
}

void MyWidget::setBoard()
{
    foreach(Tile* t, _tiles){
        t->setHasMine(false);
        t->setHint(-1);
    }
    //place mines
    int mines = nMines;
    remaining = numRows*numCols-mines;
    while ( mines ) {
        int col = int((double(rand()) / double(RAND_MAX)) * numCols);
        int row = int((double(rand()) / double(RAND_MAX)) * numRows);

        Tile* t = tile( row, col );

        if (t && !t->hasMine()) {
            t->setHasMine( true );
            mines--;
        }
    }

    //set hints
    for (int r = 0; r < numRows; r++)
        for (int c = 0; c < numCols; c++) {
            Tile* t = tile(r, c);
            if (t && !t->hasMine()) {
                int hint = getHint(r,c);
                t->setHint(hint);
            }
        }

    setPlaying(true);
}

void MyWidget::reset()
{
    foreach(Tile* t, _tiles){
        t->unflip();
        t->setHasFlag(false);
    }
    nMines = 12;
    nFlags = 0;
    setPlaying(false);
    QTimer::singleShot(600,this, SLOT(setBoard()));
}

int MyWidget::getHint(int row, int col)
{
    int hint = 0;
    for (int c = col-1; c <= col+1; c++)
        for (int r = row-1; r <= row+1; r++) {
            Tile* t = tile(r, c);
            if (t && t->hasMine())
                hint++;
        }
    return hint;
}

void MyWidget::flip(int row, int col)
{
    if(!playing)
        return;

    Tile *t = tile(row, col);
    if (!t || t->hasFlag())
        return;

    if(t->flipped()){
        int flags = 0;
        for (int c = col-1; c <= col+1; c++)
            for (int r = row-1; r <= row+1; r++) {
                Tile *nearT = tile(r, c);
                if(!nearT || nearT == t)
                    continue;
                if(nearT->hasFlag())
                    flags++;
            }
        if(!t->hint() || t->hint() != flags)
            return;
        for (int c = col-1; c <= col+1; c++)
            for (int r = row-1; r <= row+1; r++) {
                Tile *nearT = tile(r, c);
                if (nearT && !nearT->flipped() && !nearT->hasFlag()) {
                    flip( r, c );
                }
            }
        return;
    }

    t->flip();

    if (t->hint() == 0) {
        for (int c = col-1; c <= col+1; c++)
            for (int r = row-1; r <= row+1; r++) {
                Tile* t = tile(r, c);
                if (t && !t->flipped()) {
                    flip( r, c );
                }
            }
    }

    if(t->hasMine()){
        for (int r = 0; r < numRows; r++)//Flip all other mines
            for (int c = 0; c < numCols; c++) {
                Tile* t = tile(r, c);
                if (t && t->hasMine()) {
                    flip(r, c);
                }
            }
        won = false;
        hasWonChanged();
        setPlaying(false);
    }

    remaining--;
    if(!remaining){
        won = true;
        hasWonChanged();
        setPlaying(false);
    }
}

void MyWidget::flag(int row, int col)
{
    Tile *t = tile(row, col);
    if(!t)
        return;

    t->setHasFlag(!t->hasFlag());
    nFlags += (t->hasFlag()?1:-1);
    emit numFlagsChanged();
}
/////////////////////////////////////////////////////////

int main(int argc, char ** argv)
{
    QApplication app(argc, argv);

    bool frameless = false;

    int width = 370;
    int height = 480;

    QML_REGISTER_TYPE(0,0,0,Tile,Tile);

    for (int i = 1; i < argc; ++i) {
        QString arg = argv[i];
        if (arg == "-frameless") {
            frameless = true;
        } else if(arg == "-width" && i < (argc - 1)) {
            ++i;
            width = ::atoi(argv[i]);
        } else if(arg == "-height" && i < (argc - 1)) {
            ++i;
            height = ::atoi(argv[i]);
        } else if (arg[0] != '-') {
            fileName = arg;
        }
    }

    MyWidget wid(width, height, 0, frameless ? Qt::FramelessWindowHint : Qt::Widget);
    wid.show();

    return app.exec();
}

#include "main.moc"
<commit_msg>Make Minehunt demo compile.<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the demonstration applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qdeclarativeengine.h"
#include "qdeclarativecontext.h"
#include "qdeclarative.h"
#include <qdeclarativeitem.h>
#include <qdeclarativeview.h>

#include <QWidget>
#include <QApplication>
#include <QFile>
#include <QTime>
#include <QTimer>
#include <QVBoxLayout>
#include <QFileInfo>

QString fileName = "minehunt.qml";

class Tile : public QObject
{
    Q_OBJECT
public:
    Tile() : _hasFlag(false), _hasMine(false), _hint(-1), _flipped(false) {}

    Q_PROPERTY(bool hasFlag READ hasFlag WRITE setHasFlag NOTIFY hasFlagChanged);
    bool hasFlag() const { return _hasFlag; }

    Q_PROPERTY(bool hasMine READ hasMine NOTIFY hasMineChanged);
    bool hasMine() const { return _hasMine; }

    Q_PROPERTY(int hint READ hint NOTIFY hintChanged);
    int hint() const { return _hint; }

    Q_PROPERTY(bool flipped READ flipped NOTIFY flippedChanged());
    bool flipped() const { return _flipped; }

    void setHasFlag(bool flag) {if(flag==_hasFlag) return; _hasFlag = flag; emit hasFlagChanged();}
    void setHasMine(bool mine) {if(mine==_hasMine) return; _hasMine = mine; emit hasMineChanged();}
    void setHint(int hint) { if(hint == _hint) return; _hint = hint; emit hintChanged(); }
    void flip() { if (_flipped) return; _flipped = true; emit flippedChanged(); }
    void unflip() { if(!_flipped) return; _flipped = false; emit flippedChanged(); }

signals:
    void flippedChanged();
    void hasFlagChanged();
    void hintChanged();
    void hasMineChanged();

private:
    bool _hasFlag;
    bool _hasMine;
    int _hint;
    bool _flipped;
};

QML_DECLARE_TYPE(Tile);

class MyWidget : public QWidget
{
Q_OBJECT
public:
    MyWidget(int = 370, int = 480, QWidget *parent=0, Qt::WindowFlags flags=0);
    ~MyWidget();

    Q_PROPERTY(QDeclarativeListProperty<Tile> tiles READ tiles CONSTANT);
    QDeclarativeListProperty<Tile> tiles() { return _tilesProperty; }

    Q_PROPERTY(bool isPlaying READ isPlaying NOTIFY isPlayingChanged);
    bool isPlaying() {return playing;}

    Q_PROPERTY(bool hasWon READ hasWon NOTIFY hasWonChanged);
    bool hasWon() {return won;}

    Q_PROPERTY(int numMines READ numMines NOTIFY numMinesChanged);
    int numMines() const{return nMines;}

    Q_PROPERTY(int numFlags READ numFlags NOTIFY numFlagsChanged);
    int numFlags() const{return nFlags;}

public slots:
    Q_INVOKABLE bool flip(int row, int col);
    Q_INVOKABLE bool flag(int row, int col);
    void setBoard();
    void reset();

signals:
    void isPlayingChanged();
    void hasWonChanged();
    void numMinesChanged();
    void numFlagsChanged();

private:
    bool onBoard( int r, int c ) const { return r >= 0 && r < numRows && c >= 0 && c < numCols; }
    Tile *tile( int row, int col ) { return onBoard(row, col) ? _tiles[col+numRows*row] : 0; }
    int getHint(int row, int col);
    void setPlaying(bool b){if(b==playing) return; playing=b; emit isPlayingChanged();}

    QDeclarativeView *canvas;

    QList<Tile *> _tiles;
    QDeclarativeListProperty<Tile> _tilesProperty;
    int numCols;
    int numRows;
    bool playing;
    bool won;
    int remaining;
    int nMines;
    int nFlags;
};

Q_DECLARE_METATYPE(QList<Tile*>)
MyWidget::MyWidget(int width, int height, QWidget *parent, Qt::WindowFlags flags)
: QWidget(parent, flags), canvas(0), numCols(9), numRows(9), playing(true), won(false)
{
    setObjectName("mainWidget");
    srand(QTime(0,0,0).secsTo(QTime::currentTime()));

    //initialize array
    for(int ii = 0; ii < numRows * numCols; ++ii) {
        _tiles << new Tile;
    }
    reset();

    QVBoxLayout *vbox = new QVBoxLayout;
    vbox->setMargin(0);
    setLayout(vbox);

    canvas = new QDeclarativeView(this);
    canvas->setFixedSize(width, height);
    vbox->addWidget(canvas);

    _tilesProperty = QDeclarativeListProperty<Tile>(this, _tiles);

    QDeclarativeContext *ctxt = canvas->rootContext();
    ctxt->addDefaultObject(this);

    canvas->setSource(QUrl::fromLocalFile(fileName));
}

MyWidget::~MyWidget()
{
}

void MyWidget::setBoard()
{
    foreach(Tile* t, _tiles){
        t->setHasMine(false);
        t->setHint(-1);
    }
    //place mines
    int mines = nMines;
    remaining = numRows*numCols-mines;
    while ( mines ) {
        int col = int((double(rand()) / double(RAND_MAX)) * numCols);
        int row = int((double(rand()) / double(RAND_MAX)) * numRows);

        Tile* t = tile( row, col );

        if (t && !t->hasMine()) {
            t->setHasMine( true );
            mines--;
        }
    }

    //set hints
    for (int r = 0; r < numRows; r++)
        for (int c = 0; c < numCols; c++) {
            Tile* t = tile(r, c);
            if (t && !t->hasMine()) {
                int hint = getHint(r,c);
                t->setHint(hint);
            }
        }

    setPlaying(true);
}

void MyWidget::reset()
{
    foreach(Tile* t, _tiles){
        t->unflip();
        t->setHasFlag(false);
    }
    nMines = 12;
    nFlags = 0;
    setPlaying(false);
    QTimer::singleShot(600,this, SLOT(setBoard()));
}

int MyWidget::getHint(int row, int col)
{
    int hint = 0;
    for (int c = col-1; c <= col+1; c++)
        for (int r = row-1; r <= row+1; r++) {
            Tile* t = tile(r, c);
            if (t && t->hasMine())
                hint++;
        }
    return hint;
}

bool MyWidget::flip(int row, int col)
{
    if(!playing)
        return false;

    Tile *t = tile(row, col);
    if (!t || t->hasFlag())
        return false;

    if(t->flipped()){
        int flags = 0;
        for (int c = col-1; c <= col+1; c++)
            for (int r = row-1; r <= row+1; r++) {
                Tile *nearT = tile(r, c);
                if(!nearT || nearT == t)
                    continue;
                if(nearT->hasFlag())
                    flags++;
            }
        if(!t->hint() || t->hint() != flags)
            return false;
        for (int c = col-1; c <= col+1; c++)
            for (int r = row-1; r <= row+1; r++) {
                Tile *nearT = tile(r, c);
                if (nearT && !nearT->flipped() && !nearT->hasFlag()) {
                    flip( r, c );
                }
            }
        return true;
    }

    t->flip();

    if (t->hint() == 0) {
        for (int c = col-1; c <= col+1; c++)
            for (int r = row-1; r <= row+1; r++) {
                Tile* t = tile(r, c);
                if (t && !t->flipped()) {
                    flip( r, c );
                }
            }
    }

    if(t->hasMine()){
        for (int r = 0; r < numRows; r++)//Flip all other mines
            for (int c = 0; c < numCols; c++) {
                Tile* t = tile(r, c);
                if (t && t->hasMine()) {
                    flip(r, c);
                }
            }
        won = false;
        hasWonChanged();
        setPlaying(false);
    }

    remaining--;
    if(!remaining){
        won = true;
        hasWonChanged();
        setPlaying(false);
    }
    return true;
}

bool MyWidget::flag(int row, int col)
{
    Tile *t = tile(row, col);
    if(!t)
        return false;

    t->setHasFlag(!t->hasFlag());
    nFlags += (t->hasFlag()?1:-1);
    emit numFlagsChanged();
    return true;
}
/////////////////////////////////////////////////////////

int main(int argc, char ** argv)
{
    QApplication app(argc, argv);

    bool frameless = false;

    int width = 370;
    int height = 480;

    QML_REGISTER_TYPE(0,0,0,Tile,Tile);

    for (int i = 1; i < argc; ++i) {
        QString arg = argv[i];
        if (arg == "-frameless") {
            frameless = true;
        } else if(arg == "-width" && i < (argc - 1)) {
            ++i;
            width = ::atoi(argv[i]);
        } else if(arg == "-height" && i < (argc - 1)) {
            ++i;
            height = ::atoi(argv[i]);
        } else if (arg[0] != '-') {
            fileName = arg;
        }
    }

    MyWidget wid(width, height, 0, frameless ? Qt::FramelessWindowHint : Qt::Widget);
    wid.show();

    return app.exec();
}

#include "main.moc"
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the demonstration applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qmlengine.h"
#include "qmlcontext.h"
#include "qml.h"
#include <qmlgraphicsitem.h>
#include <qmlview.h>

#include <QWidget>
#include <QApplication>
#include <QFile>
#include <QTime>
#include <QTimer>
#include <QVBoxLayout>
#include <QFileInfo>

QString fileName = "minehunt.qml";

class Tile : public QObject
{
    Q_OBJECT
public:
    Tile() : _hasFlag(false), _hasMine(false), _hint(-1), _flipped(false) {}

    Q_PROPERTY(bool hasFlag READ hasFlag WRITE setHasFlag NOTIFY hasFlagChanged);
    bool hasFlag() const { return _hasFlag; }

    Q_PROPERTY(bool hasMine READ hasMine NOTIFY hasMineChanged);
    bool hasMine() const { return _hasMine; }

    Q_PROPERTY(int hint READ hint NOTIFY hintChanged);
    int hint() const { return _hint; }

    Q_PROPERTY(bool flipped READ flipped NOTIFY flippedChanged());
    bool flipped() const { return _flipped; }

    void setHasFlag(bool flag) {if(flag==_hasFlag) return; _hasFlag = flag; emit hasFlagChanged();}
    void setHasMine(bool mine) {if(mine==_hasMine) return; _hasMine = mine; emit hasMineChanged();}
    void setHint(int hint) { if(hint == _hint) return; _hint = hint; emit hintChanged(); }
    void flip() { if (_flipped) return; _flipped = true; emit flippedChanged(); }
    void unflip() { if(!_flipped) return; _flipped = false; emit flippedChanged(); }

signals:
    void flippedChanged();
    void hasFlagChanged();
    void hintChanged();
    void hasMineChanged();

private:
    bool _hasFlag;
    bool _hasMine;
    int _hint;
    bool _flipped;
};

QML_DECLARE_TYPE(Tile);
QML_DEFINE_TYPE(0,0,0,Tile,Tile);

class MyWidget : public QWidget
{
Q_OBJECT
public:
    MyWidget(int = 370, int = 480, QWidget *parent=0, Qt::WindowFlags flags=0);
    ~MyWidget();

    Q_PROPERTY(QList<Tile *> *tiles READ tiles CONSTANT);
    QList<Tile *> *tiles() { return &_tiles; }

    Q_PROPERTY(bool isPlaying READ isPlaying NOTIFY isPlayingChanged);
    bool isPlaying() {return playing;}

    Q_PROPERTY(bool hasWon READ hasWon NOTIFY hasWonChanged);
    bool hasWon() {return won;}

    Q_PROPERTY(int numMines READ numMines NOTIFY numMinesChanged);
    int numMines() const{return nMines;}

    Q_PROPERTY(int numFlags READ numFlags NOTIFY numFlagsChanged);
    int numFlags() const{return nFlags;}

public slots:
    Q_INVOKABLE void flip(int row, int col);
    Q_INVOKABLE void flag(int row, int col);
    void setBoard();
    void reset();

signals:
    void isPlayingChanged();
    void hasWonChanged();
    void numMinesChanged();
    void numFlagsChanged();

private:
    bool onBoard( int r, int c ) const { return r >= 0 && r < numRows && c >= 0 && c < numCols; }
    Tile *tile( int row, int col ) { return onBoard(row, col) ? _tiles[col+numRows*row] : 0; }
    int getHint(int row, int col);
    void setPlaying(bool b){if(b==playing) return; playing=b; emit isPlayingChanged();}

    QmlView *canvas;

    QList<Tile *> _tiles;
    int numCols;
    int numRows;
    bool playing;
    bool won;
    int remaining;
    int nMines;
    int nFlags;
};

MyWidget::MyWidget(int width, int height, QWidget *parent, Qt::WindowFlags flags)
: QWidget(parent, flags), canvas(0), numCols(9), numRows(9), playing(true), won(false)
{
    setObjectName("mainWidget");
    srand(QTime(0,0,0).secsTo(QTime::currentTime()));

    //initialize array
    for(int ii = 0; ii < numRows * numCols; ++ii) {
        _tiles << new Tile;
    }

    reset();

    QVBoxLayout *vbox = new QVBoxLayout;
    vbox->setMargin(0);
    setLayout(vbox);

    canvas = new QmlView(this);
    canvas->setFixedSize(width, height);
    vbox->addWidget(canvas);

    QFile file(fileName);
    file.open(QFile::ReadOnly);
    QString qml = file.readAll();
    canvas->setQml(qml, fileName);

    QmlContext *ctxt = canvas->rootContext();
    ctxt->addDefaultObject(this);
    ctxt->setContextProperty("tiles", QVariant::fromValue<QList<Tile*>*>(&_tiles));//QTBUG-5675

    canvas->execute();
}

MyWidget::~MyWidget()
{
}

void MyWidget::setBoard()
{
    foreach(Tile* t, _tiles){
        t->setHasMine(false);
        t->setHint(-1);
    }
    //place mines
    int mines = nMines;
    remaining = numRows*numCols-mines;
    while ( mines ) {
        int col = int((double(rand()) / double(RAND_MAX)) * numCols);
        int row = int((double(rand()) / double(RAND_MAX)) * numRows);

        Tile* t = tile( row, col );

        if (t && !t->hasMine()) {
            t->setHasMine( true );
            mines--;
        }
    }

    //set hints
    for (int r = 0; r < numRows; r++)
        for (int c = 0; c < numCols; c++) {
            Tile* t = tile(r, c);
            if (t && !t->hasMine()) {
                int hint = getHint(r,c);
                t->setHint(hint);
            }
        }

    setPlaying(true);
}

void MyWidget::reset()
{
    foreach(Tile* t, _tiles){
        t->unflip();
        t->setHasFlag(false);
    }
    nMines = 12;
    nFlags = 0;
    setPlaying(false);
    QTimer::singleShot(900,this, SLOT(setBoard()));
}

int MyWidget::getHint(int row, int col)
{
    int hint = 0;
    for (int c = col-1; c <= col+1; c++)
        for (int r = row-1; r <= row+1; r++) {
            Tile* t = tile(r, c);
            if (t && t->hasMine())
                hint++;
        }
    return hint;
}

void MyWidget::flip(int row, int col)
{
    if(!playing)
        return;

    Tile *t = tile(row, col);
    if (!t || t->hasFlag())
        return;

    if(t->flipped()){
        int flags = 0;
        for (int c = col-1; c <= col+1; c++)
            for (int r = row-1; r <= row+1; r++) {
                Tile *nearT = tile(r, c);
                if(!nearT || nearT == t)
                    continue;
                if(nearT->hasFlag())
                    flags++;
            }
        if(!t->hint() || t->hint() != flags)
            return;
        for (int c = col-1; c <= col+1; c++)
            for (int r = row-1; r <= row+1; r++) {
                Tile *nearT = tile(r, c);
                if (nearT && !nearT->flipped() && !nearT->hasFlag()) {
                    flip( r, c );
                }
            }
        return;
    }

    t->flip();

    if (t->hint() == 0) {
        for (int c = col-1; c <= col+1; c++)
            for (int r = row-1; r <= row+1; r++) {
                Tile* t = tile(r, c);
                if (t && !t->flipped()) {
                    flip( r, c );
                }
            }
    }

    if(t->hasMine()){
        for (int r = 0; r < numRows; r++)//Flip all other mines
            for (int c = 0; c < numCols; c++) {
                Tile* t = tile(r, c);
                if (t && t->hasMine()) {
                    flip(r, c);
                }
            }
        won = false;
        hasWonChanged();
        setPlaying(false);
    }

    remaining--;
    if(!remaining){
        won = true;
        hasWonChanged();
        setPlaying(false);
    }
}

void MyWidget::flag(int row, int col)
{
    Tile *t = tile(row, col);
    if(!t)
        return;

    t->setHasFlag(!t->hasFlag());
    nFlags += (t->hasFlag()?1:-1);
    emit numFlagsChanged();
}
/////////////////////////////////////////////////////////

int main(int argc, char ** argv)
{
    QApplication app(argc, argv);

    bool frameless = false;

    int width = 370;
    int height = 480;

    for (int i = 1; i < argc; ++i) {
        QString arg = argv[i];
        if (arg == "-frameless") {
            frameless = true;
        } else if(arg == "-width" && i < (argc - 1)) {
            ++i;
            width = ::atoi(argv[i]);
        } else if(arg == "-height" && i < (argc - 1)) {
            ++i;
            height = ::atoi(argv[i]);
        } else if (arg[0] != '-') {
            fileName = arg;
        }
    }

    MyWidget wid(width, height, 0, frameless ? Qt::FramelessWindowHint : Qt::Widget);
    wid.show();

    return app.exec();
}

#include "main.moc"
<commit_msg>Make minehunt more responsive<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the demonstration applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qmlengine.h"
#include "qmlcontext.h"
#include "qml.h"
#include <qmlgraphicsitem.h>
#include <qmlview.h>

#include <QWidget>
#include <QApplication>
#include <QFile>
#include <QTime>
#include <QTimer>
#include <QVBoxLayout>
#include <QFileInfo>

QString fileName = "minehunt.qml";

class Tile : public QObject
{
    Q_OBJECT
public:
    Tile() : _hasFlag(false), _hasMine(false), _hint(-1), _flipped(false) {}

    Q_PROPERTY(bool hasFlag READ hasFlag WRITE setHasFlag NOTIFY hasFlagChanged);
    bool hasFlag() const { return _hasFlag; }

    Q_PROPERTY(bool hasMine READ hasMine NOTIFY hasMineChanged);
    bool hasMine() const { return _hasMine; }

    Q_PROPERTY(int hint READ hint NOTIFY hintChanged);
    int hint() const { return _hint; }

    Q_PROPERTY(bool flipped READ flipped NOTIFY flippedChanged());
    bool flipped() const { return _flipped; }

    void setHasFlag(bool flag) {if(flag==_hasFlag) return; _hasFlag = flag; emit hasFlagChanged();}
    void setHasMine(bool mine) {if(mine==_hasMine) return; _hasMine = mine; emit hasMineChanged();}
    void setHint(int hint) { if(hint == _hint) return; _hint = hint; emit hintChanged(); }
    void flip() { if (_flipped) return; _flipped = true; emit flippedChanged(); }
    void unflip() { if(!_flipped) return; _flipped = false; emit flippedChanged(); }

signals:
    void flippedChanged();
    void hasFlagChanged();
    void hintChanged();
    void hasMineChanged();

private:
    bool _hasFlag;
    bool _hasMine;
    int _hint;
    bool _flipped;
};

QML_DECLARE_TYPE(Tile);
QML_DEFINE_TYPE(0,0,0,Tile,Tile);

class MyWidget : public QWidget
{
Q_OBJECT
public:
    MyWidget(int = 370, int = 480, QWidget *parent=0, Qt::WindowFlags flags=0);
    ~MyWidget();

    Q_PROPERTY(QList<Tile *> *tiles READ tiles CONSTANT);
    QList<Tile *> *tiles() { return &_tiles; }

    Q_PROPERTY(bool isPlaying READ isPlaying NOTIFY isPlayingChanged);
    bool isPlaying() {return playing;}

    Q_PROPERTY(bool hasWon READ hasWon NOTIFY hasWonChanged);
    bool hasWon() {return won;}

    Q_PROPERTY(int numMines READ numMines NOTIFY numMinesChanged);
    int numMines() const{return nMines;}

    Q_PROPERTY(int numFlags READ numFlags NOTIFY numFlagsChanged);
    int numFlags() const{return nFlags;}

public slots:
    Q_INVOKABLE void flip(int row, int col);
    Q_INVOKABLE void flag(int row, int col);
    void setBoard();
    void reset();

signals:
    void isPlayingChanged();
    void hasWonChanged();
    void numMinesChanged();
    void numFlagsChanged();

private:
    bool onBoard( int r, int c ) const { return r >= 0 && r < numRows && c >= 0 && c < numCols; }
    Tile *tile( int row, int col ) { return onBoard(row, col) ? _tiles[col+numRows*row] : 0; }
    int getHint(int row, int col);
    void setPlaying(bool b){if(b==playing) return; playing=b; emit isPlayingChanged();}

    QmlView *canvas;

    QList<Tile *> _tiles;
    int numCols;
    int numRows;
    bool playing;
    bool won;
    int remaining;
    int nMines;
    int nFlags;
};

MyWidget::MyWidget(int width, int height, QWidget *parent, Qt::WindowFlags flags)
: QWidget(parent, flags), canvas(0), numCols(9), numRows(9), playing(true), won(false)
{
    setObjectName("mainWidget");
    srand(QTime(0,0,0).secsTo(QTime::currentTime()));

    //initialize array
    for(int ii = 0; ii < numRows * numCols; ++ii) {
        _tiles << new Tile;
    }

    reset();

    QVBoxLayout *vbox = new QVBoxLayout;
    vbox->setMargin(0);
    setLayout(vbox);

    canvas = new QmlView(this);
    canvas->setFixedSize(width, height);
    vbox->addWidget(canvas);

    QFile file(fileName);
    file.open(QFile::ReadOnly);
    QString qml = file.readAll();
    canvas->setQml(qml, fileName);

    QmlContext *ctxt = canvas->rootContext();
    ctxt->addDefaultObject(this);
    ctxt->setContextProperty("tiles", QVariant::fromValue<QList<Tile*>*>(&_tiles));//QTBUG-5675

    canvas->execute();
}

MyWidget::~MyWidget()
{
}

void MyWidget::setBoard()
{
    foreach(Tile* t, _tiles){
        t->setHasMine(false);
        t->setHint(-1);
    }
    //place mines
    int mines = nMines;
    remaining = numRows*numCols-mines;
    while ( mines ) {
        int col = int((double(rand()) / double(RAND_MAX)) * numCols);
        int row = int((double(rand()) / double(RAND_MAX)) * numRows);

        Tile* t = tile( row, col );

        if (t && !t->hasMine()) {
            t->setHasMine( true );
            mines--;
        }
    }

    //set hints
    for (int r = 0; r < numRows; r++)
        for (int c = 0; c < numCols; c++) {
            Tile* t = tile(r, c);
            if (t && !t->hasMine()) {
                int hint = getHint(r,c);
                t->setHint(hint);
            }
        }

    setPlaying(true);
}

void MyWidget::reset()
{
    foreach(Tile* t, _tiles){
        t->unflip();
        t->setHasFlag(false);
    }
    nMines = 12;
    nFlags = 0;
    setPlaying(false);
    QTimer::singleShot(600,this, SLOT(setBoard()));
}

int MyWidget::getHint(int row, int col)
{
    int hint = 0;
    for (int c = col-1; c <= col+1; c++)
        for (int r = row-1; r <= row+1; r++) {
            Tile* t = tile(r, c);
            if (t && t->hasMine())
                hint++;
        }
    return hint;
}

void MyWidget::flip(int row, int col)
{
    if(!playing)
        return;

    Tile *t = tile(row, col);
    if (!t || t->hasFlag())
        return;

    if(t->flipped()){
        int flags = 0;
        for (int c = col-1; c <= col+1; c++)
            for (int r = row-1; r <= row+1; r++) {
                Tile *nearT = tile(r, c);
                if(!nearT || nearT == t)
                    continue;
                if(nearT->hasFlag())
                    flags++;
            }
        if(!t->hint() || t->hint() != flags)
            return;
        for (int c = col-1; c <= col+1; c++)
            for (int r = row-1; r <= row+1; r++) {
                Tile *nearT = tile(r, c);
                if (nearT && !nearT->flipped() && !nearT->hasFlag()) {
                    flip( r, c );
                }
            }
        return;
    }

    t->flip();

    if (t->hint() == 0) {
        for (int c = col-1; c <= col+1; c++)
            for (int r = row-1; r <= row+1; r++) {
                Tile* t = tile(r, c);
                if (t && !t->flipped()) {
                    flip( r, c );
                }
            }
    }

    if(t->hasMine()){
        for (int r = 0; r < numRows; r++)//Flip all other mines
            for (int c = 0; c < numCols; c++) {
                Tile* t = tile(r, c);
                if (t && t->hasMine()) {
                    flip(r, c);
                }
            }
        won = false;
        hasWonChanged();
        setPlaying(false);
    }

    remaining--;
    if(!remaining){
        won = true;
        hasWonChanged();
        setPlaying(false);
    }
}

void MyWidget::flag(int row, int col)
{
    Tile *t = tile(row, col);
    if(!t)
        return;

    t->setHasFlag(!t->hasFlag());
    nFlags += (t->hasFlag()?1:-1);
    emit numFlagsChanged();
}
/////////////////////////////////////////////////////////

int main(int argc, char ** argv)
{
    QApplication app(argc, argv);

    bool frameless = false;

    int width = 370;
    int height = 480;

    for (int i = 1; i < argc; ++i) {
        QString arg = argv[i];
        if (arg == "-frameless") {
            frameless = true;
        } else if(arg == "-width" && i < (argc - 1)) {
            ++i;
            width = ::atoi(argv[i]);
        } else if(arg == "-height" && i < (argc - 1)) {
            ++i;
            height = ::atoi(argv[i]);
        } else if (arg[0] != '-') {
            fileName = arg;
        }
    }

    MyWidget wid(width, height, 0, frameless ? Qt::FramelessWindowHint : Qt::Widget);
    wid.show();

    return app.exec();
}

#include "main.moc"
<|endoftext|>


<commit_before>/*
 * This file is part of KDevelop
 * Copyright 2017 René J.V. Bertin <rjvbertin@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include <QDialog>
#include <QUrl>
#include <QFileInfo>
#include <QVariantList>
#include <QStandardPaths>
#include <QJsonArray>
#include <QMessageBox>

#include <KLocalizedString>
#include <KPluginFactory>
#include <QJsonDocument>

#include "phabricatorjobs.h"
#include "debug.h"

#include "purpose/job.h"
#include "purpose/pluginbase.h"

// FIXME: For some reason PLUGIN_PHABRICATOR isn't exported from the PhabricatorHelpers lib
#undef qCDebug
#define qCDebug(dum)    qDebug()
#undef qCWarning
#define qCWarning(dum)  qWarning()
#undef qCCritical
#define qCCritical(dum)  qCritical()

class PhabricatorJob : public Purpose::Job
{
    Q_OBJECT
    public:
        PhabricatorJob(QObject* object = Q_NULLPTR)
            : Purpose::Job(object)
    {}

    void start() override
    {
        const QString baseDir(data().value(QStringLiteral("baseDir")).toString());
        const QUrl sourceFile(data().value(QStringLiteral("urls")).toArray().first().toString());
        const QString updateDR = data().value(QStringLiteral("updateDR")).toString();
        const bool doBrowse = data().value(QStringLiteral("doBrowse")).toBool();

        if (QFileInfo(sourceFile.toLocalFile()).size() <= 0) {
            setError(KJob::UserDefinedError+1);
            setErrorText(i18n("Phabricator refuses empty patchfiles"));
            qCCritical(PLUGIN_PHABRICATOR) << errorString();
            emitResult();
            return;
        }

        m_drTitle = data().value(QStringLiteral("drTitle")).toString();

        KJob* job;
        if (!updateDR.isEmpty()) {
            const QString updateComment = data().value(QStringLiteral("updateComment")).toString();
            job=new Phabricator::UpdateDiffRev(sourceFile, baseDir, updateDR, updateComment, doBrowse, this);
            connect(job, &KJob::finished, this, &PhabricatorJob::diffUpdated);
        } else {
            job=new Phabricator::NewDiffRev(sourceFile, baseDir, doBrowse, this);
            connect(job, &KJob::finished, this, &PhabricatorJob::diffCreated);
            if (!doBrowse) {
                QMessageBox::warning(nullptr,
                    i18n("Please note"),
                    i18n("Remember to complete the differential revision online!"));
            }
        }
        job->start();
        emit PhabricatorJob::infoMessage(this, QStringLiteral("upload job started"), QString());
    }

    void diffCreatedOrUpdated(KJob* j, bool created)
    {
        if(j->error()!=0) {
            setError(j->error());
            setErrorText(j->errorString());
            emit PhabricatorJob::warning(this, j->errorString(), QString());
            qCCritical(PLUGIN_PHABRICATOR) << "Could not upload the patch" << j->errorString();
            emitResult();
            return;
        }

        if (created) {
            Phabricator::NewDiffRev const * job = qobject_cast<Phabricator::NewDiffRev*>(j);
            qCDebug(PLUGIN_PHABRICATOR) <<"new diff:" << job->diffURI();
            setOutput({{ QStringLiteral("url"), job->diffURI() }});
        } else {
            Phabricator::UpdateDiffRev const * job = qobject_cast<Phabricator::UpdateDiffRev*>(j);
            qCDebug(PLUGIN_PHABRICATOR) << "updated diff" << job->requestId() << ":" << job->diffURI();
            setOutput({{ QStringLiteral("url"), job->diffURI() }});
            emit PhabricatorJob::infoMessage(this,
                 QStringLiteral("updated diff %1: %2").arg(job->requestId()).arg(job->diffURI()), QString());
        }
        emitResult();
    }

    void diffCreated(KJob* j)
    {
        diffCreatedOrUpdated(j, true);
    }

    void diffUpdated(KJob* j)
    {
        diffCreatedOrUpdated(j, false);
    }

    QString m_drTitle;
};

class Q_DECL_EXPORT PhabricatorPlugin : public Purpose::PluginBase
{
    Q_OBJECT
    public:
        PhabricatorPlugin(QObject* parent, const QList<QVariant>& /*args*/) : PluginBase(parent) {}
        virtual ~PhabricatorPlugin() override {}

        virtual Purpose::Job* createJob() const override
        {
            return new PhabricatorJob;
        }
};

K_PLUGIN_FACTORY_WITH_JSON(PhabricatorPluginFactory, "phabricatorplugin.json", registerPlugin<PhabricatorPlugin>();)

#include "phabricatorplugin.moc"
<commit_msg>revert to qCWarning() for the results for now<commit_after>/*
 * This file is part of KDevelop
 * Copyright 2017 René J.V. Bertin <rjvbertin@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include <QDialog>
#include <QUrl>
#include <QFileInfo>
#include <QVariantList>
#include <QStandardPaths>
#include <QJsonArray>
#include <QMessageBox>

#include <KLocalizedString>
#include <KPluginFactory>
#include <QJsonDocument>

#include "phabricatorjobs.h"
#include "debug.h"

#include "purpose/job.h"
#include "purpose/pluginbase.h"

// FIXME: For some reason PLUGIN_PHABRICATOR isn't exported from the PhabricatorHelpers lib
#undef qCDebug
#define qCDebug(dum)    qDebug()
#undef qCWarning
#define qCWarning(dum)  qWarning()
#undef qCCritical
#define qCCritical(dum)  qCritical()

class PhabricatorJob : public Purpose::Job
{
    Q_OBJECT
    public:
        PhabricatorJob(QObject* object = Q_NULLPTR)
            : Purpose::Job(object)
    {}

    void start() override
    {
        const QString baseDir(data().value(QStringLiteral("baseDir")).toString());
        const QUrl sourceFile(data().value(QStringLiteral("urls")).toArray().first().toString());
        const QString updateDR = data().value(QStringLiteral("updateDR")).toString();
        const bool doBrowse = data().value(QStringLiteral("doBrowse")).toBool();

        if (QFileInfo(sourceFile.toLocalFile()).size() <= 0) {
            setError(KJob::UserDefinedError+1);
            setErrorText(i18n("Phabricator refuses empty patchfiles"));
            qCCritical(PLUGIN_PHABRICATOR) << errorString();
            emitResult();
            return;
        }

        m_drTitle = data().value(QStringLiteral("drTitle")).toString();

        KJob* job;
        if (!updateDR.isEmpty()) {
            const QString updateComment = data().value(QStringLiteral("updateComment")).toString();
            job=new Phabricator::UpdateDiffRev(sourceFile, baseDir, updateDR, updateComment, doBrowse, this);
            connect(job, &KJob::finished, this, &PhabricatorJob::diffUpdated);
        } else {
            job=new Phabricator::NewDiffRev(sourceFile, baseDir, doBrowse, this);
            connect(job, &KJob::finished, this, &PhabricatorJob::diffCreated);
            if (!doBrowse) {
                QMessageBox::warning(nullptr,
                    i18n("Please note"),
                    i18n("Remember to complete the differential revision online!"));
            }
        }
        job->start();
        emit PhabricatorJob::infoMessage(this, QStringLiteral("upload job started"), QString());
    }

    void diffCreatedOrUpdated(KJob* j, bool created)
    {
        if(j->error()!=0) {
            setError(j->error());
            setErrorText(j->errorString());
            emit PhabricatorJob::warning(this, j->errorString(), QString());
            qCCritical(PLUGIN_PHABRICATOR) << "Could not upload the patch" << j->errorString();
            emitResult();
            return;
        }

        if (created) {
            Phabricator::NewDiffRev const * job = qobject_cast<Phabricator::NewDiffRev*>(j);
            qCWarning(PLUGIN_PHABRICATOR) <<"new diff:" << job->diffURI();
            setOutput({{ QStringLiteral("url"), job->diffURI() }});
        } else {
            Phabricator::UpdateDiffRev const * job = qobject_cast<Phabricator::UpdateDiffRev*>(j);
            qCWarning(PLUGIN_PHABRICATOR) << "updated diff" << job->requestId() << ":" << job->diffURI();
            setOutput({{ QStringLiteral("url"), job->diffURI() }});
            emit PhabricatorJob::infoMessage(this,
                 QStringLiteral("updated diff %1: %2").arg(job->requestId()).arg(job->diffURI()), QString());
        }
        emitResult();
    }

    void diffCreated(KJob* j)
    {
        diffCreatedOrUpdated(j, true);
    }

    void diffUpdated(KJob* j)
    {
        diffCreatedOrUpdated(j, false);
    }

    QString m_drTitle;
};

class Q_DECL_EXPORT PhabricatorPlugin : public Purpose::PluginBase
{
    Q_OBJECT
    public:
        PhabricatorPlugin(QObject* parent, const QList<QVariant>& /*args*/) : PluginBase(parent) {}
        virtual ~PhabricatorPlugin() override {}

        virtual Purpose::Job* createJob() const override
        {
            return new PhabricatorJob;
        }
};

K_PLUGIN_FACTORY_WITH_JSON(PhabricatorPluginFactory, "phabricatorplugin.json", registerPlugin<PhabricatorPlugin>();)

#include "phabricatorplugin.moc"
<|endoftext|>