/*****************************
File:      CollisionSphere.h
Language:   C++ (header)
Project:    H3DNetworkingUtils
The contents of this file are subject to the Mozilla Public License
Version 1.1 (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.mozilla.org/MPL/

Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific language governing rights and limitations
under the License.

The Original Code is H3DNetworkingUtils v1.0.

The Initial Developer of the Original Code is CSIRO.
Portions created by the Initial Developer are Copyright (C) 1009 CSIRO. All Rights Reserved.
Contributor(s):
    Chris Gunn  <Chris.Gunn@csiro.au> <ChrisJGunn@gmail.com>
***************************/

/// \file CollisionSphere.h
/// \brief Header file for CollisionSphere, a spherical CollisionGeometry.

#ifndef CollisionSphere_H
#define CollisionSphere_H


#include "H3DNetworkingUtils/Config.h"
#include "H3DNetworkingUtils/CollisionGeometry.h"

// This next line is needed because H3DAPI.dll instantiates this template but this class does not see the header with 
// the instantiation in it. So without the line, this class would instantiate an identical one and there would
// be a multiply defined symbol in the link stage.
template struct __declspec(dllimport) H3D::AutoUpdate <H3D::Field>;

namespace H3DNetworkingUtils {

/// \class CollisionSphere
/// The CollisiopnSphere class is a sphere which is used by a CollidableDynamic, to represent a portion of the 
/// geometry that can be tested for collisions against another sphere. CollidableSpheres 
/// can be constructed around a piece of geometry and used by a CollisionGroup to test for 
/// these collisions.  \n
/// <b>Examples:</b>
///   - <a href="../../examples/CollisionGroupTest.x3d">CollisionGroupTest.x3d</a>

class H3D_NETWORKING_UTILS_DLL_SPEC CollisionSphere : public CollisionGeometry {
public:
   
  struct H3D_NETWORKING_UTILS_DLL_SPEC Radius : public H3D::SFFloat {
     virtual void setValue(const H3D::H3DFloat & val, int id = 0) {
        H3D::SFFloat::setValue(val, id);
        CollisionSphere * cs = static_cast<CollisionSphere*>(getOwner());
        cs->rad_sqrd = val * val;
     }
     virtual void update() {
        H3D::SFFloat::update();
        CollisionSphere * cs = static_cast<CollisionSphere*>(getOwner());
        cs->rad_sqrd = value * value;
     }

  };

  /// Constructor
  CollisionSphere( H3D::Inst< Radius > _radius = 0);
  
  /// Database
  static H3D::H3DNodeDatabase database;

  
  /// Radius of the sphere \n
  /// access type: inputOutput \n
  /// basic type: SFFloat \n
  /// default value: 0.01
  auto_ptr< Radius > radius;

  /// Debug: if true, the sphere is graphicially rendered, to assist in positioning it correctly \n
  /// access type: inputOutput \n
  /// basic type: SFBool \n
  /// default value: FALSE
  auto_ptr< H3D::SFBool > debug;
  
  /// Get the radius in the global coord system
  H3D::H3DFloat getGlobalRadius() {
     H3D::Vec3f scale = child_local_info->accForwardMatrix->getValue().getScalePart();
     H3D::H3DFloat sc = (scale.x + scale.y + scale.z) / 3.0f; 
     return radius->getValue() * sc;
  }
  
  /// Initialize
  virtual void initialize();
  
  /// Return a clone of this node
  virtual CollisionGeometry * clone() {return new CollisionSphere;}

  /// Copy contents into newP.
  virtual void copy(CollisionGeometry * newP);

  /// Return true of the given point is contained within the sphere
  virtual bool contains(const H3D::Vec3f & pt) {
     return (pt - local_offset->translation->getValue()).lengthSqr() < rad_sqrd;
  } 

private:
   H3D::H3DFloat rad_sqrd;
   H3D::H3DFloat scaled_rad_sqrd;
   H3D::Vec3f scaled_trans;
};

}

#endif // COLLIDABLESPHERE_H
