diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-24 01:49:02 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-24 01:49:02 +0000 |
commit | 5de3dd4762ca33a0f92e79ffa4fe2ff67069d531 (patch) | |
tree | bad482b7afa4cdf47422d60a5dd2c61c7e333b09 /src/mechanics | |
download | ktechlab-5de3dd4762ca33a0f92e79ffa4fe2ff67069d531.tar.gz ktechlab-5de3dd4762ca33a0f92e79ffa4fe2ff67069d531.zip |
Added KDE3 version of ktechlab
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/ktechlab@1095338 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/mechanics')
-rw-r--r-- | src/mechanics/Makefile.am | 8 | ||||
-rw-r--r-- | src/mechanics/chassiscircular2.cpp | 144 | ||||
-rw-r--r-- | src/mechanics/chassiscircular2.h | 42 | ||||
-rw-r--r-- | src/mechanics/mechanicsdocument.cpp | 197 | ||||
-rw-r--r-- | src/mechanics/mechanicsdocument.h | 66 | ||||
-rw-r--r-- | src/mechanics/mechanicsgroup.cpp | 243 | ||||
-rw-r--r-- | src/mechanics/mechanicsgroup.h | 72 | ||||
-rw-r--r-- | src/mechanics/mechanicsitem.cpp | 433 | ||||
-rw-r--r-- | src/mechanics/mechanicsitem.h | 237 | ||||
-rw-r--r-- | src/mechanics/mechanicssimulation.cpp | 139 | ||||
-rw-r--r-- | src/mechanics/mechanicssimulation.h | 133 | ||||
-rw-r--r-- | src/mechanics/mechanicsview.cpp | 42 | ||||
-rw-r--r-- | src/mechanics/mechanicsview.h | 33 |
13 files changed, 1789 insertions, 0 deletions
diff --git a/src/mechanics/Makefile.am b/src/mechanics/Makefile.am new file mode 100644 index 0000000..0444358 --- /dev/null +++ b/src/mechanics/Makefile.am @@ -0,0 +1,8 @@ +INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/src/drawparts $(all_includes) +METASOURCES = AUTO +noinst_HEADERS = mechanicsitem.h chassiscircular2.h mechanicssimulation.h \ + mechanicsdocument.h mechanicsgroup.h mechanicsview.h + +noinst_LTLIBRARIES = libmechanics.la +libmechanics_la_SOURCES = mechanicsitem.cpp chassiscircular2.cpp \ + mechanicssimulation.cpp mechanicsdocument.cpp mechanicsgroup.cpp mechanicsview.cpp diff --git a/src/mechanics/chassiscircular2.cpp b/src/mechanics/chassiscircular2.cpp new file mode 100644 index 0000000..91b9f0a --- /dev/null +++ b/src/mechanics/chassiscircular2.cpp @@ -0,0 +1,144 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * 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. * + ***************************************************************************/ + +#include "chassiscircular2.h" + +#include "libraryitem.h" + +#include <klocale.h> +#include <qpainter.h> +#include <qwmatrix.h> + +#include <algorithm> +#include <cmath> + +double normalizeAngle( double angle ); + + +Item* ChassisCircular2::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ChassisCircular2( (MechanicsDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* ChassisCircular2::libraryItem() +{ + return new LibraryItem( + QString("mech/chassis_circular_2"), + i18n("Circular 2-Wheel Chassis"), + i18n("Chassis'"), + "chassis.png", + LibraryItem::lit_mechanical, + ChassisCircular2::construct ); +} + + +ChassisCircular2::ChassisCircular2( MechanicsDocument *mechanicsDocument, bool newItem, const char *id ) + : MechanicsItem( mechanicsDocument, newItem, (id) ? id : "chassis_circular_2" ) +{ + m_name = i18n("Circular 2-Wheel Chassis"); + m_desc = i18n("A circular base with two wheels and a support point."); + + m_theta1 = 0.0; + m_theta2 = 0.0; + + QPointArray pa; + pa.makeEllipse( -25, -25, 50, 50 ); + QWMatrix m(4,0,0,4,0,0); + m.setTransformationMode( QWMatrix::Areas ); + pa = m.map(pa); + setItemPoints(pa); + + itemResized(); +} + + +ChassisCircular2::~ChassisCircular2() +{ +} + + +void ChassisCircular2::itemResized() +{ + const double w = sizeRect().width(); + const double h = sizeRect().height(); + + m_wheel1Pos = QRect( int(w/5), int(h/6), int(w/4), int(h/8) ); + m_wheel2Pos = QRect( int(w/5), int(5*h/6-h/8), int(w/4), int(h/8) ); +} + + +void ChassisCircular2::advance( int phase ) +{ + if ( phase != 1 ) + return; + + double speed1 = 60.; // pixels per second + double speed2 = 160.; // pixels per second + + m_theta1 = normalizeAngle( m_theta1 + (speed1/1000.)/m_wheel1Pos.width() ); + m_theta2 = normalizeAngle( m_theta2 + (speed2/1000.)/m_wheel2Pos.width() ); + + const double d1 = speed1/1000.; + const double d2 = speed2/1000.; + const double sep = m_wheel2Pos.center().y()-m_wheel1Pos.center().y(); + + double dtheta = std::atan( (d2-d1)/sep ); // Change in orientation of chassis + double moveAngle = absolutePosition().angle()+dtheta/2; + rotateBy(dtheta); + moveBy( ((d1+d2)/2.)*std::cos(moveAngle), ((d1+d2)/2.)*std::sin(moveAngle) ); +} + + +void ChassisCircular2::drawShape( QPainter &p ) +{ + const double _x = int(sizeRect().x() + x()); + const double _y = int(sizeRect().y() + y()); + const double w = sizeRect().width(); + const double h = sizeRect().height(); + + initPainter(p); + p.setBrush( QColor( 255, 246, 210 ) ); + QRect circleRect = sizeRect(); + circleRect.moveLeft( int(circleRect.left() + x()) ); + circleRect.moveTop( int(circleRect.top() + y()) ); + p.drawEllipse(circleRect); + + // Draw wheels + // TODO get this info from m_wheel1Pos and m_wheel2Pos + const double X = _x+(w/5); // Wheel's left pos + const double H = h/8; // Wheel's height + const double y1 = _y+(h/6); // Wheel 1 y-pos + const double y2 = _y+(5*h/6)-H; // Wheel 2 y-pos + + p.setPen( Qt::NoPen ); + const double stripeWidth = 5; + const double offset2 = 1 + int(m_theta1*m_wheel1Pos.width())%int(2*stripeWidth); + const double offset1 = 1 + int(m_theta2*m_wheel2Pos.width())%int(2*stripeWidth); + p.setBrush( QColor( 255, 232, 182 ) ); + for ( double i=-1; i<std::ceil(m_wheel1Pos.width()/stripeWidth); ++i ) + { + + p.setClipRect( QRect( int(_x+m_wheel1Pos.x()+2), int(_y+m_wheel1Pos.y()+2), int(m_wheel1Pos.width()-4), int(m_wheel1Pos.height()-4) ), QPainter::CoordPainter ); + p.drawRect( int(offset1+X + i*stripeWidth*2), int(y1+1), int(stripeWidth), int(H-2) ); + + p.setClipRect( QRect( int(_x+m_wheel2Pos.x()+2), int(_y+m_wheel2Pos.y()+2), int(m_wheel2Pos.width()-4), int(m_wheel2Pos.height()-4) ), QPainter::CoordPainter ); + p.drawRect( int(offset2+X + i*stripeWidth*2), int(y2+1), int(stripeWidth), int(H-2) ); + } + p.setClipping(false); + + p.setPen( Qt::black ); + p.setBrush( Qt::NoBrush ); + p.drawRoundRect( int(X), int(y1), int(w/4), int(H), 25, 50 ); + p.drawRoundRect( int(X), int(y2), int(w/4), int(H), 25, 50 ); + + + deinitPainter(p); +} diff --git a/src/mechanics/chassiscircular2.h b/src/mechanics/chassiscircular2.h new file mode 100644 index 0000000..1c8897a --- /dev/null +++ b/src/mechanics/chassiscircular2.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * 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 CHASSISCIRCULAR2_H +#define CHASSISCIRCULAR2_H + +#include "mechanicsitem.h" + +/** +@short Mechanics Framework, circular base, two wheels +@author David Saxton +*/ +class ChassisCircular2 : public MechanicsItem +{ +public: + ChassisCircular2( MechanicsDocument *mechanicsDocument, bool newItem, const char *id = 0l ); + ~ChassisCircular2(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void advance( int phase ); + +protected: + virtual void itemResized(); + void drawShape( QPainter &p ); + + double m_theta1; // Angle of rotation of wheel 1 (used for drawing) + double m_theta2; // Angle of rotation of wheel 1 (used for drawing) + + QRect m_wheel1Pos; // Position of first wheel, with respect to top left of item + QRect m_wheel2Pos; // Position of second wheel, with respect to top left of item +}; + +#endif diff --git a/src/mechanics/mechanicsdocument.cpp b/src/mechanics/mechanicsdocument.cpp new file mode 100644 index 0000000..0b2fa3b --- /dev/null +++ b/src/mechanics/mechanicsdocument.cpp @@ -0,0 +1,197 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by David Saxton * + * david@bluehaze.org * + * * + * 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. * + ***************************************************************************/ + +#include "canvasmanipulator.h" +#include "documentiface.h" +#include "drawpart.h" +#include "itemlibrary.h" +#include "mechanicsdocument.h" +#include "mechanicsitem.h" +#include "mechanicsgroup.h" +#include "mechanicssimulation.h" +#include "mechanicsview.h" + +#include <klocale.h> + +MechanicsDocument::MechanicsDocument( const QString &caption, KTechlab *ktechlab, const char *name ) + : ItemDocument( caption, ktechlab, name ) +{ + m_type = Document::dt_mechanics; + m_pDocumentIface = new MechanicsDocumentIface(this); + m_fileExtensionInfo = i18n("*.mechanics|Mechanics (*.mechanics)\n*|All Files"); + m_canvas->retune(128); + + m_selectList = new MechanicsGroup(this); + + m_cmManager->addManipulatorInfo( CMSelect::manipulatorInfo() ); + m_cmManager->addManipulatorInfo( CMDraw::manipulatorInfo() ); + m_cmManager->addManipulatorInfo( CMRightClick::manipulatorInfo() ); + m_cmManager->addManipulatorInfo( CMRepeatedItemAdd::manipulatorInfo() ); + m_cmManager->addManipulatorInfo( CMItemResize::manipulatorInfo() ); + m_cmManager->addManipulatorInfo( CMMechItemMove::manipulatorInfo() ); + m_mechanicsSimulation = new MechanicsSimulation(this); + requestStateSave(); +} + + +MechanicsDocument::~MechanicsDocument() +{ + m_bDeleted = true; + + // Remove all items from the canvas + selectAll(); + deleteSelection(); + delete m_mechanicsSimulation; +} + +View *MechanicsDocument::createView( ViewContainer *viewContainer, uint viewAreaId, const char *name ) +{ + ItemView *itemView = new MechanicsView( this, viewContainer, viewAreaId, name ); + handleNewView(itemView); + return itemView; +} + + +ItemGroup *MechanicsDocument::selectList() const +{ + return m_selectList; +} + + + + +bool MechanicsDocument::isValidItem( const QString &itemId ) +{ + return itemId.startsWith("mech/") || itemId.startsWith("dp/"); +} + + +bool MechanicsDocument::isValidItem( Item *item ) +{ + return item && ((dynamic_cast<MechanicsItem*>(item)) || (dynamic_cast<DrawPart*>(item))); +} + + +Item* MechanicsDocument::addItem( const QString &id, const QPoint &p, bool newItem ) +{ + if ( !isValidItem(id) ) + return 0l; + + Item *item = itemLibrary()->createItem( id, this, newItem ); + if (!item) + return 0L; + + QRect rect = item->boundingRect(); + + int dx = (int)(p.x())-rect.width()/2; + int dy = (int)(p.y())-rect.height()/2; + + if ( dx < 16 || dx > canvas()->width() ) dx = 16; + if ( dy < 16 || dy > canvas()->height() ) dy = 16; + + item->move( dx, dy ); + item->show(); + + registerItem(item); +// setModified(true); + requestStateSave(); + return item; +} + + +void MechanicsDocument::deleteSelection() +{ + // End whatever editing mode we are in, as we don't want to start editing + // something that is about to no longer exist... + m_cmManager->cancelCurrentManipulation(); + + if ( m_selectList->isEmpty() ) + return; + + // We nee to tell the selete items to remove themselves, and then + // pass the items that have add themselves to the delete list to the + // CommandAddItems command + + m_selectList->deleteAllItems(); + flushDeleteList(); + setModified(true); + + // We need to emit this so that property widgets etc... + // can clear themselves. + emit itemUnselected(0L); + requestStateSave(); +} + + +bool MechanicsDocument::registerItem( QCanvasItem *qcanvasItem ) +{ + return ItemDocument::registerItem(qcanvasItem); +} + + +void MechanicsDocument::appendDeleteList( QCanvasItem *qcanvasItem ) +{ + MechanicsItem *mechItem = dynamic_cast<MechanicsItem*>(qcanvasItem); + if ( !mechItem || m_itemDeleteList.contains(mechItem) ) { + return; + } + + m_itemDeleteList.append(mechItem); + m_itemList.remove(mechItem); + + disconnect( mechItem, SIGNAL(selected(Item*,bool)), this, SIGNAL(itemSelected(Item*)) ); + disconnect( mechItem, SIGNAL(unselected(Item*,bool)), this, SIGNAL(itemUnselected(Item*)) ); + + mechItem->removeItem(); +} + + +void MechanicsDocument::flushDeleteList() +{ + // Remove duplicate items in the delete list + ItemList::iterator end = m_itemDeleteList.end(); + for ( ItemList::iterator it = m_itemDeleteList.begin(); it != end; ++it ) + { + if ( *it && m_itemDeleteList.contains(*it) > 1 ) + *it = 0l; + } + m_itemDeleteList.remove(QGuardedPtr<Item>(0l)); + + end = m_itemDeleteList.end(); + for ( ItemList::iterator it = m_itemDeleteList.begin(); it != end; ++it ) + { + m_itemList.remove(*it); + (*it)->setCanvas(0l); + delete *it; + } +} + + +MechanicsItem* MechanicsDocument::mechanicsItemWithID( const QString &id ) +{ + return dynamic_cast<MechanicsItem*>(itemWithID(id)); +} + + +void MechanicsDocument::selectAll() +{ + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + select(*it); + } +} + + +void MechanicsDocument::copy() +{ +} + +#include "mechanicsdocument.moc" diff --git a/src/mechanics/mechanicsdocument.h b/src/mechanics/mechanicsdocument.h new file mode 100644 index 0000000..dfe454f --- /dev/null +++ b/src/mechanics/mechanicsdocument.h @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (C) 2004 by David Saxton * + * david@bluehaze.org * + * * + * 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 MECHANICSDOCUMENT_H +#define MECHANICSDOCUMENT_H + +#include "itemdocument.h" + +class KTechlab; +class MechanicsGroup; +class MechanicsItem; +class MechanicsSimulation; + +typedef QValueList<MechanicsItem*> MechItemList; +typedef QValueList<MechanicsItem*> MechanicsItemList; + +/** +@author David Saxton +*/ +class MechanicsDocument : public ItemDocument +{ +Q_OBJECT +public: + MechanicsDocument( const QString &caption, KTechlab *ktechlab, const char *name = 0 ); + ~MechanicsDocument(); + + virtual View *createView( ViewContainer *viewContainer, uint viewAreaId, const char *name = 0l ); + + virtual bool isValidItem( const QString &itemId ); + virtual bool isValidItem( Item *item ); + + virtual void deleteSelection(); + virtual void copy(); + virtual void selectAll(); + virtual ItemGroup *selectList() const; + MechanicsItem *mechanicsItemWithID( const QString &id ); + virtual Item* addItem( const QString &id, const QPoint &p, bool newItem ); + /** + * Adds a QCanvasItem to the delete list to be deleted, when + * flushDeleteList() is called + */ + virtual void appendDeleteList( QCanvasItem *qcanvasItem ); + /** + * Permantly deletes all items that have been added to the delete list with + * the appendDeleteList( QCanvasItem *qcanvasItem ) function. + */ + virtual void flushDeleteList(); + /** + * Register an item with the ICNDocument. + */ + virtual bool registerItem( QCanvasItem *qcanvasItem ); + +protected: + MechanicsGroup *m_selectList; + MechanicsSimulation *m_mechanicsSimulation; +}; + + +#endif diff --git a/src/mechanics/mechanicsgroup.cpp b/src/mechanics/mechanicsgroup.cpp new file mode 100644 index 0000000..94fe703 --- /dev/null +++ b/src/mechanics/mechanicsgroup.cpp @@ -0,0 +1,243 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * 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. * + ***************************************************************************/ + +#include "mechanicsgroup.h" +#include "mechanicsitem.h" +#include "mechanicsdocument.h" + +MechanicsGroup::MechanicsGroup( MechanicsDocument *mechanicsDocument, const char *name ) + : ItemGroup( mechanicsDocument, name ) +{ + b_isRaised = false; +} + + +MechanicsGroup::~MechanicsGroup() +{ +} + + +bool MechanicsGroup::addItem( Item *item ) +{ + if ( !item || !item->canvas() || m_itemList.contains(item) ) { + return false; + } + + // Check that the item's parent isn't already selected + Item *parent = item->parentItem(); + while (parent) + { + if ( m_itemList.contains(parent) ) + return false; + parent = parent->parentItem(); + } + removeChildren(item); + + registerItem(item); + updateInfo(); + item->setSelected(true); + if ( MechanicsItem *mechanicsItem = dynamic_cast<MechanicsItem*>(item) ) + mechanicsItem->setRaised(b_isRaised); + emit itemAdded(item); + return true; +} + + +bool MechanicsGroup::removeItem( Item *item ) +{ + if ( !item || !m_itemList.contains(item) ) { + return false; + } + unregisterItem(item); + updateInfo(); + item->setSelected(false); + MechanicsItem *mechanicsItem = dynamic_cast<MechanicsItem*>(item); + if (mechanicsItem) + mechanicsItem->setRaised(false); + emit itemRemoved(item); + return true; +} + + +void MechanicsGroup::removeChildren( Item *item ) +{ + if (!item) + return; + + const ItemList children = item->children(); + const ItemList::const_iterator end = children.end(); + for ( ItemList::const_iterator it = children.begin(); it != end; ++it ) + { + removeChildren(*it); + removeItem(*it); + } +} + + +void MechanicsGroup::setRaised( bool isRaised ) +{ + b_isRaised = isRaised; + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + MechanicsItem *mechanicsItem = dynamic_cast<MechanicsItem*>((Item*)*it); + if (mechanicsItem) + mechanicsItem->setRaised(b_isRaised); + } +} + + +void MechanicsGroup::setSelectionMode( uint sm ) +{ + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + MechanicsItem *mechanicsItem = dynamic_cast<MechanicsItem*>((Item*)*it); + if (mechanicsItem) + mechanicsItem->setSelectionMode( (MechanicsItem::SelectionMode)sm ); + } +} + + +MechanicsItemList MechanicsGroup::extractMechanicsItems() const +{ + MechanicsItemList mechanicsItemList; + + const ItemList::const_iterator end = m_itemList.end(); + for ( ItemList::const_iterator it = m_itemList.begin(); it != end; ++it ) + { + MechanicsItem *mechanicsItem = dynamic_cast<MechanicsItem*>((Item*)*it); + if (mechanicsItem) + mechanicsItemList.append(mechanicsItem); + } + + return mechanicsItemList; +} + + +MechanicsItemList MechanicsGroup::toplevelMechItemList() const +{ + MechanicsItemList toplevel; + + MechanicsItemList mechItemList = extractMechanicsItems(); + + const MechanicsItemList::const_iterator end = mechItemList.end(); + for ( MechanicsItemList::const_iterator it = mechItemList.begin(); it != end; ++it ) + { + MechanicsItem* parent = *it; + while (parent) + { + if ( !parent->parentItem() && !toplevel.contains(parent) ) + toplevel.append(parent); + + parent = dynamic_cast<MechanicsItem*>(parent->parentItem()); + } + } + + return toplevel; +} + + +void MechanicsGroup::setSelected( bool sel ) +{ + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + if (*it && (*it)->isSelected() != sel ) { + (*it)->setSelected(sel); + } + } +} + + +bool MechanicsGroup::addQCanvasItem( QCanvasItem* item ) +{ + return addItem( dynamic_cast<Item*>(item) ); +} + +bool MechanicsGroup::contains(QCanvasItem* item) const +{ + return m_itemList.contains(dynamic_cast<Item*>(item)); +} + + +void MechanicsGroup::deleteAllItems() +{ + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + if (*it) + (*it)->removeItem(); + } + + removeAllItems(); +} + +void MechanicsGroup::mergeGroup(ItemGroup* itemGroup) +{ + MechanicsGroup *group = dynamic_cast<MechanicsGroup*>(itemGroup); + if (!group) { + return; + } + + const ItemList items = group->items(); + const ItemList::const_iterator end = items.end(); + for ( ItemList::const_iterator it = items.begin(); it != end; ++it ) + { + addItem(*it); + } +} + +void MechanicsGroup::removeAllItems() +{ + while ( !m_itemList.isEmpty() ) + removeItem(m_itemList.first()); +} + +void MechanicsGroup::removeQCanvasItem(QCanvasItem* item) +{ + removeItem(dynamic_cast<Item*>(item)); +} + + +void MechanicsGroup::setItems(QCanvasItemList list) +{ + { + ItemList removeList; + const ItemList::iterator end = m_itemList.end(); + for ( ItemList::iterator it = m_itemList.begin(); it != end; ++it ) + { + if ( !list.contains(*it) ) { + removeList.append(*it); + } + } + const ItemList::iterator rend = removeList.end(); + for ( ItemList::iterator it = removeList.begin(); it != rend; ++it ) + { + removeItem(*it); + (*it)->setSelected(false); + } + } + + const QCanvasItemList::iterator end = list.end(); + for ( QCanvasItemList::iterator it = list.begin(); it != end; ++it ) + { + // We don't need to check that we've already got the item as it will + // be checked in the function call + addQCanvasItem(*it); + } +} + + +void MechanicsGroup::updateInfo() +{ +} + +#include "mechanicsgroup.moc" diff --git a/src/mechanics/mechanicsgroup.h b/src/mechanics/mechanicsgroup.h new file mode 100644 index 0000000..6b49966 --- /dev/null +++ b/src/mechanics/mechanicsgroup.h @@ -0,0 +1,72 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * 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 MECHANICSGROUP_H +#define MECHANICSGROUP_H + +#include <itemgroup.h> + + +class MechanicsItem; +class MechanicsDocument; +typedef QValueList<MechanicsItem*> MechanicsItemList; + +/** +@author David Saxton +*/ +class MechanicsGroup : public ItemGroup +{ +Q_OBJECT +public: + MechanicsGroup( MechanicsDocument *mechanicsDocument, const char *name = 0); + ~MechanicsGroup(); + + /** + * Returns a list of top-level mechanics items only + */ + MechanicsItemList toplevelMechItemList() const; + /** + * Sets the selection mode of all MechanicsItems in the group + */ + void setSelectionMode( uint sm ); + /** + * "Raises" (increases the z value of) the selected group of items + */ + void setRaised( bool isRaised ); + /** + * Removes all the children of the given item from the group + */ + void removeChildren( Item *item ); + bool addItem( Item *item ); + bool removeItem( Item *item ); + virtual bool addQCanvasItem(QCanvasItem* item); + virtual bool contains(QCanvasItem* item) const; + virtual uint count() const { return itemCount(); } + virtual void deleteAllItems(); + virtual void mergeGroup(ItemGroup* group); + virtual void removeAllItems(); + virtual void removeQCanvasItem(QCanvasItem* item); + virtual void setItems(QCanvasItemList list); + /** + * Sets the selected state of all items in the group + */ + virtual void setSelected( bool sel ); + /** + * Extracts the mechanics items from the item list + */ + MechanicsItemList extractMechanicsItems() const; + +protected: + void updateInfo(); + + bool b_isRaised; +}; + +#endif diff --git a/src/mechanics/mechanicsitem.cpp b/src/mechanics/mechanicsitem.cpp new file mode 100644 index 0000000..acf2239 --- /dev/null +++ b/src/mechanics/mechanicsitem.cpp @@ -0,0 +1,433 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by David Saxton * + * david@bluehaze.org * + * * + * 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. * + ***************************************************************************/ + +#include "itemdocumentdata.h" +#include "mechanicsitem.h" +#include "mechanicsdocument.h" + +#include <kdebug.h> +#include <klocale.h> +#include <qbitarray.h> +#include <qpainter.h> +#include <qwmatrix.h> +#include <cmath> + +/** +@returns an angle between 0 and 2 pi +*/ +double normalizeAngle( double angle ) +{ + if ( angle < 0 ) + angle += 6.2832*(std::ceil(-angle)); + + return angle - 6.2832*std::floor(angle/6.2832); +} + +MechanicsItem::MechanicsItem( MechanicsDocument *mechanicsDocument, bool newItem, const QString &id ) + : Item( mechanicsDocument, newItem, id ) +{ + p_mechanicsDocument = mechanicsDocument; + m_selectionMode = MechanicsItem::sm_move; + + createProperty( "mass", Variant::Type::Double ); + property("mass")->setCaption( i18n("Mass") ); + property("mass")->setUnit("g"); + property("mass")->setValue(10.0); + property("mass")->setMinValue(1e-3); + property("mass")->setMaxValue(1e12); + property("mass")->setAdvanced(true); + + createProperty( "moi", Variant::Type::Double ); + property("moi")->setCaption( i18n("Moment of Inertia") ); + property("moi")->setUnit("gm"); + property("moi")->setValue(0.01); + property("moi")->setMinValue(1e-3); + property("moi")->setMaxValue(1e12); + property("moi")->setAdvanced(true); + + setZ(ItemDocument::Z::Item); + setAnimated(true); + p_mechanicsDocument->registerItem(this); +} + + +MechanicsItem::~MechanicsItem() +{ +} + + +int MechanicsItem::rtti() const +{ + return ItemDocument::RTTI::MechanicsItem; +} + + +void MechanicsItem::setSelectionMode( SelectionMode sm ) +{ + if ( sm == m_selectionMode ) + return; + + m_selectionMode = sm; +} + + +void MechanicsItem::setSelected( bool yes ) +{ + if ( yes == isSelected() ) + return; + + if (!yes) + // Reset the selection mode + m_selectionMode = MechanicsItem::sm_resize; + + Item::setSelected(yes); +} + + +void MechanicsItem::dataChanged() +{ + Item::dataChanged(); + m_mechanicsInfo.mass = dataDouble("mass"); + m_mechanicsInfo.momentOfInertia = dataDouble("moi"); + updateMechanicsInfoCombined(); +} + + +PositionInfo MechanicsItem::absolutePosition() const +{ + MechanicsItem *parentMechItem = dynamic_cast<MechanicsItem*>((Item*)(p_parentItem)); + if (parentMechItem) + return parentMechItem->absolutePosition() + m_relativePosition; + + return m_relativePosition; +} + + +void MechanicsItem::reparented( Item *oldItem, Item *newItem ) +{ + MechanicsItem *oldMechItem = dynamic_cast<MechanicsItem*>(oldItem); + MechanicsItem *newMechItem = dynamic_cast<MechanicsItem*>(newItem); + + if (oldMechItem) + { + m_relativePosition = oldMechItem->absolutePosition() + m_relativePosition; + disconnect( oldMechItem, SIGNAL(moved()), this, SLOT(parentMoved()) ); + } + + if (newMechItem) + { + m_relativePosition = m_relativePosition - newMechItem->absolutePosition(); + connect( newMechItem, SIGNAL(moved()), this, SLOT(parentMoved()) ); + } + + updateCanvasPoints(); +} + + +void MechanicsItem::childAdded( Item *child ) +{ + MechanicsItem *mechItem = dynamic_cast<MechanicsItem*>(child); + if (!mechItem) + return; + + connect( mechItem, SIGNAL(updateMechanicsInfoCombined()), this, SLOT(childMoved()) ); + updateMechanicsInfoCombined(); +} + + +void MechanicsItem::childRemoved( Item *child ) +{ + MechanicsItem *mechItem = dynamic_cast<MechanicsItem*>(child); + if (!mechItem) + return; + + disconnect( mechItem, SIGNAL(updateMechanicsInfoCombined()), this, SLOT(childMoved()) ); + updateMechanicsInfoCombined(); +} + + +void MechanicsItem::parentMoved() +{ + PositionInfo absPos = absolutePosition(); + Item::moveBy( absPos.x() - x(), absPos.y() - y() ); + updateCanvasPoints(); + emit moved(); +} + + +void MechanicsItem::updateCanvasPoints() +{ + const QRect ipbr = m_itemPoints.boundingRect(); + + double scalex = double(m_sizeRect.width()) / double(ipbr.width()); + double scaley = double(m_sizeRect.height()) / double(ipbr.height()); + + PositionInfo abs = absolutePosition(); + + QWMatrix m; + m.rotate(abs.angle()*57.29577951308232); + m.translate( m_sizeRect.left(), m_sizeRect.top() ); + m.scale( scalex, scaley ); + m.translate( -int(ipbr.left()), -int(ipbr.top()) ); + setPoints( m.map(m_itemPoints) ); + + QRect tempt = m.mapRect(ipbr); +} + + +void MechanicsItem::rotateBy( double dtheta ) +{ + m_relativePosition.rotate(dtheta); + updateCanvasPoints(); + updateMechanicsInfoCombined(); + emit moved(); +} + + +void MechanicsItem::moveBy( double dx, double dy ) +{ + m_relativePosition.translate( dx, dy ); + Item::moveBy( m_relativePosition.x() - x(), m_relativePosition.y() - y() ); + emit moved(); +} + + +void MechanicsItem::updateMechanicsInfoCombined() +{ + m_mechanicsInfoCombined = m_mechanicsInfo; + + double mass_x = 0.; + double mass_y = 0.; + + const ItemList::const_iterator end = m_children.end(); + for ( ItemList::const_iterator it = m_children.begin(); it != end; ++it ) + { + MechanicsItem *child = dynamic_cast<MechanicsItem*>((Item*)*it); + if (child) + { + CombinedMechanicsInfo *childInfo = child->mechanicsInfoCombined(); + const PositionInfo relativeChildPosition = child->relativePosition(); + + double mass = childInfo->mass; +// double angle = relativeChildPosition.angle(); + double dx = relativeChildPosition.x() /*+ cos(angle)*childInfo->m_x - sin(angle)*childInfo->m_y*/; + double dy = relativeChildPosition.y() /*+ sin(angle)*childInfo->m_x + cos(angle)*childInfo->m_y*/; + + m_mechanicsInfoCombined.mass += mass; + mass_x += mass * dx; + mass_y += mass * dy; + + double length_squared = dx*dx + dy*dy; + m_mechanicsInfoCombined.momentOfInertia += length_squared * childInfo->momentOfInertia; + } + } + + m_mechanicsInfoCombined.x = mass_x / m_mechanicsInfoCombined.mass; + m_mechanicsInfoCombined.y = mass_y / m_mechanicsInfoCombined.mass; +} + + +ItemData MechanicsItem::itemData() const +{ + ItemData itemData = Item::itemData(); + itemData.angleDegrees = m_relativePosition.angle()*57.29577951308232; + return itemData; +} + + +bool MechanicsItem::mousePressEvent( const EventInfo &eventInfo ) +{ + Q_UNUSED(eventInfo); + return false; +} + + +bool MechanicsItem::mouseReleaseEvent( const EventInfo &eventInfo ) +{ + Q_UNUSED(eventInfo); + return false; +} + + +bool MechanicsItem::mouseDoubleClickEvent( const EventInfo &eventInfo ) +{ + Q_UNUSED(eventInfo); + return false; +} + + +bool MechanicsItem::mouseMoveEvent( const EventInfo &eventInfo ) +{ + Q_UNUSED(eventInfo); + return false; +} + + +bool MechanicsItem::wheelEvent( const EventInfo &eventInfo ) +{ + Q_UNUSED(eventInfo); + return false; +} + + +void MechanicsItem::enterEvent() +{ +} + + +void MechanicsItem::leaveEvent() +{ +} + + +QRect MechanicsItem::maxInnerRectangle( const QRect &outerRect ) const +{ + QRect normalizedOuterRect = outerRect.normalize(); + const double LEFT = normalizedOuterRect.left(); + const double TOP = normalizedOuterRect.top(); + const double X = normalizedOuterRect.width(); + const double Y = normalizedOuterRect.height(); + const double a = normalizeAngle(absolutePosition().angle()); + + double left; + double top; + double width; + double height; + +// if ( can change width/height ratio ) + { + double x1 = X*std::cos(a) - Y*std::sin(a); + double y1 = X*std::sin(a) + Y*std::cos(a); + double x2 = X*std::cos(a); + double y2 = X*std::sin(a); + double x3 = -Y*std::sin(a); + double y3 = Y*std::cos(a); + + double xbig;/* = std::max( std::abs(x2-x3), std::abs(x1) );*/ + double ybig;/* = std::max( std::abs(y2-y3), std::abs(y1) );*/ + if ( (a - floor(a/6.2832)*6.2832) < 3.1416 ) + { + xbig = std::abs(x3-x2); + ybig = std::abs(y1); + } + else + { + xbig = std::abs(x1); + ybig = std::abs(y3-y2); + } + + width = X*(X/xbig); + height = Y*(Y/ybig); + + top = -std::sin(a) * (LEFT + width*std::sin(a)) + std::cos(a)*TOP; + left = std::cos(a) * (LEFT + width*std::sin(a)) + std::sin(a)*TOP; + } + + return QRect( int(left), int(top), int(width), int(height) ); +} + + +void MechanicsItem::initPainter( QPainter &p ) +{ + PositionInfo absPos = absolutePosition(); + p.translate( absPos.x(), absPos.y() ); + // 57.29577951308232 is the number of degrees per radian. + p.rotate( absPos.angle()*57.29577951308232 ); + p.translate( -absPos.x(), -absPos.y() ); +} + + +void MechanicsItem::deinitPainter( QPainter &p ) +{ + PositionInfo absPos = absolutePosition(); + p.translate( absPos.x(), absPos.y() ); + // 57.29577951308232 is the number of degrees per radian. + p.rotate( -absPos.angle()*57.29577951308232 ); + p.translate( -absPos.x(), -absPos.y() ); +} + + + + + +PositionInfo::PositionInfo() +{ + reset(); +} + + +const PositionInfo PositionInfo::operator+( const PositionInfo &info ) +{ + // Copy the child to a new position + PositionInfo newInfo = info; + + // Translate the newInfo by our translation amount + newInfo.translate( x(), y() ); + + // Rotate the child about us + newInfo.rotateAboutPoint( x(), y(), angle() ); + + return newInfo; +} + + +const PositionInfo PositionInfo::operator-( const PositionInfo &info ) +{ + + PositionInfo newInfo = *this; + + newInfo.translate( -info.x(), -info.y() ); + newInfo.rotate( -info.angle() ); + + return newInfo; +} + + +void PositionInfo::rotateAboutPoint( double x, double y, double angle ) +{ + m_angle += angle; + + double newx = x + (m_x-x)*std::cos(angle) - (m_y-y)*std::sin(angle); + double newy = y + (m_x-x)*std::sin(angle) + (m_y-y)*std::cos(angle); + + m_x = newx; + m_y = newy; +} + + +void PositionInfo::reset() +{ + m_x = 0.; + m_y = 0.; + m_angle = 0.; +} + + + +MechanicsInfo::MechanicsInfo() +{ + mass = 0.; + momentOfInertia = 0.; +} +CombinedMechanicsInfo::CombinedMechanicsInfo() + : MechanicsInfo() +{ + x = 0.; + y = 0.; +} +CombinedMechanicsInfo::CombinedMechanicsInfo( const MechanicsInfo &info ) + : MechanicsInfo(info) +{ + x = 0.; + y = 0.; +} + + +#include "mechanicsitem.moc" diff --git a/src/mechanics/mechanicsitem.h b/src/mechanics/mechanicsitem.h new file mode 100644 index 0000000..db500fc --- /dev/null +++ b/src/mechanics/mechanicsitem.h @@ -0,0 +1,237 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by David Saxton * + * david@bluehaze.org * + * * + * 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 diff --git a/src/mechanics/mechanicssimulation.cpp b/src/mechanics/mechanicssimulation.cpp new file mode 100644 index 0000000..d5ec98d --- /dev/null +++ b/src/mechanics/mechanicssimulation.cpp @@ -0,0 +1,139 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * 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. * + ***************************************************************************/ + +#include "mechanicsdocument.h" +#include "mechanicsitem.h" +#include "mechanicssimulation.h" + +#include <cmath> +#include <qtimer.h> + +MechanicsSimulation::MechanicsSimulation( MechanicsDocument *mechanicsDocument ) + : QObject(mechanicsDocument) +{ + p_mechanicsDocument = mechanicsDocument; + m_advanceTmr = new QTimer(this); + connect( m_advanceTmr, SIGNAL(timeout()), this, SLOT(slotAdvance()) ); + m_advanceTmr->start(1); +} + + +MechanicsSimulation::~MechanicsSimulation() +{ +} + + +void MechanicsSimulation::slotAdvance() +{ + if ( p_mechanicsDocument && p_mechanicsDocument->canvas() ) + p_mechanicsDocument->canvas()->advance(); +} + + +RigidBody::RigidBody( MechanicsDocument *mechanicsDocument ) +{ + p_mechanicsDocument = mechanicsDocument; + p_overallParent = 0l; +} + + +RigidBody::~RigidBody() +{ +} + + +bool RigidBody::addMechanicsItem( MechanicsItem *item ) +{ + if ( !item || m_mechanicsItemList.contains(item) ) + return false; + + m_mechanicsItemList.append(item); + findOverallParent(); + return true; +} + + +void RigidBody::moveBy( double dx, double dy ) +{ + if (overallParent()) + overallParent()->moveBy( dx, dy ); +} + + +void RigidBody::rotateBy( double dtheta ) +{ + if (overallParent()) + overallParent()->rotateBy(dtheta); +} + + +bool RigidBody::findOverallParent() +{ + p_overallParent = 0l; + if ( m_mechanicsItemList.isEmpty() ) + return false; + + m_mechanicsItemList.remove(0l); + + const MechanicsItemList::iterator end = m_mechanicsItemList.end(); + for ( MechanicsItemList::iterator it = m_mechanicsItemList.begin(); it != end; ++it ) + { + MechanicsItem *parentItem = *it; + MechanicsItem *parentCandidate = dynamic_cast<MechanicsItem*>((*it)->parentItem()); + + while (parentCandidate) + { + parentItem = parentCandidate; + parentCandidate = dynamic_cast<MechanicsItem*>(parentItem->parentItem()); + } + + if ( !p_overallParent ) + // Must be the first item to test + p_overallParent = parentItem; + + if ( p_overallParent != parentItem ) + { + p_overallParent = 0l; + return false; + } + } + return true; +} + + +void RigidBody::updateRigidBodyInfo() +{ + if (!p_overallParent) + return; + + m_mass = p_overallParent->mechanicsInfoCombined()->mass; + m_momentOfInertia = p_overallParent->mechanicsInfoCombined()->momentOfInertia; +} + + +Vector2D::Vector2D() +{ + x = 0.; + y = 0.; +} + +double Vector2D::length() const +{ + return std::sqrt( x*x + y*y ); +} + +RigidBodyState::RigidBodyState() +{ + angularMomentum = 0.; +} + + + +#include "mechanicssimulation.moc" diff --git a/src/mechanics/mechanicssimulation.h b/src/mechanics/mechanicssimulation.h new file mode 100644 index 0000000..19b474b --- /dev/null +++ b/src/mechanics/mechanicssimulation.h @@ -0,0 +1,133 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * 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 MECHANICSSIMULATION_H +#define MECHANICSSIMULATION_H + +#include <qguardedptr.h> +#include <qobject.h> +#include <qvaluelist.h> + +class MechanicsItem; +class MechanicsDocument; +typedef QValueList<MechanicsItem*> MechanicsItemList; + + +/** +@short 2 dimensional vector with associated length functions et al +@author David Saxton +*/ +class Vector2D +{ +public: + Vector2D(); + + double length() const; + double lengthSquared() const { return x*x + y*y; } + + double x; + double y; +}; + + +/** +@short State of a rigid body, in an inertial MechanicsDocument frame +@author David Saxton +*/ +class RigidBodyState +{ +public: + RigidBodyState(); + + Vector2D linearMomentum; + double angularMomentum; + Vector2D position; // Position of center of mass +}; + + +/** +@author David Saxton +*/ +class MechanicsSimulation : public QObject +{ +Q_OBJECT +public: + MechanicsSimulation( MechanicsDocument *mechanicsDocument ); + ~MechanicsSimulation(); + + MechanicsDocument* mechanicsDocument() const { return p_mechanicsDocument; } + +protected slots: + void slotAdvance(); + +protected: + QGuardedPtr<MechanicsDocument> p_mechanicsDocument; + QTimer *m_advanceTmr; +}; + + +/** +Rigid body with mass, inertia, etc. Collection of mechanics items with +functionality for moving them about, rotating, etc. Only one mother-parent +(has no parent itself, all other items are descendents) allowed. +@short Rigid body, handles MechanicsItems +@author David Saxton +*/ +class RigidBody +{ +public: + RigidBody( MechanicsDocument *mechanicsDocument ); + ~RigidBody(); + + /** + * + */ + void advance( int phase, double delta ); + /** + * Add the MechanicsItem to the entity. + * @returns true iff successful in adding + */ + bool addMechanicsItem( MechanicsItem *item ); + /** + * Pointer to the mother MechanicsItem. + */ + MechanicsItem *overallParent() const { return p_overallParent; } + /** + * Updates the mass and the moment of inertia info + */ + void updateRigidBodyInfo(); + +protected: + /** + * Attempt to find the overall parent. + * @returns false iff unsucessful (including if there are no MechanicsItems present) + */ + bool findOverallParent(); + /** + * Move the set of MechanicsItems by the given amount + */ + void moveBy( double dx, double dy ); + /** + * Rotate the set of MechanicsItems by the given amount about the center of + * mass. + * @param angle Rotate amount in radians + */ + void rotateBy( double dtheta ); + + MechanicsItemList m_mechanicsItemList; + MechanicsItem *p_overallParent; + MechanicsDocument *p_mechanicsDocument; + + RigidBodyState m_rigidBodyState; + double m_mass; + double m_momentOfInertia; +}; + +#endif diff --git a/src/mechanics/mechanicsview.cpp b/src/mechanics/mechanicsview.cpp new file mode 100644 index 0000000..d49c66a --- /dev/null +++ b/src/mechanics/mechanicsview.cpp @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * 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. * + ***************************************************************************/ + +#include "mechanicsdocument.h" +#include "mechanicsview.h" +#include "viewiface.h" + + +MechanicsView::MechanicsView( MechanicsDocument *mechanicsDocument, ViewContainer *viewContainer, uint viewAreaId, const char *name ) + : ItemView( mechanicsDocument, viewContainer, viewAreaId, name ) +{ + setXMLFile( "ktechlabmechanicsui.rc", true ); + m_pViewIface = new MechanicsViewIface(this); +} + + +MechanicsView::~MechanicsView() +{ + delete m_pViewIface; + m_pViewIface = 0l; +} + + + + +void MechanicsView::dragEnterEvent( QDragEnterEvent * e ) +{ + ItemView::dragEnterEvent(e); + if ( e->isAccepted() ) + return; + + e->accept( e->provides("ktechlab/mechanical") ); +} + +#include "mechanicsview.moc" diff --git a/src/mechanics/mechanicsview.h b/src/mechanics/mechanicsview.h new file mode 100644 index 0000000..f787b1c --- /dev/null +++ b/src/mechanics/mechanicsview.h @@ -0,0 +1,33 @@ +/*************************************************************************** + * Copyright (C) 2005 by David Saxton * + * david@bluehaze.org * + * * + * 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 MECHANICSVIEW_H +#define MECHANICSVIEW_H + +#include <itemview.h> + +class MechanicsDocument; + +/** +@author David Saxton +*/ +class MechanicsView : public ItemView +{ + Q_OBJECT + public: + MechanicsView( MechanicsDocument *mechanicsDocument, ViewContainer *viewContainer, uint viewAreaId, const char *name = 0l ); + ~MechanicsView(); + + protected: + virtual void dragEnterEvent( QDragEnterEvent * e ); + MechanicsDocument *m_pMechanicsDocument; +}; + +#endif |