[Libreoffice-commits] core.git: Branch 'private/quwex/gsoc-box2d-experimental' - slideshow/source

Sarper Akdemir (via logerrit) logerrit at kemper.freedesktop.org
Wed Jul 29 00:00:55 UTC 2020


Rebased ref, commits from common ancestor:
commit 61bff7181ce0a02852530b8d3370ac4b5a026c65
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: Wed Jul 29 02:59:54 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..0e774230800e 100644
--- a/slideshow/source/engine/box2dtools.cxx
+++ b/slideshow/source/engine/box2dtools.cxx
@@ -11,6 +11,14 @@
 #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 <o3tl/any.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdoashp.hxx>
 
 #define BOX2D_SLIDE_SIZE_IN_METERS 100.00f
 
@@ -62,6 +70,55 @@ b2Vec2 convertB2DPointToBox2DVec2(const basegfx::B2DPoint& aPoint, const double
     return { static_cast<float>(aPoint.getX() * fScaleFactor),
              static_cast<float>(aPoint.getY() * -fScaleFactor) };
 }
+
+void addTriangleVectorToBody(const basegfx::triangulator::B2DTriangleVector& rTriangleVector,
+                             b2Body* aBody, const basegfx::B2DRange& rShapeBounds,
+                             const float fDensity, const float fFriction, const float fRestitution,
+                             const double fScaleFactor)
+{
+    // aAdjustCenter is used to make coordinates relative to center of the shape instead of top left
+    basegfx::B2DPoint aAdjustCenter(rShapeBounds.getWidth() / 2, rShapeBounds.getHeight() / 2);
+    for (const basegfx::triangulator::B2DTriangle& aTriangle : rTriangleVector)
+    {
+        b2FixtureDef aFixture;
+        b2PolygonShape aPolygonShape;
+        b2Vec2 aTriangleVertices[3];
+        basegfx::B2DPoint aTriangleVertice = aTriangle.getA() - aAdjustCenter;
+        // putting the operation in place of aTriangleVertice creates weird behavior and i dont know why
+        aTriangleVertices[0] = convertB2DPointToBox2DVec2(aTriangleVertice, fScaleFactor);
+        aTriangleVertice = aTriangle.getB() - aAdjustCenter;
+        aTriangleVertices[1] = convertB2DPointToBox2DVec2(aTriangleVertice, fScaleFactor);
+        aTriangleVertice = aTriangle.getC() - aAdjustCenter;
+        aTriangleVertices[2] = convertB2DPointToBox2DVec2(aTriangleVertice, fScaleFactor);
+
+        // FIXME: weird bug when using a bezier curve with >10 vertices
+        // turns out bug was happening when there are triangles that have really close points
+        // box2d marks those as degenerate ones, and stops working, so we will just ignore
+        // really tiny triangles
+        bool bValidSizedTriangle = 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)
+                {
+                    bValidSizedTriangle = false;
+                }
+            }
+        }
+        if (bValidSizedTriangle)
+        {
+            aPolygonShape.Set(aTriangleVertices, 3);
+            aFixture.shape = &aPolygonShape;
+            aFixture.density = fDensity;
+            aFixture.friction = fFriction;
+            aFixture.restitution = fRestitution;
+            aBody->CreateFixture(&aFixture);
+        }
+    }
+}
 }
 
 box2DWorld::box2DWorld(const ::basegfx::B2DVector& rSlideSize)
@@ -224,7 +281,19 @@ void box2DWorld::initateAllShapesAsStaticBodies(
         slideshow::internal::ShapeSharedPtr pShape = aIt->second;
         if (pShape->isForeground())
         {
-            Box2DBodySharedPtr pBox2DBody = createStaticBodyFromBoundingBox(pShape);
+            Box2DBodySharedPtr pBox2DBody;
+
+            auto aShapeType = pShape->getXShape()->getShapeType();
+
+            if (aShapeType == "com.sun.star.drawing.PolyPolygonShape")
+                pBox2DBody = createStaticBodyFromPolygonShape(pShape);
+            else if (aShapeType == "com.sun.star.drawing.ClosedBezierShape")
+                pBox2DBody = createStaticBodyFromBezierShape(pShape);
+            else if (aShapeType == "com.sun.star.drawing.CustomShape")
+                pBox2DBody = createStaticBodyFromCustomShape(pShape);
+            else
+                pBox2DBody = createStaticBodyFromBoundingBox(pShape);
+
             mpXShapeToBodyMap.insert(std::make_pair(pShape->getXShape(), pBox2DBody));
             if (!pShape->isVisible())
             {
@@ -357,6 +426,7 @@ box2DWorld::createStaticBodyFromBoundingBox(const slideshow::internal::ShapeShar
                                             const float fDensity, const float fFriction)
 {
     assert(mpBox2DWorld);
+
     ::basegfx::B2DRectangle aShapeBounds = rShape->getBounds();
     double fShapeWidth = aShapeBounds.getWidth() * mfScaleFactor;
     double fShapeHeight = aShapeBounds.getHeight() * mfScaleFactor;
@@ -382,6 +452,119 @@ box2DWorld::createStaticBodyFromBoundingBox(const slideshow::internal::ShapeShar
     return std::make_shared<box2DBody>(pBody, mfScaleFactor);
 }
 
+Box2DBodySharedPtr
+box2DWorld::createStaticBodyFromCustomShape(const slideshow::internal::ShapeSharedPtr& rShape,
+                                            const float fDensity, const float fFriction)
+{
+    assert(mpBox2DWorld);
+
+    ::basegfx::B2DRectangle aShapeBounds = rShape->getBounds();
+
+    SdrObjCustomShape* drawObject
+        = static_cast<SdrObjCustomShape*>(SdrObject::getSdrObjectFromXShape(rShape->getXShape()));
+    basegfx::B2DPolyPolygon aPolyPolygon = drawObject->GetLineGeometry(true);
+    aPolyPolygon = basegfx::utils::distort(
+        aPolyPolygon, aPolyPolygon.getB2DRange(), { 0, 0 }, { aShapeBounds.getWidth(), 0 },
+        { 0, aShapeBounds.getHeight() }, { aShapeBounds.getWidth(), aShapeBounds.getHeight() });
+
+    b2BodyDef aBodyDef;
+    aBodyDef.type = b2_staticBody;
+    aBodyDef.position = convertB2DPointToBox2DVec2(aShapeBounds.getCenter(), mfScaleFactor);
+
+    std::shared_ptr<b2Body> pBody(mpBox2DWorld->CreateBody(&aBodyDef), [](b2Body* pB2Body) {
+        pB2Body->GetWorld()->DestroyBody(pB2Body);
+    });
+
+    //    // triangulating the B2DPolyPolygon is problematic with custom shapes, some shapes lose polygon
+    //    //   will debug it later... - think it happens when an edge is shared by exactly two B2DPolygons -
+    //    basegfx::triangulator::B2DTriangleVector aTriangleVector
+    //        = basegfx::triangulator::triangulate(aPolyPolygon);
+
+    // workaround for now - split the polygons and triangulate each one seperately
+    // causes a big performance loss (apparent when there are >9 curved bodies)
+    // - either way a simplification algorithm will help greatly with performance -
+    basegfx::triangulator::B2DTriangleVector aTriangleVector;
+    for (auto& rPolygon : aPolyPolygon)
+    {
+        basegfx::triangulator::B2DTriangleVector aTempTriangleVector(
+            basegfx::triangulator::triangulate(rPolygon));
+        aTriangleVector.insert(aTriangleVector.end(), aTempTriangleVector.begin(),
+                               aTempTriangleVector.end());
+    }
+    addTriangleVectorToBody(aTriangleVector, pBody.get(), aPolyPolygon.getB2DRange(), fDensity,
+                            fFriction, 0.1f, mfScaleFactor);
+
+    return std::make_shared<box2DBody>(pBody, mfScaleFactor);
+}
+
+Box2DBodySharedPtr
+box2DWorld::createStaticBodyFromPolygonShape(const slideshow::internal::ShapeSharedPtr& rShape,
+                                             const float fDensity, const float fFriction)
+{
+    assert(mpBox2DWorld);
+
+    ::basegfx::B2DRectangle aShapeBounds = rShape->getBounds();
+
+    b2BodyDef aBodyDef;
+    aBodyDef.type = b2_staticBody;
+    aBodyDef.position = convertB2DPointToBox2DVec2(aShapeBounds.getCenter(), mfScaleFactor);
+
+    std::shared_ptr<b2Body> pBody(mpBox2DWorld->CreateBody(&aBodyDef), [](b2Body* pB2Body) {
+        pB2Body->GetWorld()->DestroyBody(pB2Body);
+    });
+
+    // triangulate and add the geometry to box2d body
+    css::uno::Reference<css::drawing::XShape> xShape = rShape->getXShape();
+    const css::uno::Reference<css::beans::XPropertySet> xPropSet(xShape, css::uno::UNO_QUERY);
+    assert(xPropSet.is());
+
+    css::uno::Any aAny(xPropSet->getPropertyValue("Geometry"));
+    const basegfx::B2DPolyPolygon aPolyPolygon(
+        ::basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon(
+            *o3tl::doAccess<css::drawing::PointSequenceSequence>(aAny)));
+
+    // FIXME: Right now skewed/rotated shapes are not handled properly, should get and apply transformation etc to the polygon
+    basegfx::triangulator::B2DTriangleVector aTriangleVector
+        = basegfx::triangulator::triangulate(aPolyPolygon);
+    addTriangleVectorToBody(aTriangleVector, pBody.get(), aPolyPolygon.getB2DRange(), fDensity,
+                            fFriction, 0.1f, mfScaleFactor);
+    return std::make_shared<box2DBody>(pBody, mfScaleFactor);
+}
+
+Box2DBodySharedPtr
+box2DWorld::createStaticBodyFromBezierShape(const slideshow::internal::ShapeSharedPtr& rShape,
+                                            const float fDensity, const float fFriction)
+{
+    assert(mpBox2DWorld);
+
+    ::basegfx::B2DRectangle aShapeBounds = rShape->getBounds();
+
+    b2BodyDef aBodyDef;
+    aBodyDef.type = b2_staticBody;
+    aBodyDef.position = convertB2DPointToBox2DVec2(aShapeBounds.getCenter(), mfScaleFactor);
+
+    std::shared_ptr<b2Body> pBody(mpBox2DWorld->CreateBody(&aBodyDef), [](b2Body* pB2Body) {
+        pB2Body->GetWorld()->DestroyBody(pB2Body);
+    });
+
+    // triangulate and add the geometry to box2d body
+    css::uno::Reference<css::drawing::XShape> xShape = rShape->getXShape();
+    const css::uno::Reference<css::beans::XPropertySet> xPropSet(xShape, css::uno::UNO_QUERY);
+    assert(xPropSet.is());
+
+    css::uno::Any aAny(xPropSet->getPropertyValue("Geometry"));
+    const basegfx::B2DPolyPolygon aPolyPolygon(
+        ::basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon(
+            *o3tl::doAccess<css::drawing::PolyPolygonBezierCoords>(aAny)));
+
+    // FIXME: Right now skewed/rotated shapes are not handled properly, should get and apply transformation etc to the polygon
+    basegfx::triangulator::B2DTriangleVector aTriangleVector
+        = basegfx::triangulator::triangulate(aPolyPolygon);
+    addTriangleVectorToBody(aTriangleVector, pBody.get(), aPolyPolygon.getB2DRange(), fDensity,
+                            fFriction, 0.1f, mfScaleFactor);
+    return std::make_shared<box2DBody>(pBody, mfScaleFactor);
+}
+
 box2DBody::box2DBody(std::shared_ptr<b2Body> pBox2DBody, double fScaleFactor)
     : mpBox2DBody(pBox2DBody)
     , mfScaleFactor(fScaleFactor)
diff --git a/slideshow/source/inc/box2dtools.hxx b/slideshow/source/inc/box2dtools.hxx
index 0824a3c260c5..81fc2c6bf226 100644
--- a/slideshow/source/inc/box2dtools.hxx
+++ b/slideshow/source/inc/box2dtools.hxx
@@ -218,6 +218,18 @@ public:
     createStaticBodyFromBoundingBox(const slideshow::internal::ShapeSharedPtr& rShape,
                                     const float fDensity = 1.0f, const float fFriction = 0.3f);
 
+    Box2DBodySharedPtr
+    createStaticBodyFromCustomShape(const slideshow::internal::ShapeSharedPtr& rShape,
+                                    const float fDensity = 1.0f, const float fFriction = 0.3f);
+
+    Box2DBodySharedPtr
+    createStaticBodyFromPolygonShape(const slideshow::internal::ShapeSharedPtr& rShape,
+                                     const float fDensity = 1.0f, const float fFriction = 0.3f);
+
+    Box2DBodySharedPtr
+    createStaticBodyFromBezierShape(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
     initateAllShapesAsStaticBodies(const slideshow::internal::ShapeManagerSharedPtr pShapeManager);


More information about the Libreoffice-commits mailing list