// Gnurbs - A curve and surface library
// Copyright (C) 2008-2026 Eric Bechet
//
// See the LICENSE file for contributions and license information.
// Please report all bugs and problems to <bechet@cadxfem.org>.
//
// Contributions Sebastien MOREAU

#include "nvtkCurveRep.h"
#include "ncurve.h"

#include "vtkPoints.h"
#include "vtkCellArray.h"
#include "vtkPolyData.h"
#include "vtkObjectFactory.h"
#include "vtkRenderer.h"
#include "vtkIntArray.h"

vtkCxxRevisionMacro(nvtkCurveRep, "$Revision: 1.5.20.1 $");
vtkStandardNewMacro(nvtkCurveRep);


//----------------------------------------------------------------------
nvtkCurveRep::nvtkCurveRep()
{
  _curve = 0;
}

//----------------------------------------------------------------------
nvtkCurveRep::~nvtkCurveRep()
{
}

void nvtkCurveRep::SetCurve(ncurve * curve)
{
  _curve = curve;

  for (int j=0; j< _curve->nb_CP(); j++)
  {
    npoint3 aPt(_curve->CP(j));
    AddNodeAtWorldPosition(aPt.array());
  }
}

void nvtkCurveRep::BuildLines()
{
  npoint3 pt;
  if (GetActiveNodeWorldPosition(pt.array()))
  {
    if (_curve->nb_CP() ==  GetNumberOfNodes())
    {
      npoint p4=_curve ->CP(ActiveNode);
      double w=p4.w();
      if (w==0.) w=1.0;
      p4[0]=pt[0]*w;
      p4[1]=pt[1]*w;
      p4[2]=pt[2]*w;
      _curve ->set_CP(ActiveNode,p4);
    }
    else
      DeleteActiveNode();
  }
  vtkPoints *points = vtkPoints::New();
  vtkCellArray *lines = vtkCellArray::New();

  //int i, j;
  vtkIdType index = 0;

  data_container data ;
  if (!_curve) return;
  _curve ->Display(data);

  vtkIdType numLines = data.nb_lines() +1;
  points->SetNumberOfPoints(numLines);
  int count = numLines;

  if (this->ClosedLoop && count > 0)
  {
    numLines = count+1;
  }
  else
  {
    numLines = count;
  }

  if (numLines > 0)
  {
    vtkIdType *lineIndices = new vtkIdType[numLines];
    const double *pos;
    for (int i=0; i< numLines -1; i++)
    {
      pos = data.get_line(i).pts[0].array();
      points->InsertPoint(index, pos);
      lineIndices[index] = index;
      index++;
    }
    // link the last line with the last node
    pos = data.get_line(numLines-2).pts[1].array();
    points->InsertPoint(index, pos);
    lineIndices[index] = index;
    index++;

    if (this->ClosedLoop)
    {
      lineIndices[index] = 0;
    }

    lines->InsertNextCell(numLines, lineIndices);
    delete [] lineIndices;
  }

  this->Lines->SetPoints(points);
  this->Lines->SetLines(lines);

  points->Delete();
  lines->Delete();
}

double* nvtkCurveRep::GetBounds()
{
  //Retrieve the curve bounding box
  double * motherBounds = vtkOrientedGlyphContourRepresentation::GetBounds();

  //Compute the bounds of the control points
  for(int i=0;i<3;++i)
  {
    Bounds[2*i]=Bounds[2*i+1]=_curve->CP(0)[i];
  }

  for(int iCP=1; iCP< _curve->nb_CP();++iCP)
  {
    for(int i=0;i<3;++i)
    {
      if(Bounds[2*i]>_curve->CP(iCP)[i]) Bounds[2*i]=_curve->CP(iCP)[i];
      if(Bounds[2*i+1]<_curve->CP(iCP)[i]) Bounds[2*i+1]=_curve->CP(iCP)[i];
    }
  }

  //Check that the curve bounding box is not zero (the curve is actually plotted)
  double motherBoundsAbsSum=0;
  if(motherBounds)
    for(int i=0;i<6;++i)
      motherBoundsAbsSum+=fabs(motherBounds[i]);

  //Combine the bounds of the curve with the bounds of the control points
  if(motherBoundsAbsSum)
  {
   for(int i=0;i<3;++i)
    {
      if(Bounds[2*i]>motherBounds[2*i]) Bounds[2*i]=motherBounds[2*i];
      if(Bounds[2*i+1]<motherBounds[2*i+1]) Bounds[2*i+1]=motherBounds[2*i+1];
    }
  }

  return Bounds;
}

