1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
/*
Copyright 2008-2010 Stefan Majewsky <majewsky@gmx.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef KOLF_SHAPE_H
#define KOLF_SHAPE_H
#include <QPainterPath>
class b2Body;
class b2Fixture;
struct b2FixtureDef;
class b2Shape;
class CanvasItem;
namespace Kolf
{
//All coordinates and units of Kolf's coordinate system are internally
//scaled with the following factor before using them with Box2D, because
//Box2D works best with lengths between 0.1 and 10 metres.
static const qreal Box2DScaleFactor = 0.025;
/**
* @class Kolf::Shape
*
* This class represents a part of the shape of an item. Simple objects can be represented by a single shape (e.g. boxes and spheres), while complex objects may have to be constructed with multiple shapes.
*/
class Shape
{
Q_DISABLE_COPY(Shape)
private:
enum TraitBits
{
CollisionDetectionFlag = 1 << 0,
PhysicalSimulationFlag = 1 << 1
};
public:
///Defines how a shape behaves.
enum Trait
{
///This shape is not represented in the physics engine in any way. It only provides an activation and interaction area for the editor interface.
VirtualShape = 0,
///During each step of the physical simulation, this shape is checked for intersections with other shapes, and the registered Kolf::ContactCallback methods are called as appropriate.
ParticipatesInCollisionDetection = CollisionDetectionFlag,
///The shape behaves like physical matter, i.e. it allows the body to move and interact with other bodies through collisions.
ParticipatesInPhysicalSimulation = CollisionDetectionFlag | PhysicalSimulationFlag
};
Q_DECLARE_FLAGS(Traits, Trait)
///@warning Any subclass constructor *must* call update() before it exits.
Shape();
virtual ~Shape();
///Returns how this shape behaves.
Kolf::Shape::Traits traits() const;
///Configures the behavior of this shape.
void setTraits(Kolf::Shape::Traits traits);
///Returns the two-dimensional activation outline, i.e. the area of this geometry (plus some defined padding). The editor overlay is supposed to activate the editor interface of the object associated with this geometry, if a mouse click occurs inside the activation outline.
///@see ActivationOutlinePadding
QPainterPath activationOutline() const;
///Returns the two-dimensional interaction outline, i.e. the exact outline of this geometry. The editor overlay is supposed to move the object associated with this geometry, if the mouse is clicked inside the interaction outline and then dragged.
///@note The interaction outline is allowed to be greater than the object's exact shape for the sake of usability (e.g. a diagonal wall cannot be precisely hit with a mouse cursor).
QPainterPath interactionOutline() const;
protected:
friend class ::CanvasItem; //for the following method
///Binds this shape to the given @a item. Will fail if this shape is already bound to some item.
bool attach(CanvasItem* item);
///Call this method when the parameters of this geometry change (usually in setter methods of the subclass).
void update();
///Reimplement this method to provide a new b2Shape instance based on the current configuration of the shape.
///@warning Stuff will break if you return a null pointer.
virtual b2Shape* createShape() = 0;
///Reimplement this method to create the outlines of this geometry and pass them to the caller via the arguments. You will not have to call this function in subclass implementations, it's invoked by Kolf::Geometry::update.
virtual void createOutlines(QPainterPath& activationOutline, QPainterPath& interactionOutline) = 0;
///Use this padding as distance between the exact InteractionOutline and the fuzzy ActivationOutline.
static const qreal ActivationOutlinePadding;
private:
///A submethod of update().
void updateFixture(b2Shape* newShape);
private:
Kolf::Shape::Traits m_traits;
CanvasItem* m_citem;
b2Body* m_body;
b2FixtureDef* m_fixtureDef;
b2Fixture* m_fixture;
b2Shape* m_shape;
QPainterPath m_activationOutline, m_interactionOutline;
};
class EllipseShape : public Kolf::Shape
{
public:
explicit EllipseShape(const QRectF& rect);
QRectF rect() const;
void setRect(const QRectF& rect);
protected:
b2Shape* createShape() Q_DECL_OVERRIDE;
void createOutlines(QPainterPath& activationOutline, QPainterPath& interactionOutline) Q_DECL_OVERRIDE;
private:
QRectF m_rect;
};
class RectShape : public Kolf::Shape
{
public:
explicit RectShape(const QRectF& rect);
QRectF rect() const;
void setRect(const QRectF& rect);
protected:
b2Shape* createShape() Q_DECL_OVERRIDE;
void createOutlines(QPainterPath& activationOutline, QPainterPath& interactionOutline) Q_DECL_OVERRIDE;
private:
QRectF m_rect;
};
class LineShape : public Kolf::Shape
{
public:
explicit LineShape(const QLineF& line);
QLineF line() const;
void setLine(const QLineF& line);
protected:
b2Shape* createShape() Q_DECL_OVERRIDE;
void createOutlines(QPainterPath& activationOutline, QPainterPath& interactionOutline) Q_DECL_OVERRIDE;
private:
QLineF m_line;
};
}
Q_DECLARE_OPERATORS_FOR_FLAGS(Kolf::Shape::Traits)
#endif // KOLF_SHAPE_H
|