File indexing completed on 2024-04-28 07:39:37

0001 /*.
0002     SPDX-FileCopyrightText: 2007 Vladimir Kuznetsov <ks.vladimir@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "motorgraphics.h"
0008 
0009 #include "worldmodel.h"
0010 #include "worldscene.h"
0011 
0012 #include <stepcore/motor.h>
0013 #include <stepcore/particle.h>
0014 #include <stepcore/rigidbody.h>
0015 
0016 #include <QEvent>
0017 #include <QGraphicsSceneMouseEvent>
0018 #include <QItemSelectionModel>
0019 
0020 #include <KLocalizedString>
0021 
0022 bool LinearMotorCreator::sceneEvent(QEvent* event)
0023 {
0024     QGraphicsSceneMouseEvent* mouseEvent = static_cast<QGraphicsSceneMouseEvent*>(event);
0025     if(event->type() == QEvent::GraphicsSceneMousePress && mouseEvent->button() == Qt::LeftButton) {
0026         QPointF pos = mouseEvent->scenePos();
0027         QVariant vpos = QVariant::fromValue(StepGraphicsItem::pointToVector(pos));
0028 
0029         _worldModel->simulationPause();
0030         _worldModel->beginMacro(i18n("Create %1", _worldModel->newItemName(_className)));
0031         _item = _worldModel->createItem(className()); Q_ASSERT(_item != nullptr);
0032 
0033         _worldModel->setProperty(_item, QStringLiteral("localPosition"), vpos);
0034         _worldModel->addItem(_item);
0035         tryAttach(pos);
0036 
0037         _worldModel->selectionModel()->setCurrentIndex(_worldModel->objectIndex(_item),
0038                                                 QItemSelectionModel::ClearAndSelect);
0039         _worldModel->endMacro();
0040 
0041         setFinished();
0042         return true;
0043     }
0044     return false;
0045 }
0046 
0047 void LinearMotorCreator::tryAttach(const QPointF& pos)
0048 {
0049     foreach(QGraphicsItem* it, _worldScene->items(pos)) {
0050         StepCore::Item* item = _worldScene->itemFromGraphics(it);
0051         if(dynamic_cast<StepCore::Particle*>(item) || dynamic_cast<StepCore::RigidBody*>(item)) {
0052             _worldModel->setProperty(_item, QStringLiteral("body"),
0053                  QVariant::fromValue<StepCore::Object*>(item), WorldModel::UndoNoMerge);
0054 
0055             StepCore::Vector2d lPos(0, 0);
0056             if(dynamic_cast<StepCore::RigidBody*>(item))
0057                 lPos = dynamic_cast<StepCore::RigidBody*>(item)->pointWorldToLocal(StepGraphicsItem::pointToVector(pos));
0058 
0059             _worldModel->setProperty(_item, QStringLiteral("localPosition"), QVariant::fromValue(lPos));
0060             break;
0061         }
0062     }
0063 }
0064 
0065 LinearMotorGraphicsItem::LinearMotorGraphicsItem(StepCore::Item* item, WorldModel* worldModel)
0066     : StepGraphicsItem(item, worldModel), _moving(false)
0067 {
0068     Q_ASSERT(dynamic_cast<StepCore::LinearMotor*>(_item) != nullptr);
0069     setFlag(QGraphicsItem::ItemIsSelectable);
0070     setFlag(QGraphicsItem::ItemIsMovable);
0071     setZValue(HANDLER_ZVALUE);
0072 
0073     _forceHandler = new ArrowHandlerGraphicsItem(item, worldModel, this,
0074                    _item->metaObject()->property(QStringLiteral("forceValue")));
0075     _forceHandler->setVisible(false);
0076 }
0077 
0078 inline StepCore::LinearMotor* LinearMotorGraphicsItem::motor() const
0079 {
0080     return static_cast<StepCore::LinearMotor*>(_item);
0081 }
0082 
0083 QPainterPath LinearMotorGraphicsItem::shape() const
0084 {
0085     QPainterPath path;
0086     double radius = (RADIUS+1)/currentViewScale();
0087     path.addEllipse(QRectF(-radius,-radius,radius*2,radius*2));
0088     return path;
0089 }
0090 
0091 void LinearMotorGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
0092 {
0093     if ((event->buttons() & Qt::LeftButton) && (flags() & ItemIsMovable)) {
0094         QPointF newPos(mapToParent(event->pos()) - transform().map(event->buttonDownPos(Qt::LeftButton)));
0095         QVariant vpos = QVariant::fromValue(pointToVector(newPos));
0096 
0097         _worldModel->simulationPause();
0098         if(!_moving) {
0099             _moving = true;
0100             _worldModel->beginMacro(i18n("Move %1", _item->name()));
0101             _worldModel->setProperty(_item, QStringLiteral("body"),
0102                         QVariant::fromValue<StepCore::Object*>(NULL), WorldModel::UndoNoMerge);
0103         }
0104 
0105         _worldModel->setProperty(_item, QStringLiteral("localPosition"), vpos);
0106     } else {
0107         event->ignore();
0108     }
0109 }
0110 
0111 void LinearMotorGraphicsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
0112 {
0113     if(_moving) {
0114         QPointF pos = event->scenePos();
0115         foreach(QGraphicsItem* it, scene()->items(pos)) {
0116             StepCore::Item* item = static_cast<WorldScene*>(scene())->itemFromGraphics(it);
0117             if(dynamic_cast<StepCore::Particle*>(item) || dynamic_cast<StepCore::RigidBody*>(item)) {
0118                 _worldModel->simulationPause();
0119                 _worldModel->setProperty(_item, QStringLiteral("body"),
0120                             QVariant::fromValue<StepCore::Object*>(item), WorldModel::UndoNoMerge);
0121 
0122                 StepCore::Vector2d lPos(0, 0);
0123                 if(dynamic_cast<StepCore::RigidBody*>(item))
0124                     lPos = dynamic_cast<StepCore::RigidBody*>(item)->pointWorldToLocal(StepGraphicsItem::pointToVector(pos));
0125 
0126                 _worldModel->setProperty(_item, QStringLiteral("localPosition"), QVariant::fromValue(lPos));
0127 
0128                 break;
0129             }
0130         }
0131 
0132         _moving = false;
0133         _worldModel->endMacro();
0134     } else StepGraphicsItem::mouseReleaseEvent(event);
0135 }
0136 
0137 
0138 void LinearMotorGraphicsItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
0139 {
0140     double s = currentViewScale();
0141     double radius = RADIUS/s;
0142 
0143     painter->setRenderHint(QPainter::Antialiasing, true);
0144     painter->setPen(Qt::NoPen);
0145     painter->setBrush(QBrush(QColor::fromRgba(motor()->color())));
0146     painter->drawEllipse(QRectF(-radius,-radius,radius*2,radius*2));
0147     painter->setPen(QPen(QColor::fromRgba(motor()->color()), radius, Qt::SolidLine, Qt::RoundCap));
0148     drawArrow(painter, motor()->forceValue());
0149 
0150     //painter->setPen(QPen(QColor::fromRgba(particle()->color()), 2*radius, Qt::SolidLine, Qt::RoundCap));
0151     //painter->drawPoint(0,0);
0152 
0153     if(_isSelected) {
0154         painter->setPen(QPen(SELECTION_COLOR, 0, Qt::DashLine));
0155         painter->setBrush(Qt::NoBrush);
0156         //painter->setBrush(QBrush(QColor(0, 0x99, 0xff)));
0157         radius = (RADIUS+SELECTION_MARGIN)/s;
0158         painter->drawEllipse(QRectF(-radius, -radius, radius*2, radius*2));
0159     }
0160 
0161 //    painter->setRenderHint(QPainter::Antialiasing, true);
0162 //    painter->setPen(QPen(QColor::fromRgba(motor()->color()), 0));
0163 //    //painter->setBrush(QBrush(Qt::black));
0164 //
0165 //    if(_isSelected) {
0166 //        painter->setPen(QPen(SELECTION_COLOR, 0, Qt::DashLine));
0167 //    }
0168 
0169 }
0170 
0171 void LinearMotorGraphicsItem::viewScaleChanged()
0172 {
0173     prepareGeometryChange();
0174 
0175     double s = currentViewScale();
0176     const StepCore::Vector2d& f = motor()->forceValue();
0177     _boundingRect = QRectF(0,0,f[0],f[1]).normalized();
0178     _boundingRect.adjust(-(RADIUS+ARROW_STROKE)/s, -(RADIUS+ARROW_STROKE)/s,
0179                             (RADIUS+ARROW_STROKE)/s, (RADIUS+ARROW_STROKE)/s);
0180     _boundingRect |= QRectF((-RADIUS-SELECTION_MARGIN)/s,  (-RADIUS-SELECTION_MARGIN)/s,
0181                             (RADIUS+SELECTION_MARGIN)*2/s,( RADIUS+SELECTION_MARGIN)*2/s);
0182 //    worldDataChanged(false);
0183 }
0184 
0185 void LinearMotorGraphicsItem::worldDataChanged(bool dynamicOnly)
0186 {
0187     if(!dynamicOnly) {
0188         viewScaleChanged();
0189         update();
0190     }
0191     setPos(vectorToPoint(motor()->position()));       
0192 }
0193 
0194 void LinearMotorGraphicsItem::stateChanged()
0195 {
0196     if(_isSelected) _forceHandler->setVisible(true);
0197     else _forceHandler->setVisible(false);
0198 }
0199 
0200 
0201 ////////////////////////////////////////////////////////////////////////////////////////////////
0202 
0203 bool CircularMotorCreator::sceneEvent(QEvent* event)
0204 {
0205     QGraphicsSceneMouseEvent* mouseEvent = static_cast<QGraphicsSceneMouseEvent*>(event);
0206     if(event->type() == QEvent::GraphicsSceneMousePress && mouseEvent->button() == Qt::LeftButton) {
0207         QPointF pos = mouseEvent->scenePos();
0208         QVariant vpos = QVariant::fromValue(StepGraphicsItem::pointToVector(pos));
0209 
0210         _worldModel->simulationPause();
0211         _worldModel->beginMacro(i18n("Create %1", _worldModel->newItemName(_className)));
0212         _item = _worldModel->createItem(className()); Q_ASSERT(_item != nullptr);
0213 
0214         _worldModel->setProperty(_item, QStringLiteral("localPosition"), vpos);
0215         _worldModel->addItem(_item);
0216         tryAttach(pos);
0217 
0218         _worldModel->selectionModel()->setCurrentIndex(_worldModel->objectIndex(_item),
0219                                                 QItemSelectionModel::ClearAndSelect);
0220         _worldModel->endMacro();
0221 
0222         setFinished();
0223         return true;
0224     }
0225     return false;
0226 }
0227 
0228 void CircularMotorCreator::tryAttach(const QPointF& pos)
0229 {
0230     foreach(QGraphicsItem* it, _worldScene->items(pos)) {
0231         StepCore::Item* item = _worldScene->itemFromGraphics(it);
0232         if(dynamic_cast<StepCore::RigidBody*>(item)) {
0233             _worldModel->setProperty(_item, QStringLiteral("body"),
0234                     QVariant::fromValue<StepCore::Object*>(item), WorldModel::UndoNoMerge);
0235 
0236             StepCore::Vector2d lPos(0, 0);
0237             lPos = dynamic_cast<StepCore::RigidBody*>(item)->pointWorldToLocal(StepGraphicsItem::pointToVector(pos));
0238             _worldModel->setProperty(_item, QStringLiteral("localPosition"), QVariant::fromValue(lPos));
0239             break;
0240         }
0241     }
0242 }
0243 
0244 CircularMotorGraphicsItem::CircularMotorGraphicsItem(StepCore::Item* item, WorldModel* worldModel)
0245     : StepGraphicsItem(item, worldModel), _moving(false)
0246 {
0247     Q_ASSERT(dynamic_cast<StepCore::CircularMotor*>(_item) != nullptr);
0248     setFlag(QGraphicsItem::ItemIsSelectable);
0249     setFlag(QGraphicsItem::ItemIsMovable);
0250     _torqueHandler = new CircularArrowHandlerGraphicsItem(item, worldModel,  this, ARROW_RADIUS,
0251                    _item->metaObject()->property(QStringLiteral("torqueValue")));
0252     _torqueHandler->setVisible(false);
0253     setZValue(HANDLER_ZVALUE);
0254 }
0255 
0256 inline StepCore::CircularMotor* CircularMotorGraphicsItem::motor() const
0257 {
0258     return static_cast<StepCore::CircularMotor*>(_item);
0259 }
0260 
0261 QPainterPath CircularMotorGraphicsItem::shape() const
0262 {
0263     QPainterPath path;
0264     double radius = (RADIUS+1)/currentViewScale();
0265     path.addEllipse(QRectF(-radius,-radius,radius*2,radius*2));
0266     return path;
0267 }
0268 
0269 void CircularMotorGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
0270 {
0271     if ((event->buttons() & Qt::LeftButton) && (flags() & ItemIsMovable)) {
0272         QPointF newPos(mapToParent(event->pos()) - transform().map(event->buttonDownPos(Qt::LeftButton)));
0273         QVariant vpos = QVariant::fromValue(pointToVector(newPos));
0274 
0275         _worldModel->simulationPause();
0276         if(!_moving) {
0277             _moving = true;
0278             _worldModel->beginMacro(i18n("Move %1", _item->name()));
0279             _worldModel->setProperty(_item, QStringLiteral("body"),
0280                     QVariant::fromValue<StepCore::Object*>(NULL), WorldModel::UndoNoMerge);
0281         }
0282 
0283         _worldModel->setProperty(_item, QStringLiteral("localPosition"), vpos);
0284     } else {
0285         event->ignore();
0286     }
0287 }
0288 
0289 void CircularMotorGraphicsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
0290 {
0291     if(_moving) {
0292         QPointF pos = event->scenePos();
0293         foreach(QGraphicsItem* it, scene()->items(pos)) {
0294             StepCore::Item* item = static_cast<WorldScene*>(scene())->itemFromGraphics(it);
0295             if(dynamic_cast<StepCore::RigidBody*>(item)) {
0296                 _worldModel->simulationPause();
0297                 _worldModel->setProperty(_item, QStringLiteral("body"),
0298                         QVariant::fromValue<StepCore::Object*>(item), WorldModel::UndoNoMerge);
0299 
0300                 StepCore::Vector2d lPos(0, 0);
0301                 if(dynamic_cast<StepCore::RigidBody*>(item))
0302                     lPos = dynamic_cast<StepCore::RigidBody*>(item)->pointWorldToLocal(StepGraphicsItem::pointToVector(pos));
0303 
0304                 _worldModel->setProperty(_item, QStringLiteral("localPosition"), QVariant::fromValue(lPos));
0305 
0306                 break;
0307             }
0308         }
0309 
0310         _moving = false;
0311         _worldModel->endMacro();
0312     } else StepGraphicsItem::mouseReleaseEvent(event);
0313 }
0314 
0315 
0316 void CircularMotorGraphicsItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
0317 {
0318     double s = currentViewScale();
0319     double radius = RADIUS/s;
0320 
0321     painter->setRenderHint(QPainter::Antialiasing, true);
0322     painter->setPen(Qt::NoPen);
0323     painter->setBrush(QBrush(QColor::fromRgba(motor()->color())));
0324     painter->drawEllipse(QRectF(-radius,-radius,radius*2,radius*2));
0325     painter->setPen(QPen(QColor::fromRgba(motor()->color()), radius, Qt::SolidLine, Qt::RoundCap));
0326     drawCircularArrow(painter, motor()->torqueValue(), ARROW_RADIUS);
0327 
0328     //painter->setPen(QPen(QColor::fromRgba(particle()->color()), 2*radius, Qt::SolidLine, Qt::RoundCap));
0329     //painter->drawPoint(0,0);
0330 
0331     if(_isSelected) {
0332         painter->setPen(QPen(SELECTION_COLOR, 0, Qt::DashLine));
0333         painter->setBrush(Qt::NoBrush);
0334         //painter->setBrush(QBrush(QColor(0, 0x99, 0xff)));
0335         radius = (RADIUS+SELECTION_MARGIN)/s;
0336         painter->drawEllipse(QRectF(-radius, -radius, radius*2, radius*2));
0337     }
0338 
0339 //    painter->setRenderHint(QPainter::Antialiasing, true);
0340 //    painter->setPen(QPen(QColor::fromRgba(motor()->color()), 0));
0341 //    //painter->setBrush(QBrush(Qt::black));
0342 //
0343 //    if(_isSelected) {
0344 //        painter->setPen(QPen(SELECTION_COLOR, 0, Qt::DashLine));
0345 //    }
0346 
0347 }
0348 
0349 void CircularMotorGraphicsItem::viewScaleChanged()
0350 {
0351     prepareGeometryChange();
0352 
0353     double s = currentViewScale();
0354     double r = (ARROW_RADIUS + CIRCULAR_ARROW_STROKE + SELECTION_MARGIN)/s;
0355     _boundingRect = QRectF(-r, -r, 2*r, 2*r);
0356 }
0357 
0358 void CircularMotorGraphicsItem::worldDataChanged(bool dynamicOnly)
0359 {
0360     if(!dynamicOnly) {
0361         viewScaleChanged();
0362         update();
0363     }
0364     setPos(vectorToPoint(motor()->position()));       
0365 }
0366 
0367 void CircularMotorGraphicsItem::stateChanged()
0368 {
0369     if(_isSelected) _torqueHandler->setVisible(true);
0370     else _torqueHandler->setVisible(false);
0371 }
0372