11#include <config_box2d.h>
27#define BOX2D_SLIDE_SIZE_IN_METERS 100.00f
34double calculateScaleFactor(const ::basegfx::B2DVector& rSlideSize)
36 double fWidth = rSlideSize.getX();
37 double fHeight = rSlideSize.getY();
55 return b2_kinematicBody;
57 return b2_dynamicBody;
68 case b2_kinematicBody:
75b2Vec2 convertB2DPointToBox2DVec2(
const basegfx::B2DPoint& aPoint,
const double fScaleFactor)
77 return {
static_cast<float>(aPoint.
getX() * fScaleFactor),
78 static_cast<float>(aPoint.
getY() * -fScaleFactor) };
83 b2Body* aBody,
const float fDensity,
const float fFriction,
84 const float fRestitution,
const double fScaleFactor)
88 b2FixtureDef aFixture;
89 b2PolygonShape aPolygonShape;
90 b2Vec2 aTriangleVertices[3]
91 = { convertB2DPointToBox2DVec2(aTriangle.getA(), fScaleFactor),
92 convertB2DPointToBox2DVec2(aTriangle.getB(), fScaleFactor),
93 convertB2DPointToBox2DVec2(aTriangle.getC(), fScaleFactor) };
95 bool bValidPointDistance =
true;
98 for (
int nPointIndexA = 0; nPointIndexA < 3; nPointIndexA++)
100 for (
int nPointIndexB = 0; nPointIndexB < 3; nPointIndexB++)
102 if (nPointIndexA == nPointIndexB)
105 if (b2DistanceSquared(aTriangleVertices[nPointIndexA],
106 aTriangleVertices[nPointIndexB])
109 bValidPointDistance =
false;
114 if (bValidPointDistance)
117 aPolygonShape.Set(aTriangleVertices, 3);
118 aFixture.shape = &aPolygonShape;
119 aFixture.density = fDensity;
120 aFixture.friction = fFriction;
121 aFixture.restitution = fRestitution;
122 aBody->CreateFixture(&aFixture);
128void addEdgeShapeToBody(
const basegfx::B2DPolygon& rPolygon, b2Body* aBody,
const float fDensity,
129 const float fFriction,
const float fRestitution,
const double fScaleFactor)
137 const float fHalfWidth = 0.1f;
138 bool bHasPreviousQuadrilateralEdge =
false;
139 b2Vec2 aQuadrilateralVertices[4];
143 b2FixtureDef aFixture;
144 b2PolygonShape aPolygonShape;
167 b2Vec2 aEdgeUnitVec(convertB2DPointToBox2DVec2(aPointB, fScaleFactor)
168 - convertB2DPointToBox2DVec2(aPointA, fScaleFactor));
169 aEdgeUnitVec.Normalize();
172 b2Vec2 aEdgeNormal(-aEdgeUnitVec.y, aEdgeUnitVec.x);
177 if (!bHasPreviousQuadrilateralEdge)
181 aQuadrilateralVertices[0]
182 = convertB2DPointToBox2DVec2(aPointA, fScaleFactor) + fHalfWidth * aEdgeNormal;
183 aQuadrilateralVertices[1]
184 = convertB2DPointToBox2DVec2(aPointA, fScaleFactor) + -fHalfWidth * aEdgeNormal;
185 bHasPreviousQuadrilateralEdge =
true;
187 aQuadrilateralVertices[2]
188 = convertB2DPointToBox2DVec2(aPointB, fScaleFactor) + fHalfWidth * aEdgeNormal;
189 aQuadrilateralVertices[3]
190 = convertB2DPointToBox2DVec2(aPointB, fScaleFactor) + -fHalfWidth * aEdgeNormal;
193 bool bValidPointDistance
194 = b2DistanceSquared(aQuadrilateralVertices[0], aQuadrilateralVertices[2]) > 0.003f;
196 if (bValidPointDistance)
199 aPolygonShape.Set(aQuadrilateralVertices, 4);
200 aFixture.shape = &aPolygonShape;
201 aFixture.density = fDensity;
202 aFixture.friction = fFriction;
203 aFixture.restitution = fRestitution;
204 aBody->CreateFixture(&aFixture);
207 aQuadrilateralVertices[0] = aQuadrilateralVertices[2];
208 aQuadrilateralVertices[1] = aQuadrilateralVertices[3];
214 const float fDensity,
const float fFriction,
const float fRestitution,
215 const double fScaleFactor)
219 addEdgeShapeToBody(rPolygon, aBody, fDensity, fFriction, fRestitution, fScaleFactor);
226 , mfScaleFactor(calculateScaleFactor(rSlideSize))
227 , mbShapesInitialized(false)
228 , mbHasWorldStepper(false)
229 , mbAlreadyStepped(false)
230 , mnPhysicsAnimationCounter(0)
231 , mpXShapeToBodyMap()
232 , maShapeParallelUpdateQueue()
242 mpBox2DWorld = std::make_unique<b2World>(b2Vec2(0.0f, -30.0f));
256 float fWidth =
static_cast<float>(rSlideSize.getX() *
mfScaleFactor);
257 float fHeight =
static_cast<float>(rSlideSize.getY() *
mfScaleFactor);
261 aBodyDef.type = b2_staticBody;
262 aBodyDef.position.Set(0, 0);
266 b2Body* pStaticBody =
mpBox2DWorld->CreateBody(&aBodyDef);
269 b2Vec2 aEdgePoints[4];
270 aEdgePoints[0].Set(0, 0);
271 aEdgePoints[1].Set(0, -fHeight);
272 aEdgePoints[2].Set(fWidth, -fHeight);
273 aEdgePoints[3].Set(fWidth, 0);
275 b2ChainShape aEdgesChainShape;
276 aEdgesChainShape.CreateLoop(aEdgePoints, 4);
279 b2FixtureDef aFixtureDef;
280 aFixtureDef.shape = &aEdgesChainShape;
281 pStaticBody->CreateFixture(&aFixtureDef);
288 pBox2DBody->setPosition(rOutPos);
292 const css::uno::Reference<com::sun::star::drawing::XShape> xShape,
299 pBox2DBody->setPositionByLinearVelocity(rOutPos, fPassedTime);
304 const css::uno::Reference<com::sun::star::drawing::XShape> xShape,
309 pBox2DBody->setLinearVelocity(rVelocity);
316 pBox2DBody->setAngle(fAngle);
320 const css::uno::Reference<com::sun::star::drawing::XShape> xShape,
const double fAngle,
321 const double fPassedTime)
327 pBox2DBody->setAngleByAngularVelocity(fAngle, fPassedTime);
332 const css::uno::Reference<com::sun::star::drawing::XShape> xShape,
333 const double fAngularVelocity)
337 pBox2DBody->setAngularVelocity(fAngularVelocity);
341 const css::uno::Reference<com::sun::star::drawing::XShape> xShape,
bool bCanCollide)
345 pBox2DBody->setCollision(bCanCollide);
397 auto aXShapeToShapeMap = pShapeManager->getXShapeToShapeMap();
399 std::unordered_map<css::uno::Reference<css::drawing::XShape>,
bool> aXShapeBelongsToAGroup;
404 for (
auto aIt = aXShapeToShapeMap.begin(); aIt != aXShapeToShapeMap.end(); aIt++)
407 if (pShape->isForeground())
414 const size_t nObjCount(
aObjList->GetObjCount());
416 for (
size_t nObjIndex = 0; nObjIndex < nObjCount; ++nObjIndex)
419 aXShapeBelongsToAGroup.insert(
427 for (
auto aIt = aXShapeToShapeMap.begin(); aIt != aXShapeToShapeMap.end(); aIt++)
433 if (pShape->isForeground() && !aXShapeBelongsToAGroup[pShape->getXShape()])
438 if (!pShape->isVisible())
455 const css::uno::Reference<com::sun::star::drawing::XShape>& xShape,
464 const css::uno::Reference<com::sun::star::drawing::XShape>& xShape,
474 const css::uno::Reference<com::sun::star::drawing::XShape>& xShape,
const double fAngle)
477 aQueueElement.
mfAngle = fAngle;
482 const css::uno::Reference<com::sun::star::drawing::XShape>& xShape,
483 const double fAngularVelocity,
const int nDelayForSteps)
492 const css::uno::Reference<com::sun::star::drawing::XShape>& xShape,
const bool bVisibility)
500 const css::uno::Reference<com::sun::star::drawing::XShape>& xShape,
509 const css::uno::Reference<com::sun::star::drawing::XShape>& xShape,
519 const css::uno::Reference<com::sun::star::drawing::XShape>& xShape,
537 { pAttrLayer->getPosX(), pAttrLayer->getPosY() });
545 const css::uno::Reference<com::sun::star::drawing::XShape>& xShape,
589 const ::basegfx::B2DVector& rSlideSize,
602 const int nPositionIterations)
605 mpBox2DWorld->Step(fTimeStep, nVelocityIterations, nPositionIterations);
609 const int nVelocityIterations,
const int nPositionIterations)
613 unsigned int nStepAmount =
static_cast<unsigned int>(std::round(fPassedTime / fTimeStep));
616 double fTimeSteppedThrough = fTimeStep * nStepAmount;
623 for (
unsigned int nStepCounter = 0; nStepCounter < nStepAmount; nStepCounter++)
625 step(fTimeStep, nVelocityIterations, nPositionIterations);
635 return fTimeSteppedThrough;
651 const double fBounciness)
655 pBox2DBody->setDensityAndRestitution(fDensity, fBounciness);
686 const float fDensity,
const float fFriction)
693 aBodyDef.type = b2_staticBody;
698 ->getTopmostAttributeLayer();
699 if (pShapeAttributeLayer && pShapeAttributeLayer->isRotationAngleValid())
702 aBodyDef.angle = ::basegfx::deg2rad(-pShapeAttributeLayer->getRotationAngle());
706 std::shared_ptr<b2Body> pBody(
mpBox2DWorld->CreateBody(&aBodyDef), [](b2Body* pB2Body) {
707 pB2Body->GetWorld()->DestroyBody(pB2Body);
712 rtl::OUString aShapeType = rShape->getXShape()->getShapeType();
718 if (aShapeType ==
"com.sun.star.drawing.CustomShape")
720 aPolyPolygon =
static_cast<SdrObjCustomShape*
>(pSdrObject)->GetLineGeometry(
true);
738 { -aShapeBounds.getWidth() / 2, -aShapeBounds.getHeight() / 2 },
739 { aShapeBounds.getWidth() / 2, -aShapeBounds.getHeight() / 2 },
740 { -aShapeBounds.getWidth() / 2, aShapeBounds.getHeight() / 2 },
741 { aShapeBounds.getWidth() / 2, aShapeBounds.getHeight() / 2 });
747 for (
const auto& rPolygon : std::as_const(aPolyPolygon))
750 if (rPolygon.isClosed())
754 aTriangleVector.insert(aTriangleVector.end(), aTempTriangleVector.begin(),
755 aTempTriangleVector.end());
759 addEdgeShapeToBody(rPolygon, pBody.get(), fDensity, fFriction,
763 addTriangleVectorToBody(aTriangleVector, pBody.get(), fDensity, fFriction,
768 addEdgeShapeToBody(aPolyPolygon, pBody.get(), fDensity, fFriction,
777 , mfScaleFactor(fScaleFactor)
784 double fX =
static_cast<double>(aPosition.x) /
mfScaleFactor;
785 double fY =
static_cast<double>(aPosition.y) / -
mfScaleFactor;
786 return ::basegfx::B2DPoint(fX, fY);
796 const double fPassedTime)
815 double fDeltaAngle = fDesiredAngle -
getAngle();
818 while (fDeltaAngle > 180
819 || fDeltaAngle < -180)
820 fDeltaAngle += fDeltaAngle > 0 ? -360 : +360;
822 double fAngularVelocity = fDeltaAngle / fPassedTime;
828 b2Vec2 aVelocity = {
static_cast<float>(rVelocity.getX() *
mfScaleFactor),
835 float fBox2DAngularVelocity =
static_cast<float>(
basegfx::deg2rad(-fAngularVelocity));
836 mpBox2DBody->SetAngularVelocity(fBox2DAngularVelocity);
842 for (b2Fixture* pFixture =
mpBox2DBody->GetFixtureList(); pFixture;
843 pFixture = pFixture->GetNext())
845 b2Filter aFilter = pFixture->GetFilterData();
848 aFilter.maskBits = bCanCollide ? 0xFFFF : 0x0000;
849 pFixture->SetFilterData(aFilter);
855 double fAngle =
static_cast<double>(
mpBox2DBody->GetAngle());
856 return ::basegfx::rad2deg(-fAngle);
867 for (b2Fixture* pFixture =
mpBox2DBody->GetFixtureList(); pFixture;
868 pFixture = pFixture->GetNext())
870 pFixture->SetDensity(
static_cast<float>(fDensity));
871 pFixture->SetRestitution(
static_cast<float>(fRestitution));
879 for (b2Fixture* pFixture =
mpBox2DBody->GetFixtureList(); pFixture;
880 pFixture = pFixture->GetNext())
882 pFixture->SetRestitution(
static_cast<float>(fRestitution));
box2d::utils::Box2DBodySharedPtr mpBox2DBody
box2d::utils::Box2DWorldSharedPtr mpBox2DWorld
static SdrObject * getSdrObjectFromXShape(const css::uno::Reference< css::uno::XInterface > &xInt)
virtual basegfx::B2DPolyPolygon TakeXorPoly() const
virtual SdrObjList * GetSubList() const
bool IsGroupObject() const
bool HasFillStyle() const
void removeDoublePoints()
B2DRange getB2DRange() const
bool areControlPointsUsed() const
basegfx::B2DPoint const & getB2DPoint(sal_uInt32 nIndex) const
bool areControlPointsUsed() const
B2DPoint getCenter() const
void setPosition(const ::basegfx::B2DPoint &rPos)
Set the position of box2d body.
std::shared_ptr< b2Body > mpBox2DBody
Pointer to the body that this class manages.
void setAngularVelocity(const double fAngularVelocity)
Sets angular velocity of the body.
void setCollision(const bool bCanCollide)
Sets whether the body have collisions or not.
void setPositionByLinearVelocity(const ::basegfx::B2DPoint &rDesiredPos, const double fPassedTime)
Moves body to the specified position.
box2DBodyType getType() const
box2DBody(std::shared_ptr< b2Body > pBox2DBody, double fScaleFactor)
void setAngle(const double fAngle)
Set angle of the box2d body.
void setLinearVelocity(const ::basegfx::B2DVector &rVelocity)
Sets linear velocity of the body.
void setType(box2DBodyType eType)
Set type of the body.
::basegfx::B2DPoint getPosition() const
double mfScaleFactor
Scale factor for conversions between LO user space coordinates to Box2D World coordinates.
void setRestitution(const double fRestitution)
Set restitution of the box2d body.
void setDensityAndRestitution(const double fDensity, const double fRestitution)
Set density and restitution of the box2d body.
void setAngleByAngularVelocity(const double fDesiredAngle, const double fPassedTime)
Rotate body to specified angle of rotation.
void queueDynamicRotationUpdate(const css::uno::Reference< com::sun::star::drawing::XShape > &xShape, const double fAngle)
Queue a rotation update that is simulated as if shape's corresponding box2D body rotated to given ang...
double mfScaleFactor
Scale factor for conversions between LO user space coordinates to Box2D World coordinates.
void setShapeAngularVelocity(const css::uno::Reference< com::sun::star::drawing::XShape > xShape, const double fAngularVelocity)
Sets angular velocity of the shape's corresponding Box2D body.
void queueShapePositionUpdate(const css::uno::Reference< css::drawing::XShape > &xShape, const ::basegfx::B2DPoint &rOutPos)
void initiateAllShapesAsStaticBodies(const slideshow::internal::ShapeManagerSharedPtr &pShapeManager)
Initiate all the shapes in the current slide in the box2DWorld as static ones.
Box2DBodySharedPtr makeShapeStatic(const slideshow::internal::ShapeSharedPtr &pShape)
Make the Box2D body corresponding to the given shape a static one.
void queueShapeAnimationUpdate(const css::uno::Reference< css::drawing::XShape > &xShape, const slideshow::internal::ShapeAttributeLayerSharedPtr &pAttrLayer, const slideshow::internal::AttributeType eAttrType, const bool bIsFirstUpdate)
Queue an appropriate update for the animation effect that is in parallel with a physics animation.
void queueShapeAnimationEndUpdate(const css::uno::Reference< css::drawing::XShape > &xShape, const slideshow::internal::AttributeType eAttrType)
Queue an appropriate update for the animation effect that just ended.
bool mbAlreadyStepped
Flag used to stop overstepping that occurs when a physics animation effect transfers step-lock to ano...
void setHasWorldStepper(const bool bHasWorldStepper)
Set the flag for whether the box2DWorld has a stepper or not.
void setShapeCollision(const css::uno::Reference< com::sun::star::drawing::XShape > xShape, const bool bCanCollide)
Sets whether a shape's corresponding Box2D body has collision in the Box2D World or not.
std::queue< Box2DDynamicUpdateInformation > maShapeParallelUpdateQueue
Queue that holds any required information to keep LO animation effects and Box2DWorld in sync.
void queueShapeVisibilityUpdate(const css::uno::Reference< css::drawing::XShape > &xShape, const bool bVisibility)
Queue an collision update that sets the collision of shape's corresponding box2D body when processed.
void setShapePositionByLinearVelocity(const css::uno::Reference< css::drawing::XShape > xShape, const ::basegfx::B2DPoint &rOutPos, const double fPassedTime)
Moves shape's corresponding Box2D body to specified position.
void queueLinearVelocityUpdate(const css::uno::Reference< css::drawing::XShape > &xShape, const ::basegfx::B2DVector &rVelocity, const int nDelayForSteps=0)
Queue a update that sets the corresponding box2D body's linear velocity to the given value when proce...
void alertPhysicsAnimationStart(const ::basegfx::B2DVector &rSlideSize, const slideshow::internal::ShapeManagerSharedPtr &pShapeManager)
Alert that a physics animation effect has started.
box2DWorld(const ::basegfx::B2DVector &rSlideSize)
void setShapePosition(const css::uno::Reference< css::drawing::XShape > xShape, const ::basegfx::B2DPoint &rOutPos)
Sets shape's corresponding Box2D body to the specified position.
void alertPhysicsAnimationEnd(const slideshow::internal::ShapeSharedPtr &pShape)
Alert that a physics animation effect has ended.
void step(const float fTimeStep=1.0f/100.0f, const int nVelocityIterations=6, const int nPositionIterations=2)
Simulate and step through time in the Box2D World.
void queueDynamicPositionUpdate(const css::uno::Reference< css::drawing::XShape > &xShape, const ::basegfx::B2DPoint &rOutPos)
Queue a position update that is simulated as if shape's corresponding box2D body moved to given posit...
double stepAmount(const double fPassedTime, const float fTimeStep=1.0f/100.0f, const int nVelocityIterations=6, const int nPositionIterations=2)
Simulate and step through a given amount of time in the Box2D World.
int mnPhysicsAnimationCounter
Number of Physics Animations going on.
bool isInitialized() const
void queueAngularVelocityUpdate(const css::uno::Reference< com::sun::star::drawing::XShape > &xShape, const double fAngularVelocity, const int nDelayForSteps=0)
Queue an angular velocity update that sets the shape's corresponding box2D body angular velocity to t...
void processUpdateQueue(const double fPassedTime)
Process the updates queued in the maShapeParallelUpdateQueue.
void setShapeLinearVelocity(const css::uno::Reference< com::sun::star::drawing::XShape > xShape, const basegfx::B2DVector &rVelocity)
Sets linear velocity of the shape's corresponding Box2D body.
bool initiateWorld(const ::basegfx::B2DVector &rSlideSize)
bool hasWorldStepper() const
Box2DBodySharedPtr createStaticBody(const slideshow::internal::ShapeSharedPtr &rShape, const float fDensity=1.0f, const float fFriction=0.3f)
Create a static body that is represented by the shape's geometry.
bool mbHasWorldStepper
Holds whether or not there is a PhysicsAnimation that is stepping the Box2D World.
std::unique_ptr< b2World > mpBox2DWorld
Pointer to the real Box2D World that this class manages.
void createStaticFrameAroundSlide(const ::basegfx::B2DVector &rSlideSize)
Creates a static frame in Box2D world that corresponds to the slide borders.
Box2DBodySharedPtr makeShapeDynamic(const css::uno::Reference< css::drawing::XShape > &xShape, const basegfx::B2DVector &rStartVelocity, const double fDensity, const double fBounciness)
Make the shape's corresponding box2D body a dynamic one.
void setShapeAngleByAngularVelocity(const css::uno::Reference< com::sun::star::drawing::XShape > xShape, const double fAngle, const double fPassedTime)
Rotates shape's corresponding Box2D body to specified angle.
void setShapeAngle(const css::uno::Reference< com::sun::star::drawing::XShape > xShape, const double fAngle)
Sets rotation angle of the shape's corresponding Box2D body.
void queueShapePathAnimationUpdate(const css::uno::Reference< com::sun::star::drawing::XShape > &xShape, const slideshow::internal::ShapeAttributeLayerSharedPtr &pAttrLayer, const bool bIsFirstUpdate)
Queue an appropriate update for a path animation that is in parallel with a physics animation.
std::unordered_map< css::uno::Reference< css::drawing::XShape >, Box2DBodySharedPtr > mpXShapeToBodyMap
Represents an animatable shape, that can have its attributes changed.
std::deque< AttachedObject_Impl > aObjList
::std::vector< B2DTriangle > B2DTriangleVector
B2DTriangleVector triangulate(const B2DPolygon &rCandidate)
B2DPolygon removeNeutralPoints(const B2DPolygon &rCandidate)
B2DPoint distort(const B2DPoint &rCandidate, const B2DRange &rOriginal, const B2DPoint &rTopLeft, const B2DPoint &rTopRight, const B2DPoint &rBottomLeft, const B2DPoint &rBottomRight)
B2DPolygon adaptiveSubdivideByAngle(const B2DPolygon &rCandidate, double fAngleBound)
constexpr double deg2rad(double v)
Box2DBodySharedPtr makeBodyStatic(const Box2DBodySharedPtr &pBox2DBody)
Make the Box2D body a static one.
Box2DBodySharedPtr makeBodyDynamic(const Box2DBodySharedPtr &pBox2DBody)
Make the Box2D body a dynamic one.
std::shared_ptr< box2DBody > Box2DBodySharedPtr
@ BOX2D_UPDATE_LINEAR_VELOCITY
@ BOX2D_UPDATE_POSITION_CHANGE
@ BOX2D_UPDATE_VISIBILITY
@ BOX2D_UPDATE_ANGULAR_VELOCITY
::std::shared_ptr< ShapeAttributeLayer > ShapeAttributeLayerSharedPtr
AttributeType
Type of to-be-animated attribute.
std::shared_ptr< ShapeManager > ShapeManagerSharedPtr
::std::shared_ptr< Shape > ShapeSharedPtr
SVXCORE_DLLPUBLIC css::uno::Reference< css::drawing::XShape > GetXShapeForSdrObject(SdrObject *pObj) noexcept