<commit_before>#include "vtkGeoJSONFeature.h"

vtkStandardNewMacro(vtkGeoJSONFeature);

//----------------------------------------------------------------------------
vtkGeoJSONFeature::vtkGeoJSONFeature()
{
  this->outputData = NULL;
}

//----------------------------------------------------------------------------
vtkGeoJSONFeature::~vtkGeoJSONFeature()
{
  outputData->Delete();
}

//----------------------------------------------------------------------------
vtkPolyData *vtkGeoJSONFeature::GetOutput()
{
  //Check if output data contains appropriate data and return values accordingly
  return outputData;
}

//----------------------------------------------------------------------------
double *vtkGeoJSONFeature::CreatePoint(Json::Value coordinates)
{
  //Check if Coordinates corresponds to Point
  if(!IsPoint(coordinates))
    {
    vtkErrorMacro(<< "Wrong data format for a point!");
    return NULL;
    }

  //Do isDouble before asDouble to prevent inconsistency
  //Probably check for float/int too

  //Initialise the 3D coordinates to 0
  double *point = new double[3];

  if(coordinates.size() == 1)
    {
    //Update the 3D Coordinates using the 1 Value in the array and rest of the 2 as 0
    Json::Value x = coordinates[0];
    point[0] = x.asDouble();
    }
  else if(coordinates.size() == 2)
    {
    //Update the 3D Coordinates using the 2 Values in the array and 3rd as 0
    Json::Value x = coordinates[0];
    Json::Value y = coordinates[1];
    point[0] = x.asDouble();
    point[1] = y.asDouble();
    }
  else if(coordinates.size() == 3)
    {
    //Update the 3D Coordinates using the 3 Values in the array
    Json::Value x = coordinates[0];
    Json::Value y = coordinates[1];
    Json::Value z = coordinates[2];
    point[0] = x.asDouble();
    point[1] = y.asDouble();
    point[2] = z.asDouble();
    }

  //Return the 3D point as generated above
  return point;
}

//----------------------------------------------------------------------------
vtkPolyData *vtkGeoJSONFeature::ExtractPoint(Json::Value coordinates, vtkPolyData *outputData)
{
  //Check if Coordinates corresponds to Single Point
  if(!IsPoint(coordinates))
    {
    vtkErrorMacro (<< "Wrong data format for a point!");
    return NULL;
    }

  //Obtain point data from Json structure and add to outputData
  double *point = CreatePoint(coordinates);

  const int PID_SIZE = 1;
  vtkIdType pid[PID_SIZE];

  vtkPoints *points = outputData->GetPoints();
  pid[0] = points->InsertNextPoint(point);

  vtkCellArray *verts = outputData->GetVerts();
  verts->InsertNextCell(PID_SIZE, pid);

  return outputData;
}

//----------------------------------------------------------------------------
vtkPolyData *vtkGeoJSONFeature::ExtractMultiPoint(Json::Value coordinates, vtkPolyData *outputData)
{
  //Check if Coordinates corresponds to Multi Points
  if(!IsMultiPoint(coordinates))
    {
    vtkErrorMacro (<< "Wrong data format for a Multi Point!");
    return NULL;
    }

  if(coordinates.isArray())
    {
    vtkPoints *points = outputData->GetPoints();//Contain the locations of the points
    vtkCellArray *verts = outputData->GetVerts();//Contain the indices corresponding to the position of the vertices

    const int PID_SIZE = coordinates.size();
    vtkIdType pid[PID_SIZE];

    for(int i = 0; i < PID_SIZE; i++)
      {
      //Parse point from Json object to double array and add it to the points array
      double *point = CreatePoint(coordinates[i]);
      pid[i] = points->InsertNextPoint(point);
      }

    //Update polyData vertices to store multiple points
    verts->InsertNextCell(PID_SIZE, pid);
    }

  return outputData;
}

//----------------------------------------------------------------------------
vtkPolyData *vtkGeoJSONFeature::ExtractLineString(Json::Value coordinates, vtkPolyData *outputData)
{
  //Check if Coordinates corresponds to Line String
  if(!IsLineString(coordinates))
    {
    vtkErrorMacro (<< "Wrong data format for a Line String!");
    return NULL;
    }

  vtkCellArray *lines = outputData->GetLines();
  vtkPoints *points = outputData->GetPoints();

  int LINE_COUNT = coordinates.size();

  double *start = CreatePoint(coordinates[0]);
  vtkIdType lineId[2];
  lineId[0] = points->InsertNextPoint(start);

  for(int i = 1; i < LINE_COUNT; i++)
    {
    double *end = CreatePoint(coordinates[i]);
    lineId[1] = points->InsertNextPoint(end);

    vtkLine *line = vtkLine::New();

    line->GetPointIds()->SetId(0, lineId[0]);
    line->GetPointIds()->SetId(1, lineId[1]);

    lines->InsertNextCell(line);

    start = end;
    lineId[0] = lineId[1];
    }

  return outputData;
}

//----------------------------------------------------------------------------
vtkPolyData *vtkGeoJSONFeature::ExtractMultiLineString(Json::Value coordinateArray, vtkPolyData *outputData)
{
  //Check if Coordinate Array corresponds to Multi Line String
  if(!IsMultiLineString(coordinateArray))
    {
    vtkErrorMacro(<< "Wrong data format for a Multi Line String!");
    return NULL;
    }

  int LINE_STRING_COUNT = coordinateArray.size();

  for(int i = 0; i < LINE_STRING_COUNT; i++)
    {
    ExtractLineString(coordinateArray[i], outputData);
    }

  return outputData;
}

//----------------------------------------------------------------------------
vtkPolyData *vtkGeoJSONFeature::ExtractPolygon(Json::Value coordinate, vtkPolyData *outputData)
{
  //Check if Coordinate Array corresponds to Polygon
  if(!IsPolygon(coordinate))
    {
    vtkErrorMacro (<< "Wrong data format for a Polygon!");
    return NULL;
    }

  bool POLYGON_WITH_HOLES = coordinate.size() > 1 ? true : false;

  vtkPoints *points = outputData->GetPoints();
  vtkCellArray *polys = outputData->GetPolys();

  vtkPolygon *exteriorPoly = vtkPolygon::New();

  //For exterior Polygon
  Json::Value exteriorPolygon = coordinate[0];

  int EXTERIOR_POLYGON_VERTEX_COUNT = exteriorPolygon.size() - 1;
  exteriorPoly->GetPointIds()->SetNumberOfIds(EXTERIOR_POLYGON_VERTEX_COUNT);

  for(int i = 0; i < EXTERIOR_POLYGON_VERTEX_COUNT; i++)
    {
    double *point = CreatePoint(exteriorPolygon[i]);
    vtkIdType id = points->InsertNextPoint(point);
    exteriorPoly->GetPointIds()->SetId(i, id);
    }

  polys->InsertNextCell(exteriorPoly);

  if(!POLYGON_WITH_HOLES)
  return outputData;

  //Modify polydata to support polygon with holes
  //Probably use delaunay triangulation to create polygon with holes

  return outputData;
}

//----------------------------------------------------------------------------
vtkPolyData *vtkGeoJSONFeature::ExtractMultiPolygon(Json::Value coordinateArray, vtkPolyData *outputData)
{
  //Check if Coordinate Array corresponds to Multi Polygon
  if(!IsMultiPolygon(coordinateArray))
    {
    vtkErrorMacro (<< "Wrong data format for a Multi Polygon!");
    return NULL;
    }

  int POLYGON_COUNT = coordinateArray.size();

  for(int i = 0; i < POLYGON_COUNT; i++)
    {
    //Extract polygon into different polyData and append into a common polyData using the appendPolyData Filter
    ExtractPolygon(coordinateArray[i], outputData);
    }

  return outputData;
}

//----------------------------------------------------------------------------
void vtkGeoJSONFeature::ExtractGeoJSONFeature(Json::Value root, vtkPolyData *outputData)
{
  this->featureRoot = root;

  Json::Value type = root.get("type", -1);
  Json::Value geometry = root.get("geometry", -1);
  Json::Value properties = root.get("properties", -1);

  if(IsEqual(type.asString(), "feature"))
    {
    ExtractGeoJSONFeatureGeometry(geometry, outputData);
    }
  else
    {
    vtkErrorMacro (<< "Unknown data. \"feature\" expceted");
    }

  //Apply geometrical properties from "properties" on the polydata geometry.
}

//----------------------------------------------------------------------------
void vtkGeoJSONFeature::ExtractGeoJSONFeatureGeometry(Json::Value root, vtkPolyData *outputData)
{

  Json::Value type = root.get("type", -1);

  if(type.isString())
    {
    vtkStdString typeString = vtkStdString(type.asString());

    if(IsEqual(typeString, GEOMETRY_COLLECTION))
      {
      //For GeometryCollection
      Json::Value geometries = root.get("geometries", -1);

      for(int i = 0; i < geometries.size(); i++)
        {
        Json::Value child = geometries[i];
        ExtractGeoJSONFeatureGeometry(child, outputData);
        }
      }
    else
      {
      Json::Value coordinates = root.get("coordinates", -1);

      //Extract corresponding geometry into the outputData according to the type value specified in the Json data structures
      if(IsEqual(typeString, POINT))
        {
        ExtractPoint(coordinates, outputData);
        }
      else if(IsEqual(typeString, MULTI_POINT))
        {
        ExtractMultiPoint(coordinates, outputData);
        }
      else if(IsEqual(typeString, LINE_STRING))
        {
        ExtractLineString(coordinates, outputData);
        }
      else if(IsEqual(typeString, MULTI_LINE_STRING))
        {
        ExtractMultiLineString(coordinates, outputData);
        }
      else if(IsEqual(typeString, POLYGON))
        {
        ExtractPolygon(coordinates, outputData);
        }
      else if(IsEqual(typeString, MULTI_POLYGON))
        {
        ExtractMultiPolygon(coordinates, outputData);
        }
      else
        {
        vtkErrorMacro (<< "This geometry ("<< typeString << ") has not been implemented yet");
        }
      }
    }
  else
    {
    vtkErrorMacro (<< "Unknow data entry for \"type\" at " << root);
    }
}

//----------------------------------------------------------------------------
bool vtkGeoJSONFeature::IsEqual(vtkStdString str1, vtkStdString str2)
{
  //Not matching if string lengths are different
  if(str1.length() != str2.length())
    {
    return false;
    }

  int len = str1.length();
  for(int i = 0; i < len; i++)
    {
    //Exact Match of characters or Capital<->Small match or Small<->Capital match of alphabets
    if(str1[i] != str2[i] && str1[i] - 32 != str2[i] && str1[i] != str2[i] - 32)
      {
      return false;
      }
    }
  return true;
}

//----------------------------------------------------------------------------
bool vtkGeoJSONFeature::IsLineString(Json::Value root)
{
  if(!root.isArray())
    {
    vtkErrorMacro (<<"Expected Arrays as input for point at " << root);
    return false;
    }

  if(root.size() < 1)
    {
    vtkErrorMacro (<< "Expected atleast 1 value at " << root);
    return false;
    }

  for(int i = 0; i < root.size(); i++)
    {
    Json::Value child = root[i];
    if(!IsPoint(child))
      {
      return false;
      }
    }

  return true;
}

//----------------------------------------------------------------------------
bool vtkGeoJSONFeature::IsMultiLineString(Json::Value root)
{
  if(!root.isArray())
    {
    vtkErrorMacro (<< "Expected Array as input for point at " << root);
    return false;
    }
  if(root.size() < 1)
    {
    vtkErrorMacro (<< "Expected atleast 1 value at " << root);
    return false;
    }
  for(int i = 0; i < root.size(); i++)
    {
    Json::Value child = root[i];
    if(!IsLineString(child))
      {
      return false;
      }
    }
  return true;
}

//----------------------------------------------------------------------------
bool vtkGeoJSONFeature::IsPoint(Json::Value root)
{
  if(!root.isArray())
    {
    vtkErrorMacro ("Expected Array as input for point at " << root);
    return false;
    }

  if(!(root.size() > 0 && root.size() < 4))
    {
    vtkErrorMacro (<< "Expected 3 or less dimension values at " << root << " for point");
    return false;
    }

  for(int i = 0; i < root.size(); i++)
    {
    Json::Value child = root[i];
    if(!child.isNumeric())
      {
      vtkErrorMacro (<<"Value not Numeric as expected at " << child);
      return false;
      }
    }
  return true;
}

//----------------------------------------------------------------------------
bool vtkGeoJSONFeature::IsMultiPoint(Json::Value root)
{
  if(!root.isArray())
    {
    vtkErrorMacro (<< "Expected Array as input for multi point at " << root);
    return false;
    }
  if(root.size() < 1)
    {
      vtkErrorMacro (<< "Expected atleast 1 value at " << root << " for multipoint");
    return false;
    }
  for(int i = 0; i < root.size(); i++)
    {
    Json::Value child = root[i];
    if(!IsPoint(child))
      {
      return false;
      }
    }
  return true;
}

//----------------------------------------------------------------------------
bool vtkGeoJSONFeature::IsPolygon(Json::Value root)
{
  if(!root.isArray())
    {
    vtkErrorMacro (<< "Expected Array as input for polygon at " << root);
    return false;
    }
  if(root.size() < 1)
    {
    vtkErrorMacro (<< "Expected atleast 1 value at " << root << "for polygon");
    return false;
    }
  for(int i = 0; i < root.size(); i++)
    {
    Json::Value child = root[i];
    if(!IsLineString(child))
      {
      return false;
      }
    //First and last element of child must be same to complete the polygon loop.
    //Check not added.
    }
  return true;
}

//----------------------------------------------------------------------------
bool vtkGeoJSONFeature::IsMultiPolygon(Json::Value root)
{
  if(!root.isArray())
    {
    vtkErrorMacro (<< "Expected Array as input for multi polygon at " << root);
    return false;
    }

  if(root.size() < 1)
    {
      vtkErrorMacro (<< "Expected atleast 1 value at " << root << " for multi polygon");
    return false;
    }

  for(int i = 0; i < root.size(); i++)
    {
    Json::Value child = root[i];
    if(!IsPolygon(child))
      {
      return false;
      }
    }
  return true;
}

//----------------------------------------------------------------------------
void vtkGeoJSONFeature::PrintSelf(ostream &os, vtkIndent indent)
{
    Superclass::PrintSelf(os, indent);
    os << indent << "vtkGeoJSONFeature" << std::endl;
    os << indent << "Root: " << this->featureRoot << std::endl;
}
<commit_msg>Correct extractLineString<commit_after>#include "vtkGeoJSONFeature.h"

vtkStandardNewMacro(vtkGeoJSONFeature);

//----------------------------------------------------------------------------
vtkGeoJSONFeature::vtkGeoJSONFeature()
{
  this->outputData = NULL;
}

//----------------------------------------------------------------------------
vtkGeoJSONFeature::~vtkGeoJSONFeature()
{
  outputData->Delete();
}

//----------------------------------------------------------------------------
vtkPolyData *vtkGeoJSONFeature::GetOutput()
{
  //Check if output data contains appropriate data and return values accordingly
  return outputData;
}

//----------------------------------------------------------------------------
double *vtkGeoJSONFeature::CreatePoint(Json::Value coordinates)
{
  //Check if Coordinates corresponds to Point
  if(!IsPoint(coordinates))
    {
    vtkErrorMacro(<< "Wrong data format for a point!");
    return NULL;
    }

  //Do isDouble before asDouble to prevent inconsistency
  //Probably check for float/int too

  //Initialise the 3D coordinates to 0
  double *point = new double[3];
  point[0] = 0;
  point[1] = 0;
  point[2] = 0;

  if(coordinates.size() == 1)
    {
    //Update the 3D Coordinates using the 1 Value in the array and rest of the 2 as 0
    Json::Value x = coordinates[0];
    point[0] = x.asDouble();
    }
  else if(coordinates.size() == 2)
    {
    //Update the 3D Coordinates using the 2 Values in the array and 3rd as 0
    Json::Value x = coordinates[0];
    Json::Value y = coordinates[1];
    point[0] = x.asDouble();
    point[1] = y.asDouble();
    }
  else if(coordinates.size() == 3)
    {
    //Update the 3D Coordinates using the 3 Values in the array
    Json::Value x = coordinates[0];
    Json::Value y = coordinates[1];
    Json::Value z = coordinates[2];
    point[0] = x.asDouble();
    point[1] = y.asDouble();
    point[2] = z.asDouble();
    }

  //Return the 3D point as generated above
  return point;
}

//----------------------------------------------------------------------------
vtkPolyData *vtkGeoJSONFeature::ExtractPoint(Json::Value coordinates, vtkPolyData *outputData)
{
  //Check if Coordinates corresponds to Single Point
  if(!IsPoint(coordinates))
    {
    vtkErrorMacro (<< "Wrong data format for a point!");
    return NULL;
    }

  //Obtain point data from Json structure and add to outputData
  double *point = CreatePoint(coordinates);

  const int PID_SIZE = 1;
  vtkIdType pid[PID_SIZE];

  vtkPoints *points = outputData->GetPoints();
  pid[0] = points->InsertNextPoint(point);

  vtkCellArray *verts = outputData->GetVerts();
  verts->InsertNextCell(PID_SIZE, pid);

  return outputData;
}

//----------------------------------------------------------------------------
vtkPolyData *vtkGeoJSONFeature::ExtractMultiPoint(Json::Value coordinates, vtkPolyData *outputData)
{
  //Check if Coordinates corresponds to Multi Points
  if(!IsMultiPoint(coordinates))
    {
    vtkErrorMacro (<< "Wrong data format for a Multi Point!");
    return NULL;
    }

  if(coordinates.isArray())
    {
    vtkPoints *points = outputData->GetPoints();//Contain the locations of the points
    vtkCellArray *verts = outputData->GetVerts();//Contain the indices corresponding to the position of the vertices

    const int PID_SIZE = coordinates.size();
    vtkIdType pid[PID_SIZE];

    for(int i = 0; i < PID_SIZE; i++)
      {
      //Parse point from Json object to double array and add it to the points array
      double *point = CreatePoint(coordinates[i]);
      pid[i] = points->InsertNextPoint(point);
      }

    //Update polyData vertices to store multiple points
    verts->InsertNextCell(PID_SIZE, pid);
    }

  return outputData;
}

//----------------------------------------------------------------------------
vtkPolyData *vtkGeoJSONFeature::ExtractLineString(Json::Value coordinates, vtkPolyData *outputData)
{
  //Check if Coordinates corresponds to Line String
  if(!IsLineString(coordinates))
    {
    vtkErrorMacro (<< "Wrong data format for a Line String!");
    return NULL;
    }

  vtkCellArray *lines = outputData->GetLines();
  vtkPoints *points = outputData->GetPoints();

  int LINE_COUNT = coordinates.size();

  double *start = CreatePoint(coordinates[0]);

  vtkIdType lineId[2];
  lineId[0] = points->InsertNextPoint(start);

  for(int i = 1; i < LINE_COUNT; i++)
    {
    double *end = CreatePoint(coordinates[i]);

    lineId[1] = points->InsertNextPoint(end);

    vtkLine *line = vtkLine::New();

    line->GetPointIds()->SetId(0, lineId[0]);
    line->GetPointIds()->SetId(1, lineId[1]);

    lines->InsertNextCell(line);

    start = end;
    lineId[0] = lineId[1];
    }

  return outputData;
}

//----------------------------------------------------------------------------
vtkPolyData *vtkGeoJSONFeature::ExtractMultiLineString(Json::Value coordinateArray, vtkPolyData *outputData)
{
  //Check if Coordinate Array corresponds to Multi Line String
  if(!IsMultiLineString(coordinateArray))
    {
    vtkErrorMacro(<< "Wrong data format for a Multi Line String!");
    return NULL;
    }

  int LINE_STRING_COUNT = coordinateArray.size();

  for(int i = 0; i < LINE_STRING_COUNT; i++)
    {
    ExtractLineString(coordinateArray[i], outputData);
    }

  return outputData;
}

//----------------------------------------------------------------------------
vtkPolyData *vtkGeoJSONFeature::ExtractPolygon(Json::Value coordinate, vtkPolyData *outputData)
{
  //Check if Coordinate Array corresponds to Polygon
  if(!IsPolygon(coordinate))
    {
    vtkErrorMacro (<< "Wrong data format for a Polygon!");
    return NULL;
    }

  bool POLYGON_WITH_HOLES = coordinate.size() > 1 ? true : false;

  vtkPoints *points = outputData->GetPoints();
  vtkCellArray *polys = outputData->GetPolys();

  vtkPolygon *exteriorPoly = vtkPolygon::New();

  //For exterior Polygon
  Json::Value exteriorPolygon = coordinate[0];

  int EXTERIOR_POLYGON_VERTEX_COUNT = exteriorPolygon.size() - 1;
  exteriorPoly->GetPointIds()->SetNumberOfIds(EXTERIOR_POLYGON_VERTEX_COUNT);

  for(int i = 0; i < EXTERIOR_POLYGON_VERTEX_COUNT; i++)
    {
    double *point = CreatePoint(exteriorPolygon[i]);
    vtkIdType id = points->InsertNextPoint(point);
    exteriorPoly->GetPointIds()->SetId(i, id);
    }

  polys->InsertNextCell(exteriorPoly);

  if(!POLYGON_WITH_HOLES)
  return outputData;

  //Modify polydata to support polygon with holes
  //Probably use delaunay triangulation to create polygon with holes

  return outputData;
}

//----------------------------------------------------------------------------
vtkPolyData *vtkGeoJSONFeature::ExtractMultiPolygon(Json::Value coordinateArray, vtkPolyData *outputData)
{
  //Check if Coordinate Array corresponds to Multi Polygon
  if(!IsMultiPolygon(coordinateArray))
    {
    vtkErrorMacro (<< "Wrong data format for a Multi Polygon!");
    return NULL;
    }

  int POLYGON_COUNT = coordinateArray.size();

  for(int i = 0; i < POLYGON_COUNT; i++)
    {
    //Extract polygon into different polyData and append into a common polyData using the appendPolyData Filter
    ExtractPolygon(coordinateArray[i], outputData);
    }

  return outputData;
}

//----------------------------------------------------------------------------
void vtkGeoJSONFeature::ExtractGeoJSONFeature(Json::Value root, vtkPolyData *outputData)
{
  this->featureRoot = root;

  Json::Value type = root.get("type", -1);
  Json::Value geometry = root.get("geometry", -1);
  Json::Value properties = root.get("properties", -1);

  if(IsEqual(type.asString(), "feature"))
    {
    ExtractGeoJSONFeatureGeometry(geometry, outputData);
    }
  else
    {
    vtkErrorMacro (<< "Unknown data. \"feature\" expceted");
    }

  //Apply geometrical properties from "properties" on the polydata geometry.
}

//----------------------------------------------------------------------------
void vtkGeoJSONFeature::ExtractGeoJSONFeatureGeometry(Json::Value root, vtkPolyData *outputData)
{

  Json::Value type = root.get("type", -1);

  if(type.isString())
    {
    vtkStdString typeString = vtkStdString(type.asString());

    if(IsEqual(typeString, GEOMETRY_COLLECTION))
      {
      //For GeometryCollection
      Json::Value geometries = root.get("geometries", -1);

      for(int i = 0; i < geometries.size(); i++)
        {
        Json::Value child = geometries[i];
        ExtractGeoJSONFeatureGeometry(child, outputData);
        }
      }
    else
      {
      Json::Value coordinates = root.get("coordinates", -1);

      //Extract corresponding geometry into the outputData according to the type value specified in the Json data structures
      if(IsEqual(typeString, POINT))
        {
        ExtractPoint(coordinates, outputData);
        }
      else if(IsEqual(typeString, MULTI_POINT))
        {
        ExtractMultiPoint(coordinates, outputData);
        }
      else if(IsEqual(typeString, LINE_STRING))
        {
        ExtractLineString(coordinates, outputData);
        }
      else if(IsEqual(typeString, MULTI_LINE_STRING))
        {
        ExtractMultiLineString(coordinates, outputData);
        }
      else if(IsEqual(typeString, POLYGON))
        {
        ExtractPolygon(coordinates, outputData);
        }
      else if(IsEqual(typeString, MULTI_POLYGON))
        {
        ExtractMultiPolygon(coordinates, outputData);
        }
      else
        {
        vtkErrorMacro (<< "This geometry ("<< typeString << ") has not been implemented yet");
        }
      }
    }
  else
    {
    vtkErrorMacro (<< "Unknow data entry for \"type\" at " << root);
    }
}

//----------------------------------------------------------------------------
bool vtkGeoJSONFeature::IsEqual(vtkStdString str1, vtkStdString str2)
{
  //Not matching if string lengths are different
  if(str1.length() != str2.length())
    {
    return false;
    }

  int len = str1.length();
  for(int i = 0; i < len; i++)
    {
    //Exact Match of characters or Capital<->Small match or Small<->Capital match of alphabets
    if(str1[i] != str2[i] && str1[i] - 32 != str2[i] && str1[i] != str2[i] - 32)
      {
      return false;
      }
    }
  return true;
}

//----------------------------------------------------------------------------
bool vtkGeoJSONFeature::IsLineString(Json::Value root)
{
  if(!root.isArray())
    {
    vtkErrorMacro (<<"Expected Arrays as input for point at " << root);
    return false;
    }

  if(root.size() < 1)
    {
    vtkErrorMacro (<< "Expected atleast 1 value at " << root);
    return false;
    }

  for(int i = 0; i < root.size(); i++)
    {
    Json::Value child = root[i];
    if(!IsPoint(child))
      {
      return false;
      }
    }

  return true;
}

//----------------------------------------------------------------------------
bool vtkGeoJSONFeature::IsMultiLineString(Json::Value root)
{
  if(!root.isArray())
    {
    vtkErrorMacro (<< "Expected Array as input for point at " << root);
    return false;
    }
  if(root.size() < 1)
    {
    vtkErrorMacro (<< "Expected atleast 1 value at " << root);
    return false;
    }
  for(int i = 0; i < root.size(); i++)
    {
    Json::Value child = root[i];
    if(!IsLineString(child))
      {
      return false;
      }
    }
  return true;
}

//----------------------------------------------------------------------------
bool vtkGeoJSONFeature::IsPoint(Json::Value root)
{
  if(!root.isArray())
    {
    vtkErrorMacro ("Expected Array as input for point at " << root);
    return false;
    }

  if(!(root.size() > 0 && root.size() < 4))
    {
    vtkErrorMacro (<< "Expected 3 or less dimension values at " << root << " for point");
    return false;
    }

  for(int i = 0; i < root.size(); i++)
    {
    Json::Value child = root[i];
    if(!child.isNumeric())
      {
      vtkErrorMacro (<<"Value not Numeric as expected at " << child);
      return false;
      }
    }
  return true;
}

//----------------------------------------------------------------------------
bool vtkGeoJSONFeature::IsMultiPoint(Json::Value root)
{
  if(!root.isArray())
    {
    vtkErrorMacro (<< "Expected Array as input for multi point at " << root);
    return false;
    }
  if(root.size() < 1)
    {
      vtkErrorMacro (<< "Expected atleast 1 value at " << root << " for multipoint");
    return false;
    }
  for(int i = 0; i < root.size(); i++)
    {
    Json::Value child = root[i];
    if(!IsPoint(child))
      {
      return false;
      }
    }
  return true;
}

//----------------------------------------------------------------------------
bool vtkGeoJSONFeature::IsPolygon(Json::Value root)
{
  if(!root.isArray())
    {
    vtkErrorMacro (<< "Expected Array as input for polygon at " << root);
    return false;
    }
  if(root.size() < 1)
    {
    vtkErrorMacro (<< "Expected atleast 1 value at " << root << "for polygon");
    return false;
    }
  for(int i = 0; i < root.size(); i++)
    {
    Json::Value child = root[i];
    if(!IsLineString(child))
      {
      return false;
      }
    //First and last element of child must be same to complete the polygon loop.
    //Check not added.
    }
  return true;
}

//----------------------------------------------------------------------------
bool vtkGeoJSONFeature::IsMultiPolygon(Json::Value root)
{
  if(!root.isArray())
    {
    vtkErrorMacro (<< "Expected Array as input for multi polygon at " << root);
    return false;
    }

  if(root.size() < 1)
    {
      vtkErrorMacro (<< "Expected atleast 1 value at " << root << " for multi polygon");
    return false;
    }

  for(int i = 0; i < root.size(); i++)
    {
    Json::Value child = root[i];
    if(!IsPolygon(child))
      {
      return false;
      }
    }
  return true;
}

//----------------------------------------------------------------------------
void vtkGeoJSONFeature::PrintSelf(ostream &os, vtkIndent indent)
{
    Superclass::PrintSelf(os, indent);
    os << indent << "vtkGeoJSONFeature" << std::endl;
    os << indent << "Root: " << this->featureRoot << std::endl;
}
<|endoftext|>


<commit_before><commit_msg>Fix to devicepresenter.<commit_after><|endoftext|>


<commit_before><commit_msg>TODO-370: improved comments<commit_after><|endoftext|>


<commit_before><commit_msg>Arnaud: + moved some debug code under the "if (0) //DEBUG" idiom         + uses the type "bool"<commit_after><|endoftext|>


<commit_before>/*
 * Medical Image Registration ToolKit (MIRTK)
 *
 * Copyright 2008-2015 Imperial College London
 * Copyright 2008-2013 Daniel Rueckert, Julia Schnabel
 * Copyright 2013-2015 Andreas Schuh
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "mirtk/Common.h"
#include "mirtk/Options.h"

#include "mirtk/BaseImage.h"
#include "mirtk/ImageReader.h"
#include "mirtk/IOConfig.h"
#include "mirtk/Transformation.h"
#include "mirtk/HomogeneousTransformation.h"
#include "mirtk/RigidTransformation.h"
#include "mirtk/ImageTransformation.h"
#include "mirtk/InterpolateImageFunction.h"

using namespace mirtk;

// ===========================================================================
// Help
// ===========================================================================

void PrintHelp(const char *name)
{
  cout << endl;
  cout << "Usage: " << name << " <source> <output> [options]" << endl;
  cout << endl;
  cout << "Description:" << endl;
  cout << "  Applies a transformation to an input image. Each voxel center of" << endl;
  cout << "  the target image is mapped by the given transformation to the space of" << endl;
  cout << "  the source image. The output intensity for the target voxel is the" << endl;
  cout << "  source image intensity interpolated at the mapped point and cast to" << endl;
  cout << "  the output data type." << endl;
  cout << endl;
  cout << "Arguments:" << endl;
  cout << "  source   Source image." << endl;
  cout << "  output   Transformed source image." << endl;
  cout << endl;
  cout << "Optional arguments:" << endl;
  cout << "  -dof <file>      Affine source header transformation. (default: none)" << endl;
  cout << "  -dof_i <file>    Inverse affine source header transformation. (default: none)" << endl;
  cout << "  -dofin <file>    Transformation or 'Id'/'Identity'. (default: Id)" << endl;
  cout << "  -interp <mode>   Interpolation mode, e.g., \"NN\". (default: Linear)" << endl;
  cout << "  -target <file>   Target image. (default: source)" << endl;
  cout << "  -type, -dtype, -datatype <type>" << endl;
  cout << "      Data type of output image. (default: data type of source)" << endl;
  cout << "  -Tp <value>      Target padding value. (default: none)" << endl;
  cout << "  -Sp <value>      Source padding value. (default: none)" << endl;
  cout << "  -Tt <value>      Time point of target image. (default: torigin)" << endl;
  cout << "  -St <value>      Time point of source image. (default: torigin)" << endl;
  cout << "  -invert          Invert transformation. (default: off)" << endl;
  cout << "  -2d              Project transformation to 2D, ignoring mapped z coordinate. (default: off)" << endl;
  cout << endl;
  cout << "Interpolation modes:" << endl;
  for (int i = 0; i < Interpolation_Last; ++i) {
    cout << "  " << ToString(static_cast<InterpolationMode>(i)) << endl;
  }
  PrintCommonOptions(cout);
  cout << endl;
}

// ===========================================================================
// Main
// ===========================================================================

int main(int argc, char **argv)
{
  // Parse positional arguments
  EXPECTS_POSARGS(2);

  const char *input_name  = POSARG(1);
  const char *output_name = POSARG(2);

  // Read image
  InitializeIOLibrary();
  UniquePtr<ImageReader> input_reader(ImageReader::New(input_name));
  UniquePtr<BaseImage>   source(input_reader->Run());

  // Parse optional arguments
  const char       *dof_name      = nullptr;
  bool              dof_invert    = false;
  const char       *dofin_name    = nullptr;
  const char       *target_name   = nullptr;
  InterpolationMode interpolation = Interpolation_NN;
  ImageDataType     dtype         = MIRTK_VOXEL_UNKNOWN;

  double target_t = NaN;
  double source_t = NaN;

  double source_padding = 0;
  double target_padding = NaN;
  bool  invert          = false;
  bool  twod            = false;

  for (ALL_OPTIONS) {
    if      (OPTION("-dof")   ) dof_name       = ARGUMENT, dof_invert = false;
    else if (OPTION("-dof_i") ) dof_name       = ARGUMENT, dof_invert = true;
    else if (OPTION("-dofin") ) dofin_name     = ARGUMENT;
    else if (OPTION("-target")) target_name    = ARGUMENT;
    else if (OPTION("-Tp")    ) PARSE_ARGUMENT(target_padding);
    else if (OPTION("-Sp")    ) PARSE_ARGUMENT(source_padding);
    else if (OPTION("-Tt")    ) PARSE_ARGUMENT(target_t);
    else if (OPTION("-St")    ) PARSE_ARGUMENT(source_t);
    else if (OPTION("-interp")) PARSE_ARGUMENT(interpolation);
    else HANDLE_BOOL_OPTION(invert);
    else HANDLE_BOOLEAN_OPTION("2d", twod);
    // backwards compatibility options
    else if (OPTION("-nn")     ) interpolation  = Interpolation_NN;
    else if (OPTION("-linear") ) interpolation  = Interpolation_Linear;
    else if (OPTION("-bspline")) interpolation  = Interpolation_BSpline;
    else if (OPTION("-cspline")) interpolation  = Interpolation_CSpline;
    else if (OPTION("-sinc")   ) interpolation  = Interpolation_Sinc;
    else if (OPTION("-sbased") ) interpolation  = Interpolation_SBased;
    else if (OPTION("-type") || OPTION("-dtype") || OPTION("-datatype")) {
      PARSE_ARGUMENT(dtype);
    }
    else HANDLE_COMMON_OR_UNKNOWN_OPTION();
  }
  if (dtype == MIRTK_VOXEL_UNKNOWN) {
    dtype = static_cast<ImageDataType>(source->GetDataType());
  }

  // Apply affine header transformation
  if (dof_name) {
    UniquePtr<Transformation> t(Transformation::New(dof_name));
    HomogeneousTransformation *lin = dynamic_cast<HomogeneousTransformation *>(t.get());
    if (lin) {
      Matrix mat = lin->GetMatrix();
      if (dof_invert) mat.Invert();
      source->PutAffineMatrix(mat, true);
    } else {
      FatalError("Header transformation (-dof|-dof_i) can only be affine");
    }
  }

  // Read target image
  UniquePtr<BaseImage> target;
  if (target_name) {
    UniquePtr<ImageReader> target_reader(ImageReader::New(target_name));
    target.reset(target_reader->Run());
  }

  // Instantiate interpolator
  UniquePtr<InterpolateImageFunction> interpolator(InterpolateImageFunction::New(interpolation));

  // Initialize output image
  // Note: Always use floating point for intermediate interpolated image values!
  if (target) {
    if (target->T() != source->T() || (target->GetDataType() != MIRTK_VOXEL_FLOAT && target->GetDataType() != MIRTK_VOXEL_DOUBLE)) {
      UniquePtr<BaseImage> tmp(new RealImage(target->Attributes(), source->T()));
      tmp->PutTSize(source->GetTSize());
      for (int l = 0; l < tmp->T(); ++l)
      for (int k = 0; k < tmp->Z(); ++k)
      for (int j = 0; j < tmp->Y(); ++j)
      for (int i = 0; i < tmp->X(); ++i) {
        tmp->PutAsDouble(i, j, k, l, target->GetAsDouble(i, j, k, 0));
      }
      target.reset(tmp.release());
    }
  } else {
    target.reset(new RealImage(source->Attributes()));
    if (!IsNaN(target_padding)) {
      const int nvox = source->NumberOfVoxels();
      for (int vox = 0; vox < nvox; ++vox) {
        target->PutAsDouble(vox, source->GetAsDouble(vox));
      }
    }
  }
  if (IsNaN(target_padding)) target_padding = -inf;

  // Set temporal offset
  if (!IsNaN(target_t)) target->PutTOrigin(target_t);
  if (!IsNaN(source_t)) source->PutTOrigin(source_t);

  // Instantiate image transformation
  UniquePtr<Transformation> transformation;
  if (dofin_name == NULL || strcmp(dofin_name, "identity") == 0
                         || strcmp(dofin_name, "Identity") == 0
                         || strcmp(dofin_name, "Id")       == 0) {
    // Create identity transformation
    transformation.reset(new RigidTransformation());
  } else {
    // Read transformation
    transformation.reset(Transformation::New(dofin_name));
  }

  // Create image transformation filter
  ImageTransformation imagetransformation;
  imagetransformation.Input(source.get());
  imagetransformation.Transformation(transformation.get());
  imagetransformation.Output(target.get());
  imagetransformation.TargetPaddingValue(target_padding);
  imagetransformation.SourcePaddingValue(source_padding);
  imagetransformation.Interpolator(interpolator.get());
  imagetransformation.Invert(invert);
  imagetransformation.TwoD(twod);

  // Transform source image
  imagetransformation.Run();
  if (imagetransformation.NumberOfSingularPoints() > 0) {
    ostringstream msg;
    msg << "Transformation is non-invertible at "
        << imagetransformation.NumberOfSingularPoints() << " point";
    if (imagetransformation.NumberOfSingularPoints() > 1) msg << 's';
    Warning(msg.str());
  }

  // Convert to output data type
  if (target->GetDataType() != dtype) {
    UniquePtr<BaseImage> tmp(BaseImage::New(dtype));
    *tmp = *target;
    target.reset(tmp.release());
  }

  // Write the transformed image
  target->Write(output_name);

  return 0;
}
<commit_msg>enh: transform-image options, add output -spacing option [Applications]<commit_after>/*
 * Medical Image Registration ToolKit (MIRTK)
 *
 * Copyright 2008-2015 Imperial College London
 * Copyright 2008-2013 Daniel Rueckert, Julia Schnabel
 * Copyright 2013-2015 Andreas Schuh
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "mirtk/Common.h"
#include "mirtk/Options.h"

#include "mirtk/BaseImage.h"
#include "mirtk/ImageReader.h"
#include "mirtk/IOConfig.h"
#include "mirtk/Transformation.h"
#include "mirtk/HomogeneousTransformation.h"
#include "mirtk/RigidTransformation.h"
#include "mirtk/ImageTransformation.h"
#include "mirtk/InterpolateImageFunction.h"
#include "mirtk/ResamplingWithPadding.h"

using namespace mirtk;

// ===========================================================================
// Help
// ===========================================================================

void PrintHelp(const char *name)
{
  cout << "\n";
  cout << "Usage: " << name << " <source> <output> [options]\n";
  cout << "\n";
  cout << "Description:\n";
  cout << "  Applies a transformation to an input image. Each voxel center of\n";
  cout << "  the target image is mapped by the given transformation to the space of\n";
  cout << "  the source image. The output intensity for the target voxel is the\n";
  cout << "  source image intensity interpolated at the mapped point and cast to\n";
  cout << "  the output data type.\n";
  cout << "\n";
  cout << "Arguments:\n";
  cout << "  source   Source image.\n";
  cout << "  output   Transformed source image.\n";
  cout << "\n";
  cout << "Optional arguments:\n";
  cout << "  -dofin <file>\n";
  cout << "      Transformation or 'Id'/'Identity'. (default: Id)\n";
  cout << "  -invert [on|off], -noinvert\n";
  cout << "      Enable/disable inversion of :option:`-dofin` transformation. (default: off)\n";
  cout << "  -interp, -interpolation <mode>\n";
  cout << "      Interpolation mode, e.g., \"NN\". (default: Linear)\n";
  cout << "  -target <file>\n";
  cout << "      Target image. (default: source)\n";
  cout << "  -target-affdof <file>\n";
  cout << "      Affine target header transformation. (default: none)\n";
  cout << "  -target-invdof <file>\n";
  cout << "      Inverse affine target header transformation. (default: none)\n";
  cout << "  -source-affdof <file>\n";
  cout << "      Affine source header transformation. (default: none)\n";
  cout << "  -source-invdof <file>\n";
  cout << "      Inverse affine source header transformation. (default: none)\n";
  cout << "  -apply-affdof\n";
  cout << "      Apply affine header transformation to output image header.\n";
  cout << "      When this option is not specified, the output image attributes\n";
  cout << "      are identical to the :option:`-target` image. When this option\n";
  cout << "      is given, the :option:`-target-affdof` or :option:`-target-invdof`,\n";
  cout << "      respectively, is applied to the output image attributes.\n";
  cout << "  -spacing, -voxel-size <dx> [<dy> [<dz> [<dt>]]]\n";
  cout << "      Voxel size of output image. (default: :option:`-target` spacing)\n";
  cout << "  -type, -dtype, -datatype <type>\n";
  cout << "      Data type of output image. (default: data type of source)\n";
  cout << "  -Tp, -target-padding <value>\n";
  cout << "      Target padding value. (default: none)\n";
  cout << "  -Sp, -source-padding <value>\n";
  cout << "      Source padding value. (default: none)\n";
  cout << "  -padding <value>\n";
  cout << "      Set both :option:`-target-padding` and :option:`-source-padding` to same value.\n";
  cout << "  -Tt, -target-time <value>\n";
  cout << "      Time point of target image. (default: torigin)\n";
  cout << "  -St, -source-time <value>\n";
  cout << "      Time point of source image. (default: torigin)\n";
  cout << "  -2d [on|off], -no2d\n";
  cout << "      Project transformed points to 2D, i.e., ignore mapped z coordinate. (default: off)\n";
  cout << "  -3d\n";
  cout << "      Alias for :option:`-2d off`.\n";
  cout << "\n";
  cout << "Interpolation modes:\n";
  for (int i = 0; i < Interpolation_Last; ++i) {
    InterpolationMode mode = static_cast<InterpolationMode>(i);
    if (mode == InterpolationWithoutPadding(mode)) {
      cout << "  " << ToString(static_cast<InterpolationMode>(i));
      if (mode != Interpolation_Default) cout << " [with padding]";
      cout << "\n";
    }
  }
  PrintCommonOptions(cout);
  cout << endl;
}

// ===========================================================================
// Main
// ===========================================================================

int main(int argc, char **argv)
{
  // Parse positional arguments
  EXPECTS_POSARGS(2);

  const char *input_name  = POSARG(1);
  const char *output_name = POSARG(2);

  // Read image
  InitializeIOLibrary();
  UniquePtr<ImageReader> input_reader(ImageReader::New(input_name));
  UniquePtr<BaseImage>   source(input_reader->Run());

  // Parse optional arguments
  const char       *srcdof_name   = nullptr;
  bool              srcdof_invert = false;
  const char       *dofin_name    = nullptr;
  const char       *target_name   = nullptr;
  const char       *tgtdof_name   = nullptr;
  bool              tgtdof_invert = false;
  bool              affdof_apply  = false;
  InterpolationMode interpolation = Interpolation_NN;
  ImageDataType     dtype         = MIRTK_VOXEL_UNKNOWN;
  double            spacing[3]    = {0., 0., 0.};

  double target_t = NaN;
  double source_t = NaN;

  double source_padding = 0;
  double target_padding = NaN;
  bool   invert         = false;
  bool   twod           = false;

  for (ALL_OPTIONS) {
    if (OPTION("-dofin") ) {
      dofin_name = ARGUMENT;
    }
    else if (OPTION("-target")) {
      target_name = ARGUMENT;
    }
    else if (OPTION("-target-affdof")) {
      tgtdof_name   = ARGUMENT;
      tgtdof_invert = false;
    }
    else if (OPTION("-target-invdof")) {
      tgtdof_name   = ARGUMENT;
      tgtdof_invert = true;
    }
    else if (OPTION("-source-affdof") || OPTION("-dof")) {
      srcdof_name   = ARGUMENT;
      srcdof_invert = false;
    }
    else if (OPTION("-source-invdof") || OPTION("-dof_i")) {
      srcdof_name   = ARGUMENT;
      srcdof_invert = true;
    }
    else if (OPTION("-apply-affdof")) {
      affdof_apply = true;
    }
    else if (OPTION("-spacing") || OPTION("-voxel-size")) {
      PARSE_ARGUMENT(spacing[0]);
      if (HAS_ARGUMENT) {
        PARSE_ARGUMENT(spacing[1]);
        if (HAS_ARGUMENT) {
          PARSE_ARGUMENT(spacing[2]);
        }
      } else {
        spacing[1] = spacing[2] = spacing[0];
      }
    }
    else if (OPTION("-padding")) {
      PARSE_ARGUMENT(target_padding);
      source_padding = target_padding;
    }
    else if (OPTION("-Tp") || OPTION("-target-padding")) {
      PARSE_ARGUMENT(target_padding);
    }
    else if (OPTION("-Sp") || OPTION("-source-padding")) {
      PARSE_ARGUMENT(source_padding);
    }
    else if (OPTION("-Tt") || OPTION("-target-time")) {
      PARSE_ARGUMENT(target_t);
    }
    else if (OPTION("-St") || OPTION("-source-time")) {
      PARSE_ARGUMENT(source_t);
    }
    else if (OPTION("-interp") || OPTION("-interpolation")) {
      PARSE_ARGUMENT(interpolation);
    }
    else HANDLE_BOOL_OPTION(invert);
    else HANDLE_BOOLEAN_OPTION("2d", twod);
    else if (OPTION("-3d")) twod = false;
    // backwards compatibility options
    else if (OPTION("-nn")     ) interpolation  = Interpolation_NN;
    else if (OPTION("-linear") ) interpolation  = Interpolation_Linear;
    else if (OPTION("-bspline")) interpolation  = Interpolation_BSpline;
    else if (OPTION("-cspline")) interpolation  = Interpolation_CSpline;
    else if (OPTION("-sinc")   ) interpolation  = Interpolation_Sinc;
    else if (OPTION("-sbased") ) interpolation  = Interpolation_SBased;
    else if (OPTION("-type") || OPTION("-dtype") || OPTION("-datatype")) {
      PARSE_ARGUMENT(dtype);
    }
    else HANDLE_COMMON_OR_UNKNOWN_OPTION();
  }
  if (dtype == MIRTK_VOXEL_UNKNOWN) {
    dtype = static_cast<ImageDataType>(source->GetDataType());
  }

  // Instantiate interpolator
  UniquePtr<InterpolateImageFunction> interpolator(InterpolateImageFunction::New(interpolation));

  // Initialize output image
  // Note: Always use floating point for intermediate interpolated image values!
  UniquePtr<RealImage> target;
  if (target_name) {
    UniquePtr<ImageReader> reader(ImageReader::New(target_name));
    UniquePtr<BaseImage> image(reader->Run());
    if (image->T() == source->T()) {
      target.reset(dynamic_cast<RealImage *>(image.get()));
    }
    if (target) {
      image.release();
    } else {
      target.reset(new RealImage(image->Attributes(), source->T()));
      target->PutTSize(source->GetTSize());
      for (int l = 0; l < target->T(); ++l)
      for (int k = 0; k < target->Z(); ++k)
      for (int j = 0; j < target->Y(); ++j)
      for (int i = 0; i < target->X(); ++i) {
        target->PutAsDouble(i, j, k, l, image->GetAsDouble(i, j, k, 0));
      }
    }
  } else {
    target.reset(new RealImage(source->Attributes()));
    if (!IsNaN(target_padding)) {
      const int nvox = source->NumberOfVoxels();
      for (int vox = 0; vox < nvox; ++vox) {
        target->PutAsDouble(vox, source->GetAsDouble(vox));
      }
    }
  }
  if (IsNaN(target_padding)) target_padding = -inf;

  // Resample to desired output spacing
  if (spacing[0] > 0. || spacing[1] > 0. || spacing[2] > 0.) {
    double dx, dy, dz;
    target->GetPixelSize(dx, dy, dz);
    if (!fequal(dx, spacing[0]) || !fequal(dy, spacing[1]) || !fequal(dz, spacing[2])) {
      if (spacing[0] > 0.) dx = spacing[0];
      if (spacing[1] > 0.) dy = spacing[1];
      if (spacing[2] > 0.) dz = spacing[2];
      if (IsInf(target_padding)) {
        Resampling<RealPixel> resampler(dx, dy, dz);
        resampler.Input(target.get());
        resampler.Output(target.get());
        resampler.Interpolator(interpolator.get());
        resampler.Run();
      } else {
        ResamplingWithPadding<RealPixel> resampler(dx, dy, dz, target_padding);
        resampler.Input(target.get());
        resampler.Output(target.get());
        resampler.Run();
      }
    }
  }

  // Set temporal offset
  if (!IsNaN(target_t)) target->PutTOrigin(target_t);
  if (!IsNaN(source_t)) source->PutTOrigin(source_t);

  // Instantiate image transformation
  UniquePtr<Transformation> transformation;
  if (dofin_name == NULL || strcmp(dofin_name, "identity") == 0
                         || strcmp(dofin_name, "Identity") == 0
                         || strcmp(dofin_name, "Id")       == 0) {
    // Create identity transformation
    transformation.reset(new RigidTransformation());
  } else {
    // Read transformation
    transformation.reset(Transformation::New(dofin_name));
  }

  // Set affine header transformation
  if (srcdof_name) {
    UniquePtr<Transformation> t(Transformation::New(srcdof_name));
    HomogeneousTransformation *lin = dynamic_cast<HomogeneousTransformation *>(t.get());
    if (lin) {
      Matrix mat = lin->GetMatrix();
      if (srcdof_invert) mat.Invert();
      source->PutAffineMatrix(mat, false);
    } else {
      FatalError("Source header transformation must be affine");
    }
  }
  if (tgtdof_name) {
    UniquePtr<Transformation> t(Transformation::New(tgtdof_name));
    HomogeneousTransformation *lin = dynamic_cast<HomogeneousTransformation *>(t.get());
    if (lin) {
      Matrix mat = lin->GetMatrix();
      if (tgtdof_invert) mat.Invert();
      target->PutAffineMatrix(mat, affdof_apply);
    } else {
      FatalError("Target header transformation must be affine");
    }
  } else if (!target_name && srcdof_name) {
    target->PutAffineMatrix(source->GetAffineMatrix(), affdof_apply);
  }

  // Create image transformation filter
  ImageTransformation imagetransformation;
  imagetransformation.Input(source.get());
  imagetransformation.Transformation(transformation.get());
  imagetransformation.Output(target.get());
  imagetransformation.TargetPaddingValue(target_padding);
  imagetransformation.SourcePaddingValue(source_padding);
  imagetransformation.Interpolator(interpolator.get());
  imagetransformation.Invert(invert);
  imagetransformation.TwoD(twod);

  // Transform source image
  imagetransformation.Run();
  if (imagetransformation.NumberOfSingularPoints() > 0) {
    ostringstream msg;
    msg << "Transformation is non-invertible at "
        << imagetransformation.NumberOfSingularPoints() << " point";
    if (imagetransformation.NumberOfSingularPoints() > 1) msg << 's';
    Warning(msg.str());
  }

  // Reset affine header transformation
  if (!affdof_apply && (tgtdof_name || (!target_name && srcdof_name))) {
    target->ResetAffineMatrix();
  }

  // Write the transformed image
  if (target->GetDataType() != dtype) {
    UniquePtr<BaseImage> output(BaseImage::New(dtype));
    *output = *target;
    output->Write(output_name);
  } else {
    target->Write(output_name);
  }

  return 0;
}
<|endoftext|>


<commit_before>VectorXf v;
v.setLinSpaced(5,0.5f,1.5f).transpose();
cout << v << endl;
<commit_msg>Remove confusing transpose() in setLinSpaced() docs.<commit_after>VectorXf v;
v.setLinSpaced(5,0.5f,1.5f);
cout << v << endl;
<|endoftext|>


<commit_before>#include "TextManager.h"

#define STB_TRUETYPE_IMPLEMENTATION
#include "stb_truetype.h"
typedef unsigned char BYTE;

using namespace iceberg;

TextManager::TextManager()
{
    fontLoaded_ = false;
    currentFont_ = "";

    const std::string vertexShader =
        "#version 330 core\n"
        "layout (location = 0) in vec3 v_position;\n"
        "layout (location = 1) in vec2 v_texCoord;\n"
        "out vec2 f_texCoord;\n"
        "uniform mat4 mvpMatrix;\n"
        "void main()\n"
        "{\n"
        "   gl_Position = mvpMatrix * vec4(v_position, 1.0f); \n"
        "   f_texCoord = vec2(v_texCoord.x, 1.0 - v_texCoord.y); // necessary to flip texture\n"
        "}\n";

    const std::string fragmentShader =
        "#version 330 core\n"
        "in vec2 f_texCoord;\n"
        "out vec4 fragColor;\n"
        "uniform sampler2D glyphTexture;\n"
        "uniform vec3 color;\n"
        "void main()\n"
        "{\n"
        "    fragColor = vec4(color, texture(glyphTexture, f_texCoord).r); // use only the r channel\n"
        "}\n";

    shaderProgram_ = std::make_unique<ShaderProgram>();
    shaderProgram_->create_program();
    shaderProgram_->add_shader_from_source(vertexShader, GL_VERTEX_SHADER);
    shaderProgram_->add_shader_from_source(fragmentShader, GL_FRAGMENT_SHADER);
    shaderProgram_->link_program();

    textVAO = std::make_unique<VAO>();
    textVBO = std::make_unique<VBO>();
    textVBO = std::make_unique<VBO>();
}

TextManager::~TextManager()
{
}

void TextManager::load_font(const std::string& path, int scale)
{
    // TODO: Scale by dpi instead of by pixels using font metrics

    // Retrieve the font name
    std::string fontName = path.substr(path.find_last_of('/') + 1);

    // Strip the extension
    std::string extension = ".ttf";
    std::string::size_type extPos = fontName.find(extension);
    if(extPos != std::string::npos)
    {
        fontName.erase(extPos, fontName.length());
    }

    // Check if the font was already loaded
    if (fontCache_.find(fontName) != fontCache_.end())
    {
        currentFont_ = fontName;
        return; // The font was found in the font cache
    }

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    auto bytes = Utility::ReadAllBytes(path.c_str());
    unsigned char* data = bytes.data(); // needs one level of indirection to work properly

    stbtt_fontinfo fontInfo;
    stbtt_InitFont(&fontInfo, data, 0);

    Font font;

    // Generate bitmaps for ASCII 32 (space) - ASCII 126 (~)
    for(size_t codepoint = 32; codepoint <= 126; codepoint++)
    {
        // Create the glyph texture
        GlyphInfo *glyphInfo = new GlyphInfo;
        unsigned char *bitmap = stbtt_GetCodepointBitmap(&fontInfo, 0, stbtt_ScaleForPixelHeight(&fontInfo, scale), codepoint, &glyphInfo->size.x, &glyphInfo->size.y, 0, 0);
        glyphInfo->texture.create_from_data(glyphInfo->size.x, glyphInfo->size.y, bitmap, GL_RED);

        // Get the glyph metrics
        stbtt_GetCodepointHMetrics(&fontInfo, codepoint, &glyphInfo->advance, &glyphInfo->bearing.x);
        glyphInfo->bearing.y = 0; // TODO: Figure out how to load this metric

        // Add the glyph to the font
        font.insert(std::pair<char, GlyphInfo*>(char(codepoint), glyphInfo));
    }

    // Add the font to the font cache by name
    fontCache_.insert(std::pair<std::string,Font>(fontName, font));

    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);

    currentFont_ = fontName;
}<commit_msg>Update text manager  vertex shader to prepare for ortho projection and bitmap flipping.<commit_after>#include "TextManager.h"

#define STB_TRUETYPE_IMPLEMENTATION
#include "stb_truetype.h"
typedef unsigned char BYTE;

using namespace iceberg;

TextManager::TextManager()
{
    fontLoaded_ = false;
    currentFont_ = "";

    const std::string vertexShader =
        "#version 330 core\n"
        "layout (location = 0) in vec3 v_position;\n"
        "layout (location = 1) in vec2 v_texCoord;\n"
        "out vec2 f_texCoord;\n"
        "uniform mat4 projection;\n"
        "void main()\n"
        "{\n"
        "   gl_Position = projection * vec4(v_position, 1.0f); \n"
        "   f_texCoord = vec2(1.0f - v_texCoord.x, 1.0f - v_texCoord.y); // necessary to flip texture\n"
        "}\n";

    const std::string fragmentShader =
        "#version 330 core\n"
        "in vec2 f_texCoord;\n"
        "out vec4 fragColor;\n"
        "uniform sampler2D glyphTexture;\n"
        "uniform vec3 color;\n"
        "void main()\n"
        "{\n"
        "    fragColor = vec4(color, texture(glyphTexture, f_texCoord).r); // use only the r channel\n"
        "}\n";

    shaderProgram_ = std::make_unique<ShaderProgram>();
    shaderProgram_->create_program();
    shaderProgram_->add_shader_from_source(vertexShader, GL_VERTEX_SHADER);
    shaderProgram_->add_shader_from_source(fragmentShader, GL_FRAGMENT_SHADER);
    shaderProgram_->link_program();

    textVAO = std::make_unique<VAO>();
    textVBO = std::make_unique<VBO>();
    textVBO = std::make_unique<VBO>();
}

TextManager::~TextManager()
{
}

void TextManager::load_font(const std::string& path, int scale)
{
    // TODO: Scale by dpi instead of by pixels using font metrics

    // Retrieve the font name
    std::string fontName = path.substr(path.find_last_of('/') + 1);

    // Strip the extension
    std::string extension = ".ttf";
    std::string::size_type extPos = fontName.find(extension);
    if(extPos != std::string::npos)
    {
        fontName.erase(extPos, fontName.length());
    }

    // Check if the font was already loaded
    if (fontCache_.find(fontName) != fontCache_.end())
    {
        currentFont_ = fontName;
        return; // The font was found in the font cache
    }

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    auto bytes = Utility::ReadAllBytes(path.c_str());
    unsigned char* data = bytes.data(); // needs one level of indirection to work properly

    stbtt_fontinfo fontInfo;
    stbtt_InitFont(&fontInfo, data, 0);

    Font font;

    // Generate bitmaps for ASCII 32 (space) - ASCII 126 (~)
    for(size_t codepoint = 32; codepoint <= 126; codepoint++)
    {
        // Create the glyph texture
        GlyphInfo *glyphInfo = new GlyphInfo;
        unsigned char *bitmap = stbtt_GetCodepointBitmap(&fontInfo, 0, stbtt_ScaleForPixelHeight(&fontInfo, scale), codepoint, &glyphInfo->size.x, &glyphInfo->size.y, 0, 0);
        glyphInfo->texture.create_from_data(glyphInfo->size.x, glyphInfo->size.y, bitmap, GL_RED);

        // Get the glyph metrics
        stbtt_GetCodepointHMetrics(&fontInfo, codepoint, &glyphInfo->advance, &glyphInfo->bearing.x);
        glyphInfo->bearing.y = 0; // TODO: Figure out how to load this metric

        // Add the glyph to the font
        font.insert(std::pair<char, GlyphInfo*>(char(codepoint), glyphInfo));
    }

    // Add the font to the font cache by name
    fontCache_.insert(std::pair<std::string,Font>(fontName, font));

    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);

    currentFont_ = fontName;
}<|endoftext|>


<commit_before>//
// Copyright (C) 2016 University of Amsterdam
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU 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, see <http://www.gnu.org/licenses/>.
//

#include "spssimporter_test.h"

void SPSSImporterTest::initTestCase()
{

}

void SPSSImporterTest::cleanupTestCase()
{

}

void SPSSImporterTest::init()
{
  fe = new FileEvent();
  dsp = new DataSetPackage();
  asl = new AsyncLoader();

  fe2 = new FileEvent();
  dsp2 = new DataSetPackage();
  asl2 = new AsyncLoader();
}

void SPSSImporterTest::cleanup()
{
  // destroy all the objects created and delete the dataSet from the shared memory
  //SharedMemory::deleteDataSet(dsp->dataSet);
  //SharedMemory::deleteDataSet(dsp2->dataSet);

  fe->~FileEvent();
  dsp->~DataSetPackage();
  asl->~AsyncLoader();

  fe2->~FileEvent();
  dsp2->~DataSetPackage();
  asl2->~AsyncLoader();
}

void SPSSImporterTest::spssTester_data()
{
  QTest::addColumn<QString>("filename");
  int count = 0;

  boost::filesystem::path p("test_files/spss_files");

  //add files to be tested in a folder "test_files"
  for (auto i = boost::filesystem::directory_iterator(p); i != boost::filesystem::directory_iterator(); i++)
  {
    if (!boost::filesystem::is_directory(i->path())) //we eliminate directories
    {
      QTest::newRow("spss file test") << QString::fromStdString(i->path().filename().string());
      count++;
    }
  }
}

void SPSSImporterTest::spssTester()
{
  QFETCH(QString, filename);

  //spss file
  QString full_path1 = QString("test_files/spss_files/").append(filename);
  qDebug() << "filename: " << filename;

  DataSetPackage *ds_spss = new DataSetPackage();
  fe->setOperation(FileEvent::FileOpen);
  fe->setPath(full_path1);
  asl->loadTask(fe, ds_spss);
  asl->_thread.quit();

  struct fileContent fc1;
  copyToStructure(ds_spss, &fc1);
  SharedMemory::deleteDataSet(ds_spss->dataSet);
  ds_spss->~DataSetPackage();

  //csv file
  QString csvFile = filename;
  csvFile.replace(filename.size()-3, 3, "csv");
  QString full_path2 = QString("test_files/csv_files/").append(csvFile);
  qDebug() << "csv filename: " << csvFile;

  DataSetPackage *ds_csv = new DataSetPackage();
  fe2->setOperation(FileEvent::FileOpen);
  fe2->setPath(full_path2);
  asl2->loadTask(fe2, ds_csv);
  asl2->_thread.quit();

  struct fileContent fc2;
  copyToStructure(ds_csv, &fc2);
  SharedMemory::deleteDataSet(ds_csv->dataSet);
  ds_csv->~DataSetPackage();

  bool ans = checkIfEqual(&fc1, &fc2);
  QVERIFY(ans); // end of test
}

void SPSSImporterTest::copyToStructure(DataSetPackage *dsPackage, struct fileContent *fc)
{
  fc->columns = dsPackage->dataSet->columnCount();//copy column count
  fc->rows = dsPackage->dataSet->rowCount();      //copy row count

  //headers copy
  std::vector<std::string> headerNames;
  for(int i=0; i<fc->columns; ++i)
  {
    headerNames.push_back(dsPackage->dataSet->column(i).name());
  }
  fc->headers = headerNames;

  //copy data
  std::vector< std::vector<std::string> > fileRows;
  for(int j=0; j<fc->rows; ++j)
  {
    std::vector<std::string> tempRow;
    for(int i=0; i<fc->columns; ++i)
    {
      tempRow.push_back(dsPackage->dataSet->column(i)[j]);
    }
    fileRows.push_back(tempRow);
    tempRow.clear();
  }

  fc->data = fileRows;
  return;
}

/* checks if data read from file is same as the data stored in the shared memory */
bool SPSSImporterTest::checkIfEqual(struct fileContent *fc1, struct fileContent *fc2)
{
  if(fc1->columns != fc2->columns)
  {
    qDebug() << "Column size mismatch";
    return false;
  }

  if(fc1->rows != fc2->rows)
  {
    qDebug() << "Row size mismatch" << QString::number(fc1->rows) << " " << QString::number(fc2->rows);
    //return false;
  }

  for(int i=0; i<fc2->columns; ++i)
  {
    if(fc1->headers[i] != fc2->headers[i])
    {
      qDebug() << "Header name mismatch";
      return false;
    }

    for(int j=0; j<fc2->rows; ++j)
    {

      if(fc1->data[j][i] != fc2->data[j][i])
      {qDebug() << "Data mismatch " << QString::number(j);
        qDebug() << QString::fromStdString(fc2->data[j][i])<< " " << QString::fromStdString(fc1->data[j][i]);
        return false;
      }
    }
  }

  return true;
}

/* read data from the file specified from path and store it in the struct fileContent */
int SPSSImporterTest::readDataFromCSV(QString path, struct fileContent *fc)
{
  std::ifstream input(path.toStdString().c_str());
  std::vector< std::vector<std::string> > fileRows;
  std::string currentWord;

  if(input.is_open())
  {
    for(CSVIterator csvIter(input); csvIter != CSVIterator(); ++csvIter)
    {
      std::vector<std::string> tempRow; //has one row

      if((*csvIter).size() <=0)
      {
        continue;
      }
      if((*csvIter).size() == 1 && trim((*csvIter)[0]) == "")
      {
        continue;
      }
      for(int i=0; i<(*csvIter).size(); ++i)
      {
        currentWord = (*csvIter)[i];
        if(currentWord == "")
        {
          currentWord = ".";
        }
        else
        {
          if(!fileRows.empty())
          {
            if(columnIsNumeric[i])//check if the column has strings that are non-nueric
            {
              if(!checkIfNumeric(currentWord)) //check if the currentWord is numeric
              {
                columnIsNumeric[i] = false;
              }
            }
          }
        }

        tempRow.push_back(currentWord);
      }

      fileRows.push_back(tempRow);
      tempRow.clear();
    }

    fc->rows = fileRows.size() - 1;
    fc->columns = fileRows[0].size();
    fc->headers = fileRows[0];
    fileRows.erase(fileRows.begin());
    fc->data = fileRows;

    return 0;
  }
  else
  {
    qDebug() << "Unable to open file: " << path;
    return 1;
  }
}

std::string SPSSImporterTest::roundTo6Digits(double x, int n)
{
  char buff[32];
  sprintf(buff, "%.*g", n, x);
  std::string cppString(buff);
  return cppString;
}

bool SPSSImporterTest::checkIfNumeric(std::string word)
{
    std::string::const_iterator it = word.begin();
    bool decimalPoint = false;
    int minimumSize = 0;

    if( word.size()>0 && ( word[0] == '-' || word[0] == '+' ) )
    {
      it++;
      minimumSize++;
    }

    while(it != word.end())
    {
      if(*it == '.')
      {
        if(!decimalPoint)
        {
          decimalPoint = true;
        }
        else
        {
          break;
        }
      }
      else if( !std::isdigit(*it) && ( (*it!='f') || it+1 != word.end() || !decimalPoint ) )
      {
        break;
      }

      ++it;
    }

    return (word.size()>minimumSize && it == word.end());
}
<commit_msg>removed init&cleanupTestCase methods<commit_after>//
// Copyright (C) 2016 University of Amsterdam
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU 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, see <http://www.gnu.org/licenses/>.
//

#include "spssimporter_test.h"

void SPSSImporterTest::init()
{
  fe = new FileEvent();
  dsp = new DataSetPackage();
  asl = new AsyncLoader();

  fe2 = new FileEvent();
  dsp2 = new DataSetPackage();
  asl2 = new AsyncLoader();
}

void SPSSImporterTest::cleanup()
{
  // destroy all the objects created and delete the dataSet from the shared memory
  //SharedMemory::deleteDataSet(dsp->dataSet);
  //SharedMemory::deleteDataSet(dsp2->dataSet);

  fe->~FileEvent();
  dsp->~DataSetPackage();
  asl->~AsyncLoader();

  fe2->~FileEvent();
  dsp2->~DataSetPackage();
  asl2->~AsyncLoader();
}

void SPSSImporterTest::spssTester_data()
{
  QTest::addColumn<QString>("filename");
  int count = 0;

  boost::filesystem::path p("test_files/spss_files");

  //add files to be tested in a folder "test_files"
  for (auto i = boost::filesystem::directory_iterator(p); i != boost::filesystem::directory_iterator(); i++)
  {
    if (!boost::filesystem::is_directory(i->path())) //we eliminate directories
    {
      QTest::newRow("spss file test") << QString::fromStdString(i->path().filename().string());
      count++;
    }
  }
}

void SPSSImporterTest::spssTester()
{
  QFETCH(QString, filename);

  //spss file
  QString full_path1 = QString("test_files/spss_files/").append(filename);
  qDebug() << "filename: " << filename;

  DataSetPackage *ds_spss = new DataSetPackage();
  fe->setOperation(FileEvent::FileOpen);
  fe->setPath(full_path1);
  asl->loadTask(fe, ds_spss);
  asl->_thread.quit();

  struct fileContent fc1;
  copyToStructure(ds_spss, &fc1);
  SharedMemory::deleteDataSet(ds_spss->dataSet);
  ds_spss->~DataSetPackage();

  //csv file
  QString csvFile = filename;
  csvFile.replace(filename.size()-3, 3, "csv");
  QString full_path2 = QString("test_files/csv_files/").append(csvFile);
  qDebug() << "csv filename: " << csvFile;

  DataSetPackage *ds_csv = new DataSetPackage();
  fe2->setOperation(FileEvent::FileOpen);
  fe2->setPath(full_path2);
  asl2->loadTask(fe2, ds_csv);
  asl2->_thread.quit();

  struct fileContent fc2;
  copyToStructure(ds_csv, &fc2);
  SharedMemory::deleteDataSet(ds_csv->dataSet);
  ds_csv->~DataSetPackage();

  bool ans = checkIfEqual(&fc1, &fc2);
  QVERIFY(ans); // end of test
}

void SPSSImporterTest::copyToStructure(DataSetPackage *dsPackage, struct fileContent *fc)
{
  fc->columns = dsPackage->dataSet->columnCount();//copy column count
  fc->rows = dsPackage->dataSet->rowCount();      //copy row count

  //headers copy
  std::vector<std::string> headerNames;
  for(int i=0; i<fc->columns; ++i)
  {
    headerNames.push_back(dsPackage->dataSet->column(i).name());
  }
  fc->headers = headerNames;

  //copy data
  std::vector< std::vector<std::string> > fileRows;
  for(int j=0; j<fc->rows; ++j)
  {
    std::vector<std::string> tempRow;
    for(int i=0; i<fc->columns; ++i)
    {
      tempRow.push_back(dsPackage->dataSet->column(i)[j]);
    }
    fileRows.push_back(tempRow);
    tempRow.clear();
  }

  fc->data = fileRows;
  return;
}

/* checks if data read from file is same as the data stored in the shared memory */
bool SPSSImporterTest::checkIfEqual(struct fileContent *fc1, struct fileContent *fc2)
{
  if(fc1->columns != fc2->columns)
  {
    qDebug() << "Column size mismatch";
    return false;
  }

  if(fc1->rows != fc2->rows)
  {
    qDebug() << "Row size mismatch" << QString::number(fc1->rows) << " " << QString::number(fc2->rows);
    //return false;
  }

  for(int i=0; i<fc2->columns; ++i)
  {
    if(fc1->headers[i] != fc2->headers[i])
    {
      qDebug() << "Header name mismatch";
      return false;
    }

    for(int j=0; j<fc2->rows; ++j)
    {

      if(fc1->data[j][i] != fc2->data[j][i])
      {qDebug() << "Data mismatch " << QString::number(j);
        qDebug() << QString::fromStdString(fc2->data[j][i])<< " " << QString::fromStdString(fc1->data[j][i]);
        return false;
      }
    }
  }

  return true;
}

/* read data from the file specified from path and store it in the struct fileContent */
int SPSSImporterTest::readDataFromCSV(QString path, struct fileContent *fc)
{
  std::ifstream input(path.toStdString().c_str());
  std::vector< std::vector<std::string> > fileRows;
  std::string currentWord;

  if(input.is_open())
  {
    for(CSVIterator csvIter(input); csvIter != CSVIterator(); ++csvIter)
    {
      std::vector<std::string> tempRow; //has one row

      if((*csvIter).size() <=0)
      {
        continue;
      }
      if((*csvIter).size() == 1 && trim((*csvIter)[0]) == "")
      {
        continue;
      }
      for(int i=0; i<(*csvIter).size(); ++i)
      {
        currentWord = (*csvIter)[i];
        if(currentWord == "")
        {
          currentWord = ".";
        }
        else
        {
          if(!fileRows.empty())
          {
            if(columnIsNumeric[i])//check if the column has strings that are non-nueric
            {
              if(!checkIfNumeric(currentWord)) //check if the currentWord is numeric
              {
                columnIsNumeric[i] = false;
              }
            }
          }
        }

        tempRow.push_back(currentWord);
      }

      fileRows.push_back(tempRow);
      tempRow.clear();
    }

    fc->rows = fileRows.size() - 1;
    fc->columns = fileRows[0].size();
    fc->headers = fileRows[0];
    fileRows.erase(fileRows.begin());
    fc->data = fileRows;

    return 0;
  }
  else
  {
    qDebug() << "Unable to open file: " << path;
    return 1;
  }
}

std::string SPSSImporterTest::roundTo6Digits(double x, int n)
{
  char buff[32];
  sprintf(buff, "%.*g", n, x);
  std::string cppString(buff);
  return cppString;
}

bool SPSSImporterTest::checkIfNumeric(std::string word)
{
    std::string::const_iterator it = word.begin();
    bool decimalPoint = false;
    int minimumSize = 0;

    if( word.size()>0 && ( word[0] == '-' || word[0] == '+' ) )
    {
      it++;
      minimumSize++;
    }

    while(it != word.end())
    {
      if(*it == '.')
      {
        if(!decimalPoint)
        {
          decimalPoint = true;
        }
        else
        {
          break;
        }
      }
      else if( !std::isdigit(*it) && ( (*it!='f') || it+1 != word.end() || !decimalPoint ) )
      {
        break;
      }

      ++it;
    }

    return (word.size()>minimumSize && it == word.end());
}
<|endoftext|>


<commit_before>#include "pivision_grayscaleimage.h"
#include "jobdispatcher.h"
#include "pivision_events.h"
#include "pivision_services.h"
#include "pivision_grayscaleimagejob.h"
#include "pivision_threadmodel.h"

PiVisionGrayscaleImage::PiVisionGrayscaleImage() :
numJobsOngoing(0u),
NUM_JOBS_LIMIT(2u)
{
  JobDispatcher::GetApi()->SubscribeToEvent(PIVISION_EVENT_SERVICE_AVAILABLE_IND, this);
  JobDispatcher::GetApi()->SubscribeToEvent(PIVISION_EVENT_GRAYSCALE_JOB_COMPLETE_IND, this);

  auto subscribeService = std::make_shared<PiVisionSubscribeServiceInd>(PIVISION_COLOR_IMAGE_SERVICE_RX);
  JobDispatcher::GetApi()->RaiseEvent(PIVISION_EVENT_SUBSCRIBE_SERVICE_IND, subscribeService);
}

PiVisionGrayscaleImage::~PiVisionGrayscaleImage()
{
  JobDispatcher::GetApi()->UnsubscribeToEvent(PIVISION_EVENT_SERVICE_AVAILABLE_IND, this);
  JobDispatcher::GetApi()->UnsubscribeToEvent(PIVISION_EVENT_GRAYSCALE_JOB_COMPLETE_IND, this);
}

void PiVisionGrayscaleImage::HandleEvent(const uint32_t eventNo, std::shared_ptr<EventDataBase> dataPtr)
{
  switch(eventNo)
  {
    case PIVISION_COLOR_IMAGE_SERVICE_RX:
    {
      if(NUM_JOBS_LIMIT > numJobsOngoing)
      {
        auto imageData = std::static_pointer_cast<PiVisionNewDataInd>(dataPtr);
        auto grayscaleJob = std::make_shared<PiVisionGrayscaleImageJob>(imageData);
        JobDispatcher::GetApi()->ExecuteJobInGroup(grayscaleJob, PIVISION_GRAYSCALE_JOB_THREAD_ID);
        numJobsOngoing += 1u;
      }
    }
    break;
    case PIVISION_EVENT_SERVICE_AVAILABLE_IND:
    {
      auto serviceAvailable = std::static_pointer_cast<PiVisionServiceAvailableInd>(dataPtr);
      if(PIVISION_COLOR_IMAGE_SERVICE_RX == serviceAvailable->serviceNo)
      {
        JobDispatcher::GetApi()->Log("PiVisionGrayscaleImage found color image service");
        JobDispatcher::GetApi()->SubscribeToEvent(PIVISION_COLOR_IMAGE_SERVICE_RX, this);
        auto serviceProvided = std::make_shared<PiVisionServiceAvailableInd>(PIVISION_BW_IMAGE_SERVICE_RX);
        JobDispatcher::GetApi()->RaiseEvent(PIVISION_EVENT_SERVICE_PROVIDED_IND, serviceProvided);
      }
    }
    break;
    case PIVISION_EVENT_GRAYSCALE_JOB_COMPLETE_IND:
    {
      numJobsOngoing -= 1u;
    }
    break;
    default:
      JobDispatcher::GetApi()->Log("PiVisionGrayscaleImage received unexpected event: 0x%x", eventNo);
      break;
  }
}
<commit_msg>Allow at most 1 grayscale job in queue<commit_after>#include "pivision_grayscaleimage.h"
#include "jobdispatcher.h"
#include "pivision_events.h"
#include "pivision_services.h"
#include "pivision_grayscaleimagejob.h"
#include "pivision_threadmodel.h"

PiVisionGrayscaleImage::PiVisionGrayscaleImage() :
numJobsOngoing(0u),
NUM_JOBS_LIMIT(1u)
{
  JobDispatcher::GetApi()->SubscribeToEvent(PIVISION_EVENT_SERVICE_AVAILABLE_IND, this);
  JobDispatcher::GetApi()->SubscribeToEvent(PIVISION_EVENT_GRAYSCALE_JOB_COMPLETE_IND, this);

  auto subscribeService = std::make_shared<PiVisionSubscribeServiceInd>(PIVISION_COLOR_IMAGE_SERVICE_RX);
  JobDispatcher::GetApi()->RaiseEvent(PIVISION_EVENT_SUBSCRIBE_SERVICE_IND, subscribeService);
}

PiVisionGrayscaleImage::~PiVisionGrayscaleImage()
{
  JobDispatcher::GetApi()->UnsubscribeToEvent(PIVISION_EVENT_SERVICE_AVAILABLE_IND, this);
  JobDispatcher::GetApi()->UnsubscribeToEvent(PIVISION_EVENT_GRAYSCALE_JOB_COMPLETE_IND, this);
}

void PiVisionGrayscaleImage::HandleEvent(const uint32_t eventNo, std::shared_ptr<EventDataBase> dataPtr)
{
  switch(eventNo)
  {
    case PIVISION_COLOR_IMAGE_SERVICE_RX:
    {
      if(NUM_JOBS_LIMIT > numJobsOngoing)
      {
        auto imageData = std::static_pointer_cast<PiVisionNewDataInd>(dataPtr);
        auto grayscaleJob = std::make_shared<PiVisionGrayscaleImageJob>(imageData);
        JobDispatcher::GetApi()->ExecuteJobInGroup(grayscaleJob, PIVISION_GRAYSCALE_JOB_THREAD_ID);
        numJobsOngoing += 1u;
      }
    }
    break;
    case PIVISION_EVENT_SERVICE_AVAILABLE_IND:
    {
      auto serviceAvailable = std::static_pointer_cast<PiVisionServiceAvailableInd>(dataPtr);
      if(PIVISION_COLOR_IMAGE_SERVICE_RX == serviceAvailable->serviceNo)
      {
        JobDispatcher::GetApi()->Log("PiVisionGrayscaleImage found color image service");
        JobDispatcher::GetApi()->SubscribeToEvent(PIVISION_COLOR_IMAGE_SERVICE_RX, this);
        auto serviceProvided = std::make_shared<PiVisionServiceAvailableInd>(PIVISION_BW_IMAGE_SERVICE_RX);
        JobDispatcher::GetApi()->RaiseEvent(PIVISION_EVENT_SERVICE_PROVIDED_IND, serviceProvided);
      }
    }
    break;
    case PIVISION_EVENT_GRAYSCALE_JOB_COMPLETE_IND:
    {
      numJobsOngoing -= 1u;
    }
    break;
    default:
      JobDispatcher::GetApi()->Log("PiVisionGrayscaleImage received unexpected event: 0x%x", eventNo);
      break;
  }
}
<|endoftext|>


<commit_before>/*
 * Contact groups model item, represents a group in the contactlist tree
 * This file is based on TelepathyQtYell Models
 *
 * Copyright (C) 2010 Collabora Ltd. <info@collabora.com>
 * Copyright (C) 2011 Martin Klapetek <martin dot klapetek at gmail dot com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "groups-model-item.h"

#include <TelepathyQt/Account>
#include <TelepathyQt/ContactManager>

#include <KLocalizedString>

#include "groups-model.h"
#include "accounts-model.h"
#include "proxy-tree-node.h"
#include "contact-model-item.h"

struct GroupsModelItem::Private
{
    Private(const QString &groupName)
        : mGroupName(groupName)
    {
    }

    void setGroupName(const QString &value);
    QString groupName();

    QString mGroupName;
};

void GroupsModelItem::Private::setGroupName(const QString& value)
{
    mGroupName = value;
}

QString GroupsModelItem::Private::groupName()
{
    return mGroupName;
}

GroupsModelItem::GroupsModelItem(const QString &groupName)
    : mPriv(new Private(groupName))
{
}

GroupsModelItem::~GroupsModelItem()
{
    delete mPriv;
}

QVariant GroupsModelItem::data(int role) const
{
    switch (role) {
    case Qt::DisplayRole:
        if (mPriv->mGroupName.isEmpty()) {
            return i18n("Ungrouped");
        } else {
            return mPriv->mGroupName;
        }
    case AccountsModel::ItemRole:
        return QVariant::fromValue((GroupsModelItem*)this);
    case AccountsModel::IdRole:
        /* drop through*/
    case GroupsModel::GroupNameRole:
        return mPriv->mGroupName;
    default:
        return QVariant();
    }
}

bool GroupsModelItem::setData(int role, const QVariant &value)
{
    switch (role) {
    case GroupsModel::GroupNameRole:
        setGroupName(value.toString());
        return true;
    default:
        return false;
    }
}

void GroupsModelItem::setGroupName(const QString& value)
{
    mPriv->setGroupName(value);
}

QString GroupsModelItem::groupName()
{
    return mPriv->groupName();
}

void GroupsModelItem::addProxyContact(ProxyTreeNode *proxyNode)
{
    Q_EMIT childrenAdded(this, QList<TreeNode*>() << proxyNode);

    //the group counters needs to be updated
    Q_EMIT changed(this);
}

void GroupsModelItem::removeProxyContact(ProxyTreeNode *proxyNode)
{
    Q_EMIT childrenRemoved(this, indexOf(proxyNode), indexOf(proxyNode));

    //the group counters needs to be updated
    Q_EMIT changed(this);
}
<commit_msg>Return default id for groups without names<commit_after>/*
 * Contact groups model item, represents a group in the contactlist tree
 * This file is based on TelepathyQtYell Models
 *
 * Copyright (C) 2010 Collabora Ltd. <info@collabora.com>
 * Copyright (C) 2011 Martin Klapetek <martin dot klapetek at gmail dot com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "groups-model-item.h"

#include <TelepathyQt/Account>
#include <TelepathyQt/ContactManager>

#include <KLocalizedString>

#include "groups-model.h"
#include "accounts-model.h"
#include "proxy-tree-node.h"
#include "contact-model-item.h"

struct GroupsModelItem::Private
{
    Private(const QString &groupName)
        : mGroupName(groupName)
    {
    }

    void setGroupName(const QString &value);
    QString groupName();

    QString mGroupName;
};

void GroupsModelItem::Private::setGroupName(const QString& value)
{
    mGroupName = value;
}

QString GroupsModelItem::Private::groupName()
{
    return mGroupName;
}

GroupsModelItem::GroupsModelItem(const QString &groupName)
    : mPriv(new Private(groupName))
{
}

GroupsModelItem::~GroupsModelItem()
{
    delete mPriv;
}

QVariant GroupsModelItem::data(int role) const
{
    switch (role) {
    case Qt::DisplayRole:
        if (mPriv->mGroupName.isEmpty()) {
            return i18n("Ungrouped");
        } else {
            return mPriv->mGroupName;
        }
    case AccountsModel::ItemRole:
        return QVariant::fromValue((GroupsModelItem*)this);
    case AccountsModel::IdRole:
        return mPriv->mGroupName.isEmpty() ? QLatin1String("default_group_name") : mPriv->groupName();
    case GroupsModel::GroupNameRole:
        return mPriv->mGroupName;
    default:
        return QVariant();
    }
}

bool GroupsModelItem::setData(int role, const QVariant &value)
{
    switch (role) {
    case GroupsModel::GroupNameRole:
        setGroupName(value.toString());
        return true;
    default:
        return false;
    }
}

void GroupsModelItem::setGroupName(const QString& value)
{
    mPriv->setGroupName(value);
}

QString GroupsModelItem::groupName()
{
    return mPriv->groupName();
}

void GroupsModelItem::addProxyContact(ProxyTreeNode *proxyNode)
{
    Q_EMIT childrenAdded(this, QList<TreeNode*>() << proxyNode);

    //the group counters needs to be updated
    Q_EMIT changed(this);
}

void GroupsModelItem::removeProxyContact(ProxyTreeNode *proxyNode)
{
    Q_EMIT childrenRemoved(this, indexOf(proxyNode), indexOf(proxyNode));

    //the group counters needs to be updated
    Q_EMIT changed(this);
}
<|endoftext|>


<commit_before>/*The MIT License (MIT)

Copyright (c) [2015] [Sawyer Hopkins]

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 "LJPotential.h"

LennardJones::~LennardJones()
{
}

LennardJones::LennardJones(config* cfg)
{
	//Sets the name
	name = "Lennard Jones";

	kT = cfg->getParam<double>("kT", 1.0);
	wellDepth = cfg->getParam<double>("wellDepth", 10.0);

	//Get the radius
	radius = cfg->getParam<double>("radius",0.5);

	//Get the mass
	mass = cfg->getParam<double>("mass",1.0);

	//Get the well depth
	yukStr = cfg->getParam<double>("yukawaStrength",8.0);

	//Get the well depth
	ljNum = cfg->getParam<int>("ljNum",18.0);

	//Get the cutoff range
	cutOff = cfg->getParam<double>("cutOff",2.5);
	cutOffSquared = cutOff*cutOff;

	//Get the debye length for the system.
	debyeLength = cfg->getParam<double>("debyeLength",0.5);
	debyeInv = 1.0 / debyeLength;

	output = true;

	callCount=0;

	PSim::util::writeTerminal("---Lennard Jones Potential successfully added.\n\n", PSim::Colour::Cyan);
}

type3<double> LennardJones::iterCells(int index, int hash, double* sortedParticles, vector<tuple<int,int>>* cellStartEnd, systemState* state)
{
	int start = get<0>((*cellStartEnd)[hash]);

	type3<double> cellForce = type3<double>();

	if (start != 0xffffffff) {
		int end = get<1>((*cellStartEnd)[hash]);
		for (int i=start; i<end; i++) {
			if (i != index) {
				int indexOffset = 4*index;
				int iOffset = 4*i;

				double rSquared = PSim::util::pbcDist(sortedParticles[indexOffset], sortedParticles[indexOffset+1], sortedParticles[indexOffset+2],
																	sortedParticles[iOffset], sortedParticles[iOffset+1], sortedParticles[iOffset+2],
																	state->boxSize);

				//If the particles are in the potential well.
				if (rSquared < cutOffSquared)
				{
					double r = sqrt(rSquared);
					//If the particles overlap there are problems.
					double size = (sortedParticles[indexOffset+3] + sortedParticles[iOffset+3]);
					if(r< (0.8*size) )
					{
						PSim::error::throwParticleOverlapError(hash, i, index, r);
					}

					//-------------------------------------
					//-----------FORCE CALCULATION---------
					//-------------------------------------

					//Predefinitions.
					double rInv = (1.0  / r);
					double yukExp = std::exp(-1.0 * (r * debyeInv));
					double LJ = PSim::util::powBinaryDecomp((size / r),ljNum);

					//Attractive LJ.
					double attract = ((2.0*LJ) - 1.0);
					attract *= (4.0*ljNum*rInv*LJ);

					//Repulsive Yukawa.
					double repel = yukExp;
					repel *= (rInv*rInv*(debyeLength + r)*yukStr);

					double fNet = -kT*wellDepth*(attract+repel);

					//Positive is attractive; Negative repulsive.
					//fNet = -fNet;

					//-------------------------------------
					//------NORMALIZATION AND SETTING------
					//-------------------------------------

					//Normalize the force.
					double unitVec[3] {0.0,0.0,0.0};
					PSim::util::unitVectorAdv(sortedParticles[indexOffset], sortedParticles[indexOffset+1], sortedParticles[indexOffset+2],
														sortedParticles[iOffset], sortedParticles[iOffset+1], sortedParticles[iOffset+2],
														unitVec, r, state->boxSize);

					//Updates the acceleration.;
					cellForce.x += fNet*unitVec[0];
					cellForce.y += fNet*unitVec[1];
					cellForce.z += fNet*unitVec[2];
				}
			}
		}
	}
	return cellForce;
}

void LennardJones::getAcceleration(int index, double* sortedParticles, double* particleForce, vector<tuple<int,int>>* particleHashIndex, vector<tuple<int,int>>* cellStartEnd, systemState* state)
{
	int hash = 0;
	int indexOffset = index*4;
	type3<int> cell = type3<int>();
	type3<int> cRef = type3<int>();
	double netForce[3] = {0.0,0.0,0.0};
	int scale = state->cellScale;
	int cellScaleSq = scale*scale;
	int realIndex = 3*get<1>((*particleHashIndex)[index]);

	cell.x = floor(sortedParticles[indexOffset] / state->cellSize);
	cell.y = floor(sortedParticles[indexOffset+1] / state->cellSize);
	cell.z = floor(sortedParticles[indexOffset+2] / state->cellSize);

	for (int x=-1; x<=1; x++) {
		for (int y=-1; y<=1; y++) {
			for (int z=-1; z<=1; z++) {
				cRef.x = cell.x + x;
				cRef.y = cell.y + y;
				cRef.z = cell.z + z;

				cRef.x = cRef.x % scale;
				cRef.y = cRef.y % scale;
				cRef.z = cRef.z % scale;

				cRef.x = (cRef.x < 0) ? cRef.x + scale : cRef.x;
				cRef.y = (cRef.y < 0) ? cRef.y + scale : cRef.y;
				cRef.z = (cRef.z < 0) ? cRef.z + scale : cRef.z;

				hash = cRef.x + (scale * cRef.y) + (cellScaleSq * cRef.z);

				type3<double> result = iterCells(index, hash, sortedParticles, cellStartEnd, state);
				netForce[0] += result.x;
				netForce[1] += result.y;
				netForce[2] += result.z;
			}
		}
	}

	particleForce[realIndex] = netForce[0];
	particleForce[realIndex+1] = netForce[1];
	particleForce[realIndex+2] = netForce[2];
}

<commit_msg>fixed lj potential<commit_after>/*The MIT License (MIT)

Copyright (c) [2015] [Sawyer Hopkins]

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 "LJPotential.h"

LennardJones::~LennardJones()
{
}

LennardJones::LennardJones(config* cfg)
{
	//Sets the name
	name = "Lennard Jones";

	kT = cfg->getParam<double>("kT", 1.0);
	wellDepth = cfg->getParam<double>("wellDepth", 10.0);

	//Get the radius
	radius = cfg->getParam<double>("radius",0.5);

	//Get the mass
	mass = cfg->getParam<double>("mass",1.0);

	//Get the well depth
	yukStr = cfg->getParam<double>("yukawaStrength",8.0);

	//Get the well depth
	ljNum = cfg->getParam<int>("ljNum",18.0);

	//Get the cutoff range
	cutOff = cfg->getParam<double>("cutOff",2.5);
	cutOffSquared = cutOff*cutOff;

	//Get the debye length for the system.
	debyeLength = cfg->getParam<double>("debyeLength",0.5);
	debyeInv = 1.0 / debyeLength;

	output = true;

	callCount=0;

	PSim::util::writeTerminal("---Lennard Jones Potential successfully added.\n\n", PSim::Colour::Cyan);
}

type3<double> LennardJones::iterCells(int index, int hash, double* sortedParticles, vector<tuple<int,int>>* cellStartEnd, systemState* state)
{
	int start = get<0>((*cellStartEnd)[hash]);

	type3<double> cellForce = type3<double>();

	if (start != 0xffffffff) {
		int end = get<1>((*cellStartEnd)[hash]);
		for (int i=start; i<end; i++) {
			if (i != index) {
				int indexOffset = 4*index;
				int iOffset = 4*i;

				double rSquared = PSim::util::pbcDist(sortedParticles[indexOffset], sortedParticles[indexOffset+1], sortedParticles[indexOffset+2],
																	sortedParticles[iOffset], sortedParticles[iOffset+1], sortedParticles[iOffset+2],
																	state->boxSize);

				//If the particles are in the potential well.
				if (rSquared < cutOffSquared)
				{
					double r = sqrt(rSquared);
					//If the particles overlap there are problems.
					double size = (sortedParticles[indexOffset+3] + sortedParticles[iOffset+3]);
					if(r< (0.8*size) )
					{
						PSim::error::throwParticleOverlapError(hash, i, index, r);
					}

					//-------------------------------------
					//-----------FORCE CALCULATION---------
					//-------------------------------------

					//Predefinitions.
					double rInv = (1.0  / r);
					double yukExp = std::exp(-1.0 * (r * debyeInv));
					double LJ = PSim::util::powBinaryDecomp((size / r),ljNum);

					//Attractive LJ.
					double attract = ((2.0*LJ) - 1.0);
					attract *= (4.0*ljNum*rInv*LJ);

					//Repulsive Yukawa.
					double repel = yukExp;
					repel *= (rInv*rInv*(debyeLength + r)*yukStr);

					double fNet = -kT*wellDepth*(attract+repel);

					//Positive is attractive; Negative repulsive.
					//fNet = -fNet;

					//-------------------------------------
					//------NORMALIZATION AND SETTING------
					//-------------------------------------

					//Normalize the force.
					double unitVec[3] {0.0,0.0,0.0};
					PSim::util::unitVectorAdv(sortedParticles[indexOffset], sortedParticles[indexOffset+1], sortedParticles[indexOffset+2],
														sortedParticles[iOffset], sortedParticles[iOffset+1], sortedParticles[iOffset+2],
														unitVec, r, state->boxSize);

					//Updates the acceleration.;
					cellForce.x += fNet*unitVec[0];
					cellForce.y += fNet*unitVec[1];
					cellForce.z += fNet*unitVec[2];
				}
			}
		}
	}
	return cellForce;
}

void LennardJones::quench(systemState* state)
{
}

void LennardJones::getAcceleration(int index, double* sortedParticles, double* particleForce, vector<tuple<int,int>>* particleHashIndex, vector<tuple<int,int>>* cellStartEnd, systemState* state)
{
	int hash = 0;
	int indexOffset = index*4;
	type3<int> cell = type3<int>();
	type3<int> cRef = type3<int>();
	double netForce[3] = {0.0,0.0,0.0};
	int scale = state->cellScale;
	int cellScaleSq = scale*scale;
	int realIndex = 3*get<1>((*particleHashIndex)[index]);

	cell.x = floor(sortedParticles[indexOffset] / state->cellSize);
	cell.y = floor(sortedParticles[indexOffset+1] / state->cellSize);
	cell.z = floor(sortedParticles[indexOffset+2] / state->cellSize);

	for (int x=-1; x<=1; x++) {
		for (int y=-1; y<=1; y++) {
			for (int z=-1; z<=1; z++) {
				cRef.x = cell.x + x;
				cRef.y = cell.y + y;
				cRef.z = cell.z + z;

				cRef.x = cRef.x % scale;
				cRef.y = cRef.y % scale;
				cRef.z = cRef.z % scale;

				cRef.x = (cRef.x < 0) ? cRef.x + scale : cRef.x;
				cRef.y = (cRef.y < 0) ? cRef.y + scale : cRef.y;
				cRef.z = (cRef.z < 0) ? cRef.z + scale : cRef.z;

				hash = cRef.x + (scale * cRef.y) + (cellScaleSq * cRef.z);

				type3<double> result = iterCells(index, hash, sortedParticles, cellStartEnd, state);
				netForce[0] += result.x;
				netForce[1] += result.y;
				netForce[2] += result.z;
			}
		}
	}

	particleForce[realIndex] = netForce[0];
	particleForce[realIndex+1] = netForce[1];
	particleForce[realIndex+2] = netForce[2];
}

<|endoftext|>