File indexing completed on 2024-04-28 07:39:36
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 "jointgraphics.h" 0008 0009 #include "worldmodel.h" 0010 0011 #include <stepcore/particle.h> 0012 #include <stepcore/rigidbody.h> 0013 0014 #include <QGraphicsSceneMouseEvent> 0015 #include <KLocalizedString> 0016 0017 AnchorGraphicsItem::AnchorGraphicsItem(StepCore::Item* item, WorldModel* worldModel) 0018 : StepGraphicsItem(item, worldModel) 0019 { 0020 Q_ASSERT(dynamic_cast<StepCore::Anchor*>(_item) != nullptr); 0021 setFlag(QGraphicsItem::ItemIsSelectable); 0022 setFlag(QGraphicsItem::ItemIsMovable); 0023 setZValue(JOINT_ZVALUE); 0024 setExclusiveMoving(true); 0025 } 0026 0027 inline StepCore::Anchor* AnchorGraphicsItem::anchor() const 0028 { 0029 return static_cast<StepCore::Anchor*>(_item); 0030 } 0031 0032 QPainterPath AnchorGraphicsItem::shape() const 0033 { 0034 QPainterPath path; 0035 double radius = (HANDLER_SIZE+1)/currentViewScale(); 0036 path.addEllipse(QRectF(-radius,-radius,radius*2,radius*2)); 0037 return path; 0038 } 0039 0040 void AnchorGraphicsItem::mouseSetPos(const QPointF& pos, const QPointF&, MovingState movingState) 0041 { 0042 static_cast<WorldScene*>(scene())->snapItem(pos, 0043 WorldScene::SnapRigidBody | WorldScene::SnapParticle | WorldScene::SnapOnCenter | 0044 WorldScene::SnapSetPosition | WorldScene::SnapSetAngle, nullptr, movingState, _item); 0045 } 0046 0047 void AnchorGraphicsItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/) 0048 { 0049 double s = currentViewScale(); 0050 double radius = HANDLER_SIZE/s; 0051 0052 painter->setRenderHint(QPainter::Antialiasing, true); 0053 painter->setPen(QPen(QColor::fromRgba(anchor()->color()), 0, Qt::SolidLine)); 0054 painter->drawEllipse(QRectF(-radius,-radius,radius*2,radius*2)); 0055 painter->drawLine(QLineF(-radius, -radius, radius, radius)); 0056 painter->drawLine(QLineF(-radius, radius, radius, -radius)); 0057 0058 if(_isSelected) { 0059 painter->setPen(QPen(SELECTION_COLOR, 0, Qt::DashLine)); 0060 painter->setBrush(Qt::NoBrush); 0061 //painter->setBrush(QBrush(QColor(0, 0x99, 0xff))); 0062 radius = (HANDLER_SIZE+SELECTION_MARGIN)/s; 0063 painter->drawEllipse(QRectF(-radius, -radius, radius*2, radius*2)); 0064 } 0065 } 0066 0067 void AnchorGraphicsItem::viewScaleChanged() 0068 { 0069 prepareGeometryChange(); 0070 0071 double s = currentViewScale(); 0072 _boundingRect |= QRectF((-HANDLER_SIZE-SELECTION_MARGIN)/s, (-HANDLER_SIZE-SELECTION_MARGIN)/s, 0073 (HANDLER_SIZE+SELECTION_MARGIN)*2/s,( HANDLER_SIZE+SELECTION_MARGIN)*2/s); 0074 } 0075 0076 void AnchorGraphicsItem::worldDataChanged(bool dynamicOnly) 0077 { 0078 if(!dynamicOnly) update(); 0079 setPos(vectorToPoint(anchor()->position())); 0080 } 0081 0082 ////////////////////////////////////////////////////////////////////////// 0083 0084 PinGraphicsItem::PinGraphicsItem(StepCore::Item* item, WorldModel* worldModel) 0085 : StepGraphicsItem(item, worldModel) 0086 { 0087 Q_ASSERT(dynamic_cast<StepCore::Pin*>(_item) != nullptr); 0088 setFlag(QGraphicsItem::ItemIsSelectable); 0089 setFlag(QGraphicsItem::ItemIsMovable); 0090 setZValue(JOINT_ZVALUE); 0091 setExclusiveMoving(true); 0092 } 0093 0094 inline StepCore::Pin* PinGraphicsItem::pin() const 0095 { 0096 return static_cast<StepCore::Pin*>(_item); 0097 } 0098 0099 QPainterPath PinGraphicsItem::shape() const 0100 { 0101 QPainterPath path; 0102 double radius = (HANDLER_SIZE+1)/currentViewScale(); 0103 path.addEllipse(QRectF(-radius,-radius,radius*2,radius*2)); 0104 return path; 0105 } 0106 0107 void PinGraphicsItem::mouseSetPos(const QPointF& pos, const QPointF&, MovingState movingState) 0108 { 0109 static_cast<WorldScene*>(scene())->snapItem(pos, 0110 WorldScene::SnapRigidBody | WorldScene::SnapSetPosition | 0111 WorldScene::SnapSetLocalPosition, nullptr, movingState, _item); 0112 } 0113 0114 void PinGraphicsItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/) 0115 { 0116 double s = currentViewScale(); 0117 double radius = HANDLER_SIZE/s; 0118 0119 painter->setRenderHint(QPainter::Antialiasing, true); 0120 painter->setPen(QPen(QColor::fromRgba(pin()->color()), 0, Qt::SolidLine)); 0121 painter->drawEllipse(QRectF(-radius,-radius,radius*2,radius*2)); 0122 painter->drawPoint(0,0);//Rect(QRectF(-0.5/s,-0.5/s, 1/s, 1/s)); 0123 0124 if(_isSelected) { 0125 painter->setPen(QPen(SELECTION_COLOR, 0, Qt::DashLine)); 0126 painter->setBrush(Qt::NoBrush); 0127 //painter->setBrush(QBrush(QColor(0, 0x99, 0xff))); 0128 radius = (HANDLER_SIZE+SELECTION_MARGIN)/s; 0129 painter->drawEllipse(QRectF(-radius, -radius, radius*2, radius*2)); 0130 } 0131 } 0132 0133 void PinGraphicsItem::viewScaleChanged() 0134 { 0135 prepareGeometryChange(); 0136 0137 double s = currentViewScale(); 0138 _boundingRect |= QRectF((-HANDLER_SIZE-SELECTION_MARGIN)/s, (-HANDLER_SIZE-SELECTION_MARGIN)/s, 0139 (HANDLER_SIZE+SELECTION_MARGIN)*2/s,( HANDLER_SIZE+SELECTION_MARGIN)*2/s); 0140 } 0141 0142 void PinGraphicsItem::worldDataChanged(bool dynamicOnly) 0143 { 0144 if(!dynamicOnly) update(); 0145 setPos(vectorToPoint(pin()->position())); 0146 } 0147 0148 ////////////////////////////////////////////////////////////////////////// 0149 0150 StickHandlerGraphicsItem::StickHandlerGraphicsItem(StepCore::Item* item, WorldModel* worldModel, 0151 QGraphicsItem* parent, int num) 0152 : StepGraphicsItem(item, worldModel, parent), _num(num) 0153 { 0154 Q_ASSERT(_num == 1 || _num == 2); 0155 setFlag(QGraphicsItem::ItemIsMovable); 0156 setZValue(HANDLER_ZVALUE); 0157 setExclusiveMoving(true); 0158 setExclusiveMovingMessage(i18n("Move end of %1", _item->name())); 0159 setPos(0, 0); 0160 } 0161 0162 void StickHandlerGraphicsItem::viewScaleChanged() 0163 { 0164 prepareGeometryChange(); 0165 double w = HANDLER_SIZE/currentViewScale()/2; 0166 _boundingRect = QRectF(-w, -w, w*2, w*2); 0167 } 0168 0169 void StickHandlerGraphicsItem::worldDataChanged(bool) 0170 { 0171 if(_num == 2) 0172 setPos(vectorToPoint(static_cast<StepCore::Stick*>(_item)->position2()- 0173 static_cast<StepCore::Stick*>(_item)->position1())); 0174 } 0175 0176 void StickHandlerGraphicsItem::mouseSetPos(const QPointF& pos, const QPointF&, MovingState movingState) 0177 { 0178 static_cast<WorldScene*>(scene())->snapItem(parentItem()->mapToParent(pos), 0179 WorldScene::SnapParticle | WorldScene::SnapRigidBody | 0180 WorldScene::SnapSetLocalPosition, nullptr, movingState, _item, _num); 0181 0182 StepCore::Stick* stick = static_cast<StepCore::Stick*>(_item); 0183 _worldModel->setProperty(_item, QStringLiteral("restLength"), 0184 (stick->position2() - stick->position1()).norm()); 0185 0186 } 0187 0188 StickGraphicsItem::StickGraphicsItem(StepCore::Item* item, WorldModel* worldModel) 0189 : StepGraphicsItem(item, worldModel) 0190 { 0191 Q_ASSERT(dynamic_cast<StepCore::Stick*>(_item) != nullptr); 0192 setFlag(QGraphicsItem::ItemIsSelectable); 0193 setFlag(QGraphicsItem::ItemIsMovable); 0194 setZValue(JOINT_ZVALUE); 0195 _handler1 = new StickHandlerGraphicsItem(item, worldModel, this, 1); 0196 _handler2 = new StickHandlerGraphicsItem(item, worldModel, this, 2); 0197 _handler1->setVisible(false); 0198 _handler2->setVisible(false); 0199 } 0200 0201 QPainterPath StickGraphicsItem::shape() const 0202 { 0203 return _painterPath; 0204 /* 0205 QPainterPath path; 0206 0207 double u = 1/currentViewScale(); 0208 path.addRect(QRectF(-u, -_radius-u, _rnorm+u, _radius*2+u)); 0209 0210 _worldModel->simulationPause(); 0211 StepCore::Vector2d r = stick()->position2() - stick()->position1(); 0212 return QMatrix().rotate(atan2(r[1], r[0])*180/3.14).map(path); 0213 */ 0214 } 0215 0216 void StickGraphicsItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/) 0217 { 0218 StepCore::Vector2d r = stick()->position2() - stick()->position1(); 0219 0220 painter->setPen(QPen(QColor::fromRgba(stick()->color()), 0)); 0221 0222 StepCore::Vector2d p1c, p2c; 0223 if(stick()->rigidBody1()) p1c = stick()->rigidBody1()->position(); 0224 else if(stick()->particle1()) p1c = stick()->particle1()->position(); 0225 else p1c = stick()->position1(); 0226 0227 if(stick()->rigidBody2()) p2c = stick()->rigidBody2()->position(); 0228 else if(stick()->particle2()) p2c = stick()->particle2()->position(); 0229 else p2c = stick()->position2(); 0230 0231 painter->drawLine(QPointF(0, 0), vectorToPoint(p1c - stick()->position1())); 0232 painter->drawLine(vectorToPoint(r), vectorToPoint(p2c - stick()->position1())); 0233 0234 painter->rotate(atan2(r[1], r[0])*180/3.14); 0235 painter->setPen(Qt::NoPen); 0236 painter->setBrush(QBrush(QColor::fromRgba(stick()->color()))); 0237 painter->setRenderHint(QPainter::Antialiasing, true); 0238 painter->drawRect(QRectF(0, -_radius, stick()->restLength(), _radius*2)); 0239 0240 if(stick()->restLength() < _rnorm + _radius/RADIUS) { 0241 painter->setBrush(Qt::NoBrush); 0242 painter->setPen(QPen(QColor::fromRgba(stick()->color()), 0, Qt::DotLine)); 0243 painter->drawLine(QLineF(stick()->restLength(), 0, _rnorm, 0)); 0244 } 0245 0246 if(isSelected()) { 0247 painter->setRenderHint(QPainter::Antialiasing, true); 0248 painter->setPen(QPen(SELECTION_COLOR, 0, Qt::DashLine)); 0249 painter->setBrush(Qt::NoBrush); 0250 double m = SELECTION_MARGIN / currentViewScale(); 0251 //painter->scale( 1/_rscale, 1/_radius ); 0252 painter->drawRect(QRectF(-m, -_radius-m, _rnorm+m*2, (_radius+m)*2)); 0253 } 0254 } 0255 0256 void StickGraphicsItem::viewScaleChanged() 0257 { 0258 prepareGeometryChange(); 0259 0260 double s = currentViewScale(); 0261 double m = (SELECTION_MARGIN+1) / s; 0262 double u = 1/s; 0263 0264 StepCore::Vector2d r = stick()->position2() - stick()->position1(); 0265 _rnorm = r.norm(); 0266 _radius = RADIUS/s; 0267 0268 if(_rnorm < stick()->restLength()) r *= stick()->restLength() / _rnorm; 0269 0270 _boundingRect = QRectF(0, 0, r[0], r[1]).normalized(); 0271 _boundingRect.adjust(-_radius-m, -_radius-m, _radius+m, _radius+m); 0272 0273 StepCore::Vector2d p1c, p2c; 0274 if(stick()->rigidBody1()) p1c = stick()->rigidBody1()->position(); 0275 else if(stick()->particle1()) p1c = stick()->particle1()->position(); 0276 else p1c = stick()->position1(); 0277 0278 if(stick()->rigidBody2()) p2c = stick()->rigidBody2()->position(); 0279 else if(stick()->particle2()) p2c = stick()->particle2()->position(); 0280 else p2c = stick()->position2(); 0281 0282 _boundingRect |= QRectF(QPoint(0, 0), vectorToPoint(p1c - stick()->position1())).normalized(); 0283 _boundingRect |= QRectF(vectorToPoint(r), vectorToPoint(p2c - stick()->position2())).normalized(); 0284 0285 _painterPath.addRect(QRectF(-u, -_radius-u, _rnorm+u, _radius*2+u)); 0286 _painterPath = QTransform().rotate(atan2(r[1], r[0])*180/3.14).map(_painterPath); 0287 0288 //update(); // XXX: documentation says this is unnecessary, but it doesn't work without it 0289 } 0290 0291 void StickGraphicsItem::worldDataChanged(bool dynamicOnly) 0292 { 0293 Q_UNUSED(dynamicOnly) 0294 // XXX: TODO do not redraw everything each time 0295 setPos(vectorToPoint(stick()->position1())); 0296 viewScaleChanged(); 0297 update(); 0298 } 0299 0300 void StickGraphicsItem::stateChanged() 0301 { 0302 if(_isSelected) { 0303 _handler1->setVisible(true); 0304 _handler2->setVisible(true); 0305 } 0306 else { 0307 _handler1->setVisible(false); 0308 _handler2->setVisible(false); 0309 } 0310 viewScaleChanged(); 0311 update(); 0312 } 0313 0314 void StickGraphicsItem::mouseSetPos(const QPointF& /*pos*/, const QPointF& diff, MovingState) 0315 { 0316 _worldModel->simulationPause(); 0317 0318 if(stick()->body1()) { 0319 Q_ASSERT(stick()->body1()->metaObject()->inherits<StepCore::Item>()); 0320 StepGraphicsItem* gItem = static_cast<WorldScene*>( 0321 scene())->graphicsFromItem(static_cast<StepCore::Item*>(stick()->body1())); 0322 Q_ASSERT(gItem != nullptr); 0323 if(!gItem->isSelected()) { 0324 _worldModel->setProperty(_item, QStringLiteral("localPosition1"), 0325 _item->metaObject()->property(QStringLiteral("position1"))->readVariant(_item)); 0326 _worldModel->setProperty(_item, QStringLiteral("body1"), 0327 QVariant::fromValue<StepCore::Object*>(NULL), WorldModel::UndoNoMerge); 0328 } 0329 } else { 0330 _worldModel->setProperty(_item, QStringLiteral("localPosition1"), 0331 QVariant::fromValue( (stick()->position1() + pointToVector(diff)).eval() )); 0332 } 0333 0334 if(stick()->body2()) { 0335 Q_ASSERT(stick()->body2()->metaObject()->inherits<StepCore::Item>()); 0336 StepGraphicsItem* gItem = static_cast<WorldScene*>( 0337 scene())->graphicsFromItem(static_cast<StepCore::Item*>(stick()->body2())); 0338 Q_ASSERT(gItem != nullptr); 0339 if(!gItem->isSelected()) { 0340 _worldModel->setProperty(_item, QStringLiteral("localPosition2"), 0341 _item->metaObject()->property(QStringLiteral("position2"))->readVariant(_item)); 0342 _worldModel->setProperty(_item, QStringLiteral("body2"), QString(), WorldModel::UndoNoMerge); 0343 } 0344 } else { 0345 _worldModel->setProperty(_item, QStringLiteral("localPosition2"), 0346 QVariant::fromValue( (stick()->position2() + pointToVector(diff)).eval() )); 0347 } 0348 }