File indexing completed on 2025-04-13 08:17:43
0001 /*************************************************************************** 0002 * Copyright (C) 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 #include "chassiscircular2.h" 0012 0013 #include "libraryitem.h" 0014 #include "mechanicsitem.h" 0015 #include "mechanicsdocument.h" 0016 0017 #include <KLocalizedString> 0018 #include <QPainter> 0019 #include <QPainterPath> 0020 0021 #include <algorithm> 0022 #include <cmath> 0023 0024 double normalizeAngle(double angle); 0025 0026 Item *ChassisCircular2::construct(ItemDocument *itemDocument, bool newItem, const char *id) 0027 { 0028 return new ChassisCircular2(static_cast<MechanicsDocument *>(itemDocument), newItem, id); 0029 } 0030 0031 LibraryItem *ChassisCircular2::libraryItem() 0032 { 0033 return new LibraryItem(QStringList(QString("mech/chassis_circular_2")), i18n("Circular 2-Wheel Chassis"), i18n("Chassis'"), "chassis.png", LibraryItem::lit_mechanical, ChassisCircular2::construct); 0034 } 0035 0036 ChassisCircular2::ChassisCircular2(MechanicsDocument *mechanicsDocument, bool newItem, const char *id) 0037 : MechanicsItem(mechanicsDocument, newItem, id ? id : "chassis_circular_2") 0038 { 0039 m_name = i18n("Circular 2-Wheel Chassis"); 0040 0041 m_theta1 = 0.0; 0042 m_theta2 = 0.0; 0043 0044 // Q3PointArray pa; // 2018.08.14 - ported to PainterPath 0045 // pa.makeEllipse( -25, -25, 50, 50 ); 0046 QPainterPath path; 0047 path.addEllipse(-25, -25, 50, 50); 0048 QPolygon pa = path.toFillPolygon().toPolygon(); 0049 0050 QTransform m(4, 0, 0, 4, 0, 0); 0051 // m.setTransformationMode( QMatrix::Areas ); // TODO find a replacement 0052 pa = m.map(pa); 0053 setItemPoints(pa); 0054 0055 itemResized(); 0056 } 0057 0058 ChassisCircular2::~ChassisCircular2() 0059 { 0060 } 0061 0062 void ChassisCircular2::itemResized() 0063 { 0064 const double w = sizeRect().width(); 0065 const double h = sizeRect().height(); 0066 0067 m_wheel1Pos = QRect(int(w / 5), int(h / 6), int(w / 4), int(h / 8)); 0068 m_wheel2Pos = QRect(int(w / 5), int(5 * h / 6 - h / 8), int(w / 4), int(h / 8)); 0069 } 0070 0071 void ChassisCircular2::advance(int phase) 0072 { 0073 if (phase != 1) 0074 return; 0075 0076 double speed1 = 60.; // pixels per second 0077 double speed2 = 160.; // pixels per second 0078 0079 m_theta1 = normalizeAngle(m_theta1 + (speed1 / 1000.) / m_wheel1Pos.width()); 0080 m_theta2 = normalizeAngle(m_theta2 + (speed2 / 1000.) / m_wheel2Pos.width()); 0081 0082 const double d1 = speed1 / 1000.; 0083 const double d2 = speed2 / 1000.; 0084 const double sep = m_wheel2Pos.center().y() - m_wheel1Pos.center().y(); 0085 0086 double dtheta = std::atan((d2 - d1) / sep); // Change in orientation of chassis 0087 double moveAngle = absolutePosition().angle() + dtheta / 2; 0088 rotateBy(dtheta); 0089 moveBy(((d1 + d2) / 2.) * std::cos(moveAngle), ((d1 + d2) / 2.) * std::sin(moveAngle)); 0090 } 0091 0092 void ChassisCircular2::drawShape(QPainter &p) 0093 { 0094 const double _x = int(sizeRect().x() + x()); 0095 const double _y = int(sizeRect().y() + y()); 0096 const double w = sizeRect().width(); 0097 const double h = sizeRect().height(); 0098 0099 initPainter(p); 0100 p.setBrush(QColor(255, 246, 210)); 0101 QRect circleRect = sizeRect(); 0102 circleRect.moveLeft(int(circleRect.left() + x())); 0103 circleRect.moveTop(int(circleRect.top() + y())); 0104 p.drawEllipse(circleRect); 0105 0106 // Draw wheels 0107 // TODO get this info from m_wheel1Pos and m_wheel2Pos 0108 const double X = _x + (w / 5); // Wheel's left pos 0109 const double H = h / 8; // Wheel's height 0110 const double y1 = _y + (h / 6); // Wheel 1 y-pos 0111 const double y2 = _y + (5 * h / 6) - H; // Wheel 2 y-pos 0112 0113 p.setPen(Qt::NoPen); 0114 const double stripeWidth = 5; 0115 const double offset2 = 1 + int(m_theta1 * m_wheel1Pos.width()) % int(2 * stripeWidth); 0116 const double offset1 = 1 + int(m_theta2 * m_wheel2Pos.width()) % int(2 * stripeWidth); 0117 p.setBrush(QColor(255, 232, 182)); 0118 for (double i = -1; i < std::ceil(m_wheel1Pos.width() / stripeWidth); ++i) { 0119 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)), 0120 /* QPainter::CoordPainter */ 0121 Qt::ReplaceClip // TODO original Qt::UniteClip 0122 ); 0123 p.drawRect(int(offset1 + X + i * stripeWidth * 2), int(y1 + 1), int(stripeWidth), int(H - 2)); 0124 0125 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)), 0126 /* QPainter::CoordPainter */ 0127 Qt::ReplaceClip // TODO original Qt::UniteClip 0128 ); 0129 p.drawRect(int(offset2 + X + i * stripeWidth * 2), int(y2 + 1), int(stripeWidth), int(H - 2)); 0130 } 0131 p.setClipping(false); 0132 0133 p.setPen(Qt::black); 0134 p.setBrush(Qt::NoBrush); 0135 p.drawRoundedRect(int(X), int(y1), int(w / 4), int(H), 25, 50, Qt::RelativeSize); 0136 p.drawRoundedRect(int(X), int(y2), int(w / 4), int(H), 25, 50, Qt::RelativeSize); 0137 0138 deinitPainter(p); 0139 }