Shape.hpp
Go to the documentation of this file.
1 /*
2  * Original work Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
3  * Modified work Copyright (c) 2017 Louis Langholtz https://github.com/louis-langholtz/PlayRho
4  *
5  * This software is provided 'as-is', without any express or implied
6  * warranty. In no event will the authors be held liable for any damages
7  * arising from the use of this software.
8  *
9  * Permission is granted to anyone to use this software for any purpose,
10  * including commercial applications, and to alter it and redistribute it
11  * freely, subject to the following restrictions:
12  *
13  * 1. The origin of this software must not be misrepresented; you must not
14  * claim that you wrote the original software. If you use this software
15  * in a product, an acknowledgment in the product documentation would be
16  * appreciated but is not required.
17  * 2. Altered source versions must be plainly marked as such, and must not be
18  * misrepresented as being the original software.
19  * 3. This notice may not be removed or altered from any source distribution.
20  */
21 
22 #ifndef PLAYRHO_COLLISION_SHAPES_SHAPE_HPP
23 #define PLAYRHO_COLLISION_SHAPES_SHAPE_HPP
24 
25 #include <PlayRho/Common/Math.hpp>
29 #include <memory>
30 #include <functional>
31 #include <utility>
32 #include <typeinfo>
33 
34 namespace playrho {
35 namespace d2 {
36 
37 class Shape;
38 
39 // Forward declare functions.
40 // Note that these may be friend functions but that declaring these within the class that
41 // they're to be friends of, doesn't also insure that they're found within the namespace
42 // in terms of lookup.
43 
46 ChildCounter GetChildCount(const Shape& shape) noexcept;
47 
55 DistanceProxy GetChild(const Shape& shape, ChildCounter index);
56 
59 MassData GetMassData(const Shape& shape) noexcept;
60 
63 Real GetFriction(const Shape& shape) noexcept;
64 
66 Real GetRestitution(const Shape& shape) noexcept;
67 
70 NonNegative<AreaDensity> GetDensity(const Shape& shape) noexcept;
71 
93 NonNegative<Length> GetVertexRadius(const Shape& shape, ChildCounter idx);
94 
100 void Transform(Shape& shape, const Mat22& m);
101 
104 bool Visit(const Shape& shape, void* userData);
105 
110 const void* GetData(const Shape& shape) noexcept;
111 
115 const std::type_info& GetUseTypeInfo(const Shape& shape);
116 
118 using TypeInfoVisitor = std::function<void(const std::type_info& ti, const void* data)>;
119 
124 void Accept(const Shape& shape, const TypeInfoVisitor& visitor);
125 
127 bool operator== (const Shape& lhs, const Shape& rhs) noexcept;
128 
130 bool operator!= (const Shape& lhs, const Shape& rhs) noexcept;
131 
132 // Now define the shape class...
133 
140 
162 class Shape
163 {
164 public:
167  Shape();
168 
181  template <typename T>
182  explicit Shape(T arg): m_self{std::make_shared<Model<T>>(std::move(arg))}
183  {
184  // Intentionally empty.
185  }
186 
188  Shape(const Shape& other) = default;
189 
191  Shape(Shape&& other) = default;
192 
194  Shape& operator= (const Shape& other) = default;
195 
197  Shape& operator= (Shape&& other) = default;
198 
199  friend ChildCounter GetChildCount(const Shape& shape) noexcept
200  {
201  return shape.m_self->GetChildCount_();
202  }
203 
204  friend DistanceProxy GetChild(const Shape& shape, ChildCounter index)
205  {
206  return shape.m_self->GetChild_(index);
207  }
208 
209  friend MassData GetMassData(const Shape& shape) noexcept
210  {
211  return shape.m_self->GetMassData_();
212  }
213 
215  {
216  return shape.m_self->GetVertexRadius_(idx);
217  }
218 
219  friend Real GetFriction(const Shape& shape) noexcept
220  {
221  return shape.m_self->GetFriction_();
222  }
223 
224  friend Real GetRestitution(const Shape& shape) noexcept
225  {
226  return shape.m_self->GetRestitution_();
227  }
228 
229  friend NonNegative<AreaDensity> GetDensity(const Shape& shape) noexcept
230  {
231  return shape.m_self->GetDensity_();
232  }
233 
234  friend void Transform(Shape& shape, const Mat22& m)
235  {
236  auto copy = shape.m_self->Clone();
237  copy->Transform_(m);
238  shape.m_self = std::unique_ptr<const Shape::Concept>{std::move(copy)};
239  }
240 
241  friend bool Visit(const Shape& shape, void* userData)
242  {
243  return shape.m_self->Visit_(userData);
244  }
245 
246  friend const void* GetData(const Shape& shape) noexcept
247  {
248  return shape.m_self->GetData_();
249  }
250 
251  friend const std::type_info& GetUseTypeInfo(const Shape& shape)
252  {
253  return shape.m_self->GetUseTypeInfo_();
254  }
255 
256  friend void Accept(const Shape& shape, const TypeInfoVisitor& visitor)
257  {
258  const auto self = shape.m_self;
259  visitor(self->GetUseTypeInfo_(), self->GetData_());
260  }
261 
262  friend bool operator== (const Shape& lhs, const Shape& rhs) noexcept
263  {
264  return lhs.m_self == rhs.m_self || *lhs.m_self == *rhs.m_self;
265  }
266 
267  friend bool operator!= (const Shape& lhs, const Shape& rhs) noexcept
268  {
269  return !(lhs == rhs);
270  }
271 
272 private:
273 
276  struct Concept
277  {
278  virtual ~Concept() = default;
279 
284  virtual std::unique_ptr<Concept> Clone() const = 0;
285 
287  virtual ChildCounter GetChildCount_() const noexcept = 0;
288 
290  virtual DistanceProxy GetChild_(ChildCounter index) const = 0;
291 
293  virtual MassData GetMassData_() const noexcept = 0;
294 
297  virtual NonNegative<Length> GetVertexRadius_(ChildCounter idx) const = 0;
298 
300  virtual NonNegative<AreaDensity> GetDensity_() const noexcept = 0;
301 
303  virtual Real GetFriction_() const noexcept = 0;
304 
306  virtual Real GetRestitution_() const noexcept = 0;
307 
310  virtual void Transform_(const Mat22& m) = 0;
311 
313  virtual bool Visit_(void* userData) const = 0;
314 
316  virtual bool IsEqual_(const Concept& other) const noexcept = 0;
317 
320  virtual const std::type_info& GetUseTypeInfo_() const = 0;
321 
323  virtual const void* GetData_() const noexcept = 0;
324 
326  friend bool operator== (const Concept& lhs, const Concept &rhs) noexcept
327  {
328  return &lhs == &rhs || lhs.IsEqual_(rhs);
329  }
330 
332  friend bool operator!= (const Concept& lhs, const Concept &rhs) noexcept
333  {
334  return !(lhs == rhs);
335  }
336  };
337 
340  template <typename T>
341  struct Model final: Concept
342  {
344  using data_type = T;
345 
347  Model(T arg): data{std::move(arg)} {}
348 
349  std::unique_ptr<Concept> Clone() const override
350  {
351  return std::make_unique<Model>(data);
352  }
353 
354  ChildCounter GetChildCount_() const noexcept override
355  {
356  return GetChildCount(data);
357  }
358 
359  DistanceProxy GetChild_(ChildCounter index) const override
360  {
361  return GetChild(data, index);
362  }
363 
364  MassData GetMassData_() const noexcept override
365  {
366  return GetMassData(data);
367  }
368 
369  NonNegative<Length> GetVertexRadius_(ChildCounter idx) const override
370  {
371  return GetVertexRadius(data, idx);
372  }
373 
374  NonNegative<AreaDensity> GetDensity_() const noexcept override
375  {
376  return GetDensity(data);
377  }
378 
379  Real GetFriction_() const noexcept override
380  {
381  return GetFriction(data);
382  }
383 
384  Real GetRestitution_() const noexcept override
385  {
386  return GetRestitution(data);
387  }
388 
389  void Transform_(const Mat22& m) override
390  {
391  Transform(data, m);
392  }
393 
394  bool Visit_(void* userData) const override
395  {
396  return ::playrho::Visit(data, userData);
397  }
398 
399  bool IsEqual_(const Concept& other) const noexcept override
400  {
401  // Would be preferable to do this without using any kind of RTTI system.
402  // But how would that be done?
403  return (GetUseTypeInfo_() == other.GetUseTypeInfo_()) &&
404  (data == *static_cast<const T*>(other.GetData_()));
405  }
406 
407  const std::type_info& GetUseTypeInfo_() const override
408  {
409  return typeid(data_type);
410  }
411 
412  const void* GetData_() const noexcept override
413  {
414  // Note address of "data" not necessarily same as address of "this" since
415  // base class is virtual.
416  return &data;
417  }
418 
419  T data;
420  };
421 
422  std::shared_ptr<const Concept> m_self;
423 };
424 
425 // Related free functions...
426 
434 bool TestPoint(const Shape& shape, Length2 point) noexcept;
435 
436 } // namespace d2
437 
442 template <>
443 inline bool Visit<d2::Shape>(const d2::Shape& shape, void* userData)
444 {
445  return d2::Visit(shape, userData);
446 }
447 
448 } // namespace playrho
449 
450 #endif // PLAYRHO_COLLISION_SHAPES_SHAPE_HPP