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

  Program:   Visualization Toolkit
  Module:    vtkPixel.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkPixel.hh"
#include "vtkQuad.hh"
#include "vtkPolygon.hh"
#include "vtkPlane.hh"
#include "vtkMath.hh"
#include "vtkCellArray.hh"
#include "vtkLine.hh"

static vtkMath math;
static vtkPlane plane;
static vtkPolygon poly;

// Description:
// Deep copy of cell.
vtkPixel::vtkPixel(const vtkPixel& p)
{
  this->Points = p.Points;
  this->PointIds = p.PointIds;
}

int vtkPixel::EvaluatePosition(float x[3], float closestPoint[3],
                                  int& subId, float pcoords[3],
                                  float& dist2, float *weights)
{
  float *pt1, *pt2, *pt3;
  int i;
  float p[3], p21[3], p31[3];
  float l21, l31, n[3];

  subId = 0;
  pcoords[0] = pcoords[1] = pcoords[2] = 0.0;
//
// Get normal for pixel
//
  pt1 = this->Points.GetPoint(0);
  pt2 = this->Points.GetPoint(1);
  pt3 = this->Points.GetPoint(2);

  poly.ComputeNormal (pt1, pt2, pt3, n);
//
// Project point to plane
//
  plane.ProjectPoint(x,pt1,n,closestPoint);

  for (i=0; i<3; i++)
    {
    p21[i] = pt2[i] - pt1[i];
    p31[i] = pt3[i] - pt1[i];
    p[i] = x[i] - pt1[i];
    }

  if ( (l21=math.Norm(p21)) == 0.0 ) l21 = 1.0;
  if ( (l31=math.Norm(p31)) == 0.0 ) l31 = 1.0;

  pcoords[0] = math.Dot(p21,p) / (l21*l21);
  pcoords[1] = math.Dot(p31,p) / (l31*l31);

  this->InterpolationFunctions(pcoords, weights);

  if ( pcoords[0] >= 0.0 && pcoords[1] <= 1.0 &&
  pcoords[1] >= 0.0 && pcoords[1] <= 1.0 )
    {
    dist2 = math.Distance2BetweenPoints(closestPoint,x); //projection distance
    return 1;
    }
  else
    {
    float pc[3], w[4];
    for (i=0; i<2; i++)
      {
      if (pcoords[i] < 0.0) pc[i] = 0.0;
      else if (pcoords[i] > 1.0) pc[i] = 1.0;
      else pc[i] = pcoords[i];
      }
    this->EvaluateLocation(subId, pc, closestPoint, (float *)w);
    dist2 = math.Distance2BetweenPoints(closestPoint,x);
    return 0;
    }
}

void vtkPixel::EvaluateLocation(int& subId, float pcoords[3], float x[3],
                                   float *weights)
{
  float *pt1, *pt2, *pt3;
  int i;

  pt1 = this->Points.GetPoint(0);
  pt2 = this->Points.GetPoint(1);
  pt3 = this->Points.GetPoint(2);

  for (i=0; i<3; i++)
    {
    x[i] = pt1[i] + pcoords[0]*(pt2[i] - pt1[i]) +
                    pcoords[1]*(pt3[i] - pt1[i]);
    }

  this->InterpolationFunctions(pcoords, weights);
}

int vtkPixel::CellBoundary(int subId, float pcoords[3], vtkIdList& pts)
{
  float t1=pcoords[0]-pcoords[1];
  float t2=1.0-pcoords[0]-pcoords[1];

  pts.Reset();

  // compare against two lines in parametric space that divide element
  // into four pieces.
  if ( t1 >= 0.0 && t2 >= 0.0 )
    {
    pts.SetId(0,this->PointIds.GetId(0));
    pts.SetId(1,this->PointIds.GetId(1));
    }

  else if ( t1 >= 0.0 && t2 < 0.0 )
    {
    pts.SetId(0,this->PointIds.GetId(1));
    pts.SetId(1,this->PointIds.GetId(3));
    }

  else if ( t1 < 0.0 && t2 < 0.0 )
    {
    pts.SetId(0,this->PointIds.GetId(3));
    pts.SetId(1,this->PointIds.GetId(2));
    }

  else //( t1 < 0.0 && t2 >= 0.0 )
    {
    pts.SetId(0,this->PointIds.GetId(2));
    pts.SetId(1,this->PointIds.GetId(0));
    }

  if ( pcoords[0] < 0.0 || pcoords[0] > 1.0 ||
  pcoords[1] < 0.0 || pcoords[1] > 1.0 )
    return 0;
  else
    return 1;
}

//
// Marching squares
//
static int edges[4][2] = { {0,1}, {1,3}, {3,2}, {2,0} };

typedef int EDGE_LIST;
typedef struct {
       EDGE_LIST edges[5];
} LINE_CASES;

static LINE_CASES lineCases[] = {
  {{-1, -1, -1, -1, -1}},
  {{0, 3, -1, -1, -1}},
  {{1, 0, -1, -1, -1}},
  {{1, 3, -1, -1, -1}},
  {{2, 1, -1, -1, -1}},
  {{0, 3, 2, 1, -1}},
  {{2, 0, -1, -1, -1}},
  {{2, 3, -1, -1, -1}},
  {{3, 2, -1, -1, -1}},
  {{0, 2, -1, -1, -1}},
  {{1, 0, 3, 2, -1}},
  {{1, 2, -1, -1, -1}},
  {{3, 1, -1, -1, -1}},
  {{0, 1, -1, -1, -1}},
  {{3, 0, -1, -1, -1}},
  {{-1, -1, -1, -1, -1}}
};

void vtkPixel::Contour(float value, vtkFloatScalars *cellScalars,
                     vtkFloatPoints *points, vtkCellArray *verts,
                     vtkCellArray *lines, vtkCellArray *polys,
                     vtkFloatScalars *scalars)
{
  static int CASE_MASK[4] = {1,2,8,4}; //note difference!
  LINE_CASES *lineCase;
  EDGE_LIST  *edge;
  int i, j, index, *vert;
  int pts[2];
  float t, *x1, *x2, x[3];

  // Build the case table
  for ( i=0, index = 0; i < 4; i++)
      if (cellScalars->GetScalar(i) >= value)
          index |= CASE_MASK[i];

  lineCase = lineCases + index;
  edge = lineCase->edges;

  for ( ; edge[0] > -1; edge += 2 )
    {
    for (i=0; i<2; i++) // insert line
      {
      vert = edges[edge[i]];
      t = (value - cellScalars->GetScalar(vert[0])) /
          (cellScalars->GetScalar(vert[1]) - cellScalars->GetScalar(vert[0]));
      x1 = this->Points.GetPoint(vert[0]);
      x2 = this->Points.GetPoint(vert[1]);
      for (j=0; j<3; j++) x[j] = x1[j] + t * (x2[j] - x1[j]);
      pts[i] = points->InsertNextPoint(x);
      scalars->InsertNextScalar(value);
      }
    lines->InsertNextCell(2,pts);
    }
}

vtkCell *vtkPixel::GetEdge(int edgeId)
{
  static vtkLine line;
  int *verts;

  verts = edges[edgeId];

  // load point id's
  line.PointIds.SetId(0,this->PointIds.GetId(verts[0]));
  line.PointIds.SetId(1,this->PointIds.GetId(verts[1]));

  // load coordinates
  line.Points.SetPoint(0,this->Points.GetPoint(verts[0]));
  line.Points.SetPoint(1,this->Points.GetPoint(verts[1]));

  return &line;
}
//
// Compute interpolation functions (similar but different than Quad interpolation functions)
//
void vtkPixel::InterpolationFunctions(float pcoords[3], float sf[4])
{
  float rm, sm;

  rm = 1. - pcoords[0];
  sm = 1. - pcoords[1];

  sf[0] = rm * sm;
  sf[1] = pcoords[0] * sm;
  sf[2] = rm * pcoords[1];
  sf[3] = pcoords[0] * pcoords[1];
}

//
// Intersect plane; see whether point is inside.
//
int vtkPixel::IntersectWithLine(float p1[3], float p2[3], float tol, float& t,
                                float x[3], float pcoords[3], int& subId)
{
  float *pt1, *pt2, *pt3, *pt4, n[3];
  float tol2 = tol*tol;
  float closestPoint[3];
  float dist2, weights[4];
  int i;

  subId = 0;
  pcoords[0] = pcoords[1] = pcoords[2] = 0.0;
//
// Get normal for triangle
//
  pt1 = this->Points.GetPoint(0);
  pt2 = this->Points.GetPoint(1);
  pt3 = this->Points.GetPoint(2);
  pt4 = this->Points.GetPoint(3);

  n[0] = n[1] = n[2] = 0.0;
  for (i=0; i<3; i++)
    {
    if ( (pt4[i] - pt1[i]) <= 0.0 )
      {
      n[i] = 1.0;
      break;
      }
    }
//
// Intersect plane of pixel with line
//
  if ( ! plane.IntersectWithLine(p1,p2,n,pt1,t,x) ) return 0;
//
// Use evaluate position
//
  if (this->EvaluatePosition(x, closestPoint, subId, pcoords, dist2, weights) )
    if ( dist2 <= tol2 ) return 1;

  return 0;
}

int vtkPixel::Triangulate(int index, vtkFloatPoints &pts)
{
  pts.Reset();
  pts.InsertPoint(0,this->Points.GetPoint(0));
  pts.InsertPoint(1,this->Points.GetPoint(1));
  pts.InsertPoint(2,this->Points.GetPoint(2));

  pts.InsertPoint(3,this->Points.GetPoint(1));
  pts.InsertPoint(4,this->Points.GetPoint(3));
  pts.InsertPoint(5,this->Points.GetPoint(2));

  return 1;
}

void vtkPixel::Derivatives(int subId, float pcoords[3], float *values,
                            int dim, float *derivs)
{
  int i, idx;

  // The following code is incorrect. Will be fixed in future release.
  for (i=0; i<dim; i++)
    {
    idx = i*dim;
    derivs[idx] = 0.0;
    derivs[idx+1] = 0.0;
    derivs[idx+2] = 0.0;
    }
}

<commit_msg>changed some names to avoid name conflicts on Borland C++<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkPixel.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkPixel.hh"
#include "vtkQuad.hh"
#include "vtkPolygon.hh"
#include "vtkPlane.hh"
#include "vtkMath.hh"
#include "vtkCellArray.hh"
#include "vtkLine.hh"

static vtkPlane vtkAPlane;

// Description:
// Deep copy of cell.
vtkPixel::vtkPixel(const vtkPixel& p)
{
  this->Points = p.Points;
  this->PointIds = p.PointIds;
}

int vtkPixel::EvaluatePosition(float x[3], float closestPoint[3],
                                  int& subId, float pcoords[3],
                                  float& dist2, float *weights)
{
  float *pt1, *pt2, *pt3;
  int i;
  float p[3], p21[3], p31[3];
  float l21, l31, n[3];
  static vtkPolygon vtkAPoly;
  static vtkMath vtkAMath;

  subId = 0;
  pcoords[0] = pcoords[1] = pcoords[2] = 0.0;
//
// Get normal for pixel
//
  pt1 = this->Points.GetPoint(0);
  pt2 = this->Points.GetPoint(1);
  pt3 = this->Points.GetPoint(2);

  vtkAPoly.ComputeNormal (pt1, pt2, pt3, n);
//
// Project point to plane
//
  vtkAPlane.ProjectPoint(x,pt1,n,closestPoint);

  for (i=0; i<3; i++)
    {
    p21[i] = pt2[i] - pt1[i];
    p31[i] = pt3[i] - pt1[i];
    p[i] = x[i] - pt1[i];
    }

  if ( (l21=vtkAMath.Norm(p21)) == 0.0 ) l21 = 1.0;
  if ( (l31=vtkAMath.Norm(p31)) == 0.0 ) l31 = 1.0;

  pcoords[0] = vtkAMath.Dot(p21,p) / (l21*l21);
  pcoords[1] = vtkAMath.Dot(p31,p) / (l31*l31);

  this->InterpolationFunctions(pcoords, weights);

  if ( pcoords[0] >= 0.0 && pcoords[1] <= 1.0 &&
  pcoords[1] >= 0.0 && pcoords[1] <= 1.0 )
    {
    dist2 = vtkAMath.Distance2BetweenPoints(closestPoint,x); //projection distance
    return 1;
    }
  else
    {
    float pc[3], w[4];
    for (i=0; i<2; i++)
      {
      if (pcoords[i] < 0.0) pc[i] = 0.0;
      else if (pcoords[i] > 1.0) pc[i] = 1.0;
      else pc[i] = pcoords[i];
      }
    this->EvaluateLocation(subId, pc, closestPoint, (float *)w);
    dist2 = vtkAMath.Distance2BetweenPoints(closestPoint,x);
    return 0;
    }
}

void vtkPixel::EvaluateLocation(int& subId, float pcoords[3], float x[3],
                                   float *weights)
{
  float *pt1, *pt2, *pt3;
  int i;

  pt1 = this->Points.GetPoint(0);
  pt2 = this->Points.GetPoint(1);
  pt3 = this->Points.GetPoint(2);

  for (i=0; i<3; i++)
    {
    x[i] = pt1[i] + pcoords[0]*(pt2[i] - pt1[i]) +
                    pcoords[1]*(pt3[i] - pt1[i]);
    }

  this->InterpolationFunctions(pcoords, weights);
}

int vtkPixel::CellBoundary(int subId, float pcoords[3], vtkIdList& pts)
{
  float t1=pcoords[0]-pcoords[1];
  float t2=1.0-pcoords[0]-pcoords[1];

  pts.Reset();

  // compare against two lines in parametric space that divide element
  // into four pieces.
  if ( t1 >= 0.0 && t2 >= 0.0 )
    {
    pts.SetId(0,this->PointIds.GetId(0));
    pts.SetId(1,this->PointIds.GetId(1));
    }

  else if ( t1 >= 0.0 && t2 < 0.0 )
    {
    pts.SetId(0,this->PointIds.GetId(1));
    pts.SetId(1,this->PointIds.GetId(3));
    }

  else if ( t1 < 0.0 && t2 < 0.0 )
    {
    pts.SetId(0,this->PointIds.GetId(3));
    pts.SetId(1,this->PointIds.GetId(2));
    }

  else //( t1 < 0.0 && t2 >= 0.0 )
    {
    pts.SetId(0,this->PointIds.GetId(2));
    pts.SetId(1,this->PointIds.GetId(0));
    }

  if ( pcoords[0] < 0.0 || pcoords[0] > 1.0 ||
  pcoords[1] < 0.0 || pcoords[1] > 1.0 )
    return 0;
  else
    return 1;
}

//
// Marching squares
//
static int edges[4][2] = { {0,1}, {1,3}, {3,2}, {2,0} };

typedef int EDGE_LIST;
typedef struct {
       EDGE_LIST edges[5];
} LINE_CASES;

static LINE_CASES lineCases[] = {
  {{-1, -1, -1, -1, -1}},
  {{0, 3, -1, -1, -1}},
  {{1, 0, -1, -1, -1}},
  {{1, 3, -1, -1, -1}},
  {{2, 1, -1, -1, -1}},
  {{0, 3, 2, 1, -1}},
  {{2, 0, -1, -1, -1}},
  {{2, 3, -1, -1, -1}},
  {{3, 2, -1, -1, -1}},
  {{0, 2, -1, -1, -1}},
  {{1, 0, 3, 2, -1}},
  {{1, 2, -1, -1, -1}},
  {{3, 1, -1, -1, -1}},
  {{0, 1, -1, -1, -1}},
  {{3, 0, -1, -1, -1}},
  {{-1, -1, -1, -1, -1}}
};

void vtkPixel::Contour(float value, vtkFloatScalars *cellScalars,
                     vtkFloatPoints *points, vtkCellArray *verts,
                     vtkCellArray *lines, vtkCellArray *polys,
                     vtkFloatScalars *scalars)
{
  static int CASE_MASK[4] = {1,2,8,4}; //note difference!
  LINE_CASES *lineCase;
  EDGE_LIST  *edge;
  int i, j, index, *vert;
  int pts[2];
  float t, *x1, *x2, x[3];

  // Build the case table
  for ( i=0, index = 0; i < 4; i++)
      if (cellScalars->GetScalar(i) >= value)
          index |= CASE_MASK[i];

  lineCase = lineCases + index;
  edge = lineCase->edges;

  for ( ; edge[0] > -1; edge += 2 )
    {
    for (i=0; i<2; i++) // insert line
      {
      vert = edges[edge[i]];
      t = (value - cellScalars->GetScalar(vert[0])) /
          (cellScalars->GetScalar(vert[1]) - cellScalars->GetScalar(vert[0]));
      x1 = this->Points.GetPoint(vert[0]);
      x2 = this->Points.GetPoint(vert[1]);
      for (j=0; j<3; j++) x[j] = x1[j] + t * (x2[j] - x1[j]);
      pts[i] = points->InsertNextPoint(x);
      scalars->InsertNextScalar(value);
      }
    lines->InsertNextCell(2,pts);
    }
}

vtkCell *vtkPixel::GetEdge(int edgeId)
{
  static vtkLine line;
  int *verts;

  verts = edges[edgeId];

  // load point id's
  line.PointIds.SetId(0,this->PointIds.GetId(verts[0]));
  line.PointIds.SetId(1,this->PointIds.GetId(verts[1]));

  // load coordinates
  line.Points.SetPoint(0,this->Points.GetPoint(verts[0]));
  line.Points.SetPoint(1,this->Points.GetPoint(verts[1]));

  return &line;
}
//
// Compute interpolation functions (similar but different than Quad interpolation functions)
//
void vtkPixel::InterpolationFunctions(float pcoords[3], float sf[4])
{
  float rm, sm;

  rm = 1. - pcoords[0];
  sm = 1. - pcoords[1];

  sf[0] = rm * sm;
  sf[1] = pcoords[0] * sm;
  sf[2] = rm * pcoords[1];
  sf[3] = pcoords[0] * pcoords[1];
}

//
// Intersect plane; see whether point is inside.
//
int vtkPixel::IntersectWithLine(float p1[3], float p2[3], float tol, float& t,
                                float x[3], float pcoords[3], int& subId)
{
  float *pt1, *pt2, *pt3, *pt4, n[3];
  float tol2 = tol*tol;
  float closestPoint[3];
  float dist2, weights[4];
  int i;

  subId = 0;
  pcoords[0] = pcoords[1] = pcoords[2] = 0.0;
//
// Get normal for triangle
//
  pt1 = this->Points.GetPoint(0);
  pt2 = this->Points.GetPoint(1);
  pt3 = this->Points.GetPoint(2);
  pt4 = this->Points.GetPoint(3);

  n[0] = n[1] = n[2] = 0.0;
  for (i=0; i<3; i++)
    {
    if ( (pt4[i] - pt1[i]) <= 0.0 )
      {
      n[i] = 1.0;
      break;
      }
    }
//
// Intersect plane of pixel with line
//
  if ( ! vtkAPlane.IntersectWithLine(p1,p2,n,pt1,t,x) ) return 0;
//
// Use evaluate position
//
  if (this->EvaluatePosition(x, closestPoint, subId, pcoords, dist2, weights) )
    if ( dist2 <= tol2 ) return 1;

  return 0;
}

int vtkPixel::Triangulate(int index, vtkFloatPoints &pts)
{
  pts.Reset();
  pts.InsertPoint(0,this->Points.GetPoint(0));
  pts.InsertPoint(1,this->Points.GetPoint(1));
  pts.InsertPoint(2,this->Points.GetPoint(2));

  pts.InsertPoint(3,this->Points.GetPoint(1));
  pts.InsertPoint(4,this->Points.GetPoint(3));
  pts.InsertPoint(5,this->Points.GetPoint(2));

  return 1;
}

void vtkPixel::Derivatives(int subId, float pcoords[3], float *values,
                            int dim, float *derivs)
{
  int i, idx;

  // The following code is incorrect. Will be fixed in future release.
  for (i=0; i<dim; i++)
    {
    idx = i*dim;
    derivs[idx] = 0.0;
    derivs[idx+1] = 0.0;
    derivs[idx+2] = 0.0;
    }
}

<|endoftext|>


<commit_before>/**************************************************************************\
**
**  tVegetation.cpp: Functions for tVegetation and tVegCover classes
**
**  Classes tVegetation and tVegCover represents the vegetation cover
**  across a terrain. Class tVegCover represents the properties of
**  vegetation at a point on the landscape (e.g., the %cover), while
**  class tVegetation represents the landscape-wide ("global")
**  properties (e.g., regrowth coefficient). Class tVegCover is designed
**  to be embedded in a node (in other words, each node "has a"
**  vegetation cover).
**
**  Created January, 2000, GT
**
**  $Id: tVegetation.cpp,v 1.6 2002-05-01 14:48:32 arnaud Exp $
\**************************************************************************/

#include "../tAssert.h"
#include "tVegetation.h"
#include "../tMesh/tMesh.h"
#include "../tMeshList/tMeshList.h"

/**************************************************************************\
**                 FUNCTIONS FOR CLASS tVegetation
\**************************************************************************/

/**************************************************************************\
**
**  tVegetation constructors:
**    1. Default
**    2. Input file
**
\**************************************************************************/

tVegetation::tVegetation()
  :
  mdKvd(0),
  mdTVeg(1),
  mdTauCritBare(0), mdTauCritVeg(0)
{}

tVegetation::tVegetation( tMesh<tLNode> * meshPtr, tInputFile &infile )
  :
  mdKvd(0),
  mdTVeg(1),
  mdTauCritBare(0), mdTauCritVeg(0)
{
   mdKvd = infile.ReadItem( mdKvd, "VEG_KVD" );
   mdTVeg = infile.ReadItem( mdTVeg, "VEG_TV" );
   mdTauCritBare = infile.ReadItem( mdTauCritBare, "TAUC" );
   mdTauCritVeg = infile.ReadItem( mdTVeg, "VEG_TAUCVEG" );

   // Loop through nodes and set initial vegetation cover & threshold
   // (for now, assume constant; later need to add restart capability)
   // Note: assumes initially 100% cover.
   tMeshListIter<tLNode> niter( meshPtr->getNodeList() );
   tLNode * cn;

   // unused
   // intlVegCover = infile.ReadItem( intlVegCover, "INTLVEGCOV" );

   for( cn=niter.FirstP(); niter.IsActive(); cn=niter.NextP() )
   {
       cn->getVegCover().mdVeg = 1.0;
       cn->setTauCrit( mdTauCritBare + mdTauCritVeg );
   }

}

/**************************************************************************\
**
**  tVegetation::UpdateVegetation
**
**  This routine updates the % vegetation cover at each node in response
**  to a storm event and its ensuing interstorm period. It also updates
**  the critical shear stress at each node according to its present
**  vegetation cover.
**
**  Erosion of vegetation during a storm is computed as:
**    dV/dt = -Kvd V ( tau - tauc )
**  Where V represents the proportional cover (0 to 1), tau is shear
**  stress, tauc is critical shear stress, and Kvd is a vegetation
**  erodibility coefficient. The equation is solved using an analytical
**  solution, using the expedient approximation that tauc is constant
**  during a given storm.
**
**  Regrowth of vegetation following a storm is computed as:
**    dV/dt = 1/Tv ( 1 - V )
**  where Tv is the timescale of vegetation regrowth. An analytical
**  solution is used to update the vegetation cover.
**
**  Finally, the critical shear stress is updated at each node using:
**    Tc = Tcb + V Tcv
**  where Tcb is critical shear stress in the absence of cover (bare)
**  and Tcv is critical shear stress under 100% cover.
**
**  Created January 2000, GT
**
\**************************************************************************/

void tVegetation::UpdateVegetation( tMesh<tLNode> *meshPtr, double stormdur,
                                    double interstormdur )
{
   tMeshListIter< tLNode > niter( meshPtr->getNodeList() ); // Node iterator
   tLNode * cn;   // Ptr to current node
   double tauex,  // Excess shear stress
       veg;       // Fractional vegetation cover

   // Loop on active nodes, computing erosion from the previous storm
   // and regrowth during the subsequent interstorm period.
   // Key assumptions: we "cheat" by changing the critical shear stress only
   // "after" the storm, using the initial value to calculate the
   // subsequent, eroded value, rather than solving the full quadratic
   // equation for vegetation destruction.
   //   For both erosion and regrowth, we use an analytical solution for
   // veg cover given its initial value and duration of erosion/regrowth.
   for( cn=niter.FirstP(); niter.IsActive(); cn=niter.NextP() )
   {
      // Erosion of vegetation during storm (if any)
      tauex = cn->getTau() - cn->getTauCrit();
      veg = cn->getVegCover().getVeg();
      if( tauex>0.0 )
      {
          veg = veg * exp( -mdKvd * tauex * stormdur );
          cn->getVegCover().mdVeg = veg;
          //cout << "veg after erosion: " << veg << endl;
      }

      // Regrowth following storm
      //cout << "veg before regrowth: " << veg << endl;
      veg = 1.0 - (1.0 - veg) * exp( -interstormdur / mdTVeg );
      cn->getVegCover().mdVeg = veg;
      //cout << "veg after regrowth: " << veg << endl;

      // Update critical shear stress
      cn->setTauCrit( mdTauCritBare + veg*mdTauCritVeg );
      //cout << "tau crit: " << mdTauCritBare + veg*mdTauCritVeg << endl;
   }

}

<commit_msg>Arnaud: added "class" to make doxygen happy<commit_after>/**************************************************************************\
**
**  tVegetation.cpp: Functions for tVegetation and tVegCover classes
**
**  Classes tVegetation and tVegCover represents the vegetation cover
**  across a terrain. Class tVegCover represents the properties of
**  vegetation at a point on the landscape (e.g., the %cover), while
**  class tVegetation represents the landscape-wide ("global")
**  properties (e.g., regrowth coefficient). Class tVegCover is designed
**  to be embedded in a node (in other words, each node "has a"
**  vegetation cover).
**
**  Created January, 2000, GT
**
**  $Id: tVegetation.cpp,v 1.7 2003-01-17 11:33:49 childcvs Exp $
\**************************************************************************/

#include "../tAssert.h"
#include "tVegetation.h"
#include "../tMesh/tMesh.h"
#include "../tMeshList/tMeshList.h"

/**************************************************************************\
**                 FUNCTIONS FOR CLASS tVegetation
\**************************************************************************/

/**************************************************************************\
**
**  tVegetation constructors:
**    1. Default
**    2. Input file
**
\**************************************************************************/

tVegetation::tVegetation()
  :
  mdKvd(0),
  mdTVeg(1),
  mdTauCritBare(0), mdTauCritVeg(0)
{}

tVegetation::tVegetation( tMesh<class tLNode> * meshPtr, tInputFile &infile )
  :
  mdKvd(0),
  mdTVeg(1),
  mdTauCritBare(0), mdTauCritVeg(0)
{
   mdKvd = infile.ReadItem( mdKvd, "VEG_KVD" );
   mdTVeg = infile.ReadItem( mdTVeg, "VEG_TV" );
   mdTauCritBare = infile.ReadItem( mdTauCritBare, "TAUC" );
   mdTauCritVeg = infile.ReadItem( mdTVeg, "VEG_TAUCVEG" );

   // Loop through nodes and set initial vegetation cover & threshold
   // (for now, assume constant; later need to add restart capability)
   // Note: assumes initially 100% cover.
   tMeshListIter<tLNode> niter( meshPtr->getNodeList() );
   tLNode * cn;

   // unused
   // intlVegCover = infile.ReadItem( intlVegCover, "INTLVEGCOV" );

   for( cn=niter.FirstP(); niter.IsActive(); cn=niter.NextP() )
   {
       cn->getVegCover().mdVeg = 1.0;
       cn->setTauCrit( mdTauCritBare + mdTauCritVeg );
   }

}

/**************************************************************************\
**
**  tVegetation::UpdateVegetation
**
**  This routine updates the % vegetation cover at each node in response
**  to a storm event and its ensuing interstorm period. It also updates
**  the critical shear stress at each node according to its present
**  vegetation cover.
**
**  Erosion of vegetation during a storm is computed as:
**    dV/dt = -Kvd V ( tau - tauc )
**  Where V represents the proportional cover (0 to 1), tau is shear
**  stress, tauc is critical shear stress, and Kvd is a vegetation
**  erodibility coefficient. The equation is solved using an analytical
**  solution, using the expedient approximation that tauc is constant
**  during a given storm.
**
**  Regrowth of vegetation following a storm is computed as:
**    dV/dt = 1/Tv ( 1 - V )
**  where Tv is the timescale of vegetation regrowth. An analytical
**  solution is used to update the vegetation cover.
**
**  Finally, the critical shear stress is updated at each node using:
**    Tc = Tcb + V Tcv
**  where Tcb is critical shear stress in the absence of cover (bare)
**  and Tcv is critical shear stress under 100% cover.
**
**  Created January 2000, GT
**
\**************************************************************************/

void tVegetation::UpdateVegetation( tMesh<class tLNode> *meshPtr,
				    double stormdur,
                                    double interstormdur )
{
   tMeshListIter< tLNode > niter( meshPtr->getNodeList() ); // Node iterator
   tLNode * cn;   // Ptr to current node
   double tauex,  // Excess shear stress
       veg;       // Fractional vegetation cover

   // Loop on active nodes, computing erosion from the previous storm
   // and regrowth during the subsequent interstorm period.
   // Key assumptions: we "cheat" by changing the critical shear stress only
   // "after" the storm, using the initial value to calculate the
   // subsequent, eroded value, rather than solving the full quadratic
   // equation for vegetation destruction.
   //   For both erosion and regrowth, we use an analytical solution for
   // veg cover given its initial value and duration of erosion/regrowth.
   for( cn=niter.FirstP(); niter.IsActive(); cn=niter.NextP() )
   {
      // Erosion of vegetation during storm (if any)
      tauex = cn->getTau() - cn->getTauCrit();
      veg = cn->getVegCover().getVeg();
      if( tauex>0.0 )
      {
          veg = veg * exp( -mdKvd * tauex * stormdur );
          cn->getVegCover().mdVeg = veg;
          //cout << "veg after erosion: " << veg << endl;
      }

      // Regrowth following storm
      //cout << "veg before regrowth: " << veg << endl;
      veg = 1.0 - (1.0 - veg) * exp( -interstormdur / mdTVeg );
      cn->getVegCover().mdVeg = veg;
      //cout << "veg after regrowth: " << veg << endl;

      // Update critical shear stress
      cn->setTauCrit( mdTauCritBare + veg*mdTauCritVeg );
      //cout << "tau crit: " << mdTauCritBare + veg*mdTauCritVeg << endl;
   }

}

<|endoftext|>


<commit_before>static int dump_node_ia32(ir_node *n, FILE *F, dump_reason_t reason)
{
  const char *name, *p;
  ir_mode *mode;
  int bad = 0;
  char buf[1024];

  switch (reason) {
  case dump_node_opcode_txt:
    name = get_irn_opname(n);
    fprintf(F, "%s", name);
    break;
  case dump_node_mode_txt:
    mode = get_irn_mode(n);
    name = get_irn_opname(n);

    if (mode && mode != mode_BB && mode != mode_ANY && mode != mode_BAD && mode != mode_T) {
      p = name + strlen(name) - 2;
      if (p[0] == '_' && p[1] == 'i') {
        tarval_snprintf(buf, sizeof(buf), get_Immop_tarval(n));
        fprintf(F, "[%s]", buf);
      }

      fprintf(F, "%s", get_mode_name(mode));
    }
    break;

  case dump_node_nodeattr_txt:
    break;
  }
  return bad;
}
<commit_msg>improved dump of node attributes<commit_after>static void fprintf_tv(FILE *F, tarval *tv, int brackets) {
  char buf[1024];
  tarval_snprintf(buf, sizeof(buf), tv);

  if (brackets)
    fprintf(F, "[%s]", buf);
  else
    fprintf(F, "%s", buf);
}

static int dump_node_ia32(ir_node *n, FILE *F, dump_reason_t reason) {
  const char *name, *p;
  ir_mode    *mode = NULL;
  int        bad   = 0;

  switch (reason) {
    case dump_node_opcode_txt:
      name = get_irn_opname(n);
      fprintf(F, "%s", name);
      break;

    case dump_node_mode_txt:
      mode = get_irn_mode(n);

      if (mode && mode != mode_BB && mode != mode_ANY && mode != mode_BAD && mode != mode_T) {
        /* dump below */
      }
      else if (is_ia32_Load(n)) {
        mode = get_irn_mode(get_irn_n(n, 1));
      }
      else if (is_ia32_Store(n)) {
        mode = get_irn_mode(get_irn_n(n, 2));
      }

      if (mode)
        fprintf(F, "[%s]", get_mode_name(mode));
      break;

    case dump_node_nodeattr_txt:
      name = get_irn_opname(n);
      p = name + strlen(name) - 2;
      if (p[0] == '_' && p[1] == 'i') {
        tarval *tv = get_Immop_tarval(n);
        if (tv)
          fprintf_tv(F, tv, 1);
        else {
          fprintf(F, "[SymConst]");
        }
      }
      break;

    case dump_node_info_txt:
      if (is_ia32_Lea(n)) {
        tarval *o  = get_ia32_Lea_offs(n);
        tarval *tv = get_Immop_tarval(n);

        fprintf(F, "LEA ");
        if (o)
          fprintf_tv(F, o, 0);
        fprintf(F, "(%s, %s", get_irn_opname(get_irn_n(n, 0)), get_irn_opname(get_irn_n(n, 1)));
        if (tv) {
          fprintf(F, ", ");
          fprintf_tv(F, tv, 0);
        }
        fprintf(F, ")\n");
      }
      break;
  }

  return bad;
}
<|endoftext|>


<commit_before>#pragma once
/* RLTK (RogueLike Tool Kit) 1.00
 * Copyright (c) 2016-Present, Bracket Productions.
 * Licensed under the LGPL - see LICENSE file.
 *
 * Provides a wrapper for bitmap fonts.
 */

#include <functional>
#include "geometry.hpp"

namespace rltk {

namespace visibility_private {

template<class location_t_>
void internal_2d_sweep(const location_t_ &position, const location_t_ &destination, const int &range, std::function<void(location_t_)> set_visible,
	std::function<bool(location_t_)> is_opaque)
{
	bool blocked = false;
	line_func(position.x, position.y, destination.x, destination.y, [&blocked, &is_opaque, &set_visible, &range, &position] (int X, int Y) {
		float distance = distance2d(position.x, position.y, X, Y);
		if (distance <= range) {
			location_t_ pos;
			pos.x = X;
			pos.y = Y;
			if (!blocked) set_visible(pos);
			if (!is_opaque(pos)) blocked = true;
		}
	});
}

}

/* Simple all-direction visibility sweep in 2 dimensions. This requires that your location_t utilize an x and y
 * component. Parameters:
 * position - where you are sweeping from.
 * range - the number of tiles you can traverse.
 * set_visible - a callback (such as bool set_visible(location_t & loc)) to say "this is visible"
 * is_opaque - a callback to ask your map if you can see through a tile.
 */
template<class location_t_>
void visibility_sweep_2d(const location_t_ &position, const int &range, std::function<void(location_t_)> set_visible,
	std::function<bool(location_t_)> is_opaque)
{
	// You can always see yourself
	set_visible(position);

	// Box-sweep
	for (int i=0-range; i<range; ++i) {

		// Going up
		location_t_ destination;
		destination.x = position.x + i;
		destination.y = position.y - range;
		visibility_private::internal_2d_sweep(position, destination, range, set_visible, is_opaque);

		// Going down
		destination.x = position.x + i;
		destination.y = position.y + range;
		visibility_private::internal_2d_sweep(position, destination, range, set_visible, is_opaque);

		// Going left
		destination.x = position.x - range;
		destination.y = position.y + i;
		visibility_private::internal_2d_sweep(position, destination, range, set_visible, is_opaque);

		// Going right
		destination.x = position.x + range;
		destination.y = position.y + i;
		visibility_private::internal_2d_sweep(position, destination, range, set_visible, is_opaque);
	}
}

}
<commit_msg>Improve box-sweep readability by exposing an offset rather than repeatedly calculating a destination.<commit_after>#pragma once
/* RLTK (RogueLike Tool Kit) 1.00
 * Copyright (c) 2016-Present, Bracket Productions.
 * Licensed under the LGPL - see LICENSE file.
 *
 * Provides a wrapper for bitmap fonts.
 */

#include <functional>
#include "geometry.hpp"

namespace rltk {

namespace visibility_private {

template<class location_t_>
void internal_2d_sweep(const location_t_ &position, const int &range, std::function<void(location_t_)> set_visible,
	std::function<bool(location_t_)> is_opaque, const std::pair<int,int> offset)
{
	bool blocked = false;
	line_func(position.x, position.y, position.x + offset.first, position.y + offset.second, [&blocked, &is_opaque, &set_visible, &range, &position] (int X, int Y) {
		float distance = distance2d(position.x, position.y, X, Y);
		if (distance <= range) {
			location_t_ pos;
			pos.x = X;
			pos.y = Y;
			if (!blocked) set_visible(pos);
			if (!is_opaque(pos)) blocked = true;
		}
	});
}

}

/* Simple all-direction visibility sweep in 2 dimensions. This requires that your location_t utilize an x and y
 * component. Parameters:
 * position - where you are sweeping from.
 * range - the number of tiles you can traverse.
 * set_visible - a callback (such as bool set_visible(location_t & loc)) to say "this is visible"
 * is_opaque - a callback to ask your map if you can see through a tile.
 */
template<class location_t_>
void visibility_sweep_2d(const location_t_ &position, const int &range, std::function<void(location_t_)> set_visible,
	std::function<bool(location_t_)> is_opaque)
{
	// You can always see yourself
	set_visible(position);

	// Box-sweep
	for (int i=0-range; i<range; ++i) {
		visibility_private::internal_2d_sweep(position, range, set_visible, is_opaque, std::make_pair(i, 0-range));
		visibility_private::internal_2d_sweep(position, range, set_visible, is_opaque, std::make_pair(i, range));
		visibility_private::internal_2d_sweep(position, range, set_visible, is_opaque, std::make_pair(0-range, i));
		visibility_private::internal_2d_sweep(position, range, set_visible, is_opaque, std::make_pair(range, i));
	}
}

}
<|endoftext|>


<commit_before>#ifndef __RMOL_RMOL_TYPES_HPP
#define __RMOL_RMOL_TYPES_HPP

// //////////////////////////////////////////////////////////////////////
// Import section
// //////////////////////////////////////////////////////////////////////
// STL
#include <vector>
#include <list>

namespace RMOL {

   // ///////// Exceptions ///////////
  class RootException : public std::exception {
  };

  class FileNotFoundException : public RootException {
  };

  class NonInitialisedServiceException : public RootException {
  };

  class MemoryAllocationException : public RootException {
  };

  class ObjectNotFoundException : public RootException {
  };

  class DocumentNotFoundException : public RootException {
  };

  // /////////////// Log /////////////
  /** Level of logs. */
  namespace LOG {
    typedef enum {
      CRITICAL = 0,
      ERROR,
      NOTIFICATION,
      WARNING,
      DEBUG,
      VERBOSE,
      LAST_VALUE
    } EN_LogLevel;
  }

  // //////// Type definitions /////////

}
#endif // __RMOL_RMOL_TYPES_HPP
<commit_msg>Defined the smart pointer type for RMOL service.<commit_after>#ifndef __RMOL_RMOL_TYPES_HPP
#define __RMOL_RMOL_TYPES_HPP

// //////////////////////////////////////////////////////////////////////
// Import section
// //////////////////////////////////////////////////////////////////////
// STL
#include <vector>
#include <list>
// Boost
#include <boost/shared_ptr.hpp>

namespace RMOL {

  // Forward declarations
  class RMOL_Service;

   // ///////// Exceptions ///////////
  class RootException : public std::exception {
  };

  class FileNotFoundException : public RootException {
  };

  class NonInitialisedServiceException : public RootException {
  };

  class MemoryAllocationException : public RootException {
  };

  class ObjectNotFoundException : public RootException {
  };

  class DocumentNotFoundException : public RootException {
  };

  // /////////////// Log /////////////
  /** Level of logs. */
  namespace LOG {
    typedef enum {
      CRITICAL = 0,
      ERROR,
      NOTIFICATION,
      WARNING,
      DEBUG,
      VERBOSE,
      LAST_VALUE
    } EN_LogLevel;
  }

  // //////// Type definitions /////////
  /** Pointer on the RMOL Service handler. */
  typedef boost::shared_ptr<RMOL::RMOL_Service> RMOL_ServicePtr_T;

}
#endif // __RMOL_RMOL_TYPES_HPP
<|endoftext|>


<commit_before>#include "thread_pool.h"
#include <chrono>
#include <cassert>
#include <csignal>
#include <unordered_map>
#if __APPLE__ || __linux__
    #include <pthread.h>
#endif

#if __has_include("debugging.h")
#  include "debugging.h"
#endif

#define POOL_TASK_DEBUG 0

namespace rpp
{
    ///////////////////////////////////////////////////////////////////////////////

    static pool_trace_provider TraceProvider;
    static pool_signal_handler SignalHandler = [](const char* what) {
        throw std::runtime_error(what);
    };

#if POOL_TASK_DEBUG
#  ifdef LogWarning
#    define TaskDebug(fmt, ...) LogWarning(fmt, ##__VA_ARGS__)
#  else
#    define TaskDebug(fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__)
#  endif
#else
#  define TaskDebug(fmt, ...) // do nothing
#endif

#ifdef LogWarning
#  define UnhandledEx(fmt, ...) LogWarning(fmt, ##__VA_ARGS__)
#else
#  define UnhandledEx(fmt, ...) fprintf(stderr, "pool_task::unhandled_exception $ " fmt "\n", ##__VA_ARGS__)
#endif

    pool_task::pool_task()
    {
        th = thread{[this] { run(); }};
    }

    pool_task::~pool_task() noexcept
    {
        kill();
    }

    void pool_task::max_idle_time(int maxIdleSeconds) { maxIdleTime = maxIdleSeconds; }

    void pool_task::run_range(int start, int end, const action<int, int>& newTask) noexcept
    {
        assert(!taskRunning && "rpp::pool_task already running! This can cause deadlocks due to abandoned tasks!");

        { lock_guard<mutex> lock{m};
            trace.clear();
            error = nullptr;
            if (auto tracer = TraceProvider)
                trace = TraceProvider();
            genericTask  = {};
            rangeTask    = newTask;
            rangeStart   = start;
            rangeEnd     = end;
            taskRunning  = true;
        }
        notify_task();
    }

    void pool_task::run_generic(task_delegate<void()>&& newTask) noexcept
    {
        assert(!taskRunning && "rpp::pool_task already running! This can cause deadlocks due to abandoned tasks!");

        //TaskDebug("queue task");
        { lock_guard<mutex> lock{m};
            trace.clear();
            error = nullptr;
            if (auto tracer = TraceProvider)
                trace = TraceProvider();
            genericTask  = move(newTask);
            rangeTask    = {};
            rangeStart   = 0;
            rangeEnd     = 0;
            taskRunning  = true;
        }
        notify_task();
    }

    void pool_task::notify_task()
    {
        { lock_guard<mutex> lock{m};
            if (killed) {
                TaskDebug("resurrecting task");
                killed = false;
                if (th.joinable()) th.join();
                th = thread{[this] { run(); }}; // restart thread if needed
            }
        }
        cv.notify_one();
    }

    pool_task::wait_result pool_task::wait(int timeoutMillis)
    {
        unique_lock<mutex> lock{m};
        while (taskRunning)
        {
            if (timeoutMillis)
            {
                if (cv.wait_for(lock, chrono::milliseconds(timeoutMillis)) == cv_status::timeout)
                    return timeout;
            }
            else
            {
                cv.wait(lock);
            }
        }
        if (error) rethrow_exception(error);
        return finished;
    }

    pool_task::wait_result pool_task::kill(int timeoutMillis) noexcept
    {
        if (killed) {
            if (th.joinable()) th.join();
            return finished;
        }
        { unique_lock<mutex> lock{m};
            TaskDebug("killing task");
            killed = true;
        }
        cv.notify_all();
        wait_result result = wait(timeoutMillis);
        if (th.joinable()) {
            if (result == timeout) th.detach();
            else                   th.join();
        }
        return result;
    }

#if _WIN32
    #ifndef WIN32_LEAN_AND_MEAN
    #  define WIN32_LEAN_AND_MEAN 1
    #endif
    #include <Windows.h>
    #pragma pack(push,8)
    struct THREADNAME_INFO
    {
        DWORD dwType; // Must be 0x1000.
        LPCSTR szName; // Pointer to name (in user addr space).
        DWORD dwThreadID; // Thread ID (-1=caller thread).
        DWORD dwFlags; // Reserved for future use, must be zero.
    };
    #pragma pack(pop)
    void SetThreadName(const char* threadName)
    {
        THREADNAME_INFO info;
        info.dwType     = 0x1000;
        info.szName     = threadName;
        info.dwThreadID = (DWORD)-1;
        info.dwFlags    = 0;

        #pragma warning(push)
        #pragma warning(disable: 6320 6322)
            const DWORD MS_VC_EXCEPTION = 0x406D1388;
            __try {
                RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
            } __except (1){}
        #pragma warning(pop)
    }
#endif

    // really nasty case where OS threads are just abandoned
    // with none of the destructors being run
    static mutex activeTaskMutex;
    static unordered_map<int, pool_task*> activeTasks;
    static int get_thread_id()
    {
        auto id = this_thread::get_id();
        return *(int*)&id;
    }
    static void register_thread_task(pool_task* task)
    {
        lock_guard<mutex> lock{ activeTaskMutex };
        activeTasks[get_thread_id()] = task;
    }
    static void erase_thread_task()
    {
        lock_guard<mutex> lock{ activeTaskMutex };
        activeTasks.erase(get_thread_id());
    }

    static void segfault(int) { SignalHandler("SIGSEGV"); }
    static void sigterm(int)  { SignalHandler("SIGTERM"); }
    static void sigabort(int) { SignalHandler("SIGABORT"); }

    void pool_task::run() noexcept
    {
        static int pool_task_id;
        char name[32];
        snprintf(name, sizeof(name), "rpp_task_%d", pool_task_id++);

        #if __APPLE__
            pthread_setname_np(name);
        #elif __linux__
            pthread_setname_np(pthread_self(), name);
        #elif _WIN32
            SetThreadName(name);
        #endif

        signal(SIGSEGV, segfault); // set SIGSEGV handler so we can catch it
        signal(SIGTERM, sigterm);
        signal(SIGABRT, sigabort);

        register_thread_task(this);

        // mark all running threads killed during SIGTERM, before dtors run
        static int atExitRegistered;
        if (!atExitRegistered) atExitRegistered = !atexit([] {
            for (auto& task : activeTasks) {
                task.second->killed = true;
                task.second->cv.notify_all();
            }
            activeTasks.clear();
        });

        struct thread_exiter {
            pool_task* self;
            ~thread_exiter() {
                erase_thread_task();
                self->killed = true;
                self->taskRunning = false;
                self->cv.notify_all();
            }
        } markKilledOnScopeExit { this }; // however, this doesn't handle exit(0) where threads are mutilated

        //TaskDebug("%s start", name);
        for (;;)
        {
            try
            {
                decltype(rangeTask)   range;
                decltype(genericTask) generic;

                // consume the tasks atomically
                { unique_lock<mutex> lock{m};
                    //TaskDebug("%s wait for task", name);
                    if (!wait_for_task(lock)) {
                        TaskDebug("%s stop (%s)", name, killed ? "killed" : "timeout");
                        return;
                    }
                    range   = move(rangeTask);
                    generic = move(genericTask);
                    rangeTask   = {};
                    genericTask = {}; // BUG: Clang on android doesn't move genericTask properly
                    taskRunning = true;
                }
                if (range)
                {
                    //TaskDebug("%s(range_task[%d,%d))", name, rangeStart, rangeEnd);
                    range(rangeStart, rangeEnd);
                }
                else
                {
                    //TaskDebug("%s(generic_task)", name);
                    generic();
                }
            }
            // prevent failures that would terminate the thread
            catch (const exception& e) { unhandled_exception(e.what()); }
            catch (const char* e)      { unhandled_exception(e);        }
            catch (...)                { unhandled_exception("");       }
            { lock_guard<mutex> lock{m};
                taskRunning = false;
                cv.notify_all();
            }
        }
    }

    void pool_task::unhandled_exception(const char* what) noexcept
    {
        error = std::current_exception();

        string err = what;
        { lock_guard<mutex> lock{m};
            if (!trace.empty()) {
                err += "\nTask Start Trace:\n";
                err += trace;
            }
        }
        UnhandledEx("%s", err.c_str());
    }

    bool pool_task::got_task() const noexcept
    {
        return (bool)rangeTask || (bool)genericTask;
    }

    bool pool_task::wait_for_task(unique_lock<mutex>& lock) noexcept
    {
        for (;;)
        {
            if (killed)
                return false;
            if (got_task())
                return true;
            if (maxIdleTime)
            {
                if (cv.wait_for(lock, chrono::seconds(maxIdleTime)) == cv_status::timeout)
                    return false;
            }
            else
            {
                cv.wait(lock);
            }
        }
    }

    ///////////////////////////////////////////////////////////////////////////////

    thread_pool& thread_pool::global()
    {
        static thread_pool globalPool;
        return globalPool;
    }

#if _WIN32
    static int num_physical_cores()
    {
        DWORD bytes = 0;
        GetLogicalProcessorInformation(nullptr, &bytes);
        vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> coreInfo(bytes / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
        GetLogicalProcessorInformation(coreInfo.data(), &bytes);

        int cores = 0;
        for (auto& info : coreInfo)
        {
            if (info.Relationship == RelationProcessorCore)
                ++cores;
        }
        return cores;
    }
#else
    static int num_physical_cores()
    {
        return (int)thread::hardware_concurrency();
    }
#endif

    int thread_pool::physical_cores()
    {
        return global().coreCount;
    }

    void thread_pool::set_signal_handler(pool_signal_handler signalHandler)
    {
        lock_guard<mutex> lock{ tasksMutex };
        SignalHandler = signalHandler;
    }

    void thread_pool::set_task_tracer(pool_trace_provider traceProvider)
    {
        lock_guard<mutex> lock{ tasksMutex };
        TraceProvider = traceProvider;
    }

    thread_pool::thread_pool()
    {
        coreCount = num_physical_cores();
    }

    thread_pool::~thread_pool() noexcept
    {
        // defined destructor to prevent agressive inlining
    }

    int thread_pool::active_tasks() noexcept
    {
        lock_guard<mutex> lock{tasksMutex};
        int active = 0;
        for (auto& task : tasks)
            if (task->running()) ++active;
        return active;
    }

    int thread_pool::idle_tasks() noexcept
    {
        lock_guard<mutex> lock{tasksMutex};
        int idle = 0;
        for (auto& task : tasks)
            if (!task->running()) ++idle;
        return idle;
    }

    int thread_pool::total_tasks() const noexcept
    {
        return (int)tasks.size();
    }

    int thread_pool::clear_idle_tasks() noexcept
    {
        lock_guard<mutex> lock{tasksMutex};
        int cleared = 0;
        for (int i = 0; i < (int)tasks.size();)
        {
            if (!tasks[i]->running())
            {
                swap(tasks[i], tasks.back()); // erase_swap_last pattern
                tasks.pop_back();
                ++cleared;
            }
            else ++i;
        }
        return cleared;
    }

    pool_task* thread_pool::start_range_task(size_t& poolIndex, int rangeStart, int rangeEnd,
                                             const action<int, int>& rangeTask) noexcept
    {
        { lock_guard<mutex> lock{tasksMutex};
            for (; poolIndex < tasks.size(); ++poolIndex)
            {
                pool_task* task = tasks[poolIndex].get();
                if (!task->running())
                {
                    ++poolIndex;
                    task->run_range(rangeStart, rangeEnd, rangeTask);
                    return task;
                }
            }
        }

        auto t  = make_unique<pool_task>();
        auto* task = t.get();
        task->max_idle_time(taskMaxIdleTime);
        task->run_range(rangeStart, rangeEnd, rangeTask);

        lock_guard<mutex> lock{tasksMutex};
        tasks.emplace_back(move(t));
        return task;
    }

    void thread_pool::max_task_idle_time(int maxIdleSeconds) noexcept
    {
        lock_guard<mutex> lock{tasksMutex};
        taskMaxIdleTime = maxIdleSeconds;
        for (auto& task : tasks)
            task->max_idle_time(taskMaxIdleTime);
    }

    void thread_pool::parallel_for(int rangeStart, int rangeEnd,
                                   const action<int, int>& rangeTask) noexcept
    {
        assert(!rangeRunning && "Fatal error: nested parallel loops are forbidden!");
        assert(coreCount > 0 && "There appears to be no hardware concurrency");

        const int range = rangeEnd - rangeStart;
        if (range <= 0)
            return;

        const int cores = range < coreCount ? range : coreCount;
        const int len = range / cores;

        // only one physical core or only one task to run. don't run in a thread
        if (cores <= 1)
        {
            rangeTask(0, len);
            return;
        }

        pool_task** active = (pool_task**)alloca(sizeof(pool_task*) * cores);
        //vector<pool_task*> active(cores, nullptr);
        {
            rangeRunning = true;

            size_t poolIndex = 0;
            for (int i = 0; i < cores; ++i)
            {
                const int start = i * len;
                const int end   = i == cores - 1 ? rangeEnd : start + len;
                active[i] = start_range_task(poolIndex, start, end, rangeTask);
            }
        }

        for (int i = 0; i < cores; ++i)
            active[i]->wait();

        rangeRunning = false;
    }

    pool_task* thread_pool::parallel_task(task_delegate<void()>&& genericTask) noexcept
    {
        { lock_guard<mutex> lock{tasksMutex};
            for (unique_ptr<pool_task>& t : tasks)
            {
                pool_task* task = t.get();
                if (!task->running())
                {
                    task->run_generic(move(genericTask));
                    return task;
                }
            }
        }

        // create and run a new task atomically
        auto t = make_unique<pool_task>();
        auto* task = t.get();
        task->max_idle_time(taskMaxIdleTime);
        task->run_generic(move(genericTask));

        lock_guard<mutex> lock{tasksMutex};
        tasks.emplace_back(move(t));
        return task;
    }
}
<commit_msg>Removed SIGABRT and SIGTERM handlers -- they cause unnecessary bugs and issues<commit_after>#include "thread_pool.h"
#include <chrono>
#include <cassert>
#include <csignal>
#include <unordered_map>
#if __APPLE__ || __linux__
    #include <pthread.h>
#endif

#if __has_include("debugging.h")
#  include "debugging.h"
#endif

#define POOL_TASK_DEBUG 0

namespace rpp
{
    ///////////////////////////////////////////////////////////////////////////////

    static pool_trace_provider TraceProvider;
    static pool_signal_handler SignalHandler = [](const char* what) {
        throw std::runtime_error(what);
    };

#if POOL_TASK_DEBUG
#  ifdef LogWarning
#    define TaskDebug(fmt, ...) LogWarning(fmt, ##__VA_ARGS__)
#  else
#    define TaskDebug(fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__)
#  endif
#else
#  define TaskDebug(fmt, ...) // do nothing
#endif

#ifdef LogWarning
#  define UnhandledEx(fmt, ...) LogWarning(fmt, ##__VA_ARGS__)
#else
#  define UnhandledEx(fmt, ...) fprintf(stderr, "pool_task::unhandled_exception $ " fmt "\n", ##__VA_ARGS__)
#endif

    pool_task::pool_task()
    {
        th = thread{[this] { run(); }};
    }

    pool_task::~pool_task() noexcept
    {
        kill();
    }

    void pool_task::max_idle_time(int maxIdleSeconds) { maxIdleTime = maxIdleSeconds; }

    void pool_task::run_range(int start, int end, const action<int, int>& newTask) noexcept
    {
        assert(!taskRunning && "rpp::pool_task already running! This can cause deadlocks due to abandoned tasks!");

        { lock_guard<mutex> lock{m};
            trace.clear();
            error = nullptr;
            if (auto tracer = TraceProvider)
                trace = tracer();
            genericTask  = {};
            rangeTask    = newTask;
            rangeStart   = start;
            rangeEnd     = end;
            taskRunning  = true;
        }
        notify_task();
    }

    void pool_task::run_generic(task_delegate<void()>&& newTask) noexcept
    {
        assert(!taskRunning && "rpp::pool_task already running! This can cause deadlocks due to abandoned tasks!");

        //TaskDebug("queue task");
        { lock_guard<mutex> lock{m};
            trace.clear();
            error = nullptr;
            if (auto tracer = TraceProvider)
                trace = tracer();
            genericTask  = move(newTask);
            rangeTask    = {};
            rangeStart   = 0;
            rangeEnd     = 0;
            taskRunning  = true;
        }
        notify_task();
    }

    void pool_task::notify_task()
    {
        { lock_guard<mutex> lock{m};
            if (killed) {
                TaskDebug("resurrecting task");
                killed = false;
                if (th.joinable()) th.join();
                th = thread{[this] { run(); }}; // restart thread if needed
            }
        }
        cv.notify_one();
    }

    pool_task::wait_result pool_task::wait(int timeoutMillis)
    {
        unique_lock<mutex> lock{m};
        while (taskRunning)
        {
            if (timeoutMillis)
            {
                if (cv.wait_for(lock, chrono::milliseconds(timeoutMillis)) == cv_status::timeout)
                    return timeout;
            }
            else
            {
                cv.wait(lock);
            }
        }
        if (error) rethrow_exception(error);
        return finished;
    }

    pool_task::wait_result pool_task::kill(int timeoutMillis) noexcept
    {
        if (killed) {
            if (th.joinable()) th.join();
            return finished;
        }
        { unique_lock<mutex> lock{m};
            TaskDebug("killing task");
            killed = true;
        }
        cv.notify_all();
        wait_result result = wait(timeoutMillis);
        if (th.joinable()) {
            if (result == timeout) th.detach();
            else                   th.join();
        }
        return result;
    }

#if _WIN32
    #ifndef WIN32_LEAN_AND_MEAN
    #  define WIN32_LEAN_AND_MEAN 1
    #endif
    #include <Windows.h>
    #pragma pack(push,8)
    struct THREADNAME_INFO
    {
        DWORD dwType; // Must be 0x1000.
        LPCSTR szName; // Pointer to name (in user addr space).
        DWORD dwThreadID; // Thread ID (-1=caller thread).
        DWORD dwFlags; // Reserved for future use, must be zero.
    };
    #pragma pack(pop)
    void SetThreadName(const char* threadName)
    {
        THREADNAME_INFO info;
        info.dwType     = 0x1000;
        info.szName     = threadName;
        info.dwThreadID = (DWORD)-1;
        info.dwFlags    = 0;

        #pragma warning(push)
        #pragma warning(disable: 6320 6322)
            const DWORD MS_VC_EXCEPTION = 0x406D1388;
            __try {
                RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
            } __except (1){}
        #pragma warning(pop)
    }
#endif

    // really nasty case where OS threads are just abandoned
    // with none of the destructors being run
    static mutex activeTaskMutex;
    static unordered_map<int, pool_task*> activeTasks;
    static int get_thread_id()
    {
        auto id = this_thread::get_id();
        return *(int*)&id;
    }
    static void register_thread_task(pool_task* task)
    {
        lock_guard<mutex> lock{ activeTaskMutex };
        activeTasks[get_thread_id()] = task;
    }
    static void erase_thread_task()
    {
        lock_guard<mutex> lock{ activeTaskMutex };
        activeTasks.erase(get_thread_id());
    }

    static void segfault(int) { SignalHandler("SIGSEGV"); }

    void pool_task::run() noexcept
    {
        static int pool_task_id;
        char name[32];
        snprintf(name, sizeof(name), "rpp_task_%d", pool_task_id++);

        #if __APPLE__
            pthread_setname_np(name);
        #elif __linux__
            pthread_setname_np(pthread_self(), name);
        #elif _WIN32
            SetThreadName(name);
        #endif

        signal(SIGSEGV, segfault); // set SIGSEGV handler so we can catch it
        register_thread_task(this);

        // mark all running threads killed during SIGTERM, before dtors run
        static int atExitRegistered;
        if (!atExitRegistered) atExitRegistered = !atexit([] {
            for (auto& task : activeTasks) {
                task.second->killed = true;
                task.second->cv.notify_all();
            }
            activeTasks.clear();
        });

        struct thread_exiter {
            pool_task* self;
            ~thread_exiter() {
                erase_thread_task();
                self->killed = true;
                self->taskRunning = false;
                self->cv.notify_all();
            }
        } markKilledOnScopeExit { this }; // however, this doesn't handle exit(0) where threads are mutilated

        //TaskDebug("%s start", name);
        for (;;)
        {
            try
            {
                decltype(rangeTask)   range;
                decltype(genericTask) generic;

                // consume the tasks atomically
                { unique_lock<mutex> lock{m};
                    //TaskDebug("%s wait for task", name);
                    if (!wait_for_task(lock)) {
                        TaskDebug("%s stop (%s)", name, killed ? "killed" : "timeout");
                        return;
                    }
                    range   = move(rangeTask);
                    generic = move(genericTask);
                    rangeTask   = {};
                    genericTask = {};
                    taskRunning = true;
                }
                if (range)
                {
                    //TaskDebug("%s(range_task[%d,%d))", name, rangeStart, rangeEnd);
                    range(rangeStart, rangeEnd);
                }
                else
                {
                    //TaskDebug("%s(generic_task)", name);
                    generic();
                }
            }
            // prevent failures that would terminate the thread
            catch (const exception& e) { unhandled_exception(e.what()); }
            catch (const char* e)      { unhandled_exception(e);        }
            catch (...)                { unhandled_exception("");       }
            { lock_guard<mutex> lock{m};
                taskRunning = false;
                cv.notify_all();
            }
        }
    }

    void pool_task::unhandled_exception(const char* what) noexcept
    {
        error = std::current_exception();

        string err = what;
        { lock_guard<mutex> lock{m};
            if (!trace.empty()) {
                err += "\nTask Start Trace:\n";
                err += trace;
            }
        }
        UnhandledEx("%s", err.c_str());
    }

    bool pool_task::got_task() const noexcept
    {
        return (bool)rangeTask || (bool)genericTask;
    }

    bool pool_task::wait_for_task(unique_lock<mutex>& lock) noexcept
    {
        for (;;)
        {
            if (killed)
                return false;
            if (got_task())
                return true;
            if (maxIdleTime)
            {
                if (cv.wait_for(lock, chrono::seconds(maxIdleTime)) == cv_status::timeout)
                    return false;
            }
            else
            {
                cv.wait(lock);
            }
        }
    }

    ///////////////////////////////////////////////////////////////////////////////

    thread_pool& thread_pool::global()
    {
        static thread_pool globalPool;
        return globalPool;
    }

#if _WIN32
    static int num_physical_cores()
    {
        DWORD bytes = 0;
        GetLogicalProcessorInformation(nullptr, &bytes);
        vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> coreInfo(bytes / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
        GetLogicalProcessorInformation(coreInfo.data(), &bytes);

        int cores = 0;
        for (auto& info : coreInfo)
        {
            if (info.Relationship == RelationProcessorCore)
                ++cores;
        }
        return cores;
    }
#else
    static int num_physical_cores()
    {
        return (int)thread::hardware_concurrency();
    }
#endif

    int thread_pool::physical_cores()
    {
        return global().coreCount;
    }

    void thread_pool::set_signal_handler(pool_signal_handler signalHandler)
    {
        lock_guard<mutex> lock{ tasksMutex };
        SignalHandler = signalHandler;
    }

    void thread_pool::set_task_tracer(pool_trace_provider traceProvider)
    {
        lock_guard<mutex> lock{ tasksMutex };
        TraceProvider = traceProvider;
    }

    thread_pool::thread_pool()
    {
        coreCount = num_physical_cores();
    }

    thread_pool::~thread_pool() noexcept
    {
        // defined destructor to prevent agressive inlining
    }

    int thread_pool::active_tasks() noexcept
    {
        lock_guard<mutex> lock{tasksMutex};
        int active = 0;
        for (auto& task : tasks)
            if (task->running()) ++active;
        return active;
    }

    int thread_pool::idle_tasks() noexcept
    {
        lock_guard<mutex> lock{tasksMutex};
        int idle = 0;
        for (auto& task : tasks)
            if (!task->running()) ++idle;
        return idle;
    }

    int thread_pool::total_tasks() const noexcept
    {
        return (int)tasks.size();
    }

    int thread_pool::clear_idle_tasks() noexcept
    {
        lock_guard<mutex> lock{tasksMutex};
        int cleared = 0;
        for (int i = 0; i < (int)tasks.size();)
        {
            if (!tasks[i]->running())
            {
                swap(tasks[i], tasks.back()); // erase_swap_last pattern
                tasks.pop_back();
                ++cleared;
            }
            else ++i;
        }
        return cleared;
    }

    pool_task* thread_pool::start_range_task(size_t& poolIndex, int rangeStart, int rangeEnd,
                                             const action<int, int>& rangeTask) noexcept
    {
        { lock_guard<mutex> lock{tasksMutex};
            for (; poolIndex < tasks.size(); ++poolIndex)
            {
                pool_task* task = tasks[poolIndex].get();
                if (!task->running())
                {
                    ++poolIndex;
                    task->run_range(rangeStart, rangeEnd, rangeTask);
                    return task;
                }
            }
        }

        auto t  = make_unique<pool_task>();
        auto* task = t.get();
        task->max_idle_time(taskMaxIdleTime);
        task->run_range(rangeStart, rangeEnd, rangeTask);

        lock_guard<mutex> lock{tasksMutex};
        tasks.emplace_back(move(t));
        return task;
    }

    void thread_pool::max_task_idle_time(int maxIdleSeconds) noexcept
    {
        lock_guard<mutex> lock{tasksMutex};
        taskMaxIdleTime = maxIdleSeconds;
        for (auto& task : tasks)
            task->max_idle_time(taskMaxIdleTime);
    }

    void thread_pool::parallel_for(int rangeStart, int rangeEnd,
                                   const action<int, int>& rangeTask) noexcept
    {
        assert(!rangeRunning && "Fatal error: nested parallel loops are forbidden!");
        assert(coreCount > 0 && "There appears to be no hardware concurrency");

        const int range = rangeEnd - rangeStart;
        if (range <= 0)
            return;

        const int cores = range < coreCount ? range : coreCount;
        const int len = range / cores;

        // only one physical core or only one task to run. don't run in a thread
        if (cores <= 1)
        {
            rangeTask(0, len);
            return;
        }

        pool_task** active = (pool_task**)alloca(sizeof(pool_task*) * cores);
        //vector<pool_task*> active(cores, nullptr);
        {
            rangeRunning = true;

            size_t poolIndex = 0;
            for (int i = 0; i < cores; ++i)
            {
                const int start = i * len;
                const int end   = i == cores - 1 ? rangeEnd : start + len;
                active[i] = start_range_task(poolIndex, start, end, rangeTask);
            }
        }

        for (int i = 0; i < cores; ++i)
            active[i]->wait();

        rangeRunning = false;
    }

    pool_task* thread_pool::parallel_task(task_delegate<void()>&& genericTask) noexcept
    {
        { lock_guard<mutex> lock{tasksMutex};
            for (unique_ptr<pool_task>& t : tasks)
            {
                pool_task* task = t.get();
                if (!task->running())
                {
                    task->run_generic(move(genericTask));
                    return task;
                }
            }
        }

        // create and run a new task atomically
        auto t = make_unique<pool_task>();
        auto* task = t.get();
        task->max_idle_time(taskMaxIdleTime);
        task->run_generic(move(genericTask));

        lock_guard<mutex> lock{tasksMutex};
        tasks.emplace_back(move(t));
        return task;
    }
}
<|endoftext|>


<commit_before>/******************************************************************************
 * This file is part of the Gluon Development Platform
 * Copyright (c) 2009 Dan Leinir Turthra Jensen <admin@leinir.dk>
 * Copyright (c) 2009 Kim Jung Nissen <jungnissen@gmail.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 Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "btnode.h"

#include <QtCore/QDebug>

btNode::btNode(QObject* parent)
    : QObject(parent)
    , m_name("")
    , m_description("")
    , m_className("")
    , m_type(btNode::UnusableNodeType)
    , m_currentChildIndex(0)
    , m_currentChildStatus(btNode::None)
{
}

btNode::~btNode()
{
	qDeleteAll(m_children);
	m_children.clear();
}

void btNode::setName(QString name)
{
	m_name = name;
}

QString btNode::name()
{
	return m_name;
}

void btNode::setDescription(QString description)
{
	m_description = description;
}

QString btNode::description()
{
	return m_description;
}

void btNode::setClassName(QString className)
{
	m_className = className;
}

QString btNode::className()
{
	return m_className;
}

void btNode::setType(btNode::nodeType type)
{
	m_type = type;
}

btNode::nodeType btNode::type()
{
	return m_type;
}

int btNode::childCount()
{
	return m_children.count();
}

void btNode::appendChild(btNode* child)
{
	m_children.append(child);
	//has to be in the list, before this function is called
	appendingChild(m_children.count()-1);
}

btNode* btNode::child(int index)
{
	return m_children[index];
}

btNode::status btNode::run(btCharacter * self)
{
    qDebug() << "The btNode " << className() << " has either not been registered or implemented";
	return btNode::Failed;
}

void btNode::setCurrentChildStatus(status nodeStatus)
{
	m_currentChildStatus = nodeStatus;
}

btNode::status btNode::currentChildStatus()
{
	return m_currentChildStatus;
}

btNode* btNode::currentChild()
{
	return m_children[m_currentChildIndex];
}

void btNode::setCurrentChildIndex(int index)
{
	m_currentChildIndex = index;
}

int btNode::currentChildIndex()
{
	return m_currentChildIndex;
}

btNode::status btNode::runChild()
{
	return btNode::RunningChild;
}

btNode::status btNode::runChild(int index)
{
	m_currentChildIndex = index;
	return btNode::RunningChild;
}

btNode* btNode::parentNode()
{
	return m_parent;
}

void btNode::setParentNode(btNode* parent)
{
	m_parent = parent;
}

void btNode::removeChild(int index)
{
	removingChild(index);
	m_children.removeAt(index);
}

void btNode::removeChild(btNode* child)
{
	for (int i = 0; i < m_children.count(); i++)
	{
		if(m_children.at(i) == child)
		{
			removeChild(i);
		}
	}
}

void btNode::doneParsingChildren()
{
	childrenAdded();
}

int btNode::nextChildIndex()
{
	if(m_currentChildStatus == btNode::None)
		return m_currentChildIndex;
	return ++m_currentChildIndex;
}

void btNode::insertChild(int index, btNode* child)
{
	m_children.insert(index, child);
    appendingChild(index);
}

int btNode::childIndex(btNode * child)
{
    for (int i = 0; i < m_children.count(); i++)
    {
        if(m_children.at(i) == child)
        {
            return i;
        }
    }

    return -1;
}

#include "btnode.moc"
<commit_msg>Initialize the parent btNode to 0 instead of letting it dangling it<commit_after>/******************************************************************************
 * This file is part of the Gluon Development Platform
 * Copyright (c) 2009 Dan Leinir Turthra Jensen <admin@leinir.dk>
 * Copyright (c) 2009 Kim Jung Nissen <jungnissen@gmail.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 Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "btnode.h"

#include <QtCore/QDebug>

btNode::btNode(QObject* parent)
    : QObject(parent)
    , m_name("")
    , m_description("")
    , m_className("")
    , m_type(btNode::UnusableNodeType)
    , m_parent(0)
    , m_currentChildIndex(0)
    , m_currentChildStatus(btNode::None)
{
}

btNode::~btNode()
{
	qDeleteAll(m_children);
	m_children.clear();
}

void btNode::setName(QString name)
{
	m_name = name;
}

QString btNode::name()
{
	return m_name;
}

void btNode::setDescription(QString description)
{
	m_description = description;
}

QString btNode::description()
{
	return m_description;
}

void btNode::setClassName(QString className)
{
	m_className = className;
}

QString btNode::className()
{
	return m_className;
}

void btNode::setType(btNode::nodeType type)
{
	m_type = type;
}

btNode::nodeType btNode::type()
{
	return m_type;
}

int btNode::childCount()
{
	return m_children.count();
}

void btNode::appendChild(btNode* child)
{
	m_children.append(child);
	//has to be in the list, before this function is called
	appendingChild(m_children.count()-1);
}

btNode* btNode::child(int index)
{
	return m_children[index];
}

btNode::status btNode::run(btCharacter * self)
{
    qDebug() << "The btNode " << className() << " has either not been registered or implemented";
	return btNode::Failed;
}

void btNode::setCurrentChildStatus(status nodeStatus)
{
	m_currentChildStatus = nodeStatus;
}

btNode::status btNode::currentChildStatus()
{
	return m_currentChildStatus;
}

btNode* btNode::currentChild()
{
	return m_children[m_currentChildIndex];
}

void btNode::setCurrentChildIndex(int index)
{
	m_currentChildIndex = index;
}

int btNode::currentChildIndex()
{
	return m_currentChildIndex;
}

btNode::status btNode::runChild()
{
	return btNode::RunningChild;
}

btNode::status btNode::runChild(int index)
{
	m_currentChildIndex = index;
	return btNode::RunningChild;
}

btNode* btNode::parentNode()
{
	return m_parent;
}

void btNode::setParentNode(btNode* parent)
{
	m_parent = parent;
}

void btNode::removeChild(int index)
{
	removingChild(index);
	m_children.removeAt(index);
}

void btNode::removeChild(btNode* child)
{
	for (int i = 0; i < m_children.count(); i++)
	{
		if(m_children.at(i) == child)
		{
			removeChild(i);
		}
	}
}

void btNode::doneParsingChildren()
{
	childrenAdded();
}

int btNode::nextChildIndex()
{
	if(m_currentChildStatus == btNode::None)
		return m_currentChildIndex;
	return ++m_currentChildIndex;
}

void btNode::insertChild(int index, btNode* child)
{
	m_children.insert(index, child);
    appendingChild(index);
}

int btNode::childIndex(btNode * child)
{
    for (int i = 0; i < m_children.count(); i++)
    {
        if(m_children.at(i) == child)
        {
            return i;
        }
    }

    return -1;
}

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


<commit_before><commit_msg>PWGPP-426 - adding non persitent data members +bug fix+ new variables<commit_after><|endoftext|>


<commit_before>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, development version     *
*                (c) 2006-2016 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* 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 Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
*******************************************************************************
*                               SOFA :: Plugins                               *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#include "Binding_Base.h"
#include "Binding_Data.h"
#include "Binding_DisplayFlagsData.h"
#include "Binding_OptionsGroupData.h"
#include "Binding_Link.h"

#include <sofa/helper/vector.h>
#include <sofa/core/objectmodel/Base.h>
#include <sofa/core/objectmodel/BaseData.h>
using namespace sofa::core::objectmodel;
#include <sofa/helper/logging/Messaging.h>

#include "PythonFactory.h"

extern "C" PyObject * Base_findData(PyObject *self, PyObject *args )
{
    Base* obj=((PySPtr<Base>*)self)->object.get();
    char *dataName;
    if (!PyArg_ParseTuple(args, "s",&dataName))
    {
        msg_error("Base_findData") <<"Base_findData_impl not a string\n";
        Py_RETURN_NONE;
    }
    BaseData * data = obj->findData(dataName);
    if (!data)
    {
        if( obj->hasField(dataName) )
            msg_error("Base_findData")<<"object '"<<obj->getName()<<"' has a field '"<<dataName<<"' but it is not a Data";
        else
        {
            msg_error("Base_findData")<<"object '"<<obj->getName()<<"' does no have a field '"<<dataName<<"'";
            std::stringstream s;
            obj->writeDatas(s,";");
            msg_error("Base_findData")<<s.str();
        }

        PyErr_BadArgument();

        Py_RETURN_NONE;
    }

    // special cases... from factory (e.g DisplayFlags, OptionsGroup)
    {
        PyObject* res = sofa::PythonFactory::toPython(data);
        if( res ) return res;
    }

    return SP_BUILD_PYPTR(Data,BaseData,data,false);
}

extern "C" PyObject * Base_findLink(PyObject *self, PyObject *args)
{
    Base* obj=((PySPtr<Base>*)self)->object.get();
    char *linkName;
     if (!PyArg_ParseTuple(args, "s",&linkName))
         Py_RETURN_NONE;
    BaseLink * link = obj->findLink(linkName);
    if (!link)
    {
        if( obj->hasField(linkName) )
            msg_error("Base_findLink")<<"object '"<<obj->getName()<<"' has a field '"<<linkName<<"' but it is not a Link";
        else
        {
            msg_error("Base_findLink")<<"object '"<<obj->getName()<<"' does no have a field '"<<linkName<<"'";
            std::stringstream s;
            obj->writeDatas(s,";");
            msg_error("Base_findLink")<<s.str();
        }

        PyErr_BadArgument();
        Py_RETURN_NONE;
    }

    return SP_BUILD_PYPTR(Link,BaseLink,link,false);
}

// Generic accessor to Data fields (in python native type)
extern "C" PyObject* Base_GetAttr(PyObject *o, PyObject *attr_name)
{
    Base* obj=down_cast<Base>(((PySPtr<Base>*)o)->object.get());
    char *attrName = PyString_AsString(attr_name);
//    printf("Base_GetAttr type=%s name=%s attrName=%s\n",obj->getClassName().c_str(),obj->getName().c_str(),attrName);

    // see if a Data field has this name...
    BaseData * data = obj->findData(attrName);
    if (data) return GetDataValuePython(data); // we have our data... let's create the right Python type....

    // see if a Link has this name...
    BaseLink * link = obj->findLink(attrName);
    if (link) return GetLinkValuePython(link); // we have our link... let's create the right Python type....

    //        printf("Base_GetAttr ERROR data not found - type=%s name=%s attrName=%s\n",obj->getClassName().c_str(),obj->getName().c_str(),attrName);
    return PyObject_GenericGetAttr(o,attr_name);
}

extern "C" int Base_SetAttr(PyObject *o, PyObject *attr_name, PyObject *v)
{
    // attribute does not exist: see if a Data field has this name...
    Base* obj=down_cast<Base>(((PySPtr<Base>*)o)->object.get());
    char *attrName = PyString_AsString(attr_name);

//    printf("Base_SetAttr name=%s\n",dataName);
    BaseData * data = obj->findData(attrName);
    if (data)
    {
        if (SetDataValuePython(data,v)) return 0;
        else return -1;
    }

    BaseLink * link = obj->findLink(attrName);
    if (link)
    {
        if (SetLinkValuePython(link,v)) return 0;
        else return -1;
    }

    return PyObject_GenericSetAttr(o,attr_name,v);
}

extern "C" PyObject * Base_getClassName(PyObject * self, PyObject * /*args*/)
{
    // BaseNode is not bound in SofaPython, so getPathName is bound in Node instead
    Base* node = ((PySPtr<Base>*)self)->object.get();

    return PyString_FromString(node->getClassName().c_str());
}

extern "C" PyObject * Base_getTemplateName(PyObject * self, PyObject * /*args*/)
{
    // BaseNode is not bound in SofaPython, so getPathName is bound in Node instead
    Base* node = ((PySPtr<Base>*)self)->object.get();

    return PyString_FromString(node->getTemplateName().c_str());
}

extern "C" PyObject * Base_getName(PyObject * self, PyObject * /*args*/)
{
    // BaseNode is not bound in SofaPython, so getPathName is bound in Node instead
    Base* node = ((PySPtr<Base>*)self)->object.get();

    return PyString_FromString(node->getName().c_str());
}

extern "C" PyObject * Base_getDataFields(PyObject *self, PyObject * /*args*/)
{
    Base * component = ((PySPtr<Base>*)self)->object.get();

    if(!component)
    {
        PyErr_BadArgument();
        Py_RETURN_NONE;
    }

    const sofa::helper::vector<BaseData*> dataFields = component->getDataFields();

    PyObject * pyDict = PyDict_New();
    for (size_t i=0; i<dataFields.size(); i++)
        PyDict_SetItem(pyDict, PyString_FromString(dataFields[i]->getName().c_str()), GetDataValuePython(dataFields[i]));

    return pyDict;
}

SP_CLASS_METHODS_BEGIN(Base)
SP_CLASS_METHOD(Base,findData)
SP_CLASS_METHOD(Base,findLink)
SP_CLASS_METHOD(Base,getClassName)
SP_CLASS_METHOD(Base,getTemplateName)
SP_CLASS_METHOD(Base,getName)
SP_CLASS_METHOD(Base,getDataFields)
SP_CLASS_METHODS_END

//SP_CLASS_DATA_ATTRIBUTE(Base,name)

SP_CLASS_ATTRS_BEGIN(Base)
//SP_CLASS_ATTR(Base,name)
SP_CLASS_ATTRS_END

SP_CLASS_TYPE_BASE_SPTR_ATTR_GETATTR(Base,Base)
<commit_msg>[SofaPython] cleaning<commit_after>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, development version     *
*                (c) 2006-2016 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* 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 Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
*******************************************************************************
*                               SOFA :: Plugins                               *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#include "Binding_Base.h"
#include "Binding_Data.h"
#include "Binding_Link.h"

#include <sofa/helper/vector.h>
#include <sofa/core/objectmodel/Base.h>
#include <sofa/core/objectmodel/BaseData.h>
using namespace sofa::core::objectmodel;
#include <sofa/helper/logging/Messaging.h>

#include "PythonFactory.h"

extern "C" PyObject * Base_findData(PyObject *self, PyObject *args )
{
    Base* obj=((PySPtr<Base>*)self)->object.get();
    char *dataName;
    if (!PyArg_ParseTuple(args, "s",&dataName))
    {
        msg_error("Base_findData") <<"Base_findData_impl not a string\n";
        Py_RETURN_NONE;
    }
    BaseData * data = obj->findData(dataName);
    if (!data)
    {
        if( obj->hasField(dataName) )
            msg_error("Base_findData")<<"object '"<<obj->getName()<<"' has a field '"<<dataName<<"' but it is not a Data";
        else
        {
            msg_error("Base_findData")<<"object '"<<obj->getName()<<"' does no have a field '"<<dataName<<"'";
            std::stringstream s;
            obj->writeDatas(s,";");
            msg_error("Base_findData")<<s.str();
        }

        PyErr_BadArgument();

        Py_RETURN_NONE;
    }

    // special cases... from factory (e.g DisplayFlags, OptionsGroup)
    {
        PyObject* res = sofa::PythonFactory::toPython(data);
        if( res ) return res;
    }

    return SP_BUILD_PYPTR(Data,BaseData,data,false);
}

extern "C" PyObject * Base_findLink(PyObject *self, PyObject *args)
{
    Base* obj=((PySPtr<Base>*)self)->object.get();
    char *linkName;
     if (!PyArg_ParseTuple(args, "s",&linkName))
         Py_RETURN_NONE;
    BaseLink * link = obj->findLink(linkName);
    if (!link)
    {
        if( obj->hasField(linkName) )
            msg_error("Base_findLink")<<"object '"<<obj->getName()<<"' has a field '"<<linkName<<"' but it is not a Link";
        else
        {
            msg_error("Base_findLink")<<"object '"<<obj->getName()<<"' does no have a field '"<<linkName<<"'";
            std::stringstream s;
            obj->writeDatas(s,";");
            msg_error("Base_findLink")<<s.str();
        }

        PyErr_BadArgument();
        Py_RETURN_NONE;
    }

    return SP_BUILD_PYPTR(Link,BaseLink,link,false);
}

// Generic accessor to Data fields (in python native type)
extern "C" PyObject* Base_GetAttr(PyObject *o, PyObject *attr_name)
{
    Base* obj=down_cast<Base>(((PySPtr<Base>*)o)->object.get());
    char *attrName = PyString_AsString(attr_name);
//    printf("Base_GetAttr type=%s name=%s attrName=%s\n",obj->getClassName().c_str(),obj->getName().c_str(),attrName);

    // see if a Data field has this name...
    BaseData * data = obj->findData(attrName);
    if (data) return GetDataValuePython(data); // we have our data... let's create the right Python type....

    // see if a Link has this name...
    BaseLink * link = obj->findLink(attrName);
    if (link) return GetLinkValuePython(link); // we have our link... let's create the right Python type....

    //        printf("Base_GetAttr ERROR data not found - type=%s name=%s attrName=%s\n",obj->getClassName().c_str(),obj->getName().c_str(),attrName);
    return PyObject_GenericGetAttr(o,attr_name);
}

extern "C" int Base_SetAttr(PyObject *o, PyObject *attr_name, PyObject *v)
{
    // attribute does not exist: see if a Data field has this name...
    Base* obj=down_cast<Base>(((PySPtr<Base>*)o)->object.get());
    char *attrName = PyString_AsString(attr_name);

//    printf("Base_SetAttr name=%s\n",dataName);
    BaseData * data = obj->findData(attrName);
    if (data)
    {
        if (SetDataValuePython(data,v)) return 0;
        else return -1;
    }

    BaseLink * link = obj->findLink(attrName);
    if (link)
    {
        if (SetLinkValuePython(link,v)) return 0;
        else return -1;
    }

    return PyObject_GenericSetAttr(o,attr_name,v);
}

extern "C" PyObject * Base_getClassName(PyObject * self, PyObject * /*args*/)
{
    // BaseNode is not bound in SofaPython, so getPathName is bound in Node instead
    Base* node = ((PySPtr<Base>*)self)->object.get();

    return PyString_FromString(node->getClassName().c_str());
}

extern "C" PyObject * Base_getTemplateName(PyObject * self, PyObject * /*args*/)
{
    // BaseNode is not bound in SofaPython, so getPathName is bound in Node instead
    Base* node = ((PySPtr<Base>*)self)->object.get();

    return PyString_FromString(node->getTemplateName().c_str());
}

extern "C" PyObject * Base_getName(PyObject * self, PyObject * /*args*/)
{
    // BaseNode is not bound in SofaPython, so getPathName is bound in Node instead
    Base* node = ((PySPtr<Base>*)self)->object.get();

    return PyString_FromString(node->getName().c_str());
}

extern "C" PyObject * Base_getDataFields(PyObject *self, PyObject * /*args*/)
{
    Base * component = ((PySPtr<Base>*)self)->object.get();

    if(!component)
    {
        PyErr_BadArgument();
        Py_RETURN_NONE;
    }

    const sofa::helper::vector<BaseData*> dataFields = component->getDataFields();

    PyObject * pyDict = PyDict_New();
    for (size_t i=0; i<dataFields.size(); i++)
        PyDict_SetItem(pyDict, PyString_FromString(dataFields[i]->getName().c_str()), GetDataValuePython(dataFields[i]));

    return pyDict;
}

SP_CLASS_METHODS_BEGIN(Base)
SP_CLASS_METHOD(Base,findData)
SP_CLASS_METHOD(Base,findLink)
SP_CLASS_METHOD(Base,getClassName)
SP_CLASS_METHOD(Base,getTemplateName)
SP_CLASS_METHOD(Base,getName)
SP_CLASS_METHOD(Base,getDataFields)
SP_CLASS_METHODS_END

//SP_CLASS_DATA_ATTRIBUTE(Base,name)

SP_CLASS_ATTRS_BEGIN(Base)
//SP_CLASS_ATTR(Base,name)
SP_CLASS_ATTRS_END

SP_CLASS_TYPE_BASE_SPTR_ATTR_GETATTR(Base,Base)
<|endoftext|>