File indexing completed on 2024-04-28 03:51:15

0001 /*.
0002     SPDX-FileCopyrightText: 2007 Vladimir Kuznetsov <ks.vladimir@gmail.com>
0003     SPDX-FileCopyrightText: 2014 Inge Wallin <inge@lysator.liu.se>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "gasgraphics.h"
0009 
0010 #include <stepcore/gas.h>
0011 
0012 #include "ui_create_gas_particles.h"
0013 
0014 #include "worldmodel.h"
0015 #include "worldfactory.h"
0016 
0017 #include <QEvent>
0018 #include <QGraphicsScene>
0019 #include <QGraphicsSceneMouseEvent>
0020 #include <QItemSelectionModel>
0021 #include <QPainter>
0022 
0023 #include <KLocalizedString>
0024 #include <KMessageBox>
0025 
0026 #include <float.h>
0027 
0028 void GasCreator::start()
0029 {
0030     showMessage(MessageFrame::Information,
0031             i18n("Press left mouse button to position\ntop left corner of a region for %1", classNameTr()));
0032 }
0033 
0034 bool GasCreator::sceneEvent(QEvent* event)
0035 {
0036     QGraphicsSceneMouseEvent* mouseEvent = static_cast<QGraphicsSceneMouseEvent*>(event);
0037 
0038     if(event->type() == QEvent::GraphicsSceneMousePress && mouseEvent->button() == Qt::LeftButton) {
0039         QPointF pos = mouseEvent->scenePos();
0040         QVariant vpos = QVariant::fromValue(StepGraphicsItem::pointToVector(pos));
0041 
0042         _worldModel->simulationPause();
0043         _worldModel->beginMacro(i18n("Create %1", _worldModel->newItemName(_className)));
0044         _item = _worldModel->newItem(_className); Q_ASSERT(_item != nullptr);
0045         _worldModel->setProperty(_item, QStringLiteral("measureRectCenter"), vpos);
0046         _worldModel->setProperty(_item, QStringLiteral("measureRectSize"), QVariant::fromValue(StepCore::Vector2d::Zero().eval()));
0047         _worldModel->selectionModel()->setCurrentIndex(_worldModel->objectIndex(_item),
0048                                                     QItemSelectionModel::ClearAndSelect);
0049 
0050         StepCore::Gas* gas = static_cast<StepCore::Gas*>(_item);
0051         _worldModel->newItem(QStringLiteral("GasLJForce"), gas);
0052         StepCore::Object* ljforce = gas->items()[0];
0053         _worldModel->setProperty(ljforce, QStringLiteral("depth"), 0.1);
0054         _worldModel->setProperty(ljforce, QStringLiteral("rmin"), 0.1);
0055 
0056         _topLeft = StepGraphicsItem::pointToVector(pos);
0057 
0058         showMessage(MessageFrame::Information,
0059             i18n("Move mouse and release left mouse button to position\nbottom right corner of the region for %1", classNameTr()));
0060 
0061         return true;
0062     } else if(event->type() == QEvent::GraphicsSceneMouseMove &&
0063                     mouseEvent->buttons() & Qt::LeftButton) {
0064         
0065         _worldModel->simulationPause();
0066         StepCore::Vector2d pos = StepGraphicsItem::pointToVector(mouseEvent->scenePos());
0067         StepCore::Vector2d position = (_topLeft + pos) / 2.0;
0068         StepCore::Vector2d size = _topLeft - pos;
0069         _worldModel->setProperty(_item, QStringLiteral("measureRectCenter"), QVariant::fromValue(position));
0070         _worldModel->setProperty(_item, QStringLiteral("measureRectSize"), QVariant::fromValue(size));
0071         return true;
0072 
0073     } else if(event->type() == QEvent::GraphicsSceneMouseRelease &&
0074                     mouseEvent->button() == Qt::LeftButton) {
0075 
0076         _worldModel->simulationPause();
0077         StepCore::Vector2d pos = StepGraphicsItem::pointToVector(mouseEvent->scenePos());
0078         StepCore::Vector2d position = (_topLeft + pos) / 2.0;
0079         StepCore::Vector2d size = _topLeft - pos;
0080         if(size[0] == 0 && size[1] == 0) { size[0] = size[1] = 1; }
0081         _worldModel->setProperty(_item, QStringLiteral("measureRectCenter"), QVariant::fromValue(position));
0082         _worldModel->setProperty(_item, QStringLiteral("measureRectSize"), QVariant::fromValue(size));
0083 
0084         showMessage(MessageFrame::Information,
0085             i18n("Please fill in the parameters for the gas particles."));
0086 
0087         GasMenuHandler* menuHandler = new GasMenuHandler(_item, _worldModel, nullptr);
0088         menuHandler->createGasParticles();
0089         menuHandler->deleteLater();
0090 
0091         _worldModel->endMacro();
0092 
0093         showMessage(MessageFrame::Information,
0094             i18n("%1 named '%2' created", classNameTr(), _item->name()),
0095             MessageFrame::CloseButton | MessageFrame::CloseTimer);
0096 
0097         setFinished();
0098         return true;
0099     }
0100 
0101     return false;
0102 }
0103 
0104 /*
0105 class GasArrowHandlerGraphicsItem: public ArrowHandlerGraphicsItem
0106 {
0107 public:
0108     GasArrowHandlerGraphicsItem(StepCore::Item* item, WorldModel* worldModel,
0109                         QGraphicsItem* parent, const StepCore::MetaProperty* property)
0110         : ArrowHandlerGraphicsItem(item, worldModel, parent, property) {}
0111 
0112 protected:
0113     StepCore::Vector2d value() {
0114         return static_cast<StepCore::Gas*>(_item)->measureRectCenter() +
0115                 static_cast<StepCore::Gas*>(_item)->measureRectSize()/2.0;
0116     }
0117     void setValue(const StepCore::Vector2d& value) {
0118         _worldModel->simulationPause();
0119         StepCore::Vector2d v = (value - static_cast<StepCore::Gas*>(_item)->measureRectCenter())*2.0;
0120         _worldModel->setProperty(_item, _property, QVariant::fromValue(v));
0121     }
0122 };
0123 */
0124 
0125 inline StepCore::Gas* GasVertexHandlerGraphicsItem::gas() const
0126 {
0127     return static_cast<StepCore::Gas*>(_item);
0128 }
0129 
0130 StepCore::Vector2d GasVertexHandlerGraphicsItem::value() {
0131     return (gas()->measureRectSize().array()*(corners[_vertexNum]).array()).matrix();
0132 }
0133 
0134 void GasVertexHandlerGraphicsItem::setValue(const StepCore::Vector2d& value)
0135 {
0136     StepCore::Vector2d oCorner = gas()->measureRectCenter() -
0137                     (gas()->measureRectSize().array()*(corners[_vertexNum].array())).matrix();
0138 
0139     StepCore::Vector2d delta = (gas()->measureRectCenter() + value - oCorner)/2.0;
0140     StepCore::Vector2d newPos = oCorner + delta;
0141     StepCore::Vector2d newSize = (newPos - oCorner)*2.0;
0142 
0143     double d = -0.1/currentViewScale();
0144     StepCore::Vector2d sign = (delta.array()*(corners[_vertexNum].array())).matrix();
0145     if(sign[0] < d || sign[1] < d) {
0146         if(sign[0] < d) {
0147             newPos[0] = oCorner[0]; newSize[0] = 0;
0148             _vertexNum ^= 1;
0149         }
0150         if(sign[1] < d) {
0151             newPos[1] = oCorner[1]; newSize[1] = 0;
0152             _vertexNum ^= 2;
0153         }
0154         _worldModel->setProperty(_item, QStringLiteral("measureRectCenter"), QVariant::fromValue(newPos));
0155         _worldModel->setProperty(_item, QStringLiteral("measureRectSize"), QVariant::fromValue(newSize));
0156         setValue(value);
0157         return;
0158     }
0159 
0160     _worldModel->setProperty(_item, QStringLiteral("measureRectCenter"), QVariant::fromValue(newPos));
0161     _worldModel->setProperty(_item, QStringLiteral("measureRectSize"), QVariant::fromValue(newSize));
0162 }
0163 
0164 GasGraphicsItem::GasGraphicsItem(StepCore::Item* item, WorldModel* worldModel)
0165     : StepGraphicsItem(item, worldModel)
0166 {
0167     Q_ASSERT(dynamic_cast<StepCore::Gas*>(_item) != nullptr);
0168     setFlag(QGraphicsItem::ItemIsSelectable);
0169     setFlag(QGraphicsItem::ItemIsMovable);
0170     //setExclusiveMoving(true);
0171     //setFlag(QGraphicsItem::ItemIsMovable);
0172     //setAcceptHoverEvents(true);
0173     //_centerHandler = new ArrowHandlerGraphicsItem(item, worldModel, this,
0174     //                        _item->metaObject()->property("measureRectCenter"));
0175     //_centerHandler->setVisible(false);
0176     setZValue(REGION_ZVALUE);
0177     setAcceptHoverEvents(true);
0178     setOnHoverHandlerEnabled(true);
0179 }
0180 
0181 inline StepCore::Gas* GasGraphicsItem::gas() const
0182 {
0183     return static_cast<StepCore::Gas*>(_item);
0184 }
0185 
0186 void GasGraphicsItem::mouseSetPos(const QPointF& pos, const QPointF&, MovingState)
0187 {
0188 #ifdef __GNUC__
0189 #warning Consider renaming measureRectCenter to position
0190 #endif
0191     const StepCore::MetaProperty* property = _item->metaObject()->property(QStringLiteral("measureRectCenter"));
0192     _worldModel->simulationPause();
0193     _worldModel->setProperty(_item, property, QVariant::fromValue( pointToVector(pos) ));
0194 }
0195 
0196 QPainterPath GasGraphicsItem::shape() const
0197 {
0198     QPainterPath path;
0199     //path.addRect(QRectF(-radius,-radius,radius*2,radius*2));
0200     path.addRect(_boundingRect);
0201     return path;
0202 }
0203 
0204 void GasGraphicsItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
0205 {
0206     //if(_isSelected) {
0207         const StepCore::Vector2d& size = gas()->measureRectSize();
0208         painter->setPen(QPen(QColor::fromRgba(gas()->color()), 0));
0209         painter->drawRect(QRectF(-size[0]/2, -size[1]/2, size[0], size[1]));
0210     //}
0211 }
0212 
0213 void GasGraphicsItem::viewScaleChanged()
0214 {
0215     double s = currentViewScale();
0216     prepareGeometryChange();
0217     const StepCore::Vector2d& size = gas()->measureRectSize();
0218     _boundingRect = QRectF(-(size[0]+SELECTION_MARGIN/s)/2, -(size[1]+SELECTION_MARGIN/s)/2,
0219                             (size[0]+SELECTION_MARGIN/s),    (size[1]+SELECTION_MARGIN/s));
0220     update();
0221 }
0222 
0223 void GasGraphicsItem::worldDataChanged(bool dynamicOnly)
0224 {
0225     if(!dynamicOnly) {
0226         setPos(vectorToPoint(gas()->measureRectCenter()));
0227         viewScaleChanged();
0228         /*prepareGeometryChange();
0229         const StepCore::Vector2d& size = gas()->measureRectSize();
0230         StepCore::Vector2d r0 = gas()->measureRectCenter() - size/2.0;
0231         _boundingRect = QRectF(r0[0], r0[1], size[0], size[1]);*/
0232         //stateChanged();
0233     }
0234 }
0235 
0236 void GasGraphicsItem::stateChanged()
0237 {
0238 #if 0
0239     if(_isSelected) {
0240         /*
0241         const StepCore::Vector2d& size = gas()->measureRectSize();
0242         StepCore::Vector2d r0 = gas()->measureRectCenter() - size/2.0;
0243         _boundingRect = QRectF(r0[0], r0[1], size[0], size[1]);
0244         */
0245         _centerHandler->setVisible(true);
0246     }
0247     else {
0248         //_boundingRect = QRectF();
0249         _centerHandler->setVisible(false);
0250     }
0251 #endif
0252     update();
0253 }
0254 
0255 OnHoverHandlerGraphicsItem* GasGraphicsItem::createOnHoverHandler(const QPointF& pos)
0256 {
0257     double s = currentViewScale();
0258     StepCore::Vector2d size = gas()->measureRectSize();
0259     StepCore::Vector2d l = pointToVector(pos) - gas()->measureRectCenter();
0260 
0261     int num = -1; double minDist2 = HANDLER_SNAP_SIZE*HANDLER_SNAP_SIZE/s/s;
0262     for(unsigned int i=0; i<4; ++i) {
0263         double dist2 = (l - (size.array()*(OnHoverHandlerGraphicsItem::corners[i]).array()).matrix()).squaredNorm();
0264         if(dist2 < minDist2) { num = i; minDist2 = dist2; }
0265     }
0266 
0267     if(_onHoverHandler && _onHoverHandler->vertexNum() == num)
0268         return _onHoverHandler;
0269 
0270     if(num >= 0)
0271         return new GasVertexHandlerGraphicsItem(_item, _worldModel, this, num);
0272 
0273     return nullptr;
0274 }
0275 
0276 void GasMenuHandler::populateMenu(QMenu* menu, KActionCollection* actions)
0277 {
0278     _createGasParticlesUi = nullptr;
0279     _creationDialog = nullptr;
0280     //_confChanged = false;
0281 
0282     menu->addAction(QIcon::fromTheme(QStringLiteral("step_object_GasParticle")), i18n("Create Particles..."), this, &GasMenuHandler::createGasParticles);
0283     //menu->addAction(QIcon::fromTheme("edit-clear"), i18n("Clear gas"), this, SLOT(clearGas()));
0284     menu->addSeparator();
0285     ItemMenuHandler::populateMenu(menu, actions);
0286 }
0287 
0288 inline StepCore::Gas* GasMenuHandler::gas() const
0289 {
0290     return static_cast<StepCore::Gas*>(_object);
0291 }
0292 
0293 void GasMenuHandler::clearGas()
0294 {
0295 //    _worldModel->simulationPause();
0296 
0297 }
0298 
0299 void GasMenuHandler::createGasParticles()
0300 {
0301     if(_worldModel->isSimulationActive())
0302         _worldModel->simulationStop();
0303 
0304     _creationDialog = new GasCreationDialog(this, gas()); // XXX: parent?
0305         // FIXME: Remove this member variable.
0306     _createGasParticlesUi = _creationDialog->ui();
0307 
0308     createGasParticlesCountChanged();
0309     _createGasParticlesUi->labelVolume->setText(gas()->metaObject()->property(QStringLiteral("rectVolume"))->units());
0310     _createGasParticlesUi->labelCount->setText(gas()->metaObject()->property(QStringLiteral("rectParticleCount"))->units());
0311     _createGasParticlesUi->labelConcentration->setText(gas()->metaObject()->property(QStringLiteral("rectConcentration"))->units());
0312     _createGasParticlesUi->labelMass->setText(gas()->metaObject()->property(QStringLiteral("rectMeanParticleMass"))->units());
0313     _createGasParticlesUi->labelTemperature->setText(gas()->metaObject()->property(QStringLiteral("rectTemperature"))->units());
0314     _createGasParticlesUi->labelMeanVelocity->setText(gas()->metaObject()->property(QStringLiteral("rectMeanVelocity"))->units());
0315 
0316     connect(_createGasParticlesUi->lineEditCount, &QLineEdit::textEdited,
0317                 this, &GasMenuHandler::createGasParticlesCountChanged);
0318     connect(_createGasParticlesUi->lineEditConcentration, &QLineEdit::textEdited,
0319                 this, &GasMenuHandler::createGasParticlesConcentrationChanged);
0320 
0321     int retval = _creationDialog->exec();
0322     if (retval == QDialog::Accepted) {
0323     createGasParticlesApply();
0324     }
0325 
0326     delete _creationDialog; _creationDialog = nullptr;
0327     delete _createGasParticlesUi; _createGasParticlesUi = nullptr;
0328 }
0329 
0330 void GasMenuHandler::createGasParticlesCountChanged()
0331 {
0332     _createGasParticlesUi->lineEditConcentration->setText(QString::number(
0333                     _createGasParticlesUi->lineEditCount->text().toDouble() / gas()->rectVolume()
0334                 ));
0335 }
0336 
0337 void GasMenuHandler::createGasParticlesConcentrationChanged()
0338 {
0339     _createGasParticlesUi->lineEditCount->setText(QString::number(
0340                     round(_createGasParticlesUi->lineEditConcentration->text().toDouble() * gas()->rectVolume())
0341                 ));
0342 }
0343 
0344 bool GasMenuHandler::createGasParticlesApply()
0345 {
0346     Q_ASSERT(_createGasParticlesUi && _creationDialog);
0347 
0348     int count = _createGasParticlesUi->lineEditCount->text().toInt();
0349 
0350     if(count > MAX_PARTICLES) {
0351         int ret = KMessageBox::warningContinueCancel(nullptr,
0352               i18n("You are trying to create a very large number of particles. "
0353                    "This will make simulation very slow. Do you want to continue?"),
0354               i18n("Warning - Step"));
0355         if(ret != KMessageBox::Continue) return false;
0356     }
0357 
0358     double mass = _createGasParticlesUi->lineEditMass->text().toDouble();
0359     double temperature = _createGasParticlesUi->lineEditTemperature->text().toDouble();
0360 
0361     bool ok;
0362     StepCore::Vector2d meanVelocity = StepCore::stringToType<StepCore::Vector2d>(
0363                     _createGasParticlesUi->lineEditMeanVelocity->text(), &ok);
0364 
0365     _worldModel->beginMacro(i18n("Create particles for %1", gas()->name()));
0366 
0367     std::vector<StepCore::GasParticle*> particles =
0368             gas()->rectCreateParticles(count, mass, temperature, meanVelocity);
0369 
0370 
0371     const StepCore::GasParticleList::const_iterator end = particles.end();
0372     for(StepCore::GasParticleList::const_iterator it = particles.begin(); it != end; ++it) {
0373         _worldModel->addItem(*it, gas());
0374     }
0375 
0376     _worldModel->endMacro();
0377 
0378     return true;
0379 }
0380 
0381 /*
0382 void GasMenuHandler::clearGas()
0383 {
0384     _worldModel->simulationPause();
0385     //_lastPointTime = -HUGE_VAL; // XXX
0386     _worldModel->setProperty(gas(), property("points"), QVariant::fromValue(StepCore::Vector2dList()) );
0387 }
0388 */
0389 
0390 #include "moc_gasgraphics.cpp"