Rebased ref, commits from common ancestor:
commit 803c9170806f3f54a6169887b65ebc05f84b4c82
Author:     Sarper Akdemir <q.sarperakde...@gmail.com>
AuthorDate: Mon Jul 27 23:02:48 2020 +0300
Commit:     Sarper Akdemir <q.sarperakde...@gmail.com>
CommitDate: Tue Aug 4 19:12:44 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..90f1d1853dba 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,8 @@ void box2DWorld::initateAllShapesAsStaticBodies(
         slideshow::internal::ShapeSharedPtr pShape = aIt->second;
         if (pShape->isForeground())
         {
-            Box2DBodySharedPtr pBox2DBody = 
createStaticBodyFromBoundingBox(pShape);
+            Box2DBodySharedPtr pBox2DBody = createStaticBody(pShape);
+
             mpXShapeToBodyMap.insert(std::make_pair(pShape->getXShape(), 
pBox2DBody));
             if (!pShape->isVisible())
             {
@@ -352,14 +478,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 +493,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 +586,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
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to