<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkSimple2DLayoutStrategy.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*----------------------------------------------------------------------------
 Copyright (c) Sandia Corporation
 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
----------------------------------------------------------------------------*/

#include "vtkSimple2DLayoutStrategy.h"

#include <vtkCellArray.h>
#include <vtkCellData.h>
#include <vtkCommand.h>
#include <vtkDataArray.h>
#include <vtkFloatArray.h>
#include <vtkInformation.h>
#include <vtkInformationVector.h>
#include <vtkMath.h>
#include <vtkObjectFactory.h>
#include <vtkPointData.h>

#include "vtkAbstractGraph.h"
#include "vtkGraph.h"
#include "vtkTree.h"

vtkCxxRevisionMacro(vtkSimple2DLayoutStrategy, "1.21");
vtkStandardNewMacro(vtkSimple2DLayoutStrategy);

#ifndef MIN
#define MIN(x, y)       ((x) < (y) ? (x) : (y))
#endif

// Cool-down function.
static inline float CoolDown(float t, float r)
{
  return t-(t/r);
}

// ----------------------------------------------------------------------

vtkSimple2DLayoutStrategy::vtkSimple2DLayoutStrategy()
{

  // Create internal vtk classes
  this->RepulsionArray = vtkFloatArray::New();
  this->AttractionArray = vtkFloatArray::New();

  this->RandomSeed = 123;
  this->IterationsPerLayout = 200;
  this->InitialTemperature = 1;
  this->CoolDownRate = 50.0;
  this->LayoutComplete = 0;
  this->EdgeWeightField = 0;
  this->SetEdgeWeightField("weight");
  this->RestDistance = 0;
  this->Jitter = true;
  this->MaxNumberOfIterations = 200;
  this->EdgeArray = NULL;
}

// ----------------------------------------------------------------------

vtkSimple2DLayoutStrategy::~vtkSimple2DLayoutStrategy()
{
  this->SetEdgeWeightField(0);
  this->RepulsionArray->Delete();
  this->AttractionArray->Delete();
}

// ----------------------------------------------------------------------

// Set the graph that will be laid out
void vtkSimple2DLayoutStrategy::Initialize()
{
  vtkMath::RandomSeed(this->RandomSeed);

  // Set up some quick access variables
  vtkPoints* pts = this->Graph->GetPoints();
  vtkIdType numVertices = this->Graph->GetNumberOfVertices();
  vtkIdType numEdges = this->Graph->GetNumberOfEdges();

  // Make sure output point type is float
  if (pts->GetData()->GetDataType() != VTK_FLOAT)
    {
    vtkErrorMacro("Layout strategy expects to have points of type float");
    this->LayoutComplete = 1;
    return;
    }

  // Get a quick pointer to the point data
  vtkFloatArray *array = vtkFloatArray::SafeDownCast(pts->GetData());
  float *rawPointData = array->GetPointer(0);

  // Avoid divide by zero
  float div = 1;
  if (numVertices > 0)
    {
    div = static_cast<float>(numVertices);
    }

  // The optimal distance between vertices.
  if (this->RestDistance == 0)
    {
    this->RestDistance = sqrt(1.0 / div);
    }

  // Set up array to store repulsion values
  this->RepulsionArray->SetNumberOfComponents(3);
  this->RepulsionArray->SetNumberOfTuples(numVertices);
  for (vtkIdType i=0; i<numVertices*3; ++i)
    {
    this->RepulsionArray->SetValue(i, 0);
    }

  // Set up array to store attraction values
  this->AttractionArray->SetNumberOfComponents(3);
  this->AttractionArray->SetNumberOfTuples(numVertices);
  for (vtkIdType i=0; i<numVertices*3; ++i)
    {
    this->AttractionArray->SetValue(i, 0);
    }

  // Put the edge data into compact, fast access edge data structure
  if (this->EdgeArray)
    {
    delete [] this->EdgeArray;
    this->EdgeArray = NULL;
    }
  this->EdgeArray =  new vtkLayoutEdge[numEdges];

  // If jitter then do it now at initialization
  if (Jitter)
    {

    // Jitter x and y, skip z
    for (vtkIdType i=0; i<numVertices*3; i+=3)
      {
      rawPointData[i] += this->RestDistance*(vtkMath::Random() - .5);
      rawPointData[i+1] += this->RestDistance*(vtkMath::Random() - .5);
      }
    }

  // Get the weight array
  vtkDataArray* weightArray = NULL;
  double weight, maxWeight = 1;
  if (this->EdgeWeightField != NULL)
    {
    weightArray = vtkDataArray::SafeDownCast(this->Graph->GetEdgeData()->GetAbstractArray(this->EdgeWeightField));
    if (weightArray != NULL)
      {
      for (vtkIdType w = 0; w < weightArray->GetNumberOfTuples(); w++)
        {
        weight = weightArray->GetTuple1(w);
        if (weight > maxWeight)
          {
          maxWeight = weight;
          }
        }
      }
    }

  // Load up the edge data structures
  for (vtkIdType i=0; i<numEdges; ++i)
    {
    this->EdgeArray[i].from = this->Graph->GetSourceVertex(i);
    this->EdgeArray[i].to = this->Graph->GetTargetVertex(i);
    if (weightArray != NULL)
      {
      weight = weightArray->GetTuple1(i);
      this->EdgeArray[i].weight = weight / maxWeight;
      }
    else
      {
      this->EdgeArray[i].weight = 1.0;
      }
    }

  // Set some vars
  this->TotalIterations = 0;
  this->LayoutComplete = 0;
  this->Temp = this->InitialTemperature;

}

// ----------------------------------------------------------------------

// Simple graph layout method
void vtkSimple2DLayoutStrategy::Layout()
{
  // Do I have a graph to layout
  if (this->Graph == NULL)
    {
    vtkErrorMacro("Graph Layout called with Graph==NULL, call SetGraph(g) first");
    this->LayoutComplete = 1;
    return;
    }

  // Set up some variables
  vtkPoints* pts = this->Graph->GetPoints();
  vtkIdType numVertices = this->Graph->GetNumberOfVertices();
  vtkIdType numEdges = this->Graph->GetNumberOfEdges();

  // Get a quick pointer to the point data
  vtkFloatArray *array = vtkFloatArray::SafeDownCast(pts->GetData());
  float *rawPointData = array->GetPointer(0);

  // This is the mega, uber, triple inner loop
  // ye of weak hearts, tread no further!
  float delta[]={0,0,0};
  float disSquared;
  float attractValue;
  float epsilon = 1e-5;
  vtkIdType pointIndex1=0;
  vtkIdType pointIndex2=0;
  for(int i = 0; i < this->IterationsPerLayout; ++i)
    {

    // Initialize the repulsion and attraction arrays
    for (vtkIdType j=0; j<numVertices*3; ++j)
      {
      this->RepulsionArray->SetValue(j, 0);
      }

    // Set up array to store attraction values
    for (vtkIdType j=0; j<numVertices*3; ++j)
      {
      this->AttractionArray->SetValue(j, 0);
      }

    // Calculate the repulsive forces
    float *rawRepulseArray = this->RepulsionArray->GetPointer(0);
    for(vtkIdType j=0; j<numVertices; ++j)
      {
      pointIndex1 = j * 3;

      for(vtkIdType k=0; k<numVertices; ++k)
        {
        // Don't repulse against yourself :)
        if (k == j) continue;

        pointIndex2 = k * 3;

        delta[0] = rawPointData[pointIndex1] -
                  rawPointData[pointIndex2];
        delta[1] = rawPointData[pointIndex1+1] -
                  rawPointData[pointIndex2+1];
        disSquared = delta[0]*delta[0] + delta[1]*delta[1];
        // Avoid divide by zero
        disSquared += epsilon;
        rawRepulseArray[pointIndex1]   += delta[0]/disSquared;
        rawRepulseArray[pointIndex1+1] += delta[1]/disSquared;
        }
      }

    // Calculate the attractive forces
    float *rawAttractArray = this->AttractionArray->GetPointer(0);
    for (vtkIdType j=0; j<numEdges; ++j)
      {
      pointIndex1 = this->EdgeArray[j].to * 3;
      pointIndex2 = this->EdgeArray[j].from * 3;

      // No need to attract points to themselves
      if (pointIndex1 == pointIndex2) continue;

      delta[0] = rawPointData[pointIndex1] -
             rawPointData[pointIndex2];
      delta[1] = rawPointData[pointIndex1+1] -
              rawPointData[pointIndex2+1];
      disSquared = delta[0]*delta[0] + delta[1]*delta[1];

      // Perform weight adjustment
      attractValue = this->EdgeArray[j].weight*disSquared-this->RestDistance;

      rawAttractArray[pointIndex1]   -= delta[0] * attractValue;
      rawAttractArray[pointIndex1+1] -= delta[1] * attractValue;
      rawAttractArray[pointIndex2]   += delta[0] * attractValue;
      rawAttractArray[pointIndex2+1] += delta[1] * attractValue;
      }

    // Okay now set new positions based on replusion
    // and attraction 'forces'
    for(vtkIdType j=0; j<numVertices; ++j)
      {
      pointIndex1 = j * 3;

      // Get forces for this node
      float forceX = rawAttractArray[pointIndex1] + rawRepulseArray[pointIndex1];
      float forceY = rawAttractArray[pointIndex1+1] + rawRepulseArray[pointIndex1+1];

      // Forces can get extreme so limit them
      // Note: This is psuedo-normalization of the
      //       force vector, just to save some cycles

      // Avoid divide by zero
      float forceDiv = fabs(forceX) + fabs(forceY) + epsilon;
      float pNormalize = MIN(1, 1.0/forceDiv);
      pNormalize *= this->Temp;
      forceX *= pNormalize;
      forceY *= pNormalize;

      rawPointData[pointIndex1] += forceX;
      rawPointData[pointIndex1+1] += forceY;
      }

    // The point coordinates have been modified
    this->Graph->GetPoints()->Modified();

    // Reduce temperature as layout approaches a better configuration.
    this->Temp = CoolDown(this->Temp, this->CoolDownRate);

    // Announce progress
    double progress = (i+this->TotalIterations) /
                      static_cast<double>(this->MaxNumberOfIterations);
    this->InvokeEvent(vtkCommand::ProgressEvent, static_cast<void *>(&progress));

   } // End loop this->IterationsPerLayout

  // Check for completion of layout
  this->TotalIterations += this->IterationsPerLayout;
  if (this->TotalIterations >= this->MaxNumberOfIterations)
    {
    // I'm done
    this->LayoutComplete = 1;
    }
}

void vtkSimple2DLayoutStrategy::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  os << indent << "RandomSeed: " << this->RandomSeed << endl;
  os << indent << "InitialTemperature: " << this->InitialTemperature << endl;
  os << indent << "MaxNumberOfIterations: " << this->MaxNumberOfIterations << endl;
  os << indent << "IterationsPerLayout: " << this->IterationsPerLayout << endl;
  os << indent << "CoolDownRate: " << this->CoolDownRate << endl;
  os << indent << "EdgeWeightField: " << (this->EdgeWeightField ? this->EdgeWeightField : "(none)") << endl;
  os << indent << "Jitter: " << (this->Jitter ? "True" : "False") << endl;
  os << indent << "RestDistance: " << this->RestDistance << endl;
}
<commit_msg>ENH: Small tweek that should help layout for small graphs.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkSimple2DLayoutStrategy.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*----------------------------------------------------------------------------
 Copyright (c) Sandia Corporation
 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
----------------------------------------------------------------------------*/

#include "vtkSimple2DLayoutStrategy.h"

#include <vtkCellArray.h>
#include <vtkCellData.h>
#include <vtkCommand.h>
#include <vtkDataArray.h>
#include <vtkFloatArray.h>
#include <vtkInformation.h>
#include <vtkInformationVector.h>
#include <vtkMath.h>
#include <vtkObjectFactory.h>
#include <vtkPointData.h>

#include "vtkAbstractGraph.h"
#include "vtkGraph.h"
#include "vtkTree.h"

vtkCxxRevisionMacro(vtkSimple2DLayoutStrategy, "1.22");
vtkStandardNewMacro(vtkSimple2DLayoutStrategy);

#ifndef MIN
#define MIN(x, y)       ((x) < (y) ? (x) : (y))
#endif

// Cool-down function.
static inline float CoolDown(float t, float r)
{
  return t-(t/r);
}

// ----------------------------------------------------------------------

vtkSimple2DLayoutStrategy::vtkSimple2DLayoutStrategy()
{

  // Create internal vtk classes
  this->RepulsionArray = vtkFloatArray::New();
  this->AttractionArray = vtkFloatArray::New();

  this->RandomSeed = 123;
  this->IterationsPerLayout = 200;
  this->InitialTemperature = 1;
  this->CoolDownRate = 50.0;
  this->LayoutComplete = 0;
  this->EdgeWeightField = 0;
  this->SetEdgeWeightField("weight");
  this->RestDistance = 0;
  this->Jitter = true;
  this->MaxNumberOfIterations = 200;
  this->EdgeArray = NULL;
}

// ----------------------------------------------------------------------

vtkSimple2DLayoutStrategy::~vtkSimple2DLayoutStrategy()
{
  this->SetEdgeWeightField(0);
  this->RepulsionArray->Delete();
  this->AttractionArray->Delete();
}

// ----------------------------------------------------------------------

// Set the graph that will be laid out
void vtkSimple2DLayoutStrategy::Initialize()
{
  vtkMath::RandomSeed(this->RandomSeed);

  // Set up some quick access variables
  vtkPoints* pts = this->Graph->GetPoints();
  vtkIdType numVertices = this->Graph->GetNumberOfVertices();
  vtkIdType numEdges = this->Graph->GetNumberOfEdges();

  // Make sure output point type is float
  if (pts->GetData()->GetDataType() != VTK_FLOAT)
    {
    vtkErrorMacro("Layout strategy expects to have points of type float");
    this->LayoutComplete = 1;
    return;
    }

  // Get a quick pointer to the point data
  vtkFloatArray *array = vtkFloatArray::SafeDownCast(pts->GetData());
  float *rawPointData = array->GetPointer(0);

  // Avoid divide by zero
  float div = 1;
  if (numVertices > 0)
    {
    div = static_cast<float>(numVertices);
    }

  // The optimal distance between vertices.
  if (this->RestDistance == 0)
    {
    this->RestDistance = 1.0/div;
    }

  // Set up array to store repulsion values
  this->RepulsionArray->SetNumberOfComponents(3);
  this->RepulsionArray->SetNumberOfTuples(numVertices);
  for (vtkIdType i=0; i<numVertices*3; ++i)
    {
    this->RepulsionArray->SetValue(i, 0);
    }

  // Set up array to store attraction values
  this->AttractionArray->SetNumberOfComponents(3);
  this->AttractionArray->SetNumberOfTuples(numVertices);
  for (vtkIdType i=0; i<numVertices*3; ++i)
    {
    this->AttractionArray->SetValue(i, 0);
    }

  // Put the edge data into compact, fast access edge data structure
  if (this->EdgeArray)
    {
    delete [] this->EdgeArray;
    this->EdgeArray = NULL;
    }
  this->EdgeArray =  new vtkLayoutEdge[numEdges];

  // If jitter then do it now at initialization
  if (Jitter)
    {

    // Jitter x and y, skip z
    for (vtkIdType i=0; i<numVertices*3; i+=3)
      {
      rawPointData[i] += this->RestDistance*(vtkMath::Random() - .5);
      rawPointData[i+1] += this->RestDistance*(vtkMath::Random() - .5);
      }
    }

  // Get the weight array
  vtkDataArray* weightArray = NULL;
  double weight, maxWeight = 1;
  if (this->EdgeWeightField != NULL)
    {
    weightArray = vtkDataArray::SafeDownCast(this->Graph->GetEdgeData()->GetAbstractArray(this->EdgeWeightField));
    if (weightArray != NULL)
      {
      for (vtkIdType w = 0; w < weightArray->GetNumberOfTuples(); w++)
        {
        weight = weightArray->GetTuple1(w);
        if (weight > maxWeight)
          {
          maxWeight = weight;
          }
        }
      }
    }

  // Load up the edge data structures
  for (vtkIdType i=0; i<numEdges; ++i)
    {
    this->EdgeArray[i].from = this->Graph->GetSourceVertex(i);
    this->EdgeArray[i].to = this->Graph->GetTargetVertex(i);
    if (weightArray != NULL)
      {
      weight = weightArray->GetTuple1(i);
      this->EdgeArray[i].weight = weight / maxWeight;
      }
    else
      {
      this->EdgeArray[i].weight = 1.0;
      }
    }

  // Set some vars
  this->TotalIterations = 0;
  this->LayoutComplete = 0;
  this->Temp = this->InitialTemperature;

}

// ----------------------------------------------------------------------

// Simple graph layout method
void vtkSimple2DLayoutStrategy::Layout()
{
  // Do I have a graph to layout
  if (this->Graph == NULL)
    {
    vtkErrorMacro("Graph Layout called with Graph==NULL, call SetGraph(g) first");
    this->LayoutComplete = 1;
    return;
    }

  // Set up some variables
  vtkPoints* pts = this->Graph->GetPoints();
  vtkIdType numVertices = this->Graph->GetNumberOfVertices();
  vtkIdType numEdges = this->Graph->GetNumberOfEdges();

  // Get a quick pointer to the point data
  vtkFloatArray *array = vtkFloatArray::SafeDownCast(pts->GetData());
  float *rawPointData = array->GetPointer(0);

  // This is the mega, uber, triple inner loop
  // ye of weak hearts, tread no further!
  float delta[]={0,0,0};
  float disSquared;
  float attractValue;
  float epsilon = 1e-5;
  vtkIdType pointIndex1=0;
  vtkIdType pointIndex2=0;
  for(int i = 0; i < this->IterationsPerLayout; ++i)
    {

    // Initialize the repulsion and attraction arrays
    for (vtkIdType j=0; j<numVertices*3; ++j)
      {
      this->RepulsionArray->SetValue(j, 0);
      }

    // Set up array to store attraction values
    for (vtkIdType j=0; j<numVertices*3; ++j)
      {
      this->AttractionArray->SetValue(j, 0);
      }

    // Calculate the repulsive forces
    float *rawRepulseArray = this->RepulsionArray->GetPointer(0);
    for(vtkIdType j=0; j<numVertices; ++j)
      {
      pointIndex1 = j * 3;

      for(vtkIdType k=0; k<numVertices; ++k)
        {
        // Don't repulse against yourself :)
        if (k == j) continue;

        pointIndex2 = k * 3;

        delta[0] = rawPointData[pointIndex1] -
                  rawPointData[pointIndex2];
        delta[1] = rawPointData[pointIndex1+1] -
                  rawPointData[pointIndex2+1];
        disSquared = delta[0]*delta[0] + delta[1]*delta[1];
        // Avoid divide by zero
        disSquared += epsilon;
        rawRepulseArray[pointIndex1]   += delta[0]/disSquared;
        rawRepulseArray[pointIndex1+1] += delta[1]/disSquared;
        }
      }

    // Calculate the attractive forces
    float *rawAttractArray = this->AttractionArray->GetPointer(0);
    for (vtkIdType j=0; j<numEdges; ++j)
      {
      pointIndex1 = this->EdgeArray[j].to * 3;
      pointIndex2 = this->EdgeArray[j].from * 3;

      // No need to attract points to themselves
      if (pointIndex1 == pointIndex2) continue;

      delta[0] = rawPointData[pointIndex1] -
             rawPointData[pointIndex2];
      delta[1] = rawPointData[pointIndex1+1] -
              rawPointData[pointIndex2+1];
      disSquared = delta[0]*delta[0] + delta[1]*delta[1];

      // Perform weight adjustment
      attractValue = this->EdgeArray[j].weight*disSquared-this->RestDistance;

      rawAttractArray[pointIndex1]   -= delta[0] * attractValue;
      rawAttractArray[pointIndex1+1] -= delta[1] * attractValue;
      rawAttractArray[pointIndex2]   += delta[0] * attractValue;
      rawAttractArray[pointIndex2+1] += delta[1] * attractValue;
      }

    // Okay now set new positions based on replusion
    // and attraction 'forces'
    for(vtkIdType j=0; j<numVertices; ++j)
      {
      pointIndex1 = j * 3;

      // Get forces for this node
      float forceX = rawAttractArray[pointIndex1] + rawRepulseArray[pointIndex1];
      float forceY = rawAttractArray[pointIndex1+1] + rawRepulseArray[pointIndex1+1];

      // Forces can get extreme so limit them
      // Note: This is psuedo-normalization of the
      //       force vector, just to save some cycles

      // Avoid divide by zero
      float forceDiv = fabs(forceX) + fabs(forceY) + epsilon;
      float pNormalize = MIN(1, 1.0/forceDiv);
      pNormalize *= this->Temp;
      forceX *= pNormalize;
      forceY *= pNormalize;

      rawPointData[pointIndex1] += forceX;
      rawPointData[pointIndex1+1] += forceY;
      }

    // The point coordinates have been modified
    this->Graph->GetPoints()->Modified();

    // Reduce temperature as layout approaches a better configuration.
    this->Temp = CoolDown(this->Temp, this->CoolDownRate);

    // Announce progress
    double progress = (i+this->TotalIterations) /
                      static_cast<double>(this->MaxNumberOfIterations);
    this->InvokeEvent(vtkCommand::ProgressEvent, static_cast<void *>(&progress));

   } // End loop this->IterationsPerLayout

  // Check for completion of layout
  this->TotalIterations += this->IterationsPerLayout;
  if (this->TotalIterations >= this->MaxNumberOfIterations)
    {
    // I'm done
    this->LayoutComplete = 1;
    }
}

void vtkSimple2DLayoutStrategy::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  os << indent << "RandomSeed: " << this->RandomSeed << endl;
  os << indent << "InitialTemperature: " << this->InitialTemperature << endl;
  os << indent << "MaxNumberOfIterations: " << this->MaxNumberOfIterations << endl;
  os << indent << "IterationsPerLayout: " << this->IterationsPerLayout << endl;
  os << indent << "CoolDownRate: " << this->CoolDownRate << endl;
  os << indent << "EdgeWeightField: " << (this->EdgeWeightField ? this->EdgeWeightField : "(none)") << endl;
  os << indent << "Jitter: " << (this->Jitter ? "True" : "False") << endl;
  os << indent << "RestDistance: " << this->RestDistance << endl;
}
<|endoftext|>


<commit_before>#include "widgetwrapper.h"
#include "qmh-config.h"
#include "qmh-util.h"
#include "backend.h"

#include <QGraphicsView>
#include <QDeclarativeView>
#include <QShortcut>

WidgetWrapper::WidgetWrapper(QWidget *prey)
    : QWidget(0),
      m_prey(prey),
      viewport(0)
{
    QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea*>(prey);

    if (scrollArea)
        viewport = scrollArea->viewport();

    prey->setParent(this);

    setOrientation(Config::value("orientation", ScreenOrientationAuto));

    Utils::optimizeWidgetAttributes(this, true);
    Utils::optimizeWidgetAttributes(prey, true);

    if (viewport) {
        //Does not appear to work here
        //Not sure why
        Utils::optimizeWidgetAttributes(viewport, true);
    }

    installEventFilter(Backend::instance());

    new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::META + Qt::ALT + Qt::Key_Backspace), this, SLOT(resetUI()));
    new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::META + Qt::ALT + Qt::Key_Down), this, SIGNAL(shrink()));
    new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::META + Qt::ALT + Qt::Key_Up), this, SIGNAL(grow()));
    new QShortcut(QKeySequence(Qt::ALT + Qt::Key_Return), this, SIGNAL(toggleFullScreen()));

    resizeSettleTimer.setSingleShot(true);

    connect(&resizeSettleTimer, SIGNAL(timeout()), this, SLOT(handleResize()));
}

WidgetWrapper::~WidgetWrapper()
{
    delete m_prey;
}

void WidgetWrapper::resizeEvent(QResizeEvent *e)
{
    Q_UNUSED(e);
    static int staggerResizingDelay = Config::value("resize-delay", 25);
    resizeSettleTimer.start(staggerResizingDelay);
}

void WidgetWrapper::setOrientation(ScreenOrientation orientation)
{
#if defined(Q_OS_SYMBIAN)
    // If the version of Qt on the device is < 4.7.2, that attribute won't work
    if (orientation != ScreenOrientationAuto) {
        const QStringList v = QString::fromAscii(qVersion()).split(QLatin1Char('.'));
        if (v.count() == 3 && (v.at(0).toInt() << 16 | v.at(1).toInt() << 8 | v.at(2).toInt()) < 0x040702) {
            qWarning("Screen orientation locking only supported with Qt 4.7.2 and above");
            return;
        }
    }
#endif // Q_OS_SYMBIAN

    Qt::WidgetAttribute attribute;
    switch (orientation) {
#if QT_VERSION < 0x040702
    // Qt < 4.7.2 does not yet have the Qt::WA_*Orientation attributes
    case ScreenOrientationLockPortrait:
        attribute = static_cast<Qt::WidgetAttribute>(128);
        break;
    case ScreenOrientationLockLandscape:
        attribute = static_cast<Qt::WidgetAttribute>(129);
        break;
    default:
    case ScreenOrientationAuto:
        attribute = static_cast<Qt::WidgetAttribute>(130);
        break;
#else // QT_VERSION < 0x040702
    case ScreenOrientationLockPortrait:
        attribute = Qt::WA_LockPortraitOrientation;
        break;
    case ScreenOrientationLockLandscape:
        attribute = Qt::WA_LockLandscapeOrientation;
        break;
    default:
    case ScreenOrientationAuto:
        attribute = Qt::WA_AutoOrientation;
        break;
#endif // QT_VERSION < 0x040702
    };
    setAttribute(attribute, true);
}

void WidgetWrapper::handleResize()
{
    m_prey->setFixedSize(size());

    //We are deliberately avoiding this functionality for QML
    //since it handles it indepedently
    QGraphicsView *gv = (QString(m_prey->metaObject()->className()).compare("QGraphicsView") == 0) ? qobject_cast<QGraphicsView*>(m_prey) : 0;
    if (gv && Config::isEnabled("scale-ui", false)) {
        gv->resetMatrix();
        gv->scale(qreal(width())/1280, qreal(height())/720);
    }
}

void WidgetWrapper::resetUI()
{
    QDeclarativeView *declarativeWidget = qobject_cast<QDeclarativeView*>(m_prey);
    if (declarativeWidget) {
        QObject* coreObject = declarativeWidget->rootObject();
        QMetaObject::invokeMethod(coreObject, "reset");
    }
}
<commit_msg>Remove dead code<commit_after>#include "widgetwrapper.h"
#include "qmh-config.h"
#include "qmh-util.h"
#include "backend.h"

#include <QGraphicsView>
#include <QDeclarativeView>
#include <QShortcut>

WidgetWrapper::WidgetWrapper(QWidget *prey)
    : QWidget(0),
      m_prey(prey),
      viewport(0)
{
    QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea*>(prey);

    if (scrollArea)
        viewport = scrollArea->viewport();

    prey->setParent(this);

    setOrientation(Config::value("orientation", ScreenOrientationAuto));

    Utils::optimizeWidgetAttributes(this, true);
    Utils::optimizeWidgetAttributes(prey, true);

    if (viewport) {
        //Does not appear to work here
        //Not sure why
        Utils::optimizeWidgetAttributes(viewport, true);
    }

    installEventFilter(Backend::instance());

    new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::META + Qt::ALT + Qt::Key_Backspace), this, SLOT(resetUI()));
    new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::META + Qt::ALT + Qt::Key_Down), this, SIGNAL(shrink()));
    new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::META + Qt::ALT + Qt::Key_Up), this, SIGNAL(grow()));
    new QShortcut(QKeySequence(Qt::ALT + Qt::Key_Return), this, SIGNAL(toggleFullScreen()));

    resizeSettleTimer.setSingleShot(true);

    connect(&resizeSettleTimer, SIGNAL(timeout()), this, SLOT(handleResize()));
}

WidgetWrapper::~WidgetWrapper()
{
    delete m_prey;
}

void WidgetWrapper::resizeEvent(QResizeEvent *e)
{
    Q_UNUSED(e);
    static int staggerResizingDelay = Config::value("resize-delay", 25);
    resizeSettleTimer.start(staggerResizingDelay);
}

void WidgetWrapper::setOrientation(ScreenOrientation orientation)
{
#if defined(Q_OS_SYMBIAN)
    // If the version of Qt on the device is < 4.7.2, that attribute won't work
    if (orientation != ScreenOrientationAuto) {
        const QStringList v = QString::fromAscii(qVersion()).split(QLatin1Char('.'));
        if (v.count() == 3 && (v.at(0).toInt() << 16 | v.at(1).toInt() << 8 | v.at(2).toInt()) < 0x040702) {
            qWarning("Screen orientation locking only supported with Qt 4.7.2 and above");
            return;
        }
    }
#endif // Q_OS_SYMBIAN

    Qt::WidgetAttribute attribute;
    switch (orientation) {
#if QT_VERSION < 0x040702
    // Qt < 4.7.2 does not yet have the Qt::WA_*Orientation attributes
    case ScreenOrientationLockPortrait:
        attribute = static_cast<Qt::WidgetAttribute>(128);
        break;
    case ScreenOrientationLockLandscape:
        attribute = static_cast<Qt::WidgetAttribute>(129);
        break;
    default:
    case ScreenOrientationAuto:
        attribute = static_cast<Qt::WidgetAttribute>(130);
        break;
#else // QT_VERSION < 0x040702
    case ScreenOrientationLockPortrait:
        attribute = Qt::WA_LockPortraitOrientation;
        break;
    case ScreenOrientationLockLandscape:
        attribute = Qt::WA_LockLandscapeOrientation;
        break;
    default:
    case ScreenOrientationAuto:
        attribute = Qt::WA_AutoOrientation;
        break;
#endif // QT_VERSION < 0x040702
    };
    setAttribute(attribute, true);
}

void WidgetWrapper::handleResize()
{
    m_prey->setFixedSize(size());
}

void WidgetWrapper::resetUI()
{
    QDeclarativeView *declarativeWidget = qobject_cast<QDeclarativeView*>(m_prey);
    if (declarativeWidget) {
        QObject* coreObject = declarativeWidget->rootObject();
        QMetaObject::invokeMethod(coreObject, "reset");
    }
}
<|endoftext|>


<commit_before>#include <unistd.h>
#include <sys/epoll.h>
#include <sys/timerfd.h>
#include <signal.h>
#include <sys/signalfd.h>
#include <sys/eventfd.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cstdint>

using namespace std;

volatile bool stop = false;

void* thread_start(void* args) {
    int evfd = reinterpret_cast<uint64_t>(args);
    while(!stop) {
        sleep(5);
        uint64_t value = 5;
        write(evfd, &value, sizeof(value));
    }
    return nullptr;
}

int main(int argc, char *argv[]) {
    printf("=======================================================================\n");
    printf("   *****event processing demonstration, process id: [%d]*****\n", getpid());
    printf("   **send SIGUSR1 to this process:\n");
    printf("   while true; do kill -s SIGUSR1 %d 1>/dev/null 2>&1; if [ $? -ne 0 ]; then break; fi; sleep 5; done\n", getpid());
    printf("   **connect to port 8080:\n");
    printf("   while true; do nc localhost 8080 1>/dev/null 2>&1; if [ $? -ne 0 ]; then break; fi; sleep 5; done\n", getpid());
    printf("=======================================================================\n");
    constexpr int MAX_EVENTS = 10;
    struct epoll_event ev, events[MAX_EVENTS];
    auto epollfd = epoll_create1(EPOLL_CLOEXEC);
    if(-1 == epollfd) {
        printf("failed to create epoll file descriptor\n");
        return EXIT_FAILURE;
    }
    // create a notify between two threads
    // potentially mimic Event on Windows platform
    auto evfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
    if(-1 == evfd) {
        printf("failed to create event file descriptor\n");
        return EXIT_FAILURE;
    }
    memset(&ev, 0, sizeof(ev));
    ev.events = EPOLLIN;
    ev.data.fd = evfd;
    if(-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, evfd, &ev)) {
        printf("failed to event file descriptor to epoll monitoring\n");
        return EXIT_FAILURE;
    }
    // add a timer firing every 60 seconds
    auto timerfd = timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC | TFD_NONBLOCK);
    if(-1 == timerfd) {
        printf("failed to create file descriptor for timer\n");
        return EXIT_FAILURE;
    }
    struct itimerspec timerspec;
    memset(&timerspec, 0, sizeof(timerspec));
    timerspec.it_interval.tv_sec = 5;
    timerspec.it_value.tv_sec = 2;
    if(-1 == timerfd_settime(timerfd, 0, &timerspec, nullptr)) {
        printf("failed to start timer\n");
        return EXIT_FAILURE;
    }
    memset(&ev, 0, sizeof(ev));
    ev.events = EPOLLIN;
    ev.data.fd = timerfd;
    if(-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, timerfd, &ev)) {
        printf("failed to add timer file descriptor to epoll monitoring\n");
        return EXIT_FAILURE;
    }
    // add signal SIGUSR1
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGUSR1);
    sigprocmask(SIG_BLOCK, &mask, nullptr);
    auto sigfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
    if(-1 == sigfd) {
        printf("failed to create file descriptor for signal\n");
        return EXIT_FAILURE;
    }
    memset(&ev, 0, sizeof(ev));
    ev.events = EPOLLIN;
    ev.data.fd = sigfd;
    if(-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, sigfd, &ev)) {
        printf("failed to add signal file descriptor to epoll monitoring\n");
        return EXIT_FAILURE;
    }
    // IMPORTANT!
    // create another thread here so that SIGUSR1 will also be blocked in new thread
    pthread_t thread;
    if(pthread_create(&thread, nullptr, thread_start, reinterpret_cast<void*>(evfd)) == -1) {
        printf("failed to create a new thread\n");
        return EXIT_FAILURE;
    }

    // add standard input file descriptor
    auto flags = fcntl(STDIN_FILENO, F_GETFL);
    flags |= O_NONBLOCK;
    if(-1 == fcntl(STDIN_FILENO, F_SETFL, flags)) {
        printf("failed to set NONBLOCK on standard input file descriptor\n");
        return EXIT_FAILURE;
    }
    memset(&ev, 0, sizeof(ev));
    ev.events = EPOLLIN;
    ev.data.fd = STDIN_FILENO;
    if(-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev)) {
        printf("failed to add stardard input file descriptor to epoll monitoring\n");
        return EXIT_FAILURE;
    }
    // add a listening socket to monitor
    auto sockfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
    if(-1 == sockfd) {
        printf("failed to create listening socket\n");
        return EXIT_FAILURE;
    }
    int enable = 1;
    if(-1 == setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable))) {
        printf("failed to set socket option\n");
        return EXIT_FAILURE;

    }
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(8080);
    if(-1 == bind(sockfd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr))) {
        printf("failed to bind listening socket\n");
        return EXIT_FAILURE;
    }
    constexpr int BACKLOG = 10;
    if(-1 == listen(sockfd, BACKLOG)) {
        printf("failed to listening socket\n");
        return EXIT_FAILURE;
    }
    memset(&ev, 0, sizeof(ev));
    ev.events = EPOLLIN;
    ev.data.fd = sockfd;
    if(-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &ev)) {
        printf("failed to add listening socket file descriptor to epoll monitoring\n");
        return EXIT_FAILURE;
    }

    // start event loop
    while(true) {
        auto nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
        for(auto i = 0; i < nfds; ++i) {
            if(timerfd == events[i].data.fd) {
                uint64_t value;
                read(timerfd, &value, sizeof(value));
                printf("timer event received, value: %lld\n", value);
            } else if(sigfd ==  events[i].data.fd) {
                struct signalfd_siginfo fdsi;
                read(sigfd, &fdsi, sizeof(fdsi));
                printf("signal event received, sender pid: %d, signal no: %d\n", fdsi.ssi_pid, fdsi.ssi_signo);
            } else if(evfd == events[i].data.fd) {
                uint64_t value;
                read(evfd, &value, sizeof(value));
                printf("thread event received, value: %lld\n", value);
            } else if(STDIN_FILENO == events[i].data.fd) {
                constexpr int BUF_SIZE = 10;
                char buf[BUF_SIZE];
                auto n = read(STDIN_FILENO, buf, sizeof(buf));
                memset(buf + n, 0, sizeof(buf) - n);
                buf[sizeof(buf)-1] = '\0';
                printf("standard input ready event received, value: %s", buf);
            } else if(sockfd == events[i].data.fd) {
                auto cfd = accept(sockfd, nullptr, nullptr);
                close(cfd);
                printf("client connection event received, connection closed\n");
            } else {
                printf("unknown event received\n");
            }
        }
        if(-1 == nfds) {
            printf("error on epoll waiting or interrupted, exit event loop\n");
            break;
        }
    }
    stop = true;
    timerfd_settime(timerfd, 0, nullptr, nullptr);
    close(timerfd);
    close(sigfd);
    close(epollfd);
    pthread_join(thread, nullptr);
    close(evfd);
    close(sockfd);
    return EXIT_SUCCESS;
}
<commit_msg>fix a error<commit_after>#include <unistd.h>
#include <sys/epoll.h>
#include <sys/timerfd.h>
#include <signal.h>
#include <sys/signalfd.h>
#include <sys/eventfd.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cstdint>

using namespace std;

volatile bool stop = false;

void* thread_start(void* args) {
    int evfd = reinterpret_cast<uint64_t>(args);
    while(!stop) {
        sleep(5);
        uint64_t value = 5;
        write(evfd, &value, sizeof(value));
    }
    return nullptr;
}

int main(int argc, char *argv[]) {
    printf("=======================================================================\n");
    printf("   *****event processing demonstration, process id: [%d]*****\n", getpid());
    printf("   **send SIGUSR1 to this process:\n");
    printf("   while true; do kill -s SIGUSR1 %d 1>/dev/null 2>&1; if [ $? -ne 0 ]; then break; fi; sleep 5; done\n", getpid());
    printf("   **connect to port 8080:\n");
    printf("   while true; do nc localhost 8080 1>/dev/null 2>&1; if [ $? -ne 0 ]; then break; fi; sleep 5; done\n", getpid());
    printf("=======================================================================\n");
    constexpr int MAX_EVENTS = 10;
    struct epoll_event ev, events[MAX_EVENTS];
    auto epollfd = epoll_create1(EPOLL_CLOEXEC);
    if(-1 == epollfd) {
        printf("failed to create epoll file descriptor\n");
        return EXIT_FAILURE;
    }
    // create a notify between two threads
    // potentially mimic Event on Windows platform
    auto evfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
    if(-1 == evfd) {
        printf("failed to create event file descriptor\n");
        return EXIT_FAILURE;
    }
    memset(&ev, 0, sizeof(ev));
    ev.events = EPOLLIN;
    ev.data.fd = evfd;
    if(-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, evfd, &ev)) {
        printf("failed to event file descriptor to epoll monitoring\n");
        return EXIT_FAILURE;
    }
    // add a timer firing every 5 seconds
    auto timerfd = timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC | TFD_NONBLOCK);
    if(-1 == timerfd) {
        printf("failed to create file descriptor for timer\n");
        return EXIT_FAILURE;
    }
    struct itimerspec timerspec;
    memset(&timerspec, 0, sizeof(timerspec));
    timerspec.it_interval.tv_sec = 5;
    timerspec.it_value.tv_sec = 2;
    if(-1 == timerfd_settime(timerfd, 0, &timerspec, nullptr)) {
        printf("failed to start timer\n");
        return EXIT_FAILURE;
    }
    memset(&ev, 0, sizeof(ev));
    ev.events = EPOLLIN;
    ev.data.fd = timerfd;
    if(-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, timerfd, &ev)) {
        printf("failed to add timer file descriptor to epoll monitoring\n");
        return EXIT_FAILURE;
    }
    // add signal SIGUSR1
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGUSR1);
    sigprocmask(SIG_BLOCK, &mask, nullptr);
    auto sigfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
    if(-1 == sigfd) {
        printf("failed to create file descriptor for signal\n");
        return EXIT_FAILURE;
    }
    memset(&ev, 0, sizeof(ev));
    ev.events = EPOLLIN;
    ev.data.fd = sigfd;
    if(-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, sigfd, &ev)) {
        printf("failed to add signal file descriptor to epoll monitoring\n");
        return EXIT_FAILURE;
    }
    // IMPORTANT!
    // create another thread here so that SIGUSR1 will also be blocked in new thread
    pthread_t thread;
    if(pthread_create(&thread, nullptr, thread_start, reinterpret_cast<void*>(evfd)) == -1) {
        printf("failed to create a new thread\n");
        return EXIT_FAILURE;
    }

    // add standard input file descriptor
    auto flags = fcntl(STDIN_FILENO, F_GETFL);
    flags |= O_NONBLOCK;
    if(-1 == fcntl(STDIN_FILENO, F_SETFL, flags)) {
        printf("failed to set NONBLOCK on standard input file descriptor\n");
        return EXIT_FAILURE;
    }
    memset(&ev, 0, sizeof(ev));
    ev.events = EPOLLIN;
    ev.data.fd = STDIN_FILENO;
    if(-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev)) {
        printf("failed to add stardard input file descriptor to epoll monitoring\n");
        return EXIT_FAILURE;
    }
    // add a listening socket to monitor
    auto sockfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
    if(-1 == sockfd) {
        printf("failed to create listening socket\n");
        return EXIT_FAILURE;
    }
    int enable = 1;
    if(-1 == setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable))) {
        printf("failed to set socket option\n");
        return EXIT_FAILURE;

    }
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(8080);
    if(-1 == bind(sockfd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr))) {
        printf("failed to bind listening socket\n");
        return EXIT_FAILURE;
    }
    constexpr int BACKLOG = 10;
    if(-1 == listen(sockfd, BACKLOG)) {
        printf("failed to listening socket\n");
        return EXIT_FAILURE;
    }
    memset(&ev, 0, sizeof(ev));
    ev.events = EPOLLIN;
    ev.data.fd = sockfd;
    if(-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &ev)) {
        printf("failed to add listening socket file descriptor to epoll monitoring\n");
        return EXIT_FAILURE;
    }

    // start event loop
    while(true) {
        auto nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
        for(auto i = 0; i < nfds; ++i) {
            if(timerfd == events[i].data.fd) {
                uint64_t value;
                read(timerfd, &value, sizeof(value));
                printf("timer event received, value: %lld\n", value);
            } else if(sigfd ==  events[i].data.fd) {
                struct signalfd_siginfo fdsi;
                read(sigfd, &fdsi, sizeof(fdsi));
                printf("signal event received, sender pid: %d, signal no: %d\n", fdsi.ssi_pid, fdsi.ssi_signo);
            } else if(evfd == events[i].data.fd) {
                uint64_t value;
                read(evfd, &value, sizeof(value));
                printf("thread event received, value: %lld\n", value);
            } else if(STDIN_FILENO == events[i].data.fd) {
                constexpr int BUF_SIZE = 10;
                char buf[BUF_SIZE];
                auto n = read(STDIN_FILENO, buf, sizeof(buf));
                memset(buf + n, 0, sizeof(buf) - n);
                buf[sizeof(buf)-1] = '\0';
                printf("standard input ready event received, value: %s", buf);
            } else if(sockfd == events[i].data.fd) {
                auto cfd = accept(sockfd, nullptr, nullptr);
                close(cfd);
                printf("client connection event received, connection closed\n");
            } else {
                printf("unknown event received\n");
            }
        }
        if(-1 == nfds) {
            printf("error on epoll waiting or interrupted, exit event loop\n");
            break;
        }
    }
    stop = true;
    timerfd_settime(timerfd, 0, nullptr, nullptr);
    close(timerfd);
    close(sigfd);
    close(epollfd);
    pthread_join(thread, nullptr);
    close(evfd);
    close(sockfd);
    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2014 Alexander Shafranov <shafranov@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include "corridormap/vec2.h"
#include "corridormap/runtime.h"
#include "debugdraw.h"

namespace corridormap {

namespace
{
    Vec2 to_image(Vec2 v, const Draw_Params& params)
    {
        Vec2 inv_dim = sub(params.bounds_max, params.bounds_min);
        inv_dim = make_vec2(1.f / inv_dim.x, 1.f / inv_dim.y);
        return mul(mul(sub(v, params.bounds_min), inv_dim), params.image_dimensions);
    }

    struct NVG_State_Scope
    {
        NVGcontext* _vg;

        NVG_State_Scope(NVGcontext* vg)
            : _vg(vg)
        {
            nvgSave(_vg);
        }

        ~NVG_State_Scope()
        {
            nvgRestore(_vg);
        }
    };
}

void draw_voronoi_diagram(NVGcontext* vg, const Draw_Params& params)
{
    // background.
    {
        NVG_State_Scope s(vg);
        nvgFillColor(vg, nvgRGB(120, 120, 120));
        nvgBeginPath(vg);
        nvgRect(vg, 0, 0, params.image_dimensions.x, params.image_dimensions.y);
        nvgFill(vg);
    }

    // obstacles.
    {
        NVG_State_Scope s(vg);
        nvgFillColor(vg, nvgRGB(255, 255, 255));

        int offset = 0;
        for (int i = 0; i < params.obstacles->num_polys; ++i)
        {
            nvgBeginPath(vg);

            Vec2 vert = make_vec2(params.obstacles->x[offset], params.obstacles->y[offset]);
            Vec2 img_vert = to_image(vert, params);
            nvgMoveTo(vg, img_vert.x, img_vert.y);

            for (int v = 1; v < params.obstacles->num_poly_verts[i]; ++v)
            {
                Vec2 vert = make_vec2(params.obstacles->x[offset + v], params.obstacles->y[offset + v]);
                Vec2 img_vert = to_image(vert, params);
                nvgLineTo(vg, img_vert.x, img_vert.y);
            }

            nvgClosePath(vg);
            nvgFill(vg);

            offset += params.obstacles->num_poly_verts[i];
        }
    }

    // edges.
    {
        NVG_State_Scope s(vg);
        nvgStrokeColor(vg, nvgRGB(0, 0, 255));
        nvgStrokeWidth(vg, 2.f);

        for (Edge* edge = first(params.diagram->edges); edge != 0; edge = next(params.diagram->edges, edge))
        {
            Half_Edge* e0 = edge->dir + 0;

            Vec2 u = to_image(source(*params.diagram, e0)->pos, params);
            Vec2 v = to_image(target(*params.diagram, e0)->pos, params);

            nvgBeginPath(vg);
            nvgMoveTo(vg, u.x, u.y);

            for (Event* e = event(*params.diagram, e0); e != 0; e = next(*params.diagram, e, 0))
            {
                Vec2 p = to_image(e->pos, params);
                nvgLineTo(vg, p.x, p.y);
            }

            nvgLineTo(vg, v.x, v.y);
            nvgStroke(vg);
        }
    }

    // events.
    {
        NVG_State_Scope s(vg);
        nvgBeginPath(vg);
        nvgStrokeColor(vg, nvgRGB(0, 0, 255));
        nvgStrokeWidth(vg, 2.f);

        for (Event* e = first(params.diagram->events); e != 0; e = next(params.diagram->events, e))
        {
            Vec2 p = to_image(e->pos, params);
            nvgCircle(vg, p.x, p.y, 4.f);
        }

        nvgStroke(vg);
    }

    // vertices.
    {
        NVG_State_Scope s(vg);
        nvgBeginPath(vg);
        nvgStrokeColor(vg, nvgRGB(0, 0, 255));
        nvgStrokeWidth(vg, 2.f);

        for (Vertex* v = first(params.diagram->vertices); v != 0; v = next(params.diagram->vertices, v))
        {
            Vec2 p = to_image(v->pos, params);
            nvgCircle(vg, p.x, p.y, 8.f);
        }

        nvgStroke(vg);
    }
}

}
<commit_msg>debug-draw: corridor bounds drawing wip.<commit_after>//
// Copyright (c) 2014 Alexander Shafranov <shafranov@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include "corridormap/vec2.h"
#include "corridormap/runtime.h"
#include "debugdraw.h"

namespace corridormap {

namespace
{
    Vec2 to_image(Vec2 v, const Draw_Params& params)
    {
        Vec2 inv_dim = sub(params.bounds_max, params.bounds_min);
        inv_dim = make_vec2(1.f / inv_dim.x, 1.f / inv_dim.y);
        return mul(mul(sub(v, params.bounds_min), inv_dim), params.image_dimensions);
    }

    struct NVG_State_Scope
    {
        NVGcontext* _vg;

        NVG_State_Scope(NVGcontext* vg)
            : _vg(vg)
        {
            nvgSave(_vg);
        }

        ~NVG_State_Scope()
        {
            nvgRestore(_vg);
        }
    };
}

void draw_voronoi_diagram(NVGcontext* vg, const Draw_Params& params)
{
    // background.
    {
        NVG_State_Scope s(vg);
        nvgFillColor(vg, nvgRGB(120, 120, 120));
        nvgBeginPath(vg);
        nvgRect(vg, 0, 0, params.image_dimensions.x, params.image_dimensions.y);
        nvgFill(vg);
    }

    // obstacles.
    {
        NVG_State_Scope s(vg);
        nvgFillColor(vg, nvgRGB(255, 255, 255));

        int offset = 0;
        for (int i = 0; i < params.obstacles->num_polys; ++i)
        {
            nvgBeginPath(vg);

            Vec2 vert = make_vec2(params.obstacles->x[offset], params.obstacles->y[offset]);
            Vec2 img_vert = to_image(vert, params);
            nvgMoveTo(vg, img_vert.x, img_vert.y);

            for (int v = 1; v < params.obstacles->num_poly_verts[i]; ++v)
            {
                Vec2 vert = make_vec2(params.obstacles->x[offset + v], params.obstacles->y[offset + v]);
                Vec2 img_vert = to_image(vert, params);
                nvgLineTo(vg, img_vert.x, img_vert.y);
            }

            nvgClosePath(vg);
            nvgFill(vg);

            offset += params.obstacles->num_poly_verts[i];
        }
    }

    // edges.
    {
        NVG_State_Scope s(vg);
        nvgStrokeColor(vg, nvgRGB(0, 0, 255));
        nvgStrokeWidth(vg, 2.f);

        for (Edge* edge = first(params.diagram->edges); edge != 0; edge = next(params.diagram->edges, edge))
        {
            Half_Edge* e0 = edge->dir + 0;

            Vec2 u = to_image(source(*params.diagram, e0)->pos, params);
            Vec2 v = to_image(target(*params.diagram, e0)->pos, params);

            nvgBeginPath(vg);
            nvgMoveTo(vg, u.x, u.y);

            for (Event* e = event(*params.diagram, e0); e != 0; e = next(*params.diagram, e, 0))
            {
                Vec2 p = to_image(e->pos, params);
                nvgLineTo(vg, p.x, p.y);
            }

            nvgLineTo(vg, v.x, v.y);
            nvgStroke(vg);
        }
    }

    // events.
    {
        NVG_State_Scope s(vg);
        nvgBeginPath(vg);
        nvgStrokeColor(vg, nvgRGB(0, 0, 255));
        nvgStrokeWidth(vg, 2.f);

        for (Event* e = first(params.diagram->events); e != 0; e = next(params.diagram->events, e))
        {
            Vec2 p = to_image(e->pos, params);
            nvgCircle(vg, p.x, p.y, 4.f);
        }

        nvgStroke(vg);
    }

    // vertices.
    {
        NVG_State_Scope s(vg);
        nvgBeginPath(vg);
        nvgStrokeColor(vg, nvgRGB(0, 0, 255));
        nvgStrokeWidth(vg, 2.f);

        for (Vertex* v = first(params.diagram->vertices); v != 0; v = next(params.diagram->vertices, v))
        {
            Vec2 p = to_image(v->pos, params);
            nvgCircle(vg, p.x, p.y, 8.f);
        }

        nvgStroke(vg);
    }

    // corridor bounds.
    {
        NVG_State_Scope s(vg);
        nvgStrokeColor(vg, nvgRGB(255, 0, 0));
        nvgStrokeWidth(vg, 2.f);

        for (Edge* edge = first(params.diagram->edges); edge != 0; edge = next(params.diagram->edges, edge))
        {
            Half_Edge* e0 = edge->dir + 0;
            Vec2 u = to_image(source(*params.diagram, e0)->pos, params);

            nvgBeginPath(vg);
            nvgMoveTo(vg, u.x, u.y);

            for (Event* e = event(*params.diagram, e0); e != 0; e = next(*params.diagram, e, 0))
            {
                Vec2 diff = sub(e->sides[0], e->pos);
                float dist = len(diff);
                Vec2 n = normalized(diff);
                Vec2 p = add(e->pos, scale(n, dist * 0.6f));
                p = to_image(p, params);
                nvgLineTo(vg, p.x, p.y);
            }

            nvgStroke(vg);

            nvgBeginPath(vg);
            nvgMoveTo(vg, u.x, u.y);

            for (Event* e = event(*params.diagram, e0); e != 0; e = next(*params.diagram, e, 1))
            {
                Vec2 diff = sub(e->sides[1], e->pos);
                float dist = len(diff);
                Vec2 n = normalized(diff);
                Vec2 p = add(e->pos, scale(n, dist * 0.6f));
                p = to_image(p, params);
                nvgLineTo(vg, p.x, p.y);
            }

            nvgStroke(vg);
        }
    }
}

}
<|endoftext|>


<commit_before>#include "Vector2.h"

#include <ostream>

#ifndef M_PI
#define M_PI 3.14159265358979323846264338327
#endif

#ifndef EQ_THRESHOLD
#define EQ_THRESHOLD 0.00001
#endif

std::ostream& operator<<(std::ostream& os, const Vector2& v)
{
	os << "(" << v.x << ", " << v.y << ")";
	return os;
}

Vector2::Vector2() :
	x(0.0),
	y(0.0)
{

}

Vector2::Vector2(double angle) :
	x(cos(angle * M_PI / 180)),
	y(sin(angle * M_PI / 180))
{

}

Vector2::Vector2(double _x, double _y) :
	x(_x),
	y(_y)
{

}

Vector2::Vector2(const Vector2& v1, const Vector2& v2) :
	x(v2.x - v1.x),
	y(v2.y - v1.y)
{

}

Vector2::~Vector2()
{

}

Vector2::Vector2(const Vector2& v) :
	x(v.x),
	y(v.y)
{

}

Vector2::Vector2(Vector2&& v) :
	x(v.x),
	y(v.y)
{

}

Vector2& Vector2::operator=(const Vector2& v)
{
	if (&v == this)
	{
		return *this;
	}

	x = v.x;
	y = v.y;

	return *this;
}

Vector2& Vector2::operator=(Vector2&& v)
{
	if (&v == this)
	{
		return *this;
	}

	x = v.x;
	y = v.y;

	return *this;
}

Vector2& Vector2::operator+=(const Vector2& v)
{
	x += v.x;
	y += v.y;

	return *this;
}

Vector2& Vector2::operator+=(const double f)
{
	x += f;
	y += f;

	return *this;
}

Vector2& Vector2::operator-=(const Vector2& v)
{
	x -= v.x;
	y -= v.y;

	return *this;
}

Vector2& Vector2::operator-=(const double f)
{
	x -= f;
	y -= f;

	return *this;
}

Vector2& Vector2::operator*=(const double f)
{
	x *= f;
	y *= f;

	return *this;
}

Vector2& Vector2::operator/=(const double f)
{
	x /= f;
	y /= f;

	return *this;
}

bool Vector2::operator==(const Vector2& v) const
{
	double diffX = abs(x - v.x);
	double diffY = abs(y - v.y);

	return diffX < EQ_THRESHOLD && diffY < EQ_THRESHOLD;
}

bool Vector2::operator!=(const Vector2& v) const
{
	return !(*this == v);
}

void Vector2::Normalize()
{
	double mod = Length();

	if (mod > 0)
	{
		x /= mod;
		y /= mod;
	}
}

void Vector2::Reflect(const Vector2& v)
{
	*this += 2.0 * DotProduct(v) * Vector2(v.x * -1, v.y * -1);
}

void Vector2::Reverse()
{
	x *= -1;
	y *= -1;
}

void Vector2::Truncate(double maxLength)
{
	if (Length() > maxLength)
	{
		Normalize();
		*this *= maxLength;
	}
}

void Vector2::RotateByDegree(double degree)
{
	RotateByRadian(degree * M_PI / 180);
}

void Vector2::RotateByRadian(double radian)
{
	double newX = x * cos(radian) - y * sin(radian);
	double newY = x * sin(radian) + y * cos(radian);

	x = newX;
	y = newY;
}

double Vector2::DotProduct(const Vector2& v) const
{
	return x * v.x + y * v.y;
}

double Vector2::CrossProduct(const Vector2& v) const
{
	return x * v.y - v.x * y;
}

double Vector2::Length() const
{
	return sqrt(x * x + y * y);
}

double Vector2::LengthSqrt() const
{
	return x * x + y * y;
}<commit_msg>Implement Distance(), DistanceSqrt()<commit_after>#include "Vector2.h"

#include <ostream>

#ifndef M_PI
#define M_PI 3.14159265358979323846264338327
#endif

#ifndef EQ_THRESHOLD
#define EQ_THRESHOLD 0.00001
#endif

std::ostream& operator<<(std::ostream& os, const Vector2& v)
{
	os << "(" << v.x << ", " << v.y << ")";
	return os;
}

Vector2::Vector2() :
	x(0.0),
	y(0.0)
{

}

Vector2::Vector2(double angle) :
	x(cos(angle * M_PI / 180)),
	y(sin(angle * M_PI / 180))
{

}

Vector2::Vector2(double _x, double _y) :
	x(_x),
	y(_y)
{

}

Vector2::Vector2(const Vector2& v1, const Vector2& v2) :
	x(v2.x - v1.x),
	y(v2.y - v1.y)
{

}

Vector2::~Vector2()
{

}

Vector2::Vector2(const Vector2& v) :
	x(v.x),
	y(v.y)
{

}

Vector2::Vector2(Vector2&& v) :
	x(v.x),
	y(v.y)
{

}

Vector2& Vector2::operator=(const Vector2& v)
{
	if (&v == this)
	{
		return *this;
	}

	x = v.x;
	y = v.y;

	return *this;
}

Vector2& Vector2::operator=(Vector2&& v)
{
	if (&v == this)
	{
		return *this;
	}

	x = v.x;
	y = v.y;

	return *this;
}

Vector2& Vector2::operator+=(const Vector2& v)
{
	x += v.x;
	y += v.y;

	return *this;
}

Vector2& Vector2::operator+=(const double f)
{
	x += f;
	y += f;

	return *this;
}

Vector2& Vector2::operator-=(const Vector2& v)
{
	x -= v.x;
	y -= v.y;

	return *this;
}

Vector2& Vector2::operator-=(const double f)
{
	x -= f;
	y -= f;

	return *this;
}

Vector2& Vector2::operator*=(const double f)
{
	x *= f;
	y *= f;

	return *this;
}

Vector2& Vector2::operator/=(const double f)
{
	x /= f;
	y /= f;

	return *this;
}

bool Vector2::operator==(const Vector2& v) const
{
	double diffX = abs(x - v.x);
	double diffY = abs(y - v.y);

	return diffX < EQ_THRESHOLD && diffY < EQ_THRESHOLD;
}

bool Vector2::operator!=(const Vector2& v) const
{
	return !(*this == v);
}

void Vector2::Normalize()
{
	double mod = Length();

	if (mod > 0)
	{
		x /= mod;
		y /= mod;
	}
}

void Vector2::Reflect(const Vector2& v)
{
	*this += 2.0 * DotProduct(v) * Vector2(v.x * -1, v.y * -1);
}

void Vector2::Reverse()
{
	x *= -1;
	y *= -1;
}

void Vector2::Truncate(double maxLength)
{
	if (Length() > maxLength)
	{
		Normalize();
		*this *= maxLength;
	}
}

void Vector2::RotateByDegree(double degree)
{
	RotateByRadian(degree * M_PI / 180);
}

void Vector2::RotateByRadian(double radian)
{
	double newX = x * cos(radian) - y * sin(radian);
	double newY = x * sin(radian) + y * cos(radian);

	x = newX;
	y = newY;
}

double Vector2::DotProduct(const Vector2& v) const
{
	return x * v.x + y * v.y;
}

double Vector2::CrossProduct(const Vector2& v) const
{
	return x * v.y - v.x * y;
}

double Vector2::Length() const
{
	return sqrt(x * x + y * y);
}

double Vector2::LengthSqrt() const
{
	return x * x + y * y;
}

double Vector2::Distance(const Vector2& v) const
{
	Vector2 dist(*this, v);
	return dist.Length();
}

double Vector2::DistanceSqrt(const Vector2& v) const
{
	Vector2 dist(*this, v);
	return dist.LengthSqrt();
}<|endoftext|>


<commit_before>/* Jim Viebke
May 15 2015 */

#include "player_character.h"
#include "npc_enemy.h"
#include "npc_unaffiliated.h"

string PC::print() const
{
	stringstream output;

	// if the player is carrying any materials, list them above equipment
	if (material_inventory.size() > 0)
	{
		for (multimap<string, shared_ptr<Material>>::const_iterator item_it = material_inventory.cbegin(); // for each item
			item_it != material_inventory.cend(); ++item_it)
		{
			output << item_it->second->name << " (x" << item_it->second->amount << ") "; // add its name to the output: stick (x5)
		}
	}

	// if the player is carrying any equipment, list them after materials
	if (equipment_inventory.size() > 0) // if the player is carrying anything
	{
		for (multimap<string, shared_ptr<Equipment>>::const_iterator item_it = equipment_inventory.cbegin(); // for each item
			item_it != equipment_inventory.cend(); ++item_it)
		{
			output << item_it->second->name << " "; // add its name to the output
		}
	}

	return (output.str().size() > 0) ? // if there is anything to print
		"You have " + output.str() : // return the output
		"You aren't carrying anything."; // return generic "no items" message
}

// Build and return a top-down area map around a given coordinate
string PC::generate_area_map(const World & world, const map<string, shared_ptr<Character>> & actors) const
{
	bool
		// is a wall present in a given direction?
		n, e, s, w, // "north"

		// is there a door present in a given location?
		nd, ed, sd, wd, // "north door?"

		// is a wall rubble in a given direction?
		nr, er, sr, wr, // "north rubble?"

		// is a forest area in a given direction from a coordinate? (f_n == forest_north)
		f_n, f_ne, f_e, f_se, f_s, f_sw, f_w, f_nw;

	stringstream user_map, a, b, c; // three stringstreams feed into one master stringstream

	// create a 2D vector to represent whether or not a tree is at a location
	vector<vector<bool>> forest_grid;
	for (int i = 0; i < (C::VIEW_DISTANCE * 2) + 3; ++i) // (view+1+view) plus a padding of 1 on each side
	{
		vector<bool> row;
		for (int j = 0; j < (C::VIEW_DISTANCE * 2) + 3; ++j)
		{
			row.push_back(false);
		}
		forest_grid.push_back(row);
	}

	/*
	We're looking for presence/absence info on trees in a 11*11 radius, and fitting it into a 13x13 grid, with a ring around for bounds padding.

	Top row is an example of indexes, botttom row is the forest_grid indexes these have to line up with

	player ---------v
	45 46 47 48 49 (50) 51 52 53 54 55
	1   2  3  4  5   6   7  8  9 10 11

	The following formula is applied to the indexes we're iterating over:
	tree_grid index = current index - (player index - (view distance + 1)) */
	for (int cx = x - (int)C::VIEW_DISTANCE; cx <= x + (int)C::VIEW_DISTANCE; ++cx)
	{
		int i = cx - (x - (C::VIEW_DISTANCE + 1));
		for (int cy = y - (int)C::VIEW_DISTANCE; cy <= y + (int)C::VIEW_DISTANCE; ++cy)
		{
			if (R::bounds_check(cx, cy))
			{
				forest_grid[i][cy - (y - (C::VIEW_DISTANCE + 1))] = world.room_at(cx, cy, C::GROUND_INDEX)->contains_item(C::TREE_ID);
			}
		}
	}

	/* for each row in sight range
	for each room in sight range in the row
	set n, e, s, w to(room contains surface ? ); */
	for (int cx = x - (int)C::VIEW_DISTANCE; cx <= x + (int)C::VIEW_DISTANCE; ++cx)
	{
		for (int cy = y - (int)C::VIEW_DISTANCE; cy <= y + (int)C::VIEW_DISTANCE; ++cy)
		{
			// if the room is out of bounds
			if (!R::bounds_check(cx, cy, C::GROUND_INDEX))
			{
				// draw the "room"
				a << "***";
				b << "***";
				c << "***";

				// nothing left to do with this room, skip to next room
				continue;
			}

			// if the coordinates are valid but the room is not loaded (this would be an error)
			if (world.room_at(cx, cy, C::GROUND_INDEX) == nullptr)
			{
				// draw the room as an exclaimation mark
				a << "   ";
				b << " ! ";
				c << "   ";

				// skip to next room
				continue;
			}

			// if there is a forest char at the given location
			// Somehow a tree is currently chosen to represent a forest room.

			// 23 24 25 26 27 (28) 29 30 31 32 33

			//  1  2  3  4  5   6   7  8  9 10 11

			// access_x = current index - (player index - (view distance + 1)) */
			//      1   =     23        - (      28     - (    5        + 1 ))

			// FGA = forest grid access
			int fga_x = cx - (x - (C::VIEW_DISTANCE + 1));
			int fga_y = cy - (y - (C::VIEW_DISTANCE + 1));
			if (forest_grid[fga_x][fga_y]) // if there is a tree here, determine how the tile should be drawn
			{
				// is a forest area at the neighbouring coordinates? f_n == forest_north
				f_n = forest_grid[fga_x - 1][fga_y];
				f_ne = forest_grid[fga_x - 1][fga_y + 1];
				f_e = forest_grid[fga_x][fga_y + 1];
				f_se = forest_grid[fga_x + 1][fga_y + 1];
				f_s = forest_grid[fga_x + 1][fga_y];
				f_sw = forest_grid[fga_x + 1][fga_y - 1];
				f_w = forest_grid[fga_x][fga_y - 1];
				f_nw = forest_grid[fga_x - 1][fga_y - 1];

				// conditionally draw a tree or an empty space in the corners, other five are always draw as trees
				a << ((f_n || f_nw || f_w) ? C::FOREST_CHAR : C::LAND_CHAR) << C::FOREST_CHAR << ((f_n || f_ne || f_e) ? C::FOREST_CHAR : C::LAND_CHAR);
				b << C::FOREST_CHAR << ((cx == x && cy == y) ? C::PLAYER_CHAR : C::FOREST_CHAR) << C::FOREST_CHAR;
				c << ((f_s || f_sw || f_w) ? C::FOREST_CHAR : C::LAND_CHAR) << C::FOREST_CHAR << ((f_s || f_se || f_e) ? C::FOREST_CHAR : C::LAND_CHAR);
			}
			// if the room is water
			else if (world.room_at(cx, cy, C::GROUND_INDEX)->is_water())
			{
				// Either draw a 3x3 grid with a "wave", or a 3x3 grid with the player's icon.

				a << "   ";
				b << " " << ((cx == x && cy == y) ? C::PLAYER_CHAR : C::WATER_CHAR) << " ";
				c << "   ";
			}
			// there is no tree, so there may be a structure
			else
			{
				// use a boolean value to indicate the presence or absence of a wall
				n = world.room_at(cx, cy, C::GROUND_INDEX)->has_surface(C::NORTH);
				e = world.room_at(cx, cy, C::GROUND_INDEX)->has_surface(C::EAST);
				s = world.room_at(cx, cy, C::GROUND_INDEX)->has_surface(C::SOUTH);
				w = world.room_at(cx, cy, C::GROUND_INDEX)->has_surface(C::WEST);

				nd = ed = sd = wd = nr = er = sr = wr = false; // set all door and rubble flags to false

				/*
				if a north wall is present
				-- north_has_door = room_at(x, y, z)...(surface_ID)...has_door();
				-- north_is_rubble = (the wall is rubble OR
				-- -- (a door exists AND the door is rubble)
				*/
				if (n)
				{
					nd = world.room_at(cx, cy, C::GROUND_INDEX)->get_room_sides().find(C::NORTH)->second.has_door();
					nr = (!world.room_at(cx, cy, C::GROUND_INDEX)->is_standing_wall(C::NORTH) ||
						(nd && world.room_at(cx, cy, C::GROUND_INDEX)->get_room_sides().find(C::NORTH)->second.get_door()->is_rubble()));
				}
				if (e)
				{
					ed = world.room_at(cx, cy, C::GROUND_INDEX)->get_room_sides().find(C::EAST)->second.has_door();
					er = (!world.room_at(cx, cy, C::GROUND_INDEX)->is_standing_wall(C::EAST) ||
						(ed && world.room_at(cx, cy, C::GROUND_INDEX)->get_room_sides().find(C::EAST)->second.get_door()->is_rubble()));
				}
				if (s)
				{
					sd = world.room_at(cx, cy, C::GROUND_INDEX)->get_room_sides().find(C::SOUTH)->second.has_door();
					sr = (!world.room_at(cx, cy, C::GROUND_INDEX)->is_standing_wall(C::SOUTH) ||
						(sd && world.room_at(cx, cy, C::GROUND_INDEX)->get_room_sides().find(C::SOUTH)->second.get_door()->is_rubble()));
				}
				if (w)
				{
					wd = world.room_at(cx, cy, C::GROUND_INDEX)->get_room_sides().find(C::WEST)->second.has_door();
					wr = (!world.room_at(cx, cy, C::GROUND_INDEX)->is_standing_wall(C::WEST) ||
						(wd && world.room_at(cx, cy, C::GROUND_INDEX)->get_room_sides().find(C::WEST)->second.get_door()->is_rubble()));
				}

				// count the enemies standing at a coordinate
				unsigned enemy_count = 0, neutral_count = 0;
				// for each actor in the room
				for (const string & actor_ID : world.room_at(cx, cy, z)->get_actor_ids())
				{
					// if the actor is a hostile NPC
					if (R::is<Hostile_NPC>(actors.find(actor_ID)->second))
					{
						++enemy_count; // count one more enemy in the room
					}
					else if (R::is<Neutral_NPC>(actors.find(actor_ID)->second))
					{
						++neutral_count;
					}
				}
				// reduce enemy count to a single-digit number
				enemy_count = ((enemy_count > 9) ? 9 : enemy_count);

				// debugging only
				if (enemy_count > 0) { cout << "\nAt " << cx << "," << cy << " there are " << enemy_count << " enemies."; }
				if (neutral_count > 0) { cout << "\nAt " << cx << "," << cy << " there are " << neutral_count << " neutrals."; }

				// time for glorious nested ternary statements to do this cheap
				a
					<< ((n && w) ? C::NW_CORNER : (n) ? C::WE_WALL : (w) ? C::NS_WALL : C::LAND_CHAR)
					<< ((nr) ? C::RUBBLE_CHAR : ((nd) ? C::WE_DOOR : ((n) ? C::WE_WALL : C::LAND_CHAR)))
					<< ((n && e) ? C::NE_CORNER : (n) ? C::WE_WALL : (e) ? C::NS_WALL : C::LAND_CHAR);
				b
					<< ((wr) ? C::RUBBLE_CHAR : ((wd) ? C::NS_DOOR : ((w) ? C::NS_WALL : C::LAND_CHAR)))
					// if the current coordinates are the player's, draw an @ icon, else if there is an enemy, draw enemy count, else if there is an item, draw an item char, else empty
					<< ((cx == x && cy == y) ? C::PLAYER_CHAR : ((enemy_count > 0) ? R::to_char(enemy_count) : ((neutral_count > 0) ? C::NPC_NEUTRAL_CHAR : ((world.room_at(cx, cy, C::GROUND_INDEX)->contains_no_items()) ? C::LAND_CHAR : C::ITEM_CHAR))))
					<< ((er) ? C::RUBBLE_CHAR : ((ed) ? C::NS_DOOR : ((e) ? C::NS_WALL : C::LAND_CHAR)));
				c
					<< ((s && w) ? C::SW_CORNER : (s) ? C::WE_WALL : (w) ? C::NS_WALL : C::LAND_CHAR)
					<< ((sr) ? C::RUBBLE_CHAR : ((sd) ? C::WE_DOOR : ((s) ? C::WE_WALL : C::LAND_CHAR)))
					<< ((s && e) ? C::SE_CORNER : (s) ? C::WE_WALL : (e) ? C::NS_WALL : C::LAND_CHAR);
			}
		} // end for each room in row

		// each iteration, push the three stringstreams representing the row into the user's map
		user_map << a.str() << endl << b.str() << endl << c.str() << endl;

		// reset the stringstreams for the next row of rooms
		a.str(std::string()); b.str(std::string()); c.str(std::string());
	} // end for each row

	return user_map.str(); // this now contains the client's entire visible area. No formatting is required, just dump this to console.
}
<commit_msg>update appearance of unloaded rooms on the map<commit_after>/* Jim Viebke
May 15 2015 */

#include "player_character.h"
#include "npc_enemy.h"
#include "npc_unaffiliated.h"

string PC::print() const
{
	stringstream output;

	// if the player is carrying any materials, list them above equipment
	if (material_inventory.size() > 0)
	{
		for (multimap<string, shared_ptr<Material>>::const_iterator item_it = material_inventory.cbegin(); // for each item
			item_it != material_inventory.cend(); ++item_it)
		{
			output << item_it->second->name << " (x" << item_it->second->amount << ") "; // add its name to the output: stick (x5)
		}
	}

	// if the player is carrying any equipment, list them after materials
	if (equipment_inventory.size() > 0) // if the player is carrying anything
	{
		for (multimap<string, shared_ptr<Equipment>>::const_iterator item_it = equipment_inventory.cbegin(); // for each item
			item_it != equipment_inventory.cend(); ++item_it)
		{
			output << item_it->second->name << " "; // add its name to the output
		}
	}

	return (output.str().size() > 0) ? // if there is anything to print
		"You have " + output.str() : // return the output
		"You aren't carrying anything."; // return generic "no items" message
}

// Build and return a top-down area map around a given coordinate
string PC::generate_area_map(const World & world, const map<string, shared_ptr<Character>> & actors) const
{
	bool
		// is a wall present in a given direction?
		n, e, s, w, // "north"

		// is there a door present in a given location?
		nd, ed, sd, wd, // "north door?"

		// is a wall rubble in a given direction?
		nr, er, sr, wr, // "north rubble?"

		// is a forest area in a given direction from a coordinate? (f_n == forest_north)
		f_n, f_ne, f_e, f_se, f_s, f_sw, f_w, f_nw;

	stringstream user_map, a, b, c; // three stringstreams feed into one master stringstream

	// create a 2D vector to represent whether or not a tree is at a location
	vector<vector<bool>> forest_grid;
	for (int i = 0; i < (C::VIEW_DISTANCE * 2) + 3; ++i) // (view+1+view) plus a padding of 1 on each side
	{
		vector<bool> row;
		for (int j = 0; j < (C::VIEW_DISTANCE * 2) + 3; ++j)
		{
			row.push_back(false);
		}
		forest_grid.push_back(row);
	}

	/*
	We're looking for presence/absence info on trees in a 11*11 radius, and fitting it into a 13x13 grid, with a ring around for bounds padding.

	Top row is an example of indexes, botttom row is the forest_grid indexes these have to line up with

	player ---------v
	45 46 47 48 49 (50) 51 52 53 54 55
	1   2  3  4  5   6   7  8  9 10 11

	The following formula is applied to the indexes we're iterating over:
	tree_grid index = current index - (player index - (view distance + 1)) */
	for (int cx = x - (int)C::VIEW_DISTANCE; cx <= x + (int)C::VIEW_DISTANCE; ++cx)
	{
		int i = cx - (x - (C::VIEW_DISTANCE + 1));
		for (int cy = y - (int)C::VIEW_DISTANCE; cy <= y + (int)C::VIEW_DISTANCE; ++cy)
		{
			if (R::bounds_check(cx, cy))
			{
				forest_grid[i][cy - (y - (C::VIEW_DISTANCE + 1))] = world.room_at(cx, cy, C::GROUND_INDEX)->contains_item(C::TREE_ID);
			}
		}
	}

	/* for each row in sight range
	for each room in sight range in the row
	set n, e, s, w to(room contains surface ? ); */
	for (int cx = x - (int)C::VIEW_DISTANCE; cx <= x + (int)C::VIEW_DISTANCE; ++cx)
	{
		for (int cy = y - (int)C::VIEW_DISTANCE; cy <= y + (int)C::VIEW_DISTANCE; ++cy)
		{
			// if the room is out of bounds
			if (!R::bounds_check(cx, cy, C::GROUND_INDEX))
			{
				// draw the "room"
				a << "***";
				b << "***";
				c << "***";

				// nothing left to do with this room, skip to next room
				continue;
			}

			// if the coordinates are valid but the room is not loaded (this would be an error)
			if (world.room_at(cx, cy, C::GROUND_INDEX) == nullptr)
			{
				// draw the room with "err"
				a << "! !";
				b << "err";
				c << "! !";

				// skip to next room
				continue;
			}

			// if there is a forest char at the given location
			// Somehow a tree is currently chosen to represent a forest room.

			// 23 24 25 26 27 (28) 29 30 31 32 33

			//  1  2  3  4  5   6   7  8  9 10 11

			// access_x = current index - (player index - (view distance + 1)) */
			//      1   =     23        - (      28     - (    5        + 1 ))

			// FGA = forest grid access
			int fga_x = cx - (x - (C::VIEW_DISTANCE + 1));
			int fga_y = cy - (y - (C::VIEW_DISTANCE + 1));
			if (forest_grid[fga_x][fga_y]) // if there is a tree here, determine how the tile should be drawn
			{
				// is a forest area at the neighbouring coordinates? f_n == forest_north
				f_n = forest_grid[fga_x - 1][fga_y];
				f_ne = forest_grid[fga_x - 1][fga_y + 1];
				f_e = forest_grid[fga_x][fga_y + 1];
				f_se = forest_grid[fga_x + 1][fga_y + 1];
				f_s = forest_grid[fga_x + 1][fga_y];
				f_sw = forest_grid[fga_x + 1][fga_y - 1];
				f_w = forest_grid[fga_x][fga_y - 1];
				f_nw = forest_grid[fga_x - 1][fga_y - 1];

				// conditionally draw a tree or an empty space in the corners, other five are always draw as trees
				a << ((f_n || f_nw || f_w) ? C::FOREST_CHAR : C::LAND_CHAR) << C::FOREST_CHAR << ((f_n || f_ne || f_e) ? C::FOREST_CHAR : C::LAND_CHAR);
				b << C::FOREST_CHAR << ((cx == x && cy == y) ? C::PLAYER_CHAR : C::FOREST_CHAR) << C::FOREST_CHAR;
				c << ((f_s || f_sw || f_w) ? C::FOREST_CHAR : C::LAND_CHAR) << C::FOREST_CHAR << ((f_s || f_se || f_e) ? C::FOREST_CHAR : C::LAND_CHAR);
			}
			// if the room is water
			else if (world.room_at(cx, cy, C::GROUND_INDEX)->is_water())
			{
				// Either draw a 3x3 grid with a "wave", or a 3x3 grid with the player's icon.

				a << "   ";
				b << " " << ((cx == x && cy == y) ? C::PLAYER_CHAR : C::WATER_CHAR) << " ";
				c << "   ";
			}
			// there is no tree, so there may be a structure
			else
			{
				// use a boolean value to indicate the presence or absence of a wall
				n = world.room_at(cx, cy, C::GROUND_INDEX)->has_surface(C::NORTH);
				e = world.room_at(cx, cy, C::GROUND_INDEX)->has_surface(C::EAST);
				s = world.room_at(cx, cy, C::GROUND_INDEX)->has_surface(C::SOUTH);
				w = world.room_at(cx, cy, C::GROUND_INDEX)->has_surface(C::WEST);

				nd = ed = sd = wd = nr = er = sr = wr = false; // set all door and rubble flags to false

				/*
				if a north wall is present
				-- north_has_door = room_at(x, y, z)...(surface_ID)...has_door();
				-- north_is_rubble = (the wall is rubble OR
				-- -- (a door exists AND the door is rubble)
				*/
				if (n)
				{
					nd = world.room_at(cx, cy, C::GROUND_INDEX)->get_room_sides().find(C::NORTH)->second.has_door();
					nr = (!world.room_at(cx, cy, C::GROUND_INDEX)->is_standing_wall(C::NORTH) ||
						(nd && world.room_at(cx, cy, C::GROUND_INDEX)->get_room_sides().find(C::NORTH)->second.get_door()->is_rubble()));
				}
				if (e)
				{
					ed = world.room_at(cx, cy, C::GROUND_INDEX)->get_room_sides().find(C::EAST)->second.has_door();
					er = (!world.room_at(cx, cy, C::GROUND_INDEX)->is_standing_wall(C::EAST) ||
						(ed && world.room_at(cx, cy, C::GROUND_INDEX)->get_room_sides().find(C::EAST)->second.get_door()->is_rubble()));
				}
				if (s)
				{
					sd = world.room_at(cx, cy, C::GROUND_INDEX)->get_room_sides().find(C::SOUTH)->second.has_door();
					sr = (!world.room_at(cx, cy, C::GROUND_INDEX)->is_standing_wall(C::SOUTH) ||
						(sd && world.room_at(cx, cy, C::GROUND_INDEX)->get_room_sides().find(C::SOUTH)->second.get_door()->is_rubble()));
				}
				if (w)
				{
					wd = world.room_at(cx, cy, C::GROUND_INDEX)->get_room_sides().find(C::WEST)->second.has_door();
					wr = (!world.room_at(cx, cy, C::GROUND_INDEX)->is_standing_wall(C::WEST) ||
						(wd && world.room_at(cx, cy, C::GROUND_INDEX)->get_room_sides().find(C::WEST)->second.get_door()->is_rubble()));
				}

				// count the enemies standing at a coordinate
				unsigned enemy_count = 0, neutral_count = 0;
				// for each actor in the room
				for (const string & actor_ID : world.room_at(cx, cy, z)->get_actor_ids())
				{
					// if the actor is a hostile NPC
					if (R::is<Hostile_NPC>(actors.find(actor_ID)->second))
					{
						++enemy_count; // count one more enemy in the room
					}
					else if (R::is<Neutral_NPC>(actors.find(actor_ID)->second))
					{
						++neutral_count;
					}
				}
				// reduce enemy count to a single-digit number
				enemy_count = ((enemy_count > 9) ? 9 : enemy_count);

				// debugging only
				if (enemy_count > 0) { cout << "\nAt " << cx << "," << cy << " there are " << enemy_count << " enemies."; }
				if (neutral_count > 0) { cout << "\nAt " << cx << "," << cy << " there are " << neutral_count << " neutrals."; }

				// time for glorious nested ternary statements to do this cheap
				a
					<< ((n && w) ? C::NW_CORNER : (n) ? C::WE_WALL : (w) ? C::NS_WALL : C::LAND_CHAR)
					<< ((nr) ? C::RUBBLE_CHAR : ((nd) ? C::WE_DOOR : ((n) ? C::WE_WALL : C::LAND_CHAR)))
					<< ((n && e) ? C::NE_CORNER : (n) ? C::WE_WALL : (e) ? C::NS_WALL : C::LAND_CHAR);
				b
					<< ((wr) ? C::RUBBLE_CHAR : ((wd) ? C::NS_DOOR : ((w) ? C::NS_WALL : C::LAND_CHAR)))
					// if the current coordinates are the player's, draw an @ icon, else if there is an enemy, draw enemy count, else if there is an item, draw an item char, else empty
					<< ((cx == x && cy == y) ? C::PLAYER_CHAR : ((enemy_count > 0) ? R::to_char(enemy_count) : ((neutral_count > 0) ? C::NPC_NEUTRAL_CHAR : ((world.room_at(cx, cy, C::GROUND_INDEX)->contains_no_items()) ? C::LAND_CHAR : C::ITEM_CHAR))))
					<< ((er) ? C::RUBBLE_CHAR : ((ed) ? C::NS_DOOR : ((e) ? C::NS_WALL : C::LAND_CHAR)));
				c
					<< ((s && w) ? C::SW_CORNER : (s) ? C::WE_WALL : (w) ? C::NS_WALL : C::LAND_CHAR)
					<< ((sr) ? C::RUBBLE_CHAR : ((sd) ? C::WE_DOOR : ((s) ? C::WE_WALL : C::LAND_CHAR)))
					<< ((s && e) ? C::SE_CORNER : (s) ? C::WE_WALL : (e) ? C::NS_WALL : C::LAND_CHAR);
			}
		} // end for each room in row

		// each iteration, push the three stringstreams representing the row into the user's map
		user_map << a.str() << endl << b.str() << endl << c.str() << endl;

		// reset the stringstreams for the next row of rooms
		a.str(std::string()); b.str(std::string()); c.str(std::string());
	} // end for each row

	return user_map.str(); // this now contains the client's entire visible area. No formatting is required, just dump this to console.
}
<|endoftext|>