[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