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

  Program:   Visualization Toolkit
  Module:    vtkImageAlgorithm.cxx

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

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

=========================================================================*/
#include "vtkImageAlgorithm.h"

#include "vtkCellData.h"
#include "vtkCommand.h"
#include "vtkDataArray.h"
#include "vtkImageData.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkStreamingDemandDrivenPipeline.h"

vtkCxxRevisionMacro(vtkImageAlgorithm, "1.19");

//----------------------------------------------------------------------------
vtkImageAlgorithm::vtkImageAlgorithm()
{
  this->SetNumberOfInputPorts(1);
  this->SetNumberOfOutputPorts(1);
  this->InputScalarsSelection = NULL;
}

//----------------------------------------------------------------------------
vtkImageAlgorithm::~vtkImageAlgorithm()
{
  this->SetInputScalarsSelection(NULL);
}

//----------------------------------------------------------------------------
void vtkImageAlgorithm::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}

//----------------------------------------------------------------------------
// This is the superclasses style of Execute method.  Convert it into
// an imaging style Execute method.
int vtkImageAlgorithm::RequestData(
  vtkInformation* request,
  vtkInformationVector** vtkNotUsed( inputVector ),
  vtkInformationVector* outputVector)
{
  // the default implimentation is to do what the old pipeline did find what
  // output is requesting the data, and pass that into ExecuteData

  // which output port did the request come from
  int outputPort =
    request->Get(vtkDemandDrivenPipeline::FROM_OUTPUT_PORT());

  // if output port is negative then that means this filter is calling the
  // update directly, in that case just assume port 0
  if (outputPort == -1)
      {
      outputPort = 0;
      }

  // get the data object
  vtkInformation *outInfo =
    outputVector->GetInformationObject(outputPort);
  // call ExecuteData
  if (outInfo)
    {
    this->ExecuteData( outInfo->Get(vtkDataObject::DATA_OBJECT()) );
    }
  else
    {
    this->ExecuteData(NULL);
    }
  return 1;
}

//----------------------------------------------------------------------------
int vtkImageAlgorithm::ProcessRequest(vtkInformation* request,
                                      vtkInformationVector** inputVector,
                                      vtkInformationVector* outputVector)
{
  // generate the data
  if(request->Has(vtkDemandDrivenPipeline::REQUEST_DATA()))
    {
    this->RequestData(request, inputVector, outputVector);
    return 1;
    }

  // execute information
  if(request->Has(vtkDemandDrivenPipeline::REQUEST_INFORMATION()))
    {
    this->RequestInformation(request, inputVector, outputVector);
    return 1;
    }

  // propagate update extent
  if(request->Has(vtkStreamingDemandDrivenPipeline::REQUEST_UPDATE_EXTENT()))
    {
    this->RequestUpdateExtent(request, inputVector, outputVector);
    return 1;
    }

  return this->Superclass::ProcessRequest(request, inputVector, outputVector);
}

//----------------------------------------------------------------------------
// Assume that any source that implements ExecuteData
// can handle an empty extent.
void vtkImageAlgorithm::ExecuteData(vtkDataObject *)
{
  this->Execute();
}

//----------------------------------------------------------------------------
void vtkImageAlgorithm::Execute()
{
  vtkErrorMacro(<< "Definition of Execute() method should be in subclass and you should really use the ExecuteData(vtkInformation *request,...) signature instead");
}

int vtkImageAlgorithm::RequestInformation(
  vtkInformation* vtkNotUsed(request),
  vtkInformationVector** vtkNotUsed(inputVector),
  vtkInformationVector* vtkNotUsed(outputVector))
{
  // do nothing let subclasses handle it
  return 1;
}

int vtkImageAlgorithm::RequestUpdateExtent(
  vtkInformation* vtkNotUsed(request),
  vtkInformationVector** vtkNotUsed(inputVector),
  vtkInformationVector* vtkNotUsed(outputVector))
{
  // do nothing let subclasses handle it
  return 1;
}

//----------------------------------------------------------------------------
void vtkImageAlgorithm::AllocateOutputData(vtkImageData *output,
                                           int *uExtent)
{
  // set the extent to be the update extent
  output->SetExtent(uExtent);
  output->AllocateScalars();
}

//----------------------------------------------------------------------------
vtkImageData *vtkImageAlgorithm::AllocateOutputData(vtkDataObject *output)
{
  // set the extent to be the update extent
  vtkImageData *out = vtkImageData::SafeDownCast(output);
  if (out)
    {
    // this needs to be fixed -Ken
    vtkStreamingDemandDrivenPipeline *sddp =
      vtkStreamingDemandDrivenPipeline::SafeDownCast(this->GetExecutive());
    if (sddp)
      {
      int extent[6];
      sddp->GetOutputInformation(0)->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(),extent);
      out->SetExtent(extent);
      }
    out->AllocateScalars();
    }
  return out;
}

// by default copy the attr from the first input to the first output
void vtkImageAlgorithm::CopyAttributeData(vtkImageData *input,
                                          vtkImageData *output)
{
  if (!input || !output)
    {
    return;
    }

  int inExt[6];
  int outExt[6];
  vtkDataArray *inArray;
  vtkDataArray *outArray;

  input->GetExtent(inExt);
  output->GetExtent(outExt);

  // Do not copy the array we will be generating.
  inArray = input->GetPointData()->GetScalars(this->InputScalarsSelection);

  // Conditionally copy point and cell data.  Only copy if corresponding
  // indexes refer to identical points.
  double *oIn = input->GetOrigin();
  double *sIn = input->GetSpacing();
  double *oOut = output->GetOrigin();
  double *sOut = output->GetSpacing();
  if (oIn[0] == oOut[0] && oIn[1] == oOut[1] && oIn[2] == oOut[2] &&
      sIn[0] == sOut[0] && sIn[1] == sOut[1] && sIn[2] == sOut[2])
    {
    output->GetPointData()->CopyAllOn();
    output->GetCellData()->CopyAllOn();
    // Scalar copy flag trumps the array copy flag.
    if (inArray == input->GetPointData()->GetScalars())
      {
      output->GetPointData()->CopyScalarsOff();
      }
    else
      {
      output->GetPointData()->CopyFieldOff(this->InputScalarsSelection);
      }

    // If the extents are the same, then pass the attribute data for
    // efficiency.
    if (inExt[0] == outExt[0] && inExt[1] == outExt[1] &&
        inExt[2] == outExt[2] && inExt[3] == outExt[3] &&
        inExt[4] == outExt[4] && inExt[5] == outExt[5])
      {// Pass
      output->GetPointData()->PassData(input->GetPointData());
      output->GetCellData()->PassData(input->GetCellData());
      }
    else
      {// Copy
       // Since this can be expensive to copy all of these values,
       // lets make sure there are arrays to copy (other than the scalars)
      if (input->GetPointData()->GetNumberOfArrays() > 1)
        {
        // Copy the point data.
        // CopyAllocate frees all arrays.
        // Keep the old scalar array (not being copied).
        // This is a hack, but avoids reallocation ...
        vtkDataArray *tmp = NULL;
        if ( ! output->GetPointData()->GetCopyScalars() )
          {
          tmp = output->GetPointData()->GetScalars();
          }
        output->GetPointData()->CopyAllocate(input->GetPointData(),
                                             output->GetNumberOfPoints());
        if (tmp)
          { // Restore the array.
          output->GetPointData()->SetScalars(tmp);
          }
        // Now Copy The point data, but only if output is a subextent of the
        // input.
        if (outExt[0] >= inExt[0] && outExt[1] <= inExt[1] &&
            outExt[2] >= inExt[2] && outExt[3] <= inExt[3] &&
            outExt[4] >= inExt[4] && outExt[5] <= inExt[5])
          {
          output->GetPointData()->CopyStructuredData(input->GetPointData(),
                                                     inExt, outExt);
          }
        }

      if (input->GetCellData()->GetNumberOfArrays() > 0)
        {
        output->GetCellData()->CopyAllocate(input->GetCellData(),
                                            output->GetNumberOfCells());
        // Cell extent is one less than point extent.
        // Conditional to handle a colapsed axis (lower dimensional cells).
        if (inExt[0] < inExt[1]) {--inExt[1];}
        if (inExt[2] < inExt[3]) {--inExt[3];}
        if (inExt[4] < inExt[5]) {--inExt[5];}
        // Cell extent is one less than point extent.
        if (outExt[0] < outExt[1]) {--outExt[1];}
        if (outExt[2] < outExt[3]) {--outExt[3];}
        if (outExt[4] < outExt[5]) {--outExt[5];}
        // Now Copy The cell data, but only if output is a subextent of the input.
        if (outExt[0] >= inExt[0] && outExt[1] <= inExt[1] &&
            outExt[2] >= inExt[2] && outExt[3] <= inExt[3] &&
            outExt[4] >= inExt[4] && outExt[5] <= inExt[5])
          {
          output->GetCellData()->CopyStructuredData(input->GetCellData(),
                                                    inExt, outExt);
          }
        }
      }
    }

  // set the name of the output to match the input name
  outArray = output->GetPointData()->GetScalars();
  if (inArray)
    {
    outArray->SetName(inArray->GetName());
    }
}

//----------------------------------------------------------------------------
vtkImageData* vtkImageAlgorithm::GetOutput()
{
  return this->GetOutput(0);
}

//----------------------------------------------------------------------------
vtkImageData* vtkImageAlgorithm::GetOutput(int port)
{
  return vtkImageData::SafeDownCast(this->GetOutputDataObject(port));
}

//----------------------------------------------------------------------------
void vtkImageAlgorithm::SetOutput(vtkDataObject* d)
{
  this->GetExecutive()->SetOutputData(0, d);
}

//----------------------------------------------------------------------------
int vtkImageAlgorithm::FillOutputPortInformation(
  int vtkNotUsed(port), vtkInformation* info)
{
  // now add our info
  info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkImageData");

  return 1;
}

int vtkImageAlgorithm::FillInputPortInformation(
  int vtkNotUsed(port), vtkInformation* info)
{
  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkImageData");
  return 1;
}

//----------------------------------------------------------------------------
void vtkImageAlgorithm::SetInput(vtkDataObject* input)
{
  this->SetInput(0, input);
}

//----------------------------------------------------------------------------
void vtkImageAlgorithm::SetInput(int index, vtkDataObject* input)
{
  if(input)
    {
    this->SetInputConnection(index, input->GetProducerPort());
    }
  else
    {
    // Setting a NULL input removes the connection.
    this->SetInputConnection(index, 0);
    }
}

//----------------------------------------------------------------------------
vtkDataObject* vtkImageAlgorithm::GetInput(int port)
{
  if (this->GetNumberOfInputConnections(port) < 1)
    {
    return 0;
    }
  return this->GetExecutive()->GetInputData(port, 0);
}

//----------------------------------------------------------------------------
void vtkImageAlgorithm::AddInput(vtkDataObject* input)
{
  this->AddInput(0, input);
}

//----------------------------------------------------------------------------
void vtkImageAlgorithm::AddInput(int index, vtkDataObject* input)
{
  if(input)
    {
    this->AddInputConnection(index, input->GetProducerPort());
    }
}
<commit_msg>BUG: Changing the usage of PointData or CellData (such as changing which array is the Scalar field with vtkAssignAttributes) could cause the output scalar array to be overwritten by an input array.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkImageAlgorithm.cxx

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

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

=========================================================================*/
#include "vtkImageAlgorithm.h"

#include "vtkCellData.h"
#include "vtkCommand.h"
#include "vtkDataArray.h"
#include "vtkImageData.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkStreamingDemandDrivenPipeline.h"

vtkCxxRevisionMacro(vtkImageAlgorithm, "1.20");

//----------------------------------------------------------------------------
vtkImageAlgorithm::vtkImageAlgorithm()
{
  this->SetNumberOfInputPorts(1);
  this->SetNumberOfOutputPorts(1);
  this->InputScalarsSelection = NULL;
}

//----------------------------------------------------------------------------
vtkImageAlgorithm::~vtkImageAlgorithm()
{
  this->SetInputScalarsSelection(NULL);
}

//----------------------------------------------------------------------------
void vtkImageAlgorithm::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}

//----------------------------------------------------------------------------
// This is the superclasses style of Execute method.  Convert it into
// an imaging style Execute method.
int vtkImageAlgorithm::RequestData(
  vtkInformation* request,
  vtkInformationVector** vtkNotUsed( inputVector ),
  vtkInformationVector* outputVector)
{
  // the default implimentation is to do what the old pipeline did find what
  // output is requesting the data, and pass that into ExecuteData

  // which output port did the request come from
  int outputPort =
    request->Get(vtkDemandDrivenPipeline::FROM_OUTPUT_PORT());

  // if output port is negative then that means this filter is calling the
  // update directly, in that case just assume port 0
  if (outputPort == -1)
      {
      outputPort = 0;
      }

  // get the data object
  vtkInformation *outInfo =
    outputVector->GetInformationObject(outputPort);
  // call ExecuteData
  if (outInfo)
    {
    this->ExecuteData( outInfo->Get(vtkDataObject::DATA_OBJECT()) );
    }
  else
    {
    this->ExecuteData(NULL);
    }
  return 1;
}

//----------------------------------------------------------------------------
int vtkImageAlgorithm::ProcessRequest(vtkInformation* request,
                                      vtkInformationVector** inputVector,
                                      vtkInformationVector* outputVector)
{
  // generate the data
  if(request->Has(vtkDemandDrivenPipeline::REQUEST_DATA()))
    {
    this->RequestData(request, inputVector, outputVector);
    return 1;
    }

  // execute information
  if(request->Has(vtkDemandDrivenPipeline::REQUEST_INFORMATION()))
    {
    this->RequestInformation(request, inputVector, outputVector);
    return 1;
    }

  // propagate update extent
  if(request->Has(vtkStreamingDemandDrivenPipeline::REQUEST_UPDATE_EXTENT()))
    {
    this->RequestUpdateExtent(request, inputVector, outputVector);
    return 1;
    }

  return this->Superclass::ProcessRequest(request, inputVector, outputVector);
}

//----------------------------------------------------------------------------
// Assume that any source that implements ExecuteData
// can handle an empty extent.
void vtkImageAlgorithm::ExecuteData(vtkDataObject *)
{
  this->Execute();
}

//----------------------------------------------------------------------------
void vtkImageAlgorithm::Execute()
{
  vtkErrorMacro(<< "Definition of Execute() method should be in subclass and you should really use the ExecuteData(vtkInformation *request,...) signature instead");
}

int vtkImageAlgorithm::RequestInformation(
  vtkInformation* vtkNotUsed(request),
  vtkInformationVector** vtkNotUsed(inputVector),
  vtkInformationVector* vtkNotUsed(outputVector))
{
  // do nothing let subclasses handle it
  return 1;
}

int vtkImageAlgorithm::RequestUpdateExtent(
  vtkInformation* vtkNotUsed(request),
  vtkInformationVector** vtkNotUsed(inputVector),
  vtkInformationVector* vtkNotUsed(outputVector))
{
  // do nothing let subclasses handle it
  return 1;
}

//----------------------------------------------------------------------------
void vtkImageAlgorithm::AllocateOutputData(vtkImageData *output,
                                           int *uExtent)
{
  // set the extent to be the update extent
  output->SetExtent(uExtent);
  output->AllocateScalars();
}

//----------------------------------------------------------------------------
vtkImageData *vtkImageAlgorithm::AllocateOutputData(vtkDataObject *output)
{
  // set the extent to be the update extent
  vtkImageData *out = vtkImageData::SafeDownCast(output);
  if (out)
    {
    // this needs to be fixed -Ken
    vtkStreamingDemandDrivenPipeline *sddp =
      vtkStreamingDemandDrivenPipeline::SafeDownCast(this->GetExecutive());
    if (sddp)
      {
      int extent[6];
      sddp->GetOutputInformation(0)->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(),extent);
      out->SetExtent(extent);
      }
    out->AllocateScalars();
    }
  return out;
}

// by default copy the attr from the first input to the first output
void vtkImageAlgorithm::CopyAttributeData(vtkImageData *input,
                                          vtkImageData *output)
{
  if (!input || !output)
    {
    return;
    }

  int inExt[6];
  int outExt[6];
  vtkDataArray *inArray;
  vtkDataArray *outArray;

  input->GetExtent(inExt);
  output->GetExtent(outExt);

  // Do not copy the array we will be generating.
  inArray = input->GetPointData()->GetScalars();

  // Conditionally copy point and cell data.  Only copy if corresponding
  // indexes refer to identical points.
  double *oIn = input->GetOrigin();
  double *sIn = input->GetSpacing();
  double *oOut = output->GetOrigin();
  double *sOut = output->GetSpacing();
  if (oIn[0] == oOut[0] && oIn[1] == oOut[1] && oIn[2] == oOut[2] &&
      sIn[0] == sOut[0] && sIn[1] == sOut[1] && sIn[2] == sOut[2])
    {
    output->GetPointData()->CopyAllOn();
    output->GetCellData()->CopyAllOn();
    output->GetPointData()->CopyScalarsOff();

    // If the extents are the same, then pass the attribute data for
    // efficiency.
    if (inExt[0] == outExt[0] && inExt[1] == outExt[1] &&
        inExt[2] == outExt[2] && inExt[3] == outExt[3] &&
        inExt[4] == outExt[4] && inExt[5] == outExt[5])
      {// Pass
      // set the name of the output to match the input name
      outArray = output->GetPointData()->GetScalars();
      if (inArray)
        {
        outArray->SetName(inArray->GetName());
        }
      output->GetPointData()->PassData(input->GetPointData());
      output->GetCellData()->PassData(input->GetCellData());
      }
    else
      {// Copy
       // Since this can be expensive to copy all of these values,
       // lets make sure there are arrays to copy (other than the scalars)
      if (input->GetPointData()->GetNumberOfArrays() > 1)
        {
        // Copy the point data.
        // CopyAllocate frees all arrays.
        // Keep the old scalar array (not being copied).
        // This is a hack, but avoids reallocation ...
        vtkDataArray *tmp = NULL;
        if ( ! output->GetPointData()->GetCopyScalars() )
          {
          tmp = output->GetPointData()->GetScalars();
          }
        output->GetPointData()->CopyAllocate(input->GetPointData(),
                                             output->GetNumberOfPoints());
        if (tmp)
          { // Restore the array.
          output->GetPointData()->SetScalars(tmp);
          }
        // Now Copy The point data, but only if output is a subextent of the
        // input.
        if (outExt[0] >= inExt[0] && outExt[1] <= inExt[1] &&
            outExt[2] >= inExt[2] && outExt[3] <= inExt[3] &&
            outExt[4] >= inExt[4] && outExt[5] <= inExt[5])
          {
          output->GetPointData()->CopyStructuredData(input->GetPointData(),
                                                     inExt, outExt);
          }
        }

      if (input->GetCellData()->GetNumberOfArrays() > 0)
        {
        output->GetCellData()->CopyAllocate(input->GetCellData(),
                                            output->GetNumberOfCells());
        // Cell extent is one less than point extent.
        // Conditional to handle a colapsed axis (lower dimensional cells).
        if (inExt[0] < inExt[1]) {--inExt[1];}
        if (inExt[2] < inExt[3]) {--inExt[3];}
        if (inExt[4] < inExt[5]) {--inExt[5];}
        // Cell extent is one less than point extent.
        if (outExt[0] < outExt[1]) {--outExt[1];}
        if (outExt[2] < outExt[3]) {--outExt[3];}
        if (outExt[4] < outExt[5]) {--outExt[5];}
        // Now Copy The cell data, but only if output is a subextent of the input.
        if (outExt[0] >= inExt[0] && outExt[1] <= inExt[1] &&
            outExt[2] >= inExt[2] && outExt[3] <= inExt[3] &&
            outExt[4] >= inExt[4] && outExt[5] <= inExt[5])
          {
          output->GetCellData()->CopyStructuredData(input->GetCellData(),
                                                    inExt, outExt);
          }
        }
      }
    // set the name of the output to match the input name
    outArray = output->GetPointData()->GetScalars();
    if (inArray)
      {
      outArray->SetName(inArray->GetName());
      }
    }
}

//----------------------------------------------------------------------------
vtkImageData* vtkImageAlgorithm::GetOutput()
{
  return this->GetOutput(0);
}

//----------------------------------------------------------------------------
vtkImageData* vtkImageAlgorithm::GetOutput(int port)
{
  return vtkImageData::SafeDownCast(this->GetOutputDataObject(port));
}

//----------------------------------------------------------------------------
void vtkImageAlgorithm::SetOutput(vtkDataObject* d)
{
  this->GetExecutive()->SetOutputData(0, d);
}

//----------------------------------------------------------------------------
int vtkImageAlgorithm::FillOutputPortInformation(
  int vtkNotUsed(port), vtkInformation* info)
{
  // now add our info
  info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkImageData");

  return 1;
}

int vtkImageAlgorithm::FillInputPortInformation(
  int vtkNotUsed(port), vtkInformation* info)
{
  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkImageData");
  return 1;
}

//----------------------------------------------------------------------------
void vtkImageAlgorithm::SetInput(vtkDataObject* input)
{
  this->SetInput(0, input);
}

//----------------------------------------------------------------------------
void vtkImageAlgorithm::SetInput(int index, vtkDataObject* input)
{
  if(input)
    {
    this->SetInputConnection(index, input->GetProducerPort());
    }
  else
    {
    // Setting a NULL input removes the connection.
    this->SetInputConnection(index, 0);
    }
}

//----------------------------------------------------------------------------
vtkDataObject* vtkImageAlgorithm::GetInput(int port)
{
  if (this->GetNumberOfInputConnections(port) < 1)
    {
    return 0;
    }
  return this->GetExecutive()->GetInputData(port, 0);
}

//----------------------------------------------------------------------------
void vtkImageAlgorithm::AddInput(vtkDataObject* input)
{
  this->AddInput(0, input);
}

//----------------------------------------------------------------------------
void vtkImageAlgorithm::AddInput(int index, vtkDataObject* input)
{
  if(input)
    {
    this->AddInputConnection(index, input->GetProducerPort());
    }
}
<|endoftext|>


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

  Program:   Insight Segmentation & Registration Toolkit
  Module:    fltkShape3D.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 2001 Insight Consortium
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

 * The name of the Insight Consortium, nor the names of any consortium members,
   nor of any contributors, may be used to endorse or promote products derived
   from this software without specific prior written permission.

  * Modified source versions must be plainly marked as such, and must not be
    misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=========================================================================*/

#include "fltkShape3D.h"

namespace fltk {

//--------------------------------------------------
//
//    Constructor
//
//--------------------------------------------------
Shape3D::Shape3D()
{
  m_DrawingMode   = triangles;
  m_CompileMode   = noCompile;
  m_DisplayList   = 0;

  m_Color.Set( 1.0f, 1.0f, 1.0f );

  m_Transparency  = 0.0f;

  m_ScheduledToRemoveDisplayList = false;
  m_ScheduledToUpdateDisplayList = false;

  m_Father = 0;

  m_AutoSensing       = true;
  m_RestoreTransform  = false;

  m_DrawCommand = DrawCommandType::New();
  m_DrawCommand->SetCallbackFunction( this, &(Self::glDraw) );

  m_DisplayListUpdateCommand = DisplayListUpdateCommandType::New();
  m_DisplayListUpdateCommand->SetCallbackFunction(
                                  this,
                                  &(Self::ScheduleToUpdateDisplayList) );

}

//--------------------------------------------------
//
//    Destructor
//
//--------------------------------------------------
Shape3D::~Shape3D()
{

  if( m_Father )
    {
    m_Father->RemoveComponent( this );
    }

  ContainerType::iterator it = m_Components.begin();
  while( it != m_Components.end() )
    {
    (*it)->m_Father = 0;
    ++it;
    }

  m_Components.clear();

  // The only secure way to destroy the
  // display list (if one exists) is to
  // schedule its removal and force a
  // last and slow redraw
  // ... before calling the destructor
  // So maybe the GL windows should be
  // observers of the DestroyEvent of
  // this object.
  ScheduleToRemoveDisplayList();

}

//---------------------------------------------------------------------
//
// Chaining method to print an object's instance variables, as well as
// its superclasses.
//
//----------------------------------------------------------------------
void
Shape3D
::PrintSelf( std::ostream& os, itk::Indent indent) const
{
  Superclass::PrintSelf(os, indent);

  os << indent << "Current Position     : " << m_CurrentPosition   << std::endl;
  os << indent << "Restore Transform    : " << m_RestoreTransform  << std::endl;
  os << indent << "Auto Sensing         : " << m_AutoSensing       << std::endl;
  os << indent << "Display List Id      : " << m_DisplayList       << std::endl;
  os << indent << "Scheduled to Update Display List: " << m_ScheduledToUpdateDisplayList << std::endl;
  os << indent << "Scheduled to Remove Display List: " << m_ScheduledToRemoveDisplayList << std::endl;
  os << indent << "OpenGL Compile Mode  : " << m_CompileMode << std::endl;
  os << indent << "Drawing Mode         : " << m_DrawingMode << std::endl;
  os << indent << "Number of Components : " << m_Components.size() << std::endl;
  os << indent << "Color                : " << m_Color << std::endl;
  os << indent << "Transparency         : " << m_Transparency << std::endl;

  os << indent << "Transform            : " << std::endl;
  for(unsigned int row=0; row<4; row++)
    {
    for(unsigned int col=0; col<4; col++)
      {
      os << m_Transform[ row + 4 * col ];  // or the transpose ?
      }
    os << std::endl;
    }

}

//--------------------------------------------------
//
//    Schedule the shape to update the display list
//    during the next redraw
//
//--------------------------------------------------
void Shape3D::ScheduleToUpdateDisplayList( void ) const
{
  m_ScheduledToUpdateDisplayList = true;
  if( m_Father )
  {
    m_Father->ScheduleToUpdateDisplayList();
  }
}

//--------------------------------------------------
//
//    Choose drawing mode
//
//--------------------------------------------------
void Shape3D::SetDrawingMode(enum drawingModes newmode)
{
  m_DrawingMode = newmode;

  ContainerType::iterator it = m_Components.begin();
  while( it != m_Components.end() )
  {
    (*it)->SetDrawingMode( newmode );
    ++it;
  }

  if( m_CompileMode != noCompile && m_DisplayList )
  {
    ScheduleToUpdateDisplayList();
  }
}

//--------------------------------------------------
//
//    Get Draw Command
//
//--------------------------------------------------
Shape3D::DrawCommandPointer
Shape3D::GetDrawCommand(void)
{
  return m_DrawCommand.GetPointer();
}

//--------------------------------------------------
//
//    Get Command for scheduling the
//    update of the display list
//
//--------------------------------------------------
Shape3D::DisplayListUpdateCommandPointer
Shape3D::GetDisplayListUpdateCommand(void)
{
  return m_DisplayListUpdateCommand.GetPointer();
}

//--------------------------------------------------
//
//    Choose compile mode
//
//--------------------------------------------------
void Shape3D::SetCompileMode(enum compileModes newmode)
{
  m_CompileMode = newmode;
  if( m_CompileMode == noCompile && m_DisplayList )
  {
    ScheduleToUpdateDisplayList();
  }
}

//--------------------------------------------------
//
//      Choose color for drawing
//
//--------------------------------------------------
void Shape3D::SetColor(const Shape3D::ColorType &newcolor )
{

  m_Color = newcolor;

  ContainerType::iterator it = m_Components.begin();
  while( it != m_Components.end() )
  {
    (*it)->SetColor( newcolor );
    ++it;
  }

  ScheduleToUpdateDisplayList();

}

//--------------------------------------------------
//
//      Choose transparency for drawing
//
//--------------------------------------------------
void Shape3D::SetTransparency(GLfloat transparency)
{

  m_Transparency = transparency;

  ContainerType::iterator it = m_Components.begin();
  while( it != m_Components.end() )
  {
    (*it)->SetTransparency( transparency );
    ++it;
  }

  ScheduleToUpdateDisplayList();

}

//--------------------------------------------------
//
//    Set the selection for computing current position
//    during the next OpenGL redraw
//
//--------------------------------------------------
void Shape3D::SetAutoSensing( bool sensing ) const
{
  m_AutoSensing = sensing;

  ContainerType::const_iterator it = m_Components.begin();
  while( it != m_Components.end() )
  {
    (*it)->SetAutoSensing( sensing );
    ++it;
  }

}

//--------------------------------------------------
//
//    Set the selection for restoring the transform
//    during the next OpenGL redraw
//
//--------------------------------------------------
void Shape3D::SetRestoreTransform( bool restoring ) const
{
  m_RestoreTransform = restoring;

  ContainerType::const_iterator it = m_Components.begin();
  while( it != m_Components.end() )
  {
    (*it)->SetRestoreTransform( restoring );
    ++it;
  }

}

//--------------------------------------------------
//
//    Return the selection for computing current position
//    during the next OpenGL redraw
//
//--------------------------------------------------
bool Shape3D::GetAutoSensing( void ) const
{
  return m_AutoSensing;
}

//--------------------------------------------------
//
//      Prepare color in OpenGL
//
//--------------------------------------------------
void Shape3D::glColor(void) const
{
  glColor3f(  m_Color.GetRed(),
              m_Color.GetGreen(),
              m_Color.GetBlue()   );
}

//--------------------------------------------------
//
//      Prepare color in OpenGL
//
//--------------------------------------------------
void Shape3D::glMaterialColor(void) const
{
  GLfloat color[] = { m_Color.GetRed(),
                       m_Color.GetGreen(),
                       m_Color.GetBlue(),
                       (GLfloat)(1.0-m_Transparency) };
  glMaterialfv(GL_FRONT,GL_DIFFUSE,color);
}

//--------------------------------------------------
//
//      Remove display list
//
//--------------------------------------------------
void Shape3D::ScheduleToRemoveDisplayList(void) const
{
  m_ScheduledToRemoveDisplayList = true;
}

//--------------------------------------------------
//
//      Add a Component
//
//--------------------------------------------------
void Shape3D::AddComponent(Shape3D * newcomponent)
{

  if( newcomponent == 0 )
  {
    return;
  }

  newcomponent->m_Father = this;
  m_Components.push_back( newcomponent );
}

//--------------------------------------------------
//
//      Remove a Component
//
//--------------------------------------------------
void Shape3D::RemoveComponent(Shape3D * oldcomponent)
{

  if( oldcomponent == 0 )
  {
    return;
  }

  oldcomponent->m_Father = 0;
  m_Components.remove( oldcomponent );

}

//--------------------------------------------------
//
//      Get First Component
//
//--------------------------------------------------
Shape3D::ContainerType::iterator
Shape3D::GetFirstComponent(void)
{
   return m_Components.begin();
}

//--------------------------------------------------
//
//      Get the current position in OpenGL
//      Model Space
//
//--------------------------------------------------
void
Shape3D::ComputeCurrentTransform( void ) const
{
  glGetFloatv( GL_MODELVIEW_MATRIX, m_Transform );
}

//--------------------------------------------------
//
//      Get the current position in OpenGL
//      Model Space
//
//--------------------------------------------------
const Shape3D::PointType &
Shape3D::GetCurrentPosition(void) const
{
  PointType here;
  here = 0.0, 0.0, 0.0;
  m_CurrentPosition = ComputeCurrentPosition( here );
  return m_CurrentPosition;
}

//--------------------------------------------------
//
//      Get the current position in OpenGL
//      Model Space
//
//--------------------------------------------------
Shape3D::PointType
Shape3D::ComputeCurrentPosition(const PointType & pnt) const
{
  const GLfloat *m = m_Transform;
  PointType result;
  double  d =   m[3] * pnt[0] + m[7] * pnt[1] + m[11] * pnt[2] + m[15];
  result[0] = ( m[0] * pnt[0] + m[4] * pnt[1] + m[ 8] * pnt[2] + m[12] ) / d;
  result[1] = ( m[1] * pnt[0] + m[5] * pnt[1] + m[ 9] * pnt[2] + m[13] ) / d;
  result[2] = ( m[2] * pnt[0] + m[6] * pnt[1] + m[10] * pnt[2] + m[14] ) / d;

  return result;
}

//--------------------------------------------------
//
//      Get the current orientation in OpenGL
//      Model Space
//
//--------------------------------------------------
Shape3D::VectorType
Shape3D::ComputeCurrentOrientation(const VectorType & vec ) const
{
  const GLfloat *m = m_Transform;
  VectorType result;
  result[0] = ( m[0] * vec[0] + m[4] * vec[1] + m[ 8] * vec[2]  );
  result[1] = ( m[1] * vec[0] + m[5] * vec[1] + m[ 9] * vec[2]  );
  result[2] = ( m[2] * vec[0] + m[6] * vec[1] + m[10] * vec[2]  );
  return result;
}

//--------------------------------------------------
//
//    Draw Geometry
//
//--------------------------------------------------
void Shape3D::DrawGeometry(void) const
{
  itkWarningMacro( << "Shape3D::DrawGeometry this method should not be called" );
}

//--------------------------------------------------
//
//    Redraw ask the eventual Observer to refresh
//    their views
//
//--------------------------------------------------
void Shape3D::Redraw(void) const
{
    InvokeEvent( RedrawEvent );
}

//--------------------------------------------------
//
//    Invoke an event in the top of the hierarchy
//
//--------------------------------------------------
void Shape3D::InvokeEvent( unsigned long event ) const
{

  this->itk::Object::InvokeEvent( event );

  if( m_Father )
  {
    m_Father->InvokeEvent( event );
  }

}

//--------------------------------------------------
//
//      draw the shape
//
//--------------------------------------------------
void Shape3D::glDraw(void) const
{

  if( m_ScheduledToRemoveDisplayList && m_DisplayList )
  {
    glDeleteLists( m_DisplayList, 1 );
    m_ScheduledToRemoveDisplayList = false;
    m_DisplayList = 0;
    return;
  }

  if( m_ScheduledToUpdateDisplayList && m_DisplayList )
  {
    glDeleteLists( m_DisplayList, 1 );
    m_ScheduledToUpdateDisplayList = false;
    m_DisplayList = 0;
  }

  if( m_CompileMode != noCompile && m_DisplayList )
  {
    glCallList( m_DisplayList );
    return;
  }

  switch( m_CompileMode )
  {
    case noCompile:
    {
      if( m_DisplayList )
      {
        glDeleteLists( m_DisplayList, 1 );
        m_DisplayList = 0;
      }
      break;
    }
    case onlyCompile:
    {
      m_DisplayList = glGenLists( 1 );
      glNewList( m_DisplayList, GL_COMPILE );
      break;
    }
    case compileExecute:
    {
      m_DisplayList = glGenLists( 1 );
      glNewList( m_DisplayList, GL_COMPILE_AND_EXECUTE );
      break;
    }
  }

  switch( m_DrawingMode )
  {
    case none     :
        {
          break;
        }
    case points   :
        {
          glDisable( GL_LIGHTING );
          glColor();
          break;
        }
    case lines    :
        {
          glDisable( GL_LIGHTING );
          glColor();
          break;
        }
    case triangles:
        {
        glEnable( GL_LIGHTING );
        glMaterialColor();
        break;
        }

    case surfacepoints:
        {
        break;
        }
  }

  if( m_AutoSensing )
  {
    ComputeCurrentTransform();
  }

  if( m_RestoreTransform )
  {
    glLoadMatrixf( m_Transform );
  }

  DrawGeometry();

  if( m_DisplayList != 0 )
  {
    glEndList();
  }

}

} // end namespace fltk

<commit_msg>FIX: VC++ has trouble understanding scope specifiers for base class methods.      In order to call InvokeMethod, a const pointer to itk::Object has been used.<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    fltkShape3D.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 2001 Insight Consortium
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

 * The name of the Insight Consortium, nor the names of any consortium members,
   nor of any contributors, may be used to endorse or promote products derived
   from this software without specific prior written permission.

  * Modified source versions must be plainly marked as such, and must not be
    misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=========================================================================*/

#include "fltkShape3D.h"

namespace fltk {

//--------------------------------------------------
//
//    Constructor
//
//--------------------------------------------------
Shape3D::Shape3D()
{
  m_DrawingMode   = triangles;
  m_CompileMode   = noCompile;
  m_DisplayList   = 0;

  m_Color.Set( 1.0f, 1.0f, 1.0f );

  m_Transparency  = 0.0f;

  m_ScheduledToRemoveDisplayList = false;
  m_ScheduledToUpdateDisplayList = false;

  m_Father = 0;

  m_AutoSensing       = true;
  m_RestoreTransform  = false;

  m_DrawCommand = DrawCommandType::New();
  m_DrawCommand->SetCallbackFunction( this, &(Self::glDraw) );

  m_DisplayListUpdateCommand = DisplayListUpdateCommandType::New();
  m_DisplayListUpdateCommand->SetCallbackFunction(
                                  this,
                                  &(Self::ScheduleToUpdateDisplayList) );

}

//--------------------------------------------------
//
//    Destructor
//
//--------------------------------------------------
Shape3D::~Shape3D()
{

  if( m_Father )
    {
    m_Father->RemoveComponent( this );
    }

  ContainerType::iterator it = m_Components.begin();
  while( it != m_Components.end() )
    {
    (*it)->m_Father = 0;
    ++it;
    }

  m_Components.clear();

  // The only secure way to destroy the
  // display list (if one exists) is to
  // schedule its removal and force a
  // last and slow redraw
  // ... before calling the destructor
  // So maybe the GL windows should be
  // observers of the DestroyEvent of
  // this object.
  ScheduleToRemoveDisplayList();

}

//---------------------------------------------------------------------
//
// Chaining method to print an object's instance variables, as well as
// its superclasses.
//
//----------------------------------------------------------------------
void
Shape3D
::PrintSelf( std::ostream& os, itk::Indent indent) const
{
  Superclass::PrintSelf(os, indent);

  os << indent << "Current Position     : " << m_CurrentPosition   << std::endl;
  os << indent << "Restore Transform    : " << m_RestoreTransform  << std::endl;
  os << indent << "Auto Sensing         : " << m_AutoSensing       << std::endl;
  os << indent << "Display List Id      : " << m_DisplayList       << std::endl;
  os << indent << "Scheduled to Update Display List: " << m_ScheduledToUpdateDisplayList << std::endl;
  os << indent << "Scheduled to Remove Display List: " << m_ScheduledToRemoveDisplayList << std::endl;
  os << indent << "OpenGL Compile Mode  : " << m_CompileMode << std::endl;
  os << indent << "Drawing Mode         : " << m_DrawingMode << std::endl;
  os << indent << "Number of Components : " << m_Components.size() << std::endl;
  os << indent << "Color                : " << m_Color << std::endl;
  os << indent << "Transparency         : " << m_Transparency << std::endl;

  os << indent << "Transform            : " << std::endl;
  for(unsigned int row=0; row<4; row++)
    {
    for(unsigned int col=0; col<4; col++)
      {
      os << m_Transform[ row + 4 * col ];  // or the transpose ?
      }
    os << std::endl;
    }

}

//--------------------------------------------------
//
//    Schedule the shape to update the display list
//    during the next redraw
//
//--------------------------------------------------
void Shape3D::ScheduleToUpdateDisplayList( void ) const
{
  m_ScheduledToUpdateDisplayList = true;
  if( m_Father )
  {
    m_Father->ScheduleToUpdateDisplayList();
  }
}

//--------------------------------------------------
//
//    Choose drawing mode
//
//--------------------------------------------------
void Shape3D::SetDrawingMode(enum drawingModes newmode)
{
  m_DrawingMode = newmode;

  ContainerType::iterator it = m_Components.begin();
  while( it != m_Components.end() )
  {
    (*it)->SetDrawingMode( newmode );
    ++it;
  }

  if( m_CompileMode != noCompile && m_DisplayList )
  {
    ScheduleToUpdateDisplayList();
  }
}

//--------------------------------------------------
//
//    Get Draw Command
//
//--------------------------------------------------
Shape3D::DrawCommandPointer
Shape3D::GetDrawCommand(void)
{
  return m_DrawCommand.GetPointer();
}

//--------------------------------------------------
//
//    Get Command for scheduling the
//    update of the display list
//
//--------------------------------------------------
Shape3D::DisplayListUpdateCommandPointer
Shape3D::GetDisplayListUpdateCommand(void)
{
  return m_DisplayListUpdateCommand.GetPointer();
}

//--------------------------------------------------
//
//    Choose compile mode
//
//--------------------------------------------------
void Shape3D::SetCompileMode(enum compileModes newmode)
{
  m_CompileMode = newmode;
  if( m_CompileMode == noCompile && m_DisplayList )
  {
    ScheduleToUpdateDisplayList();
  }
}

//--------------------------------------------------
//
//      Choose color for drawing
//
//--------------------------------------------------
void Shape3D::SetColor(const Shape3D::ColorType &newcolor )
{

  m_Color = newcolor;

  ContainerType::iterator it = m_Components.begin();
  while( it != m_Components.end() )
  {
    (*it)->SetColor( newcolor );
    ++it;
  }

  ScheduleToUpdateDisplayList();

}

//--------------------------------------------------
//
//      Choose transparency for drawing
//
//--------------------------------------------------
void Shape3D::SetTransparency(GLfloat transparency)
{

  m_Transparency = transparency;

  ContainerType::iterator it = m_Components.begin();
  while( it != m_Components.end() )
  {
    (*it)->SetTransparency( transparency );
    ++it;
  }

  ScheduleToUpdateDisplayList();

}

//--------------------------------------------------
//
//    Set the selection for computing current position
//    during the next OpenGL redraw
//
//--------------------------------------------------
void Shape3D::SetAutoSensing( bool sensing ) const
{
  m_AutoSensing = sensing;

  ContainerType::const_iterator it = m_Components.begin();
  while( it != m_Components.end() )
  {
    (*it)->SetAutoSensing( sensing );
    ++it;
  }

}

//--------------------------------------------------
//
//    Set the selection for restoring the transform
//    during the next OpenGL redraw
//
//--------------------------------------------------
void Shape3D::SetRestoreTransform( bool restoring ) const
{
  m_RestoreTransform = restoring;

  ContainerType::const_iterator it = m_Components.begin();
  while( it != m_Components.end() )
  {
    (*it)->SetRestoreTransform( restoring );
    ++it;
  }

}

//--------------------------------------------------
//
//    Return the selection for computing current position
//    during the next OpenGL redraw
//
//--------------------------------------------------
bool Shape3D::GetAutoSensing( void ) const
{
  return m_AutoSensing;
}

//--------------------------------------------------
//
//      Prepare color in OpenGL
//
//--------------------------------------------------
void Shape3D::glColor(void) const
{
  glColor3f(  m_Color.GetRed(),
              m_Color.GetGreen(),
              m_Color.GetBlue()   );
}

//--------------------------------------------------
//
//      Prepare color in OpenGL
//
//--------------------------------------------------
void Shape3D::glMaterialColor(void) const
{
  GLfloat color[] = { m_Color.GetRed(),
                       m_Color.GetGreen(),
                       m_Color.GetBlue(),
                       (GLfloat)(1.0-m_Transparency) };
  glMaterialfv(GL_FRONT,GL_DIFFUSE,color);
}

//--------------------------------------------------
//
//      Remove display list
//
//--------------------------------------------------
void Shape3D::ScheduleToRemoveDisplayList(void) const
{
  m_ScheduledToRemoveDisplayList = true;
}

//--------------------------------------------------
//
//      Add a Component
//
//--------------------------------------------------
void Shape3D::AddComponent(Shape3D * newcomponent)
{

  if( newcomponent == 0 )
  {
    return;
  }

  newcomponent->m_Father = this;
  m_Components.push_back( newcomponent );
}

//--------------------------------------------------
//
//      Remove a Component
//
//--------------------------------------------------
void Shape3D::RemoveComponent(Shape3D * oldcomponent)
{

  if( oldcomponent == 0 )
  {
    return;
  }

  oldcomponent->m_Father = 0;
  m_Components.remove( oldcomponent );

}

//--------------------------------------------------
//
//      Get First Component
//
//--------------------------------------------------
Shape3D::ContainerType::iterator
Shape3D::GetFirstComponent(void)
{
   return m_Components.begin();
}

//--------------------------------------------------
//
//      Get the current position in OpenGL
//      Model Space
//
//--------------------------------------------------
void
Shape3D::ComputeCurrentTransform( void ) const
{
  glGetFloatv( GL_MODELVIEW_MATRIX, m_Transform );
}

//--------------------------------------------------
//
//      Get the current position in OpenGL
//      Model Space
//
//--------------------------------------------------
const Shape3D::PointType &
Shape3D::GetCurrentPosition(void) const
{
  PointType here;
  here = 0.0, 0.0, 0.0;
  m_CurrentPosition = ComputeCurrentPosition( here );
  return m_CurrentPosition;
}

//--------------------------------------------------
//
//      Get the current position in OpenGL
//      Model Space
//
//--------------------------------------------------
Shape3D::PointType
Shape3D::ComputeCurrentPosition(const PointType & pnt) const
{
  const GLfloat *m = m_Transform;
  PointType result;
  double  d =   m[3] * pnt[0] + m[7] * pnt[1] + m[11] * pnt[2] + m[15];
  result[0] = ( m[0] * pnt[0] + m[4] * pnt[1] + m[ 8] * pnt[2] + m[12] ) / d;
  result[1] = ( m[1] * pnt[0] + m[5] * pnt[1] + m[ 9] * pnt[2] + m[13] ) / d;
  result[2] = ( m[2] * pnt[0] + m[6] * pnt[1] + m[10] * pnt[2] + m[14] ) / d;

  return result;
}

//--------------------------------------------------
//
//      Get the current orientation in OpenGL
//      Model Space
//
//--------------------------------------------------
Shape3D::VectorType
Shape3D::ComputeCurrentOrientation(const VectorType & vec ) const
{
  const GLfloat *m = m_Transform;
  VectorType result;
  result[0] = ( m[0] * vec[0] + m[4] * vec[1] + m[ 8] * vec[2]  );
  result[1] = ( m[1] * vec[0] + m[5] * vec[1] + m[ 9] * vec[2]  );
  result[2] = ( m[2] * vec[0] + m[6] * vec[1] + m[10] * vec[2]  );
  return result;
}

//--------------------------------------------------
//
//    Draw Geometry
//
//--------------------------------------------------
void Shape3D::DrawGeometry(void) const
{
  itkWarningMacro( << "Shape3D::DrawGeometry this method should not be called" );
}

//--------------------------------------------------
//
//    Redraw ask the eventual Observer to refresh
//    their views
//
//--------------------------------------------------
void Shape3D::Redraw(void) const
{
    InvokeEvent( RedrawEvent );
}

//--------------------------------------------------
//
//    Invoke an event in the top of the hierarchy
//
//--------------------------------------------------
void Shape3D::InvokeEvent( unsigned long event ) const
{

  const itk::Object * super = this;
  super->InvokeEvent( event );

  if( m_Father )
  {
    m_Father->InvokeEvent( event );
  }

}

//--------------------------------------------------
//
//      draw the shape
//
//--------------------------------------------------
void Shape3D::glDraw(void) const
{

  if( m_ScheduledToRemoveDisplayList && m_DisplayList )
  {
    glDeleteLists( m_DisplayList, 1 );
    m_ScheduledToRemoveDisplayList = false;
    m_DisplayList = 0;
    return;
  }

  if( m_ScheduledToUpdateDisplayList && m_DisplayList )
  {
    glDeleteLists( m_DisplayList, 1 );
    m_ScheduledToUpdateDisplayList = false;
    m_DisplayList = 0;
  }

  if( m_CompileMode != noCompile && m_DisplayList )
  {
    glCallList( m_DisplayList );
    return;
  }

  switch( m_CompileMode )
  {
    case noCompile:
    {
      if( m_DisplayList )
      {
        glDeleteLists( m_DisplayList, 1 );
        m_DisplayList = 0;
      }
      break;
    }
    case onlyCompile:
    {
      m_DisplayList = glGenLists( 1 );
      glNewList( m_DisplayList, GL_COMPILE );
      break;
    }
    case compileExecute:
    {
      m_DisplayList = glGenLists( 1 );
      glNewList( m_DisplayList, GL_COMPILE_AND_EXECUTE );
      break;
    }
  }

  switch( m_DrawingMode )
  {
    case none     :
        {
          break;
        }
    case points   :
        {
          glDisable( GL_LIGHTING );
          glColor();
          break;
        }
    case lines    :
        {
          glDisable( GL_LIGHTING );
          glColor();
          break;
        }
    case triangles:
        {
        glEnable( GL_LIGHTING );
        glMaterialColor();
        break;
        }

    case surfacepoints:
        {
        break;
        }
  }

  if( m_AutoSensing )
  {
    ComputeCurrentTransform();
  }

  if( m_RestoreTransform )
  {
    glLoadMatrixf( m_Transform );
  }

  DrawGeometry();

  if( m_DisplayList != 0 )
  {
    glEndList();
  }

}

} // end namespace fltk

<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2017 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "Volume.h"
#include "sg/common/World.h"

namespace ospray {
  namespace sg {

    static vec3i checkForAndEnableDistributedVolumes()
    {
      auto dpFromEnv = getEnvVar<std::string>("OSPRAY_DATA_PARALLEL");

      if (dpFromEnv.first) {
        // Create the OSPRay object.
        vec3i blockDims;
        int rc = sscanf(dpFromEnv.second.c_str(), "%dx%dx%d",
                        &blockDims.x, &blockDims.y, &blockDims.z);
        if (rc != 3) {
          throw std::runtime_error("could not parse OSPRAY_DATA_PARALLEL "
                                   "env-var. Must be of format <X>x<Y>x<>Z "
                                   "(e.g., '4x4x4'");
        }
        Volume::useDataDistributedVolume = true;
        return blockDims;
      } else {
        return {0, 0, 0,};
      }
    }

    /*! helper function to help build voxel ranges during parsing */
    template<typename T>
    inline void extendVoxelRange(ospcommon::vec2f &voxelRange,
                                 const T *voxel, size_t num)
    {
      for (size_t i = 0; i < num; ++i) {
        voxelRange.x = std::min(voxelRange.x, static_cast<float>(voxel[i]));
        voxelRange.y = std::max(voxelRange.y, static_cast<float>(voxel[i]));
      }
    }

    //! Convenient wrapper that will do the template dispatch for you based on
    //  the voxelType passed
    inline void extendVoxelRange(ospcommon::vec2f &voxelRange,
                                 const OSPDataType voxelType,
                                 const unsigned char *voxels,
                                 const size_t numVoxels)
    {
      switch (voxelType) {
        case OSP_UCHAR:
          extendVoxelRange(voxelRange, voxels, numVoxels);
          break;
        case OSP_SHORT:
          extendVoxelRange(voxelRange,
                           reinterpret_cast<const short*>(voxels),
                           numVoxels);
          break;
        case OSP_USHORT:
          extendVoxelRange(voxelRange,
                           reinterpret_cast<const unsigned short*>(voxels),
                           numVoxels);
          break;
        case OSP_FLOAT:
          extendVoxelRange(voxelRange,
                           reinterpret_cast<const float*>(voxels),
                           numVoxels);
          break;
        case OSP_DOUBLE:
          extendVoxelRange(voxelRange,
                           reinterpret_cast<const double*>(voxels),
                           numVoxels);
          break;
        default:
          throw std::runtime_error("sg::extendVoxelRange: unsupported voxel type!");
      }
    }

    // =======================================================
    // base volume class
    // =======================================================

    bool Volume::useDataDistributedVolume = false;

    /*! \brief returns a std::string with the c++ name of this class */
    Volume::Volume()
    {
      createChildNode("transferFunction", "TransferFunction");
      createChildNode("gradientShadingEnabled", "bool", true);
      createChildNode("preIntegration", "bool", true);
      createChildNode("singleShade", "bool", true);
      createChildNode("voxelRange", "vec2f",
                      vec2f(std::numeric_limits<float>::infinity(),
                            -std::numeric_limits<float>::infinity()));
      createChildNode("adaptiveSampling", "bool", true);
      createChildNode("adaptiveScalar", "float", 15.f);
      createChildNode("adaptiveBacktrack", "float", 0.03f);
      createChildNode("samplingRate", "float", 0.125f);
      createChildNode("adaptiveMaxSamplingRate", "float", 2.f);
      createChildNode("volumeClippingBoxLower", "vec3f", vec3f(0.f));
      createChildNode("volumeClippingBoxUpper", "vec3f", vec3f(0.f));
      createChildNode("specular", "vec3f", vec3f(0.3f));
      createChildNode("gridOrigin", "vec3f", vec3f(0.0f));
      createChildNode("gridSpacing", "vec3f", vec3f(0.002f));
      createChildNode("isosurfaceEnabled", "bool", false);
      createChildNode("isosurface", "float",
                      -std::numeric_limits<float>::infinity(),
                      NodeFlags::valid_min_max |
                      NodeFlags::gui_slider).setMinMax(0.f,255.f);
    }

    std::string Volume::toString() const
    {
      return "ospray::sg::Volume";
    }

    void Volume::serialize(sg::Serialization::State &state)
    {
      Node::serialize(state);
    }

    void Volume::preRender(RenderContext &ctx)
    {
      if (volume) {
        ospAddVolume(ctx.world->ospModel,volume);
        if (child("isosurfaceEnabled").valueAs<bool>() == true
            && isosurfacesGeometry)
          ospAddGeometry(ctx.world->ospModel, isosurfacesGeometry);
      }
    }

    // =======================================================
    // structured volume class
    // =======================================================

    //! constructor
    StructuredVolume::StructuredVolume()
      : dimensions(-1), voxelType("<undefined>"), mappedPointer(nullptr)
    {
    }

    /*! \brief returns a std::string with the c++ name of this class */
    std::string StructuredVolume::toString() const
    {
      return "ospray::sg::StructuredVolume";
    }

    //! return bounding box of all primitives
    box3f StructuredVolume::bounds() const
    {
      return {vec3f(0.f),
              vec3f(getDimensions())*child("gridSpacing").valueAs<vec3f>()};
    }

    //! \brief Initialize this node's value from given XML node

    void StructuredVolume::setFromXML(const xml::Node &node,
                                      const unsigned char *binBasePtr)
    {
      Assert2(binBasePtr,
              "mapped binary file is nullptr, in XML node that "
              "needs mapped binary data (sg::StructuredVolume)");
      voxelType = node.getProp("voxelType");
      if (node.hasProp("ofs"))
        mappedPointer = binBasePtr + std::stoll(node.getProp("ofs","0"));
      dimensions = toVec3i(node.getProp("dimensions").c_str());

      if (voxelType == "uint8")
        voxelType = "uchar";
      if (voxelType != "float" &&
          voxelType != "uint8" &&
          voxelType != "uchar") {
        throw std::runtime_error("unknown StructuredVolume.voxelType (currently"
                                 " only supporting 'float' and 'uint8')");
      }

      std::cout << "#osp:sg: created StructuredVolume from XML file, "
                << "dimensions = " << getDimensions() << std::endl;
    }

    void StructuredVolume::postCommit(RenderContext &ctx)
    {
    }

    OSP_REGISTER_SG_NODE(StructuredVolume);

    // =======================================================
    // structured volume that is stored in a separate file (ie, a file
    // other than the ospbin file)
    // =======================================================

    //! constructor
    StructuredVolumeFromFile::StructuredVolumeFromFile()
      : dimensions(-1), fileName(""), voxelType("<undefined>")
    {}

    /*! \brief returns a std::string with the c++ name of this class */
    std::string StructuredVolumeFromFile::toString() const
    {
      return "ospray::sg::StructuredVolumeFromFile";
    }

    //! return bounding box of all primitives
    box3f StructuredVolumeFromFile::bounds() const
    {
      return {vec3f(0.f),
              vec3f(getDimensions())*child("gridSpacing").valueAs<vec3f>()};
    }

    //! \brief Initialize this node's value from given XML node
    void StructuredVolumeFromFile::setFromXML(const xml::Node &node,
                                              const unsigned char *binBasePtr)
    {
      voxelType = node.getProp("voxelType");
      if (voxelType == "uint8") voxelType = "uchar";
      dimensions = toVec3i(node.getProp("dimensions").c_str());
      fileName = node.getProp("fileName");

      if (fileName.empty()) {
        throw std::runtime_error("sg::StructuredVolumeFromFile: "
                                 "no 'fileName' specified");
      }

      fileNameOfCorrespondingXmlDoc = node.doc->fileName;

      if (voxelType != "float" && voxelType != "uchar") {
        throw std::runtime_error("unknown StructuredVolume.voxelType "
                                 "(currently support 'float' and 'uchar')");
      }

      std::cout << "#osp:sg: created StructuredVolume from XML file, "
                << "dimensions = " << getDimensions() << std::endl;
    }

    void StructuredVolumeFromFile::preCommit(RenderContext &ctx)
    {
      if (volume) {
        ospCommit(volume);
        if (child("isosurfaceEnabled").valueAs<bool>() == true
            && isosurfacesGeometry) {
          OSPData isovaluesData = ospNewData(1, OSP_FLOAT,
            &child("isosurface").valueAs<float>());
          ospSetData(isosurfacesGeometry, "isovalues", isovaluesData);
          ospCommit(isosurfacesGeometry);
        }
        return;
      }

      if (dimensions.x <= 0 || dimensions.y <= 0 || dimensions.z <= 0) {
        throw std::runtime_error("StructuredVolume::render(): "
                                 "invalid volume dimensions");
      }

      vec3i dataDistributedBlocks = checkForAndEnableDistributedVolumes();

      bool useBlockBricked = 1;

      if (useDataDistributedVolume) {
        volume = ospNewVolume("data_distributed_volume");
        ospSetVec3i(volume,"num_dp_blocks",(osp::vec3i&)dataDistributedBlocks);
      }
      else
        volume = ospNewVolume(useBlockBricked ? "block_bricked_volume" :
                                                "shared_structured_volume");

      if (!volume) THROW_SG_ERROR("could not allocate volume");

      isosurfacesGeometry = ospNewGeometry("isosurfaces");
      ospSetObject(isosurfacesGeometry, "volume", volume);

      setValue((OSPObject)volume);

      ospSetString(volume,"voxelType",voxelType.c_str());
      ospSetVec3i(volume,"dimensions",(const osp::vec3i&)dimensions);

      FileName realFileName = fileNameOfCorrespondingXmlDoc.path()+fileName;
      FILE *file = fopen(realFileName.c_str(),"rb");
      if (!file)
        throw std::runtime_error("StructuredVolumeFromFile::render(): could not open file '"
                                 +realFileName.str()+"' (expanded from xml file '"
                                 +fileNameOfCorrespondingXmlDoc.str()
                                 +"' and file name '"+fileName+"')");

      vec2f voxelRange(std::numeric_limits<float>::infinity(), -std::numeric_limits<float>::infinity());
      const OSPDataType ospVoxelType = getOSPDataTypeFor(voxelType);
      const size_t voxelSize = sizeOf(ospVoxelType);
      if (useBlockBricked || useDataDistributedVolume) {
        const size_t nPerSlice = (size_t)dimensions.x * (size_t)dimensions.y;
        std::vector<uint8_t> slice(nPerSlice * voxelSize, 0);

        for (size_t z = 0; z < dimensions.z; ++z) {
          if (fread(slice.data(), voxelSize, nPerSlice, file) != nPerSlice) {
            throw std::runtime_error("StructuredVolume::render(): read incomplete slice "
                "data ... partial file or wrong format!?");
          }
          const vec3i region_lo(0, 0, z);
          const vec3i region_sz(dimensions.x, dimensions.y, 1);
          extendVoxelRange(voxelRange, ospVoxelType, slice.data(), nPerSlice);
          ospSetRegion(volume, slice.data(), (const osp::vec3i&)region_lo, (const osp::vec3i&)region_sz);
        }
      } else {
        const size_t nVoxels = (size_t)dimensions.x * (size_t)dimensions.y * (size_t)dimensions.z;
        uint8_t *voxels = new uint8_t[nVoxels * voxelSize];
        if (fread(voxels, voxelSize, nVoxels, file) != nVoxels) {
          THROW_SG_ERROR("read incomplete data (truncated file or wrong format?!)");
        }
        extendVoxelRange(voxelRange, ospVoxelType, voxels, nVoxels);
        OSPData data = ospNewData(nVoxels, ospVoxelType, voxels, OSP_DATA_SHARED_BUFFER);
        ospSetData(volume,"voxelData",data);
      }
      fclose(file);

      child("voxelRange").setValue(voxelRange);
      child("isosurface").setMinMax(voxelRange.x, voxelRange.y);
      float iso = child("isosurface").valueAs<float>();
      if (iso < voxelRange.x || iso > voxelRange.y)
        child("isosurface").setValue((voxelRange.y-voxelRange.x)/2.f);
      child("transferFunction")["valueRange"].setValue(voxelRange);
      child("transferFunction").preCommit(ctx);

      ospSetObject(volume,
                   "transferFunction",
                   child("transferFunction").valueAs<OSPObject>());
      ospCommit(volume);
    }

    void StructuredVolumeFromFile::postCommit(RenderContext &ctx)
    {
      ospSetObject(volume,"transferFunction",
                   child("transferFunction").valueAs<OSPObject>());
      ospCommit(volume);
    }

    OSP_REGISTER_SG_NODE(StructuredVolumeFromFile);

    // =======================================================
    // stacked slices volume class
    // =======================================================

    StackedRawSlices::StackedRawSlices()
      : baseName(""), voxelType("uint8_t"), dimensions(-1)
    {}

    /*! \brief returns a std::string with the c++ name of this class */
    std::string StackedRawSlices::toString() const
    {
      return "ospray::sg::StackedRawSlices";
    }

    //! return bounding box of all primitives
    box3f StackedRawSlices::bounds() const
    {
      return box3f(vec3f(0.f),vec3f(getDimensions()));
    }

    //! \brief Initialize this node's value from given XML node
    void StackedRawSlices::setFromXML(const xml::Node &node,
                                      const unsigned char *binBasePtr)
    {
      voxelType       = node.getProp("voxelType");
      sliceResolution = toVec2i(node.getProp("sliceResolution").c_str());
      baseName        = node.getProp("baseName");
      firstSliceID    = std::stoll(node.getProp("firstSliceID","0"));
      numSlices       = std::stoll(node.getProp("numSlices"));

      if (voxelType != "uint8_t") {
        throw std::runtime_error("unknown StackedRawSlices.voxelType "
                                 "(currently only supporting 'uint8_t')");
      }
    }

    OSP_REGISTER_SG_NODE(StackedRawSlices);

  } // ::ospray::sg
} // ::ospray
<commit_msg>Enable other volume types, they were supported but check was not updated<commit_after>// ======================================================================== //
// Copyright 2009-2017 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "Volume.h"
#include "sg/common/World.h"

namespace ospray {
  namespace sg {

    static vec3i checkForAndEnableDistributedVolumes()
    {
      auto dpFromEnv = getEnvVar<std::string>("OSPRAY_DATA_PARALLEL");

      if (dpFromEnv.first) {
        // Create the OSPRay object.
        vec3i blockDims;
        int rc = sscanf(dpFromEnv.second.c_str(), "%dx%dx%d",
                        &blockDims.x, &blockDims.y, &blockDims.z);
        if (rc != 3) {
          throw std::runtime_error("could not parse OSPRAY_DATA_PARALLEL "
                                   "env-var. Must be of format <X>x<Y>x<>Z "
                                   "(e.g., '4x4x4'");
        }
        Volume::useDataDistributedVolume = true;
        return blockDims;
      } else {
        return {0, 0, 0,};
      }
    }

    /*! helper function to help build voxel ranges during parsing */
    template<typename T>
    inline void extendVoxelRange(ospcommon::vec2f &voxelRange,
                                 const T *voxel, size_t num)
    {
      for (size_t i = 0; i < num; ++i) {
        voxelRange.x = std::min(voxelRange.x, static_cast<float>(voxel[i]));
        voxelRange.y = std::max(voxelRange.y, static_cast<float>(voxel[i]));
      }
    }

    //! Convenient wrapper that will do the template dispatch for you based on
    //  the voxelType passed
    inline void extendVoxelRange(ospcommon::vec2f &voxelRange,
                                 const OSPDataType voxelType,
                                 const unsigned char *voxels,
                                 const size_t numVoxels)
    {
      switch (voxelType) {
        case OSP_UCHAR:
          extendVoxelRange(voxelRange, voxels, numVoxels);
          break;
        case OSP_SHORT:
          extendVoxelRange(voxelRange,
                           reinterpret_cast<const short*>(voxels),
                           numVoxels);
          break;
        case OSP_USHORT:
          extendVoxelRange(voxelRange,
                           reinterpret_cast<const unsigned short*>(voxels),
                           numVoxels);
          break;
        case OSP_FLOAT:
          extendVoxelRange(voxelRange,
                           reinterpret_cast<const float*>(voxels),
                           numVoxels);
          break;
        case OSP_DOUBLE:
          extendVoxelRange(voxelRange,
                           reinterpret_cast<const double*>(voxels),
                           numVoxels);
          break;
        default:
          throw std::runtime_error("sg::extendVoxelRange: unsupported voxel type!");
      }
    }

    bool unsupportedVoxelType(const std::string &type) {
      return type != "uchar" && type != "ushort" && type != "short"
        && type != "float" && type != "double";
    }

    // =======================================================
    // base volume class
    // =======================================================

    bool Volume::useDataDistributedVolume = false;

    /*! \brief returns a std::string with the c++ name of this class */
    Volume::Volume()
    {
      createChildNode("transferFunction", "TransferFunction");
      createChildNode("gradientShadingEnabled", "bool", true);
      createChildNode("preIntegration", "bool", true);
      createChildNode("singleShade", "bool", true);
      createChildNode("voxelRange", "vec2f",
                      vec2f(std::numeric_limits<float>::infinity(),
                            -std::numeric_limits<float>::infinity()));
      createChildNode("adaptiveSampling", "bool", true);
      createChildNode("adaptiveScalar", "float", 15.f);
      createChildNode("adaptiveBacktrack", "float", 0.03f);
      createChildNode("samplingRate", "float", 0.125f);
      createChildNode("adaptiveMaxSamplingRate", "float", 2.f);
      createChildNode("volumeClippingBoxLower", "vec3f", vec3f(0.f));
      createChildNode("volumeClippingBoxUpper", "vec3f", vec3f(0.f));
      createChildNode("specular", "vec3f", vec3f(0.3f));
      createChildNode("gridOrigin", "vec3f", vec3f(0.0f));
      createChildNode("gridSpacing", "vec3f", vec3f(0.002f));
      createChildNode("isosurfaceEnabled", "bool", false);
      createChildNode("isosurface", "float",
                      -std::numeric_limits<float>::infinity(),
                      NodeFlags::valid_min_max |
                      NodeFlags::gui_slider).setMinMax(0.f,255.f);
    }

    std::string Volume::toString() const
    {
      return "ospray::sg::Volume";
    }

    void Volume::serialize(sg::Serialization::State &state)
    {
      Node::serialize(state);
    }

    void Volume::preRender(RenderContext &ctx)
    {
      if (volume) {
        ospAddVolume(ctx.world->ospModel,volume);
        if (child("isosurfaceEnabled").valueAs<bool>() == true
            && isosurfacesGeometry)
          ospAddGeometry(ctx.world->ospModel, isosurfacesGeometry);
      }
    }

    // =======================================================
    // structured volume class
    // =======================================================

    //! constructor
    StructuredVolume::StructuredVolume()
      : dimensions(-1), voxelType("<undefined>"), mappedPointer(nullptr)
    {
    }

    /*! \brief returns a std::string with the c++ name of this class */
    std::string StructuredVolume::toString() const
    {
      return "ospray::sg::StructuredVolume";
    }

    //! return bounding box of all primitives
    box3f StructuredVolume::bounds() const
    {
      return {vec3f(0.f),
              vec3f(getDimensions())*child("gridSpacing").valueAs<vec3f>()};
    }

    //! \brief Initialize this node's value from given XML node

    void StructuredVolume::setFromXML(const xml::Node &node,
                                      const unsigned char *binBasePtr)
    {
      Assert2(binBasePtr,
              "mapped binary file is nullptr, in XML node that "
              "needs mapped binary data (sg::StructuredVolume)");
      voxelType = node.getProp("voxelType");
      if (node.hasProp("ofs"))
        mappedPointer = binBasePtr + std::stoll(node.getProp("ofs","0"));
      dimensions = toVec3i(node.getProp("dimensions").c_str());

      if (voxelType == "uint8")
        voxelType = "uchar";
      if (unsupportedVoxelType(voxelType)) {
        THROW_SG_ERROR("unknown StructuredVolume.voxelType '" + voxelType + "'");
      }

      std::cout << "#osp:sg: created StructuredVolume from XML file, "
                << "dimensions = " << getDimensions() << std::endl;
    }

    void StructuredVolume::postCommit(RenderContext &ctx)
    {
    }

    OSP_REGISTER_SG_NODE(StructuredVolume);

    // =======================================================
    // structured volume that is stored in a separate file (ie, a file
    // other than the ospbin file)
    // =======================================================

    //! constructor
    StructuredVolumeFromFile::StructuredVolumeFromFile()
      : dimensions(-1), fileName(""), voxelType("<undefined>")
    {}

    /*! \brief returns a std::string with the c++ name of this class */
    std::string StructuredVolumeFromFile::toString() const
    {
      return "ospray::sg::StructuredVolumeFromFile";
    }

    //! return bounding box of all primitives
    box3f StructuredVolumeFromFile::bounds() const
    {
      return {vec3f(0.f),
              vec3f(getDimensions())*child("gridSpacing").valueAs<vec3f>()};
    }

    //! \brief Initialize this node's value from given XML node
    void StructuredVolumeFromFile::setFromXML(const xml::Node &node,
                                              const unsigned char *binBasePtr)
    {
      voxelType = node.getProp("voxelType");
      if (voxelType == "uint8") voxelType = "uchar";
      dimensions = toVec3i(node.getProp("dimensions").c_str());
      fileName = node.getProp("fileName");

      if (fileName.empty()) {
        throw std::runtime_error("sg::StructuredVolumeFromFile: "
                                 "no 'fileName' specified");
      }
      if (unsupportedVoxelType(voxelType)) {
        THROW_SG_ERROR("unknown StructuredVolume.voxelType '" + voxelType + "'");
      }

      fileNameOfCorrespondingXmlDoc = node.doc->fileName;

      std::cout << "#osp:sg: created StructuredVolume from XML file, "
                << "dimensions = " << getDimensions() << std::endl;
    }

    void StructuredVolumeFromFile::preCommit(RenderContext &ctx)
    {
      if (volume) {
        ospCommit(volume);
        if (child("isosurfaceEnabled").valueAs<bool>() == true
            && isosurfacesGeometry) {
          OSPData isovaluesData = ospNewData(1, OSP_FLOAT,
            &child("isosurface").valueAs<float>());
          ospSetData(isosurfacesGeometry, "isovalues", isovaluesData);
          ospCommit(isosurfacesGeometry);
        }
        return;
      }

      if (dimensions.x <= 0 || dimensions.y <= 0 || dimensions.z <= 0) {
        throw std::runtime_error("StructuredVolume::render(): "
                                 "invalid volume dimensions");
      }

      vec3i dataDistributedBlocks = checkForAndEnableDistributedVolumes();

      bool useBlockBricked = 1;

      if (useDataDistributedVolume) {
        volume = ospNewVolume("data_distributed_volume");
        ospSetVec3i(volume,"num_dp_blocks",(osp::vec3i&)dataDistributedBlocks);
      }
      else
        volume = ospNewVolume(useBlockBricked ? "block_bricked_volume" :
                                                "shared_structured_volume");

      if (!volume) THROW_SG_ERROR("could not allocate volume");

      isosurfacesGeometry = ospNewGeometry("isosurfaces");
      ospSetObject(isosurfacesGeometry, "volume", volume);

      setValue((OSPObject)volume);

      ospSetString(volume,"voxelType",voxelType.c_str());
      ospSetVec3i(volume,"dimensions",(const osp::vec3i&)dimensions);

      FileName realFileName = fileNameOfCorrespondingXmlDoc.path()+fileName;
      FILE *file = fopen(realFileName.c_str(),"rb");
      if (!file)
        throw std::runtime_error("StructuredVolumeFromFile::render(): could not open file '"
                                 +realFileName.str()+"' (expanded from xml file '"
                                 +fileNameOfCorrespondingXmlDoc.str()
                                 +"' and file name '"+fileName+"')");

      vec2f voxelRange(std::numeric_limits<float>::infinity(), -std::numeric_limits<float>::infinity());
      const OSPDataType ospVoxelType = getOSPDataTypeFor(voxelType);
      const size_t voxelSize = sizeOf(ospVoxelType);
      if (useBlockBricked || useDataDistributedVolume) {
        const size_t nPerSlice = (size_t)dimensions.x * (size_t)dimensions.y;
        std::vector<uint8_t> slice(nPerSlice * voxelSize, 0);

        for (size_t z = 0; z < dimensions.z; ++z) {
          if (fread(slice.data(), voxelSize, nPerSlice, file) != nPerSlice) {
            throw std::runtime_error("StructuredVolume::render(): read incomplete slice "
                "data ... partial file or wrong format!?");
          }
          const vec3i region_lo(0, 0, z);
          const vec3i region_sz(dimensions.x, dimensions.y, 1);
          extendVoxelRange(voxelRange, ospVoxelType, slice.data(), nPerSlice);
          ospSetRegion(volume, slice.data(), (const osp::vec3i&)region_lo, (const osp::vec3i&)region_sz);
        }
      } else {
        const size_t nVoxels = (size_t)dimensions.x * (size_t)dimensions.y * (size_t)dimensions.z;
        uint8_t *voxels = new uint8_t[nVoxels * voxelSize];
        if (fread(voxels, voxelSize, nVoxels, file) != nVoxels) {
          THROW_SG_ERROR("read incomplete data (truncated file or wrong format?!)");
        }
        extendVoxelRange(voxelRange, ospVoxelType, voxels, nVoxels);
        OSPData data = ospNewData(nVoxels, ospVoxelType, voxels, OSP_DATA_SHARED_BUFFER);
        ospSetData(volume,"voxelData",data);
      }
      fclose(file);

      child("voxelRange").setValue(voxelRange);
      child("isosurface").setMinMax(voxelRange.x, voxelRange.y);
      float iso = child("isosurface").valueAs<float>();
      if (iso < voxelRange.x || iso > voxelRange.y)
        child("isosurface").setValue((voxelRange.y-voxelRange.x)/2.f);
      child("transferFunction")["valueRange"].setValue(voxelRange);
      child("transferFunction").preCommit(ctx);

      ospSetObject(volume,
                   "transferFunction",
                   child("transferFunction").valueAs<OSPObject>());
      ospCommit(volume);
    }

    void StructuredVolumeFromFile::postCommit(RenderContext &ctx)
    {
      ospSetObject(volume,"transferFunction",
                   child("transferFunction").valueAs<OSPObject>());
      ospCommit(volume);
    }

    OSP_REGISTER_SG_NODE(StructuredVolumeFromFile);

    // =======================================================
    // stacked slices volume class
    // =======================================================

    StackedRawSlices::StackedRawSlices()
      : baseName(""), voxelType("uint8_t"), dimensions(-1)
    {}

    /*! \brief returns a std::string with the c++ name of this class */
    std::string StackedRawSlices::toString() const
    {
      return "ospray::sg::StackedRawSlices";
    }

    //! return bounding box of all primitives
    box3f StackedRawSlices::bounds() const
    {
      return box3f(vec3f(0.f),vec3f(getDimensions()));
    }

    //! \brief Initialize this node's value from given XML node
    void StackedRawSlices::setFromXML(const xml::Node &node,
                                      const unsigned char *binBasePtr)
    {
      voxelType       = node.getProp("voxelType");
      sliceResolution = toVec2i(node.getProp("sliceResolution").c_str());
      baseName        = node.getProp("baseName");
      firstSliceID    = std::stoll(node.getProp("firstSliceID","0"));
      numSlices       = std::stoll(node.getProp("numSlices"));

      if (voxelType != "uint8_t") {
        throw std::runtime_error("unknown StackedRawSlices.voxelType "
                                 "(currently only supporting 'uint8_t')");
      }
    }

    OSP_REGISTER_SG_NODE(StackedRawSlices);

  } // ::ospray::sg
} // ::ospray
<|endoftext|>


<commit_before>#include "aquila/global.h"
#include "aquila/ml/Dtw.h"
#include <unittestpp.h>
#include <vector>

SUITE(Dtw)
{
    TEST(DistanceToItself)
    {
        const std::size_t SIZE = 3;
        double arr1[SIZE] = {0, 1, 2}, arr2[SIZE] = {1, 2, 3};
        std::vector<double> v1(arr1, arr1 + SIZE), v2(arr2, arr2 + SIZE);

        Aquila::DtwDataType from, to;
        from.push_back(v1);
        from.push_back(v2);
        to.push_back(v1);
        to.push_back(v2);

        Aquila::Dtw dtw;
        double distance = dtw.getDistance(from, to);

        CHECK_CLOSE(0.0, distance, 0.000001);
    }

    TEST(ZeroDiagonalDistance)
    {
        const std::size_t SIZE = 3;
        double arr1[SIZE] = {0, 0, 0}, arr2[SIZE] = {1, 1, 1};
        std::vector<double> zeros(arr1, arr1 + SIZE), ones(arr2, arr2 + SIZE);

        Aquila::DtwDataType from, to;
        from.push_back(zeros);
        from.push_back(ones);
        from.push_back(ones);
        to.push_back(zeros);
        to.push_back(ones);
        to.push_back(ones);

        /**
         * this will give the following local Manhattan distances:
         *
         * 3 0 0
         * 3 0 0
         * 0 3 3
         *
         * and the lowest-cost path will be on the diagonal.
         */

        Aquila::Dtw dtw(Aquila::manhattanDistance);
        double distance = dtw.getDistance(from, to);

        CHECK_CLOSE(0.0, distance, 0.000001);
    }

    TEST(NonZeroDiagonalDistance)
    {
        const std::size_t SIZE = 3;
        double arr1[SIZE] = {0, 0, 0}, arr2[SIZE] = {1, 1, 1};
        std::vector<double> zeros(arr1, arr1 + SIZE), ones(arr2, arr2 + SIZE);

        Aquila::DtwDataType from, to;
        from.push_back(zeros);
        from.push_back(zeros);
        from.push_back(zeros);
        to.push_back(ones);
        to.push_back(ones);
        to.push_back(ones);

        /**
         * this will give the following distances (using Manhattan for local):
         *
         * local      accumulated
         *
         * 3 3 3         3 6 9
         * 3 3 3         3 6 6
         * 3 3 3         3 3 3
         *
         * and the lowest-cost path will still be on the diagonal, but this time
         * the distance is a non-zero value.
         */

        Aquila::Dtw dtw(Aquila::manhattanDistance);
        double distance = dtw.getDistance(from, to);

        CHECK_CLOSE(9.0, distance, 0.000001);
    }
}

<commit_msg>Similarity test.<commit_after>#include "aquila/global.h"
#include "aquila/ml/Dtw.h"
#include <unittestpp.h>
#include <vector>

SUITE(Dtw)
{
    TEST(DistanceToItself)
    {
        const std::size_t SIZE = 3;
        double arr1[SIZE] = {0, 1, 2}, arr2[SIZE] = {1, 2, 3};
        std::vector<double> v1(arr1, arr1 + SIZE), v2(arr2, arr2 + SIZE);

        Aquila::DtwDataType from, to;
        from.push_back(v1);
        from.push_back(v2);
        to.push_back(v1);
        to.push_back(v2);

        Aquila::Dtw dtw;
        double distance = dtw.getDistance(from, to);

        CHECK_CLOSE(0.0, distance, 0.000001);
    }

    TEST(ZeroDiagonalDistance)
    {
        const std::size_t SIZE = 3;
        double arr1[SIZE] = {0, 0, 0}, arr2[SIZE] = {1, 1, 1};
        std::vector<double> zeros(arr1, arr1 + SIZE), ones(arr2, arr2 + SIZE);

        Aquila::DtwDataType from, to;
        from.push_back(zeros);
        from.push_back(ones);
        from.push_back(ones);
        to.push_back(zeros);
        to.push_back(ones);
        to.push_back(ones);

        /**
         * this will give the following local Manhattan distances:
         *
         * 3 0 0
         * 3 0 0
         * 0 3 3
         *
         * and the lowest-cost path will be on the diagonal.
         */

        Aquila::Dtw dtw(Aquila::manhattanDistance);
        double distance = dtw.getDistance(from, to);

        CHECK_CLOSE(0.0, distance, 0.000001);
    }

    TEST(NonZeroDiagonalDistance)
    {
        const std::size_t SIZE = 3;
        double arr1[SIZE] = {0, 0, 0}, arr2[SIZE] = {1, 1, 1};
        std::vector<double> zeros(arr1, arr1 + SIZE), ones(arr2, arr2 + SIZE);

        Aquila::DtwDataType from, to;
        from.push_back(zeros);
        from.push_back(zeros);
        from.push_back(zeros);
        to.push_back(ones);
        to.push_back(ones);
        to.push_back(ones);

        /**
         * this will give the following distances (using Manhattan for local):
         *
         * local      accumulated
         *
         * 3 3 3         3 6 9
         * 3 3 3         3 6 6
         * 3 3 3         3 3 3
         *
         * and the lowest-cost path will still be on the diagonal, but this time
         * the distance is a non-zero value.
         */

        Aquila::Dtw dtw(Aquila::manhattanDistance);
        double distance = dtw.getDistance(from, to);

        CHECK_CLOSE(9.0, distance, 0.000001);
    }

    TEST(Similarity)
    {
        const std::size_t SIZE = 3;
        double arr1[SIZE] = {0, 0, 0}, arr2[SIZE] = {1, 1, 1};
        std::vector<double> zeros(arr1, arr1 + SIZE), ones(arr2, arr2 + SIZE);

        Aquila::DtwDataType from, to1, to2;
        from.push_back(zeros);
        from.push_back(zeros);
        from.push_back(zeros);
        to1.push_back(zeros);
        to1.push_back(zeros);
        to1.push_back(ones);
        to2.push_back(zeros);
        to2.push_back(ones);
        to2.push_back(ones);

        /**
         * 000 is more "similar" to 001 than 011, therefore distance between
         * from and to1 should be smaller
         */
        Aquila::Dtw dtw;
        double distance1 = dtw.getDistance(from, to1);
        double distance2 = dtw.getDistance(from, to2);

        CHECK(distance1 < distance2);
    }
}

<|endoftext|>