Body.hpp
Go to the documentation of this file.
1 /*
2  * Original work Copyright (c) 2006-2011 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_DYNAMICS_BODY_HPP
23 #define PLAYRHO_DYNAMICS_BODY_HPP
24 
27 
28 #include <PlayRho/Common/Math.hpp>
29 #include <PlayRho/Common/Range.hpp>
37 
38 #include <vector>
39 #include <memory>
40 #include <cassert>
41 #include <utility>
42 #include <iterator>
43 
44 namespace playrho {
45 namespace d2 {
46 
47 class World;
48 struct FixtureConf;
49 class Shape;
50 struct BodyConf;
51 
73 class Body
74 {
75 public:
76 
78  using Fixtures = std::vector<Fixture*>;
79 
81  using KeyedJointPtr = std::pair<Body*, Joint*>;
82 
84  using Joints = std::vector<KeyedJointPtr>;
85 
87  using Contacts = std::vector<KeyedContactPtr>;
88 
90  static PLAYRHO_CONSTEXPR const auto InvalidIslandIndex = static_cast<BodyCounter>(-1);
91 
94  using FlagsType = std::uint16_t;
95 
99  {
102 
105 
108 
113 
116 
119 
124 
129 
132  };
133 
135  static FlagsType GetFlags(BodyType type) noexcept;
136 
138  static FlagsType GetFlags(const BodyConf& bd) noexcept;
139 
171  Fixture* CreateFixture(const Shape& shape,
172  const FixtureConf& def = GetDefaultFixtureConf(),
173  bool resetMassData = true);
174 
197  bool Destroy(Fixture* fixture, bool resetMassData = true);
198 
207  void DestroyFixtures();
208 
216  void SetTransform(Length2 location, Angle angle);
217 
221  Transformation GetTransformation() const noexcept;
222 
234  Length2 GetLocation() const noexcept;
235 
237  const Sweep& GetSweep() const noexcept;
238 
241  Angle GetAngle() const noexcept;
242 
244  Length2 GetWorldCenter() const noexcept;
245 
247  Length2 GetLocalCenter() const noexcept;
248 
250  Velocity GetVelocity() const noexcept;
251 
256  void SetVelocity(const Velocity& velocity) noexcept;
257 
263  void SetAcceleration(LinearAcceleration2 linear, AngularAcceleration angular) noexcept;
264 
267 
270 
278  InvMass GetInvMass() const noexcept;
279 
286  InvRotInertia GetInvRotInertia() const noexcept;
287 
293  void SetMassData(const MassData& massData);
294 
300  void ResetMassData();
301 
303  Frequency GetLinearDamping() const noexcept;
304 
306  void SetLinearDamping(NonNegative<Frequency> linearDamping) noexcept;
307 
309  Frequency GetAngularDamping() const noexcept;
310 
312  void SetAngularDamping(NonNegative<Frequency> angularDamping) noexcept;
313 
316  void SetType(BodyType type);
317 
319  BodyType GetType() const noexcept;
320 
324  bool IsSpeedable() const noexcept;
325 
330  bool IsAccelerable() const noexcept;
331 
335  void SetBullet(bool flag) noexcept;
336 
338  bool IsImpenetrable() const noexcept;
339 
342  void SetSleepingAllowed(bool flag) noexcept;
343 
345  bool IsSleepingAllowed() const noexcept;
346 
357  void SetAwake() noexcept;
358 
370  void UnsetAwake() noexcept;
371 
375  bool IsAwake() const noexcept;
376 
380  Time GetUnderActiveTime() const noexcept;
381 
390  void SetUnderActiveTime(Time value) noexcept;
391 
395  void ResetUnderActiveTime() noexcept;
396 
411  void SetEnabled(bool flag);
412 
414  bool IsEnabled() const noexcept;
415 
418  void SetFixedRotation(bool flag);
419 
421  bool IsFixedRotation() const noexcept;
422 
424  SizedRange<Fixtures::const_iterator> GetFixtures() const noexcept;
425 
427  SizedRange<Fixtures::iterator> GetFixtures() noexcept;
428 
430  SizedRange<Joints::const_iterator> GetJoints() const noexcept;
431 
433  SizedRange<Joints::iterator> GetJoints() noexcept;
434 
438  SizedRange<Contacts::const_iterator> GetContacts() const noexcept;
439 
441  void* GetUserData() const noexcept;
442 
444  void SetUserData(void* data) noexcept;
445 
447  World* GetWorld() const noexcept;
448 
450  bool IsMassDataDirty() const noexcept;
451 
452 private:
453 
454  friend class BodyAtty;
455 
456  Body() = delete;
457 
458  Body(const Body& other) = delete;
459 
463  Body(World* world, const BodyConf& bd);
464 
465  ~Body() noexcept;
466 
468  bool IsIslanded() const noexcept;
469 
471  void SetIslandedFlag() noexcept;
472 
474  void UnsetIslandedFlag() noexcept;
475 
480  void SetAwakeFlag() noexcept;
481 
483  void UnsetAwakeFlag() noexcept;
484 
491  void Advance(Real alpha) noexcept;
492 
494  void SetMassDataDirty() noexcept;
495 
497  void UnsetMassDataDirty() noexcept;
498 
500  void SetEnabledFlag() noexcept;
501 
503  void UnsetEnabledFlag() noexcept;
504 
506  bool Insert(ContactKey key, Contact* contact);
507 
509  bool Insert(Joint* joint);
510 
512  bool Erase(const Contact* contact);
513 
515  bool Erase(const Joint* joint);
516 
518  void ClearContacts();
519 
521  void ClearJoints();
522 
528  void SetTransformation(Transformation value) noexcept;
529 
530  //
531  // Member variables. Try to keep total size small.
532  //
533 
537  Transformation m_xf;
538 
539  Sweep m_sweep;
540 
541  Velocity m_velocity;
542  FlagsType m_flags = 0;
543 
546  LinearAcceleration2 m_linearAcceleration = LinearAcceleration2{};
547 
548  World* const m_world;
549  void* m_userData;
550 
551  Fixtures m_fixtures;
552  Contacts m_contacts;
553  Joints m_joints;
554 
557  AngularAcceleration m_angularAcceleration = AngularAcceleration{0};
558 
563  InvMass m_invMass = 0;
564 
568  InvRotInertia m_invRotI = 0;
569 
570  NonNegative<Frequency> m_linearDamping;
571  NonNegative<Frequency> m_angularDamping;
572 
577  Time m_underActiveTime = 0;
578 };
579 
583 
585 {
586  auto flags = FlagsType{0};
587  switch (type)
588  {
589  case BodyType::Dynamic: flags |= (e_velocityFlag|e_accelerationFlag); break;
590  case BodyType::Kinematic: flags |= (e_impenetrableFlag|e_velocityFlag); break;
591  case BodyType::Static: flags |= (e_impenetrableFlag); break;
592  }
593  return flags;
594 }
595 
596 inline BodyType Body::GetType() const noexcept
597 {
598  switch (m_flags & (e_accelerationFlag|e_velocityFlag))
599  {
601  case e_velocityFlag: return BodyType::Kinematic;
602  default: break; // handle case 0 this way so compiler doesn't warn of no default handling.
603  }
604  return BodyType::Static;
605 }
606 
608 {
609  return m_xf;
610 }
611 
612 inline Length2 Body::GetLocation() const noexcept
613 {
614  return GetTransformation().p;
615 }
616 
617 inline const Sweep& Body::GetSweep() const noexcept
618 {
619  return m_sweep;
620 }
621 
622 inline Angle Body::GetAngle() const noexcept
623 {
624  return GetSweep().pos1.angular;
625 }
626 
627 inline Length2 Body::GetWorldCenter() const noexcept
628 {
629  return GetSweep().pos1.linear;
630 }
631 
632 inline Length2 Body::GetLocalCenter() const noexcept
633 {
634  return GetSweep().GetLocalCenter();
635 }
636 
637 inline Velocity Body::GetVelocity() const noexcept
638 {
639  return m_velocity;
640 }
641 
642 inline InvMass Body::GetInvMass() const noexcept
643 {
644  return m_invMass;
645 }
646 
647 inline InvRotInertia Body::GetInvRotInertia() const noexcept
648 {
649  return m_invRotI;
650 }
651 
652 inline Frequency Body::GetLinearDamping() const noexcept
653 {
654  return m_linearDamping;
655 }
656 
657 inline void Body::SetLinearDamping(NonNegative<Frequency> linearDamping) noexcept
658 {
659  m_linearDamping = linearDamping;
660 }
661 
662 inline Frequency Body::GetAngularDamping() const noexcept
663 {
664  return m_angularDamping;
665 }
666 
667 inline void Body::SetAngularDamping(NonNegative<Frequency> angularDamping) noexcept
668 {
669  m_angularDamping = angularDamping;
670 }
671 
672 inline void Body::SetBullet(bool flag) noexcept
673 {
674  if (flag)
675  {
676  m_flags |= e_impenetrableFlag;
677  }
678  else
679  {
680  m_flags &= ~e_impenetrableFlag;
681  }
682 }
683 
684 inline bool Body::IsImpenetrable() const noexcept
685 {
686  return (m_flags & e_impenetrableFlag) != 0;
687 }
688 
689 inline void Body::SetAwakeFlag() noexcept
690 {
691  // Protect the body's invariant that only "speedable" bodies can be awake.
692  assert(IsSpeedable());
693 
694  m_flags |= e_awakeFlag;
695 }
696 
697 inline void Body::UnsetAwakeFlag() noexcept
698 {
699  assert(!IsSpeedable() || IsSleepingAllowed());
700  m_flags &= ~e_awakeFlag;
701 }
702 
703 inline void Body::SetAwake() noexcept
704 {
705  // Ignore this request unless this body is speedable so as to maintain the body's invariant
706  // that only "speedable" bodies can be awake.
707  if (IsSpeedable())
708  {
709  SetAwakeFlag();
711  }
712 }
713 
714 inline void Body::UnsetAwake() noexcept
715 {
716  if (!IsSpeedable() || IsSleepingAllowed())
717  {
718  UnsetAwakeFlag();
719  m_underActiveTime = 0;
720  m_velocity = Velocity{LinearVelocity2{}, 0_rpm};
721  }
722 }
723 
724 inline bool Body::IsAwake() const noexcept
725 {
726  return (m_flags & e_awakeFlag) != 0;
727 }
728 
729 inline Time Body::GetUnderActiveTime() const noexcept
730 {
731  return m_underActiveTime;
732 }
733 
734 inline void Body::SetUnderActiveTime(Time value) noexcept
735 {
736  if ((value == 0_s) || IsAccelerable())
737  {
738  m_underActiveTime = value;
739  }
740 }
741 
742 inline void Body::ResetUnderActiveTime() noexcept
743 {
744  m_underActiveTime = 0_s;
745 }
746 
747 inline bool Body::IsEnabled() const noexcept
748 {
749  return (m_flags & e_enabledFlag) != 0;
750 }
751 
752 inline bool Body::IsFixedRotation() const noexcept
753 {
754  return (m_flags & e_fixedRotationFlag) != 0;
755 }
756 
757 inline bool Body::IsSpeedable() const noexcept
758 {
759  return (m_flags & e_velocityFlag) != 0;
760 }
761 
762 inline bool Body::IsAccelerable() const noexcept
763 {
764  return (m_flags & e_accelerationFlag) != 0;
765 }
766 
767 inline void Body::SetSleepingAllowed(bool flag) noexcept
768 {
769  if (flag)
770  {
771  m_flags |= e_autoSleepFlag;
772  }
773  else if (IsSpeedable())
774  {
775  m_flags &= ~e_autoSleepFlag;
776  SetAwakeFlag();
777  ResetUnderActiveTime();
778  }
779 }
780 
781 inline bool Body::IsSleepingAllowed() const noexcept
782 {
783  return (m_flags & e_autoSleepFlag) != 0;
784 }
785 
787 {
788  return {begin(m_fixtures), end(m_fixtures), size(m_fixtures)};
789 }
790 
792 {
793  return {begin(m_fixtures), end(m_fixtures), size(m_fixtures)};
794 }
795 
797 {
798  return {begin(m_joints), end(m_joints), size(m_joints)};
799 }
800 
802 {
803  return {begin(m_joints), end(m_joints), size(m_joints)};
804 }
805 
807 {
808  return {begin(m_contacts), end(m_contacts), size(m_contacts)};
809 }
810 
811 inline void Body::SetUserData(void* data) noexcept
812 {
813  m_userData = data;
814 }
815 
816 inline void* Body::GetUserData() const noexcept
817 {
818  return m_userData;
819 }
820 
822 {
823  return m_linearAcceleration;
824 }
825 
827 {
828  return m_angularAcceleration;
829 }
830 
831 inline void Body::Advance(Real alpha) noexcept
832 {
833  //assert(m_sweep.GetAlpha0() <= alpha);
834  assert(IsSpeedable() || m_sweep.pos1 == m_sweep.pos0);
835 
836  // Advance to the new safe time. This doesn't sync the broad-phase.
837  m_sweep.Advance0(alpha);
838  m_sweep.pos1 = m_sweep.pos0;
840 }
841 
842 inline World* Body::GetWorld() const noexcept
843 {
844  return m_world;
845 }
846 
847 inline void Body::SetMassDataDirty() noexcept
848 {
849  m_flags |= e_massDataDirtyFlag;
850 }
851 
852 inline void Body::UnsetMassDataDirty() noexcept
853 {
854  m_flags &= ~e_massDataDirtyFlag;
855 }
856 
857 inline bool Body::IsMassDataDirty() const noexcept
858 {
859  return (m_flags & e_massDataDirtyFlag) != 0;
860 }
861 
862 inline void Body::SetEnabledFlag() noexcept
863 {
864  m_flags |= e_enabledFlag;
865 }
866 
867 inline void Body::UnsetEnabledFlag() noexcept
868 {
869  m_flags &= ~e_enabledFlag;
870 }
871 
872 inline bool Body::IsIslanded() const noexcept
873 {
874  return (m_flags & e_islandFlag) != 0;
875 }
876 
877 inline void Body::SetIslandedFlag() noexcept
878 {
879  m_flags |= e_islandFlag;
880 }
881 
882 inline void Body::UnsetIslandedFlag() noexcept
883 {
884  m_flags &= ~e_islandFlag;
885 }
886 
887 // Free functions...
888 
892 inline Acceleration GetAcceleration(const Body& body) noexcept
893 {
894  return Acceleration{body.GetLinearAcceleration(), body.GetAngularAcceleration()};
895 }
896 
903 inline void SetAcceleration(Body& body, Acceleration value) noexcept
904 {
905  body.SetAcceleration(value.linear, value.angular);
906 }
907 
913 Acceleration CalcGravitationalAcceleration(const Body& body) noexcept;
914 
917 inline bool Awaken(Body& body) noexcept
918 {
919  if (!body.IsAwake() && body.IsSpeedable())
920  {
921  body.SetAwake();
922  return true;
923  }
924  return false;
925 }
926 
929 inline bool Unawaken(Body& body) noexcept
930 {
931  if (body.IsAwake() && body.IsSleepingAllowed())
932  {
933  body.UnsetAwake();
934  return true;
935  }
936  return false;
937 }
938 
943 bool ShouldCollide(const Body& lhs, const Body& rhs) noexcept;
944 
947 inline Position GetPosition1(const Body& body) noexcept
948 {
949  return body.GetSweep().pos1;
950 }
951 
957 inline Mass GetMass(const Body& body) noexcept
958 {
959  const auto invMass = body.GetInvMass();
960  return (invMass != InvMass{0})? Mass{Real{1} / invMass}: 0_kg;
961 }
962 
965 inline void SetLinearAcceleration(Body& body, LinearAcceleration2 value) noexcept
966 {
967  body.SetAcceleration(value, body.GetAngularAcceleration());
968 }
969 
972 inline void SetAngularAcceleration(Body& body, AngularAcceleration value) noexcept
973 {
974  body.SetAcceleration(body.GetLinearAcceleration(), value);
975 }
976 
980 {
981  SetLinearAcceleration(body, body.GetLinearAcceleration() + amount);
982 }
983 
986 inline void SetForce(Body& body, Force2 force, Length2 point) noexcept
987 {
988  const auto linAccel = LinearAcceleration2{force * body.GetInvMass()};
989  const auto invRotI = body.GetInvRotInertia();
990  const auto dp = point - body.GetWorldCenter();
991  const auto cp = Torque{Cross(dp, force) / Radian};
992  const auto angAccel = AngularAcceleration{cp * invRotI};
993  body.SetAcceleration(linAccel, angAccel);
994 }
995 
1004 inline void ApplyForce(Body& body, Force2 force, Length2 point) noexcept
1005 {
1006  // Torque is L^2 M T^-2 QP^-1.
1007  const auto linAccel = LinearAcceleration2{force * body.GetInvMass()};
1008  const auto invRotI = body.GetInvRotInertia(); // L^-2 M^-1 QP^2
1009  const auto dp = Length2{point - body.GetWorldCenter()}; // L
1010  const auto cp = Torque{Cross(dp, force) / Radian}; // L * M L T^-2 is L^2 M T^-2
1011  // L^2 M T^-2 QP^-1 * L^-2 M^-1 QP^2 = QP T^-2;
1012  const auto angAccel = AngularAcceleration{cp * invRotI};
1013  body.SetAcceleration(body.GetLinearAcceleration() + linAccel,
1014  body.GetAngularAcceleration() + angAccel);
1015 }
1016 
1022 inline void ApplyForceToCenter(Body& body, Force2 force) noexcept
1023 {
1024  const auto linAccel = body.GetLinearAcceleration() + force * body.GetInvMass();
1025  const auto angAccel = body.GetAngularAcceleration();
1026  body.SetAcceleration(linAccel, angAccel);
1027 }
1028 
1031 inline void SetTorque(Body& body, Torque torque) noexcept
1032 {
1033  const auto linAccel = body.GetLinearAcceleration();
1034  const auto invRotI = body.GetInvRotInertia();
1035  const auto angAccel = torque * invRotI;
1036  body.SetAcceleration(linAccel, angAccel);
1037 }
1038 
1046 inline void ApplyTorque(Body& body, Torque torque) noexcept
1047 {
1048  const auto linAccel = body.GetLinearAcceleration();
1049  const auto invRotI = body.GetInvRotInertia();
1050  const auto angAccel = body.GetAngularAcceleration() + torque * invRotI;
1051  body.SetAcceleration(linAccel, angAccel);
1052 }
1053 
1063 inline void ApplyLinearImpulse(Body& body, Momentum2 impulse, Length2 point) noexcept
1064 {
1065  auto velocity = body.GetVelocity();
1066  velocity.linear += body.GetInvMass() * impulse;
1067  const auto invRotI = body.GetInvRotInertia();
1068  const auto dp = point - body.GetWorldCenter();
1069  velocity.angular += AngularVelocity{invRotI * Cross(dp, impulse) / Radian};
1070  body.SetVelocity(velocity);
1071 }
1072 
1077 inline void ApplyAngularImpulse(Body& body, AngularMomentum impulse) noexcept
1078 {
1079  auto velocity = body.GetVelocity();
1080  const auto invRotI = body.GetInvRotInertia();
1081  velocity.angular += AngularVelocity{invRotI * impulse};
1082  body.SetVelocity(velocity);
1083 }
1084 
1088 Force2 GetCentripetalForce(const Body& body, Length2 axis);
1089 
1094 inline RotInertia GetRotInertia(const Body& body) noexcept
1095 {
1096  return Real{1} / body.GetInvRotInertia();
1097 }
1098 
1102 inline RotInertia GetLocalRotInertia(const Body& body) noexcept
1103 {
1104  return GetRotInertia(body)
1105  + GetMass(body) * GetMagnitudeSquared(body.GetLocalCenter()) / SquareRadian;
1106 }
1107 
1112 inline LinearVelocity2 GetLinearVelocity(const Body& body) noexcept
1113 {
1114  return body.GetVelocity().linear;
1115 }
1116 
1121 inline AngularVelocity GetAngularVelocity(const Body& body) noexcept
1122 {
1123  return body.GetVelocity().angular;
1124 }
1125 
1130 inline void SetLinearVelocity(Body& body, const LinearVelocity2 v) noexcept
1131 {
1132  body.SetVelocity(Velocity{v, GetAngularVelocity(body)});
1133 }
1134 
1139 inline void SetAngularVelocity(Body& body, AngularVelocity omega) noexcept
1140 {
1141  body.SetVelocity(Velocity{GetLinearVelocity(body), omega});
1142 }
1143 
1149 inline Length2 GetWorldPoint(const Body& body, const Length2 localPoint) noexcept
1150 {
1151  return Transform(localPoint, body.GetTransformation());
1152 }
1153 
1159 inline Length2 GetWorldVector(const Body& body, const Length2 localVector) noexcept
1160 {
1161  return Rotate(localVector, body.GetTransformation().q);
1162 }
1163 
1166 inline UnitVec GetWorldVector(const Body& body, const UnitVec localVector) noexcept
1167 {
1168  return Rotate(localVector, body.GetTransformation().q);
1169 }
1170 
1176 inline Length2 GetLocalPoint(const Body& body, const Length2 worldPoint) noexcept
1177 {
1178  return InverseTransform(worldPoint, body.GetTransformation());
1179 }
1180 
1186 inline UnitVec GetLocalVector(const Body& body, const UnitVec uv) noexcept
1187 {
1188  return InverseRotate(uv, body.GetTransformation().q);
1189 }
1190 
1197  const Length2 worldPoint) noexcept
1198 {
1199  const auto velocity = body.GetVelocity();
1200  const auto worldCtr = body.GetWorldCenter();
1201  const auto dp = Length2{worldPoint - worldCtr};
1202  const auto rlv = LinearVelocity2{GetRevPerpendicular(dp) * (velocity.angular / Radian)};
1203  return velocity.linear + rlv;
1204 }
1205 
1212  const Length2 localPoint) noexcept
1213 {
1214  return GetLinearVelocityFromWorldPoint(body, GetWorldPoint(body, localPoint));
1215 }
1216 
1219 inline Force2 GetForce(const Body& body) noexcept
1220 {
1221  return body.GetLinearAcceleration() * GetMass(body);
1222 }
1223 
1226 inline Torque GetTorque(const Body& body) noexcept
1227 {
1228  return body.GetAngularAcceleration() * GetRotInertia(body);
1229 }
1230 
1237 Velocity Cap(Velocity velocity, Time h, MovementConf conf) noexcept;
1238 
1245 Velocity GetVelocity(const Body& body, Time h) noexcept;
1246 
1249 BodyCounter GetWorldIndex(const Body* body) noexcept;
1250 
1253 std::size_t GetFixtureCount(const Body& body) noexcept;
1254 
1262 void RotateAboutWorldPoint(Body& body, Angle amount, Length2 worldPoint);
1263 
1273 void RotateAboutLocalPoint(Body& body, Angle amount, Length2 localPoint);
1274 
1287 inline Length2 GetLocation(const Body& body) noexcept
1288 {
1289  return body.GetTransformation().p;
1290 }
1291 
1295 inline Angle GetAngle(const Body& body) noexcept
1296 {
1297  return body.GetSweep().pos1.angular;
1298 }
1299 
1301 inline Transformation GetTransformation(const Body& body) noexcept
1302 {
1303  return body.GetTransformation();
1304 }
1305 
1309 inline void SetTransformation(Body& body, const Transformation& xfm) noexcept
1310 {
1311  body.SetTransform(xfm.p, GetAngle(xfm.q));
1312 }
1313 
1315 inline Position GetPosition(const Body& body) noexcept
1316 {
1317  return Position{body.GetLocation(), body.GetAngle()};
1318 }
1319 
1328 inline void SetLocation(Body& body, Length2 value) noexcept
1329 {
1330  body.SetTransform(value, GetAngle(body));
1331 }
1332 
1341 inline void SetAngle(Body& body, Angle value) noexcept
1342 {
1343  body.SetTransform(GetLocation(body), value);
1344 }
1345 
1346 } // namespace d2
1347 } // namespace playrho
1348 
1349 #endif // PLAYRHO_DYNAMICS_BODY_HPP