00001 #ifndef OPENTISSUE_CORE_GEOMETRY_GEOMETRY_CYLINDER_H
00002 #define OPENTISSUE_CORE_GEOMETRY_GEOMETRY_CYLINDER_H
00003
00004
00005
00006
00007
00008
00009
00010 #include <OpenTissue/configuration.h>
00011
00012 #include <OpenTissue/core/geometry/geometry_volume_shape.h>
00013 #include <OpenTissue/core/function/function_signed_distance_function.h>
00014 #include <OpenTissue/utility/utility_class_id.h>
00015
00016 #include <OpenTissue/core/containers/mesh/polymesh/polymesh.h>
00017 #include <OpenTissue/core/containers/mesh/common/util/mesh_make_cylinder.h>
00018
00019 #include <cassert>
00020 #include <cmath>
00021
00022 namespace OpenTissue
00023 {
00024
00025 namespace geometry
00026 {
00027
00031 template< typename math_types_ >
00032 class Cylinder
00033 : public VolumeShape< math_types_ >
00034 , public function::SignedDistanceFunction< math_types_ >
00035 , public OpenTissue::utility::ClassID< Cylinder<math_types_> >
00036 {
00037 public:
00038
00039 typedef math_types_ math_types;
00040 typedef typename math_types::value_traits value_traits;
00041 typedef typename math_types::real_type real_type;
00042 typedef typename math_types::vector3_type vector3_type;
00043 typedef typename math_types::matrix3x3_type matrix3x3_type;
00044 typedef typename math_types::quaternion_type quaternion_type;
00045
00046 protected:
00047
00048 vector3_type m_axis;
00049 vector3_type m_center;
00050 real_type m_radius;
00051 real_type m_height;
00052
00053 public:
00054
00055 size_t const class_id() const { return OpenTissue::utility::ClassID<OpenTissue::geometry::Cylinder<math_types_> >::class_id(); }
00056
00057 virtual ~Cylinder(){}
00058
00059 public:
00060
00061 vector3_type center() const { return vector3_type(m_center); }
00062 real_type const & radius() const { return m_radius; }
00063 real_type const & height() const { return m_height; }
00064 vector3_type const & axis() const { return m_axis; }
00065
00066 Cylinder()
00067 : m_axis(value_traits::zero(),value_traits::zero(),value_traits::one())
00068 , m_center(value_traits::zero(),value_traits::zero(),value_traits::zero())
00069 , m_radius(value_traits::one())
00070 , m_height(value_traits::one())
00071 {}
00072
00073 explicit Cylinder(
00074 vector3_type const & new_center
00075 , vector3_type const & new_axis
00076 , real_type const & new_height
00077 , real_type const & new_radius
00078 )
00079 {
00080 set(new_center,new_axis,new_height,new_radius);
00081 }
00082
00083 Cylinder(Cylinder const & copy)
00084 {
00085 set(copy);
00086 }
00087
00088 public:
00089
00090 void set (Cylinder const& other_cylinder)
00091 {
00092 m_center = other_cylinder.m_center;
00093 m_axis = other_cylinder.m_axis;
00094 m_height = other_cylinder.m_height;
00095 m_radius = other_cylinder.m_radius;
00096 }
00097
00098 void set (
00099 vector3_type const & new_center
00100 , vector3_type const & new_axis
00101 , real_type const & new_height
00102 , real_type const & new_radius
00103 )
00104 {
00105 assert(new_radius>=value_traits::zero() || !"Cylinder::set(): radius must be non-negative");
00106 assert(new_height>=value_traits::zero() || !"Cylinder::set(): height must be non-negative");
00107
00108 this->m_center = new_center;
00109 this->m_axis = unit(new_axis);
00110 this->m_height = new_height;
00111 this->m_radius = new_radius;
00112 }
00113
00114 void place(vector3_type const & new_center,vector3_type const & new_axis)
00115 {
00116 this->m_axis = unit(new_axis);
00117 this->m_center = new_center;
00118 }
00119
00127 void xform(vector3_type const & T,matrix3x3_type const & R)
00128 {
00129 this->m_center = R * this->m_center + T;
00130 this->m_axis = R * this->m_axis;
00131 }
00132
00138 real_type diameter() const { return value_traits::two()*m_radius; }
00139
00145 real_type area() const
00146 {
00147 return value_traits::two()*value_traits::pi()*m_radius*m_height + (value_traits::two()*value_traits::pi()*m_radius*m_radius);
00148 }
00149
00155 real_type volume() const { return value_traits::pi()*m_radius*m_radius*m_height; }
00156
00157 void compute_surface_points(std::vector<vector3_type> & points) const
00158 {
00159 using std::acos;
00160
00161 real_type rad = value_traits::zero();
00162 vector3_type u(value_traits::one(),value_traits::zero(),value_traits::zero());
00163
00164
00165 if((m_axis[0]==value_traits::zero()) && (m_axis[1]==value_traits::zero()))
00166 {
00167 if(m_axis[2]>value_traits::zero())
00168 {
00169 rad = value_traits::zero();
00170 }
00171 else
00172 {
00173 rad = value_traits::pi();
00174 }
00175 }
00176 else
00177 {
00178 vector3_type k(value_traits::zero(),value_traits::zero(),value_traits::one());
00179
00180 u = unit(m_axis % k);
00181 rad = -acos(m_axis*k);
00182 }
00183 matrix3x3_type R;
00184 R = Ru(rad,u);
00185
00186 polymesh::PolyMesh<math_types> mesh;
00187 mesh::make_cylinder(m_radius,m_height,12,mesh);
00188 mesh::CoordinateIterator<polymesh::PolyMesh<math_types> > c(mesh.vertex_begin());
00189 mesh::CoordinateIterator<polymesh::PolyMesh<math_types> > cend(mesh.vertex_end());
00190 for(;c!=cend;++c)
00191 points.push_back( (R*(*c) + m_center));
00192 }
00193
00194 void translate(vector3_type const & T) { m_center += T; }
00195
00196 void rotate(matrix3x3_type const & R) { m_axis = R * m_axis; }
00197
00198 void scale(real_type const & s) { m_radius *= s; m_height *= s; }
00199
00200 vector3_type get_support_point(vector3_type const & v) const
00201 {
00202 vector3_type c,p;
00203 c = unit(v);
00204 real_type proj = c * m_axis;
00205 p = m_axis;
00206 if(proj>value_traits::zero())
00207 p *= m_height;
00208 else if(proj<value_traits::zero())
00209 p *= -m_height;
00210 else
00211 p.clear();
00212 p += m_center;
00213 vector3_type a = proj*m_axis;
00214 vector3_type b = (c - a);
00215 real_type delta = sqrt(b*b);
00216
00217 if(delta)
00218 {
00219 b *= m_radius/delta;
00220 p += b;
00221 }
00222 return p;
00223 }
00224
00225 real_type evaluate(vector3_type const & x) const
00226 {
00227
00228 vector3_type const r = x-m_center;
00229 return real_type(value_traits::one()/(m_radius*m_radius)*(r[0]*r[0]+r[1]*r[1])-m_height*m_height);
00230 }
00231
00232 vector3_type gradient(vector3_type const & x) const
00233 {
00234
00235 vector3_type const r = x-m_center;
00236 return vector3_type(r[0], r[1], value_traits::zero())*(value_traits::two()/(m_radius*m_radius));
00237 }
00238
00239 vector3_type normal(vector3_type const & x) const
00240 {
00241
00242 return unit(gradient(x));
00243 }
00244
00245 real_type signed_distance(vector3_type const & x) const
00246 {
00247
00248
00249 using std::sqrt;
00250 real_type const f = evaluate(x);
00251 real_type const sign = OpenTissue::math::sgn(f);
00252 return real_type(boost::numeric_cast<real_type>(0.1)*sign*sqrt(sign*f));
00253 }
00254
00266 void compute_collision_aabb(
00267 vector3_type const &
00268 , matrix3x3_type const &
00269 , vector3_type & min_coord
00270 , vector3_type & max_coord
00271 ) const
00272 {
00273 vector3_type p;
00274
00275 p = get_support_point( vector3_type( value_traits::one(), value_traits::zero(), value_traits::zero() ) );
00276 min_coord = p;
00277 max_coord = p;
00278
00279 p = get_support_point( vector3_type( -value_traits::one(), value_traits::zero(), value_traits::zero() ) );
00280 min_coord = min(min_coord, p);
00281 max_coord = max(min_coord, p);
00282
00283 p = get_support_point( vector3_type( value_traits::zero(), value_traits::one(), value_traits::zero() ) );
00284 min_coord = min(min_coord, p);
00285 max_coord = max(min_coord, p);
00286
00287 p = get_support_point( vector3_type( value_traits::zero(), -value_traits::one(), value_traits::zero() ) );
00288 min_coord = min(min_coord, p);
00289 max_coord = max(min_coord, p);
00290
00291 p = get_support_point( vector3_type( value_traits::zero(), value_traits::zero(), value_traits::one() ) );
00292 min_coord = min(min_coord, p);
00293 max_coord = max(min_coord, p);
00294
00295 p = get_support_point( vector3_type( value_traits::zero(), value_traits::zero(), -value_traits::one() ) );
00296 min_coord = min(min_coord, p);
00297 max_coord = max(min_coord, p);
00298 }
00299
00300 };
00301
00302 }
00303
00304 }
00305
00306
00307 #endif