Rebased ref, commits from common ancestor: commit 61bff7181ce0a02852530b8d3370ac4b5a026c65 Author: Sarper Akdemir <q.sarperakde...@gmail.com> AuthorDate: Mon Jul 27 23:02:48 2020 +0300 Commit: Sarper Akdemir <q.sarperakde...@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); _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits