File indexing completed on 2024-12-08 08:10:33

0001 /***************************************************************************
0002  *   Copyright (C) 2004-2005 by David Saxton                               *
0003  *   david@bluehaze.org                                                    *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  ***************************************************************************/
0010 
0011 #ifndef MECHANICSITEM_H
0012 #define MECHANICSITEM_H
0013 
0014 #include <QList>
0015 #include <item.h>
0016 
0017 class LibraryItem;
0018 class MechanicsItem;
0019 // class MechanicsItemOverlayItem;
0020 class MechanicsDocument;
0021 typedef QList<MechanicsItem *> MechanicsItemList;
0022 
0023 /**
0024 @short Stores mass, moment of inertia
0025 @author David Saxton
0026 */
0027 class MechanicsInfo
0028 {
0029 public:
0030     MechanicsInfo();
0031 
0032     double mass;            // Mass
0033     double momentOfInertia; // Moment of inertia
0034 };
0035 
0036 class CombinedMechanicsInfo : public MechanicsInfo
0037 {
0038 public:
0039     CombinedMechanicsInfo();
0040     CombinedMechanicsInfo(const MechanicsInfo &info);
0041 
0042     double x; // X coordinate of center of mass
0043     double y; // Y coordinate of center of mass
0044 };
0045 
0046 /**
0047 @short Stores a position and orientation
0048 @author David Saxton
0049 */
0050 class PositionInfo
0051 {
0052 public:
0053     PositionInfo();
0054     /**
0055      * Adds together two positions: for this=PARENT +(CHILD), the new position
0056      * is formed by translating this position by that of the CHILDs
0057      * translation, and then rotating everything about the center of this item
0058      */
0059     const PositionInfo operator+(const PositionInfo &info);
0060     /**
0061      * Not quite the inverse of operator+. Subtracts the given position info
0062      * as if it was applied before this current info.
0063      */
0064     const PositionInfo operator-(const PositionInfo &info);
0065     /**
0066      * x position (0 is left)
0067      */
0068     double x() const
0069     {
0070         return m_x;
0071     }
0072     /**
0073      * y position (0 is top)
0074      */
0075     double y() const
0076     {
0077         return m_y;
0078     }
0079     /**
0080      * Angle in radians, positive direction is anticlockwise
0081      */
0082     double angle() const
0083     {
0084         return m_angle;
0085     }
0086     /**
0087      * Sets the x-position
0088      */
0089     void setX(double x)
0090     {
0091         m_x = x;
0092     }
0093     /**
0094      * Sets the y-position
0095      */
0096     void setY(double y)
0097     {
0098         m_y = y;
0099     }
0100     /**
0101      * Sets the angle
0102      */
0103     void setAngle(double angle)
0104     {
0105         m_angle = angle;
0106     }
0107     /**
0108      * Adds (x,y) to the current position
0109      */
0110     void translate(double dx, const double dy)
0111     {
0112         m_x += dx;
0113         m_y += dy;
0114     }
0115     /**
0116      * Rotates anticlockwise by the given amount (in radians)
0117      */
0118     void rotate(double angle)
0119     {
0120         m_angle += angle;
0121     }
0122     /**
0123      * Resets the position to (0,0), and the orientation to 0
0124      */
0125     void reset();
0126     /**
0127      * Rotates the current position about the given point through the given
0128      * angle in radians anticlockwise. This will change the position and
0129      * orientation.
0130      */
0131     void rotateAboutPoint(double x, double y, double angle);
0132 
0133 protected:
0134     double m_x;
0135     double m_y;
0136     double m_angle;
0137 };
0138 
0139 /**
0140 @author David Saxton
0141 */
0142 class MechanicsItem : public Item
0143 {
0144     Q_OBJECT
0145 public:
0146     MechanicsItem(MechanicsDocument *mechanicsDocument, bool newItem, const QString &id);
0147     ~MechanicsItem() override;
0148 
0149     enum SelectionMode { sm_move, sm_resize, sm_rotate };
0150     /**
0151      * Sets the selection mode (sm_resize or sm_rotate). Note that setSelected
0152      * also needs to be called to select the item.
0153      */
0154     void setSelectionMode(SelectionMode sm);
0155     void setSelected(bool yes) override;
0156     /**
0157      * @returns the selection mode
0158      */
0159     SelectionMode selectionMode() const
0160     {
0161         return m_selectionMode;
0162     }
0163     /**
0164      * Move the MechanicsItem by the given amount
0165      */
0166     void moveBy(double dx, double dy) override;
0167     /**
0168      * Returns the absolute position on the canvas
0169      */
0170     PositionInfo absolutePosition() const;
0171     /**
0172      * Returns the position relative to the parent item (or the absolute
0173      * position if there is no parent item)
0174      */
0175     PositionInfo relativePosition() const
0176     {
0177         return m_relativePosition;
0178     }
0179     /**
0180      * Returns the mechanics info for this item (so not taking into account that
0181      * of attached children)
0182      */
0183     MechanicsInfo *mechanicsInfo()
0184     {
0185         return &m_mechanicsInfo;
0186     }
0187     /**
0188      * Returns the combined mechanics info for this item (which takes into
0189      * account that of attached children).
0190      */
0191     CombinedMechanicsInfo *mechanicsInfoCombined()
0192     {
0193         return &m_mechanicsInfoCombined;
0194     }
0195     /**
0196      * Returns the rectangle that can legitimately fit inside the given bounding
0197      * rectangle, given this items current rotation. Legitimately means that
0198      * whether this item is allowed to be distorted, inverted, resized, etc.
0199      */
0200     QRect maxInnerRectangle(const QRect &outerRect) const;
0201 
0202     ItemData itemData() const override;
0203 
0204     bool mousePressEvent(const EventInfo &eventInfo) override;
0205     bool mouseReleaseEvent(const EventInfo &eventInfo) override;
0206     bool mouseDoubleClickEvent(const EventInfo &eventInfo) override;
0207     bool mouseMoveEvent(const EventInfo &eventInfo) override;
0208     bool wheelEvent(const EventInfo &eventInfo) override;
0209     void enterEvent(QEvent *) override;
0210     void leaveEvent(QEvent *) override;
0211 
0212 public slots:
0213     /**
0214      * Rotate the item by the given amount (in radians)
0215      */
0216     void rotateBy(double dtheta);
0217     void parentMoved();
0218 
0219 signals:
0220     /**
0221      * Emitted when this item moves (translates or rotates)
0222      */
0223     void moved();
0224 
0225 protected slots:
0226     /**
0227      * Recalculate the combined mechanics info (e.g. when mass is changed, or child added)
0228      */
0229     void updateMechanicsInfoCombined();
0230 
0231 protected:
0232     void reparented(Item *oldItem, Item *newItem) override;
0233     void childAdded(Item *child) override;
0234     void childRemoved(Item *child) override;
0235     /**
0236      * Called when this item is resized, so that sub classes can do whatever
0237      */
0238     virtual void itemResized() {};
0239     /**
0240      * Sets the correct orientation on the painter
0241      */
0242     void initPainter(QPainter &p);
0243     /**
0244      * *Must* be called after calling initPainter, if initPainter was called
0245      */
0246     void deinitPainter(QPainter &p);
0247     void dataChanged() override;
0248     void itemPointsChanged() override
0249     {
0250         updateCanvasPoints();
0251     }
0252     /**
0253      * Calculates the setPoints required from the current m_itemPoints and the
0254      * current position / angle
0255      */
0256     void updateCanvasPoints();
0257 
0258     MechanicsDocument *p_mechanicsDocument;
0259     PositionInfo m_relativePosition; // Absolution position if not attached to a parent item, or otherwise relative to parent item
0260     MechanicsInfo m_mechanicsInfo;
0261     CombinedMechanicsInfo m_mechanicsInfoCombined;
0262 
0263 private:
0264     SelectionMode m_selectionMode;
0265 };
0266 
0267 #endif