text: /*=========================================================================
   *
   *  Copyright Insight Software Consortium
   *
   *  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.txt
   *
   *  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.
   *
   *=========================================================================*/
  #ifndef itkLineSpatialObject_hxx
  #define itkLineSpatialObject_hxx
  
  
  #include "itkLineSpatialObject.h"
  
  namespace itk
  {
  /** Constructor */
  template< unsigned int TDimension >
  LineSpatialObject< TDimension >
  ::LineSpatialObject()
  {
    this->SetDimension(TDimension);
    this->SetTypeName("LineSpatialObject");
    this->GetProperty()->SetRed(1);
    this->GetProperty()->SetGreen(0);
    this->GetProperty()->SetBlue(0);
    this->GetProperty()->SetAlpha(1);
    this->ComputeBoundingBox();
  }
  
  /** Destructor */
  template< unsigned int TDimension >
  LineSpatialObject< TDimension >
  ::~LineSpatialObject() = default;
  
  /** Set the list of Line points. */
  template< unsigned int TDimension >
  void
  LineSpatialObject< TDimension >
  ::SetPoints(PointListType & points)
  {
    // in this function, passing a null pointer as argument will
    // just clear the list...
    m_Points.clear();
  
    typename PointListType::iterator it, end;
    it = points.begin();
    end = points.end();
    while ( it != end )
      {
      m_Points.push_back(*it);
      it++;
      }
  
    this->ComputeBoundingBox();
    this->Modified();
  }
  
  /** Print the object. */
  template< unsigned int TDimension >
  void
  LineSpatialObject< TDimension >
  ::PrintSelf(std::ostream & os, Indent indent) const
  {
    os << indent << "LineSpatialObject(" << this << ")" << std::endl;
    os << indent << "ID: " << this->GetId() << std::endl;
    os << indent << "nb of points: "
       << static_cast< SizeValueType >( m_Points.size() ) << std::endl;
    Superclass::PrintSelf(os, indent);
  }
  
  /** Compute the boundaries of the line. */
  template< unsigned int TDimension >
  bool
  LineSpatialObject< TDimension >
  ::ComputeLocalBoundingBox() const
  {
    itkDebugMacro("Computing tube bounding box");
    if ( this->GetBoundingBoxChildrenName().empty()
         || strstr( typeid( Self ).name(),
                    this->GetBoundingBoxChildrenName().c_str() ) )
      {
      auto it  = m_Points.begin();
      auto end = m_Points.end();
  
      if ( it == end )
        {
        return false;
        }
      else
        {
        PointType pt =  this->GetIndexToWorldTransform()->TransformPoint(
          ( *it ).GetPosition() );
        const_cast< BoundingBoxType * >( this->GetBounds() )->SetMinimum(pt);
        const_cast< BoundingBoxType * >( this->GetBounds() )->SetMaximum(pt);
        it++;
  
        while ( it != end )
          {
          pt = this->GetIndexToWorldTransform()->TransformPoint(
            ( *it ).GetPosition() );
          const_cast< BoundingBoxType * >( this->GetBounds() )->ConsiderPoint(pt);
          it++;
          }
        }
      }
    return true;
  }
  
  /** Test whether a point is inside or outside the object
   *  For computational speed purposes, it is faster if the method does not
   *  check the name of the class and the current depth */
  template< unsigned int TDimension >
  bool
  LineSpatialObject< TDimension >
  ::IsInside(const PointType & point) const
  {
    auto it = m_Points.begin();
    auto itEnd = m_Points.end();
  
    if ( !this->SetInternalInverseTransformToWorldToIndexTransform() )
      {
      return false;
      }
  
    PointType transformedPoint =
      this->GetInternalInverseTransform()->TransformPoint(point);
  
    if ( this->GetBounds()->IsInside(transformedPoint) )
      {
      while ( it != itEnd )
        {
        if ( ( *it ).GetPosition() == transformedPoint )
          {
          return true;
          }
        it++;
        }
      }
  
    return false;
  }
  
  /** Check if a given point is inside a line
   *  return True only if the point is in the point list */
  template< unsigned int TDimension >
  bool
  LineSpatialObject< TDimension >
  ::IsInside(const PointType & point, unsigned int depth, char *name) const
  {
    itkDebugMacro("Checking the point [" << point << "] is on the Line");
  
    if ( name == nullptr )
      {
      if ( IsInside(point) )
        {
        return true;
        }
      }
    else if ( strstr(typeid( Self ).name(), name) )
      {
      if ( IsInside(point) )
        {
        return true;
        }
      }
  
    return Superclass::IsInside(point, depth, name);
  }
  
  /** Returns true if the line is evaluable at the requested point,
   *  false otherwise. */
  template< unsigned int TDimension >
  bool
  LineSpatialObject< TDimension >
  ::IsEvaluableAt(const PointType & point,
                  unsigned int depth, char *name) const
  {
    itkDebugMacro("Checking if the tube is evaluable at " << point);
    return IsInside(point, depth, name);
  }
  
  /** Returns the value of the line at that point.
   * Currently this function returns a binary value,
   * but it might want to return a degree of membership
   * in case of fuzzy Lines. */
  template< unsigned int TDimension >
  bool
  LineSpatialObject< TDimension >
  ::ValueAt(const PointType & point, double & value, unsigned int depth,
            char *name) const
  {
    itkDebugMacro("Getting the value of the tube at " << point);
  
    if ( IsInside(point, 0, name) )
      {
      value = this->GetDefaultInsideValue();
      return true;
      }
    else if ( Superclass::IsEvaluableAt(point, depth, name) )
      {
      Superclass::ValueAt(point, value, depth, name);
      return true;
      }
    value = this->GetDefaultOutsideValue();
    return false;
  }
  } // end namespace itk
  
  #endif
  