[Libreoffice-commits] core.git: Branch 'private/quwex/gsoc-box2d-experimental' - slideshow/source
Sarper Akdemir (via logerrit)
logerrit at kemper.freedesktop.org
Mon Aug 3 23:51:15 UTC 2020
Rebased ref, commits from common ancestor:
commit 3c5585e482953080fa9cd518393c7babe4808910
Author: Sarper Akdemir <q.sarperakdemir at gmail.com>
AuthorDate: Mon Jul 27 23:02:48 2020 +0300
Commit: Sarper Akdemir <q.sarperakdemir at gmail.com>
CommitDate: Tue Aug 4 02:50:16 2020 +0300
work-in-progress complex shapes
Change-Id: I807bbde92c143b8c96792b3d8bf9603a31216486
diff --git a/slideshow/source/engine/box2dtools.cxx b/slideshow/source/engine/box2dtools.cxx
index 8729300184f6..34794065df14 100644
--- a/slideshow/source/engine/box2dtools.cxx
+++ b/slideshow/source/engine/box2dtools.cxx
@@ -11,6 +11,13 @@
#include <Box2D/Box2D.h>
#include <shapemanager.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygontriangulator.hxx>
+#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
+
+#include <svx/svdobj.hxx>
+#include <svx/svdoashp.hxx>
#define BOX2D_SLIDE_SIZE_IN_METERS 100.00f
@@ -62,6 +69,124 @@ b2Vec2 convertB2DPointToBox2DVec2(const basegfx::B2DPoint& aPoint, const double
return { static_cast<float>(aPoint.getX() * fScaleFactor),
static_cast<float>(aPoint.getY() * -fScaleFactor) };
}
+
+// expects rPolygon to have coordinates relative to it's center
+void addTriangleVectorToBody(const basegfx::triangulator::B2DTriangleVector& rTriangleVector,
+ b2Body* aBody, const float fDensity, const float fFriction,
+ const float fRestitution, const double fScaleFactor)
+{
+ for (const basegfx::triangulator::B2DTriangle& aTriangle : rTriangleVector)
+ {
+ b2FixtureDef aFixture;
+ b2PolygonShape aPolygonShape;
+ b2Vec2 aTriangleVertices[3]
+ = { convertB2DPointToBox2DVec2(aTriangle.getA(), fScaleFactor),
+ convertB2DPointToBox2DVec2(aTriangle.getB(), fScaleFactor),
+ convertB2DPointToBox2DVec2(aTriangle.getC(), fScaleFactor) };
+
+ bool bValidPointDistance = true;
+ for (int a = 0; a < 3; a++)
+ {
+ for (int b = 0; b < 3; b++)
+ {
+ if (a == b)
+ continue;
+ if (b2DistanceSquared(aTriangleVertices[a], aTriangleVertices[b]) < 0.003f)
+ {
+ bValidPointDistance = false;
+ }
+ }
+ }
+ if (bValidPointDistance)
+ {
+ aPolygonShape.Set(aTriangleVertices, 3);
+ aFixture.shape = &aPolygonShape;
+ aFixture.density = fDensity;
+ aFixture.friction = fFriction;
+ aFixture.restitution = fRestitution;
+ aBody->CreateFixture(&aFixture);
+ }
+ }
+}
+
+// expects rPolygon to have coordinates relative to it's center
+void addEdgeShapeToBody(const basegfx::B2DPolygon& rPolygon, b2Body* aBody, const float fDensity,
+ const float fFriction, const float fRestitution, const double fScaleFactor)
+{
+ basegfx::B2DPolygon aPolygon = basegfx::utils::removeNeutralPoints(rPolygon);
+ const float fHalfWidth = 0.1;
+ bool bHaveEdgeA = false;
+ b2Vec2 aEdgeBoxVertices[4];
+
+ for (sal_uInt32 nIndex = 0; nIndex < aPolygon.count(); nIndex++)
+ {
+ b2FixtureDef aFixture;
+ b2PolygonShape aPolygonShape;
+
+ basegfx::B2DPoint aPointA;
+ basegfx::B2DPoint aPointB;
+ if (nIndex != 0)
+ {
+ aPointA = aPolygon.getB2DPoint(nIndex - 1);
+ aPointB = aPolygon.getB2DPoint(nIndex);
+ }
+ else if (/* nIndex == 0 && */ aPolygon.isClosed())
+ {
+ // start by connecting the last point to the first one
+ aPointA = aPolygon.getB2DPoint(aPolygon.count() - 1);
+ aPointB = aPolygon.getB2DPoint(nIndex);
+ }
+ else // the polygon isn't closed, won't connect last and first points
+ {
+ continue;
+ }
+
+ b2Vec2 aEdgeUnitVec = (convertB2DPointToBox2DVec2(aPointB, fScaleFactor)
+ - convertB2DPointToBox2DVec2(aPointA, fScaleFactor));
+ aEdgeUnitVec.Normalize();
+
+ b2Vec2 aEdgeNormal(-aEdgeUnitVec.y, aEdgeUnitVec.x);
+
+ if (!bHaveEdgeA)
+ {
+ aEdgeBoxVertices[0]
+ = convertB2DPointToBox2DVec2(aPointA, fScaleFactor) + fHalfWidth * aEdgeNormal;
+ aEdgeBoxVertices[1]
+ = convertB2DPointToBox2DVec2(aPointA, fScaleFactor) + -fHalfWidth * aEdgeNormal;
+ bHaveEdgeA = true;
+ }
+ aEdgeBoxVertices[2]
+ = convertB2DPointToBox2DVec2(aPointB, fScaleFactor) + fHalfWidth * aEdgeNormal;
+ aEdgeBoxVertices[3]
+ = convertB2DPointToBox2DVec2(aPointB, fScaleFactor) + -fHalfWidth * aEdgeNormal;
+
+ bool bValidPointDistance
+ = (b2DistanceSquared(aEdgeBoxVertices[0], aEdgeBoxVertices[2]) > 0.003f);
+
+ if (bValidPointDistance)
+ {
+ aPolygonShape.Set(aEdgeBoxVertices, 4);
+ aFixture.shape = &aPolygonShape;
+ aFixture.density = fDensity;
+ aFixture.friction = fFriction;
+ aFixture.restitution = fRestitution;
+ aBody->CreateFixture(&aFixture);
+
+ aEdgeBoxVertices[0] = aEdgeBoxVertices[2];
+ aEdgeBoxVertices[1] = aEdgeBoxVertices[3];
+ }
+ }
+}
+
+void addEdgeShapeToBody(const basegfx::B2DPolyPolygon& rPolyPolygon, b2Body* aBody,
+ const float fDensity, const float fFriction, const float fRestitution,
+ const double fScaleFactor)
+{
+ for (const basegfx::B2DPolygon& rPolygon : rPolyPolygon)
+ {
+ addEdgeShapeToBody(rPolygon, aBody, fDensity, fFriction, fRestitution, fScaleFactor);
+ }
+}
}
box2DWorld::box2DWorld(const ::basegfx::B2DVector& rSlideSize)
@@ -224,7 +349,9 @@ void box2DWorld::initateAllShapesAsStaticBodies(
slideshow::internal::ShapeSharedPtr pShape = aIt->second;
if (pShape->isForeground())
{
- Box2DBodySharedPtr pBox2DBody = createStaticBodyFromBoundingBox(pShape);
+ Box2DBodySharedPtr pBox2DBody;
+ pBox2DBody = createStaticBody(pShape);
+
mpXShapeToBodyMap.insert(std::make_pair(pShape->getXShape(), pBox2DBody));
if (!pShape->isVisible())
{
@@ -352,14 +479,12 @@ Box2DBodySharedPtr box2DWorld::makeBodyStatic(const Box2DBodySharedPtr pBox2DBod
return pBox2DBody;
}
-Box2DBodySharedPtr
-box2DWorld::createStaticBodyFromBoundingBox(const slideshow::internal::ShapeSharedPtr& rShape,
- const float fDensity, const float fFriction)
+Box2DBodySharedPtr box2DWorld::createStaticBody(const slideshow::internal::ShapeSharedPtr& rShape,
+ const float fDensity, const float fFriction)
{
assert(mpBox2DWorld);
+
::basegfx::B2DRectangle aShapeBounds = rShape->getBounds();
- double fShapeWidth = aShapeBounds.getWidth() * mfScaleFactor;
- double fShapeHeight = aShapeBounds.getHeight() * mfScaleFactor;
b2BodyDef aBodyDef;
aBodyDef.type = b2_staticBody;
@@ -369,16 +494,63 @@ box2DWorld::createStaticBodyFromBoundingBox(const slideshow::internal::ShapeShar
pB2Body->GetWorld()->DestroyBody(pB2Body);
});
- b2PolygonShape aDynamicBox;
- aDynamicBox.SetAsBox(static_cast<float>(fShapeWidth / 2), static_cast<float>(fShapeHeight / 2));
+ SdrObject* pSdrObject = SdrObject::getSdrObjectFromXShape(rShape->getXShape());
- b2FixtureDef aFixtureDef;
- aFixtureDef.shape = &aDynamicBox;
- aFixtureDef.density = fDensity;
- aFixtureDef.friction = fFriction;
- aFixtureDef.restitution = 0.1f;
+ auto aShapeType = rShape->getXShape()->getShapeType();
+
+ basegfx::B2DPolyPolygon aPolyPolygon;
+ // workaround:
+ // TakeXorPoly() doesn't return beziers for CustomShapes and we want the beziers
+ // so that we can decide the complexity of the polygons generated from them
+ if (aShapeType == "com.sun.star.drawing.CustomShape")
+ {
+ aPolyPolygon = static_cast<SdrObjCustomShape*>(pSdrObject)->GetLineGeometry(true);
+ }
+ else
+ {
+ aPolyPolygon = pSdrObject->TakeXorPoly();
+ }
+
+ // make beziers into polygons, using a high degree angle as fAngleBound in
+ // adaptiveSubdivideByAngle reduces complexity of the resulting polygon shapes
+ aPolyPolygon = aPolyPolygon.areControlPointsUsed()
+ ? basegfx::utils::adaptiveSubdivideByAngle(aPolyPolygon, 20)
+ : aPolyPolygon;
+ aPolyPolygon.removeDoublePoints();
+
+ // make polygon coordinates relative to the center of the shape instead of top left of the slide
+ aPolyPolygon
+ = basegfx::utils::distort(aPolyPolygon, aPolyPolygon.getB2DRange(),
+ { -aShapeBounds.getWidth() / 2, -aShapeBounds.getHeight() / 2 },
+ { aShapeBounds.getWidth() / 2, -aShapeBounds.getHeight() / 2 },
+ { -aShapeBounds.getWidth() / 2, aShapeBounds.getHeight() / 2 },
+ { aShapeBounds.getWidth() / 2, aShapeBounds.getHeight() / 2 });
+
+ if (pSdrObject->IsClosedObj() && !pSdrObject->IsEdgeObj() && pSdrObject->HasFillStyle())
+ {
+ basegfx::triangulator::B2DTriangleVector aTriangleVector;
+ for (auto& rPolygon : aPolyPolygon)
+ {
+ if (rPolygon.isClosed())
+ {
+ basegfx::triangulator::B2DTriangleVector aTempTriangleVector(
+ basegfx::triangulator::triangulate(rPolygon));
+ aTriangleVector.insert(aTriangleVector.end(), aTempTriangleVector.begin(),
+ aTempTriangleVector.end());
+ }
+ else
+ {
+ addEdgeShapeToBody(rPolygon, pBody.get(), fDensity, fFriction, 0.1f, mfScaleFactor);
+ }
+ }
+ addTriangleVectorToBody(aTriangleVector, pBody.get(), fDensity, fFriction, 0.1f,
+ mfScaleFactor);
+ }
+ else
+ {
+ addEdgeShapeToBody(aPolyPolygon, pBody.get(), fDensity, fFriction, 0.1f, mfScaleFactor);
+ }
- pBody->CreateFixture(&aFixtureDef);
return std::make_shared<box2DBody>(pBody, mfScaleFactor);
}
@@ -415,7 +587,6 @@ void box2DBody::setAngleByAngularVelocity(const double fDesiredAngle, const doub
double fDeltaAngle = fDesiredAngle - getAngle();
- // temporary hack for repeating animation effects
while (fDeltaAngle > 180
|| fDeltaAngle < -180) // if it is bigger than 180 opposite rotation is actually closer
fDeltaAngle += fDeltaAngle > 0 ? -360 : +360;
diff --git a/slideshow/source/inc/box2dtools.hxx b/slideshow/source/inc/box2dtools.hxx
index 0824a3c260c5..a468b886fcba 100644
--- a/slideshow/source/inc/box2dtools.hxx
+++ b/slideshow/source/inc/box2dtools.hxx
@@ -213,10 +213,9 @@ public:
*/
Box2DBodySharedPtr makeBodyStatic(const Box2DBodySharedPtr pBox2DBody);
- /// Create a static body from the given shape's bounding box
- Box2DBodySharedPtr
- createStaticBodyFromBoundingBox(const slideshow::internal::ShapeSharedPtr& rShape,
- const float fDensity = 1.0f, const float fFriction = 0.3f);
+ /// Create a static body from the given shape's geometry
+ Box2DBodySharedPtr createStaticBody(const slideshow::internal::ShapeSharedPtr& rShape,
+ const float fDensity = 1.0f, const float fFriction = 0.3f);
/// Initiate all the shapes in the current slide in the box2DWorld as static ones
void
More information about the Libreoffice-commits
mailing list