File indexing completed on 2024-04-28 03:51:19
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 "springgraphics.h" 0008 0009 #include <stepcore/spring.h> 0010 0011 #include "worldmodel.h" 0012 #include "worldscene.h" 0013 #include "worldfactory.h" 0014 0015 #include <QGraphicsSceneMouseEvent> 0016 #include <QPainter> 0017 0018 #include <KLocalizedString> 0019 0020 #include <cmath> 0021 0022 SpringHandlerGraphicsItem::SpringHandlerGraphicsItem(StepCore::Item* item, WorldModel* worldModel, 0023 QGraphicsItem* parent, int num) 0024 : StepGraphicsItem(item, worldModel, parent), _num(num) 0025 { 0026 Q_ASSERT(_num == 1 || _num == 2); 0027 setFlag(QGraphicsItem::ItemIsMovable); 0028 setZValue(HANDLER_ZVALUE); 0029 setExclusiveMoving(true); 0030 setExclusiveMovingMessage(i18n("Move end of %1", _item->name())); 0031 setPos(0, 0); 0032 } 0033 0034 void SpringHandlerGraphicsItem::viewScaleChanged() 0035 { 0036 prepareGeometryChange(); 0037 double w = HANDLER_SIZE/currentViewScale()/2; 0038 _boundingRect = QRectF(-w, -w, w*2, w*2); 0039 } 0040 0041 void SpringHandlerGraphicsItem::worldDataChanged(bool) 0042 { 0043 if(_num == 2) 0044 setPos(vectorToPoint(static_cast<StepCore::Spring*>(_item)->position2()- 0045 static_cast<StepCore::Spring*>(_item)->position1())); 0046 } 0047 0048 void SpringHandlerGraphicsItem::mouseSetPos(const QPointF& pos, const QPointF&, MovingState movingState) 0049 { 0050 static_cast<WorldScene*>(scene())->snapItem(parentItem()->mapToParent(pos), 0051 WorldScene::SnapParticle | WorldScene::SnapRigidBody | 0052 WorldScene::SnapSetLocalPosition, nullptr, movingState, _item, _num); 0053 0054 } 0055 0056 SpringGraphicsItem::SpringGraphicsItem(StepCore::Item* item, WorldModel* worldModel) 0057 : StepGraphicsItem(item, worldModel) 0058 { 0059 Q_ASSERT(dynamic_cast<StepCore::Spring*>(_item) != nullptr); 0060 setFlag(QGraphicsItem::ItemIsSelectable); 0061 setFlag(QGraphicsItem::ItemIsMovable); 0062 setZValue(FORCE_ZVALUE); 0063 _handler1 = new SpringHandlerGraphicsItem(item, worldModel, this, 1); 0064 _handler2 = new SpringHandlerGraphicsItem(item, worldModel, this, 2); 0065 _handler1->setVisible(false); 0066 _handler2->setVisible(false); 0067 } 0068 0069 QPainterPath SpringGraphicsItem::shape() const 0070 { 0071 return _painterPath; 0072 /* 0073 QPainterPath path; 0074 0075 double u = 1/currentViewScale(); 0076 path.addRect(QRectF(-u, -_radius-u, _rnorm+u, _radius*2+u)); 0077 0078 _worldModel->simulationPause(); 0079 StepCore::Vector2d r = spring()->position2() - spring()->position1(); 0080 return QMatrix().rotate(atan2(r[1], r[0])*180/3.14).map(path); 0081 */ 0082 } 0083 0084 void SpringGraphicsItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/) 0085 { 0086 static const int seq[4] = { 0,1,0,-1 }; 0087 0088 StepCore::Vector2d r = spring()->position2() - spring()->position1(); 0089 0090 painter->setPen(QPen(QColor::fromRgba(spring()->color()), 0)); 0091 0092 StepCore::Vector2d p1c, p2c; 0093 if(spring()->rigidBody1()) p1c = spring()->rigidBody1()->position(); 0094 else if(spring()->particle1()) p1c = spring()->particle1()->position(); 0095 else p1c = spring()->position1(); 0096 0097 if(spring()->rigidBody2()) p2c = spring()->rigidBody2()->position(); 0098 else if(spring()->particle2()) p2c = spring()->particle2()->position(); 0099 else p2c = spring()->position2(); 0100 0101 painter->drawLine(QPointF(0, 0), vectorToPoint(p1c - spring()->position1())); 0102 painter->drawLine(vectorToPoint(r), vectorToPoint(p2c - spring()->position1())); 0103 0104 painter->rotate(atan2(r[1], r[0])*180/3.14); 0105 0106 if(_rscale != 0) { 0107 painter->scale( _rscale, _radius ); 0108 int n = int(_rnorm/_rscale) & ~1; 0109 for(int i=1; i<=n; i++) { 0110 painter->drawLine(QLineF( i-1, seq[(i-1)&3], i, seq[i&3] )); 0111 } 0112 painter->drawLine(QLineF(n, seq[n&3], _rnorm/_rscale, 0)); 0113 painter->scale( 1/_rscale, 1/_radius ); 0114 } else { 0115 painter->drawLine(QLineF( 0, 0, _rnorm, 0 )); 0116 } 0117 0118 if(isSelected()) { 0119 painter->setRenderHint(QPainter::Antialiasing, true); 0120 painter->setPen(QPen(SELECTION_COLOR, 0, Qt::DashLine)); 0121 double m = SELECTION_MARGIN / currentViewScale(); 0122 painter->drawRect(QRectF(-m, -_radius-m, _rnorm+m*2, (_radius+m)*2)); 0123 } 0124 } 0125 0126 void SpringGraphicsItem::viewScaleChanged() 0127 { 0128 prepareGeometryChange(); 0129 0130 StepCore::Vector2d r = spring()->position2() - spring()->position1(); 0131 _rnorm = r.norm(); 0132 0133 double sc = _rnorm / spring()->restLength(); 0134 if(sc < 1.41) { 0135 _radius = sqrt(2-sc*sc)*RADIUS; 0136 _rscale = sc*RADIUS; 0137 if(_radius < 1) { _rscale = 0; _radius = 1; } 0138 } else { _rscale = 0; _radius = 1; } 0139 0140 double s = currentViewScale(); 0141 double m = (SELECTION_MARGIN+1) / s; 0142 _radius /= s; 0143 _rscale /= s; 0144 0145 _boundingRect = QRectF(0, 0, r[0], r[1]).normalized(); 0146 _boundingRect.adjust(-_radius-m, -_radius-m, _radius+m, _radius+m); 0147 0148 StepCore::Vector2d p1c, p2c; 0149 if(spring()->rigidBody1()) p1c = spring()->rigidBody1()->position(); 0150 else if(spring()->particle1()) p1c = spring()->particle1()->position(); 0151 else p1c = spring()->position1(); 0152 0153 if(spring()->rigidBody2()) p2c = spring()->rigidBody2()->position(); 0154 else if(spring()->particle2()) p2c = spring()->particle2()->position(); 0155 else p2c = spring()->position2(); 0156 0157 _boundingRect |= QRectF(QPoint(0, 0), vectorToPoint(p1c - spring()->position1())).normalized(); 0158 _boundingRect |= QRectF(vectorToPoint(r), vectorToPoint(p2c - spring()->position2())).normalized(); 0159 0160 double u = 1/s; 0161 _painterPath.addRect(QRectF(-u, -_radius-u, _rnorm+u, _radius*2+u)); 0162 _painterPath = QTransform().rotate(atan2(r[1], r[0])*180/3.14).map(_painterPath); 0163 0164 //update(); // XXX: documentation says this is unnecessary, but it doesn't work without it 0165 } 0166 0167 void SpringGraphicsItem::worldDataChanged(bool dynamicOnly) 0168 { 0169 Q_UNUSED(dynamicOnly) 0170 // XXX: TODO do not redraw everything each time 0171 setPos(vectorToPoint(spring()->position1())); 0172 viewScaleChanged(); 0173 update(); 0174 } 0175 0176 void SpringGraphicsItem::stateChanged() 0177 { 0178 if(_isSelected) { 0179 _handler1->setVisible(true); 0180 _handler2->setVisible(true); 0181 } 0182 else { 0183 _handler1->setVisible(false); 0184 _handler2->setVisible(false); 0185 } 0186 viewScaleChanged(); 0187 update(); 0188 } 0189 0190 void SpringGraphicsItem::mouseSetPos(const QPointF& /*pos*/, const QPointF& diff, MovingState) 0191 { 0192 _worldModel->simulationPause(); 0193 0194 if(spring()->body1()) { 0195 Q_ASSERT(spring()->body1()->metaObject()->inherits<StepCore::Item>()); 0196 StepGraphicsItem* gItem = static_cast<WorldScene*>( 0197 scene())->graphicsFromItem(static_cast<StepCore::Item*>(spring()->body1())); 0198 Q_ASSERT(gItem != nullptr); 0199 if(!gItem->isSelected()) { 0200 _worldModel->setProperty(_item, QStringLiteral("localPosition1"), 0201 _item->metaObject()->property(QStringLiteral("position1"))->readVariant(_item)); 0202 _worldModel->setProperty(_item, QStringLiteral("body1"), 0203 QVariant::fromValue<StepCore::Object*>(NULL), WorldModel::UndoNoMerge); 0204 } 0205 } else { 0206 _worldModel->setProperty(_item, QStringLiteral("localPosition1"), 0207 QVariant::fromValue( (spring()->position1() + pointToVector(diff)).eval() )); 0208 } 0209 0210 if(spring()->body2()) { 0211 Q_ASSERT(spring()->body2()->metaObject()->inherits<StepCore::Item>()); 0212 StepGraphicsItem* gItem = static_cast<WorldScene*>( 0213 scene())->graphicsFromItem(static_cast<StepCore::Item*>(spring()->body2())); 0214 Q_ASSERT(gItem != nullptr); 0215 if(!gItem->isSelected()) { 0216 _worldModel->setProperty(_item, QStringLiteral("localPosition2"), 0217 _item->metaObject()->property(QStringLiteral("position2"))->readVariant(_item)); 0218 _worldModel->setProperty(_item, QStringLiteral("body2"), QString(), WorldModel::UndoNoMerge); 0219 } 0220 } else { 0221 _worldModel->setProperty(_item, QStringLiteral("localPosition2"), 0222 QVariant::fromValue( (spring()->position2() + pointToVector(diff)).eval() )); 0223 } 0224 }