summaryrefslogtreecommitdiffstats
path: root/src/mechanics/mechanicsitem.h
blob: db500fc92dbaf1bac33156715833f634499d84df (plain)
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
/***************************************************************************
 *   Copyright (C) 2004-2005 by David Saxton                               *
 *   [email protected]                                                    *
 *                                                                         *
 *   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.                                   *
 ***************************************************************************/

#ifndef MECHANICSITEM_H
#define MECHANICSITEM_H

#include <item.h>
#include <qvaluelist.h>

class LibraryItem;
class MechanicsItem;
// class MechanicsItemOverlayItem;
class MechanicsDocument;
typedef QValueList<MechanicsItem*> MechanicsItemList;

/**
@short Stores mass, moment of inertia
@author David Saxton
*/
class MechanicsInfo
{
public:
	MechanicsInfo();
	
	double mass; // Mass
	double momentOfInertia; // Moment of inertia
};

class CombinedMechanicsInfo : public MechanicsInfo
{
public:
	CombinedMechanicsInfo();
	CombinedMechanicsInfo( const MechanicsInfo &info );
	
	double x; // X coordinate of center of mass
	double y; // Y coordinate of center of mass
};

/**
@short Stores a position and orientation
@author David Saxton
*/
class PositionInfo
{
public:
	PositionInfo();
	/**
	 * Adds together two positions: for this=PARENT +(CHILD), the new position
	 * is formed by translating this position by that of the CHILDs
	 * translation, and then rotating everything about the center of this item
	 */
	const PositionInfo operator+( const PositionInfo &info );
	/**
	 * Not quite the inverse of operator+. Subtracts the given position info
	 * as if it was applied before this current info.
	 */
	const PositionInfo operator-( const PositionInfo &info );
	/**
	 * x position (0 is left)
	 */
	double x() const { return m_x; }
	/**
	 * y position (0 is top)
	 */
	double y() const { return m_y; }
	/**
	 * Angle in radians, positive direction is anticlockwise
	 */
	double angle() const { return m_angle; }
	/**
	 * Sets the x-position
	 */
	void setX( double x ) { m_x = x; }
	/**
	 * Sets the y-position
	 */
	void setY( double y ) { m_y = y; }
	/**
	 * Sets the angle
	 */
	void setAngle( double angle ) { m_angle = angle; }
	/**
	 * Adds (x,y) to the current position
	 */
	void translate( double dx, const double dy ) { m_x += dx; m_y += dy; }
	/**
	 * Rotates anticlockwise by the given amount (in radians)
	 */
	void rotate( double angle ) { m_angle += angle; }
	/**
	 * Resets the position to (0,0), and the orientation to 0
	 */
	void reset();
	/**
	 * Rotates the current position about the given point through the given
	 * angle in radians anticlockwise. This will change the position and
	 * orientation.
	 */
	void rotateAboutPoint( double x, double y, double angle );
	
protected:
	double m_x;
	double m_y;
	double m_angle;
};


/**
@author David Saxton
*/
class MechanicsItem : public Item
{
Q_OBJECT
public:
	MechanicsItem( MechanicsDocument *mechanicsDocument, bool newItem, const QString &id );
	virtual ~MechanicsItem();
	
	enum SelectionMode
	{
		sm_move,
		sm_resize,
		sm_rotate
	};
	/**
	 * Returns the run-time identifier for the MechanicsItem
	 */
	int rtti() const;
	/**
	 * Sets the selection mode (sm_resize or sm_rotate). Note that setSelected
	 * also needs to be called to select the item.
	 */
	void setSelectionMode( SelectionMode sm );
	virtual void setSelected( bool yes );
	/**
	 * @returns the selection mode
	 */
	SelectionMode selectionMode() const { return m_selectionMode; }
	/**
	 * Move the MechanicsItem by the given amount
	 */
	virtual void moveBy( double dx, double dy );
	/**
	 * Returns the absolute position on the canvas
	 */
	PositionInfo absolutePosition() const;
	/**
	 * Returns the position relative to the parent item (or the absolute
	 * position if there is no parent item)
	 */
	PositionInfo relativePosition() const { return m_relativePosition; }
	/**
	 * Returns the mechanics info for this item (so not taking into account that
	 * of attached children)
	 */
	MechanicsInfo *mechanicsInfo() { return &m_mechanicsInfo; }
	/**
	 * Returns the combined mechanics info for this item (which takes into
	 * account that of attached children).
	 */
	CombinedMechanicsInfo *mechanicsInfoCombined() { return &m_mechanicsInfoCombined; }
	/**
	 * Returns the rectangle that can legitimately fit inside the given bounding
	 * rectangle, given this items current rotation. Legitimately means that
	 * whether this item is allowed to be distorted, inverted, resized, etc.
	 */
	QRect maxInnerRectangle( const QRect &outerRect ) const;
	
	virtual ItemData itemData() const;
	
	virtual bool mousePressEvent( const EventInfo &eventInfo );
	virtual bool mouseReleaseEvent( const EventInfo &eventInfo );
	virtual bool mouseDoubleClickEvent ( const EventInfo &eventInfo );
	virtual bool mouseMoveEvent( const EventInfo &eventInfo );
	virtual bool wheelEvent( const EventInfo &eventInfo );
	virtual void enterEvent();
	virtual void leaveEvent();
	
public slots:
	/**
	 * Rotate the item by the given amount (in radians)
	 */
	void rotateBy( double dtheta );
	void parentMoved();
	 
signals:
	/**
	 * Emitted when this item moves (translates or rotates)
	 */
	void moved();
	
protected slots:
	/**
	 * Recalculate the combined mechanics info (e.g. when mass is changed, or child added)
	 */
	void updateMechanicsInfoCombined();
	
protected:
	virtual void reparented( Item *oldItem, Item *newItem );
	virtual void childAdded( Item *child );
	virtual void childRemoved( Item *child );
	/**
	 * Called when this item is resized, so that sub classes can do whatever
	 */
	virtual void itemResized() {};
	/**
	 * Sets the correct orientation on the painter
	 */
	void initPainter( QPainter &p );
	/**
	 * *Must* be called after calling initPainter, if initPainter was called
	 */
	void deinitPainter( QPainter &p );
	virtual void dataChanged();
	virtual void itemPointsChanged() { updateCanvasPoints(); }
	/**
	 * Calculates the setPoints required from the current m_itemPoints and the
	 * current position / angle
	 */
	void updateCanvasPoints();
	
	MechanicsDocument *p_mechanicsDocument;
	PositionInfo m_relativePosition; // Absolution position if not attached to a parent item, or otherwise relative to parent item
	MechanicsInfo m_mechanicsInfo;
	CombinedMechanicsInfo m_mechanicsInfoCombined;
	
private:
	SelectionMode m_selectionMode;
};

#endif