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"