/** * @RDE_HEADER@ * Interface-Implementation of SingleFire * $Id$ * $HeadURL$ * $Author$ */ // Own #include "single_fire_central_impl.h" #include "single_fire_impl.h" #include #include #include #include #include // ESRI #include #include #include // Qt #include #include #include #include namespace SituationMap { class MyAnimation : public QVariantAnimation { public: MyAnimation(GraphicalObjectSceneMarker *detonationSceneMarker) : m_detonationSceneMarker(detonationSceneMarker) {} ~MyAnimation() = default; void updateCurrentValue(const QVariant &value) { if (!m_detonationSceneMarker) return; fs = m_detonationSceneMarker->fillStyle(); col = fs.fillColor(); col.setAlphaF(value.toFloat()); fs.setFillColor(col); m_detonationSceneMarker->setFillStyle(fs); m_detonationSceneMarker->updateView(); } private: GraphicalObjectSceneMarker *m_detonationSceneMarker{nullptr}; FillStyle fs; QColor col; }; //----------------------------------------------------------------------------- // class SingleFireCentralImpl //----------------------------------------------------------------------------- SingleFireCentralImpl::SingleFireCentralImpl(const QString &debugInfo) : SingleFireCentral() // Interface , BaseClass(debugInfo) // Implementation , m_logger(getLogger("SingleFireCentralImpl")) { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; m_fillColorAlpha = 200; TRACE_LOG(m_logger) << LOGFUNCTION << " END"; } SingleFireCentralImpl::~SingleFireCentralImpl() { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; delete m_animation; delete m_centerImage; delete m_detonationPath; delete m_detonationSceneMarker; TRACE_LOG(m_logger) << LOGFUNCTION << " END"; } QString SingleFireCentralImpl::toString() const { QString str; str.append(BaseClass::toString()); str.append(BasicPathObjectImpl::toString()); return str; } Point3D SingleFireCentralImpl::impactOrigin() const { return BaseClass::tacticalOrigin(); } void SingleFireCentralImpl::setImpactOrigin(const Point3D &impactOrigin) { BaseClass::setTacticalOrigin(impactOrigin); } void SingleFireCentralImpl::setDetonation(const SingleFireCentral::DetonationData &detonationData) { if (m_detonationOrigin.value().origin() != detonationData.m_origin) m_detonationOrigin.refValue().setOrigin(detonationData.m_origin); m_detonationRadius = detonationData.m_radius; } SingleFireCentral::DetonationData SingleFireCentralImpl::detonation() const { return {m_detonationOrigin.value().origin(), m_detonationRadius.value()}; } bool SingleFireCentralImpl::startDetonationAnimation() { if (!m_detonationSceneMarker) return false; if (!m_animation) { m_animation = new MyAnimation(m_detonationSceneMarker); m_animation->setDuration(500); m_animation->setKeyValueAt(0.0 , 1.0); m_animation->setKeyValueAt(0.2 , 0.5); m_animation->setKeyValueAt(1.0 , 0.1); // m_animation.setEasingCurve(QEasingCurve::InOutQuart); } m_animation->stop(); m_animation->start(); if (!m_symbol3D) { qCritical() << " ModelSceneSymbol: ....:"; // m_symbol3D = new Esri::ArcGISRuntime::ModelSceneSymbol(QUrl(QLatin1Literal("/shd/CTC/TOOLS/ArcGIS/Runtime/Data/3D/Bristol/Collada/Bristol.dae")), 5.0); // works // m_symbol3D = new Esri::ArcGISRuntime::ModelSceneSymbol(QUrl(QLatin1Literal("/shd/CTC/TOOLS/ArcGIS/Proof_of_concept_Explosion_DAE/Proof_of_concept_Explosion_DAE_01.dae")), 10.0); // m_symbol3D = new Esri::ArcGISRuntime::ModelSceneSymbol(QUrl(QLatin1Literal("/shd/CTC/TOOLS/ArcGIS/Proof_of_concept_Explosion_DAE/Proof_of_concept_Explosion_DAE_02_60FPS.dae")), 10.0); // m_symbol3D = new Esri::ArcGISRuntime::ModelSceneSymbol(QUrl(QLatin1Literal("/shd/CTC/TOOLS/ArcGIS/Proof_of_concept_Explosion_DAE/Proof_of_concept_Explosion_DAE_Sampled.dae")), 10.0); // m_symbol3D = new Esri::ArcGISRuntime::ModelSceneSymbol(QUrl(QLatin1Literal("/shd/CTC/TOOLS/ArcGIS/Proof_of_concept_Explosion_DAE/Proof_of_concept_Explosion_DAE_unbaked.dae")), 10.0); // m_symbol3D = new Esri::ArcGISRuntime::ModelSceneSymbol(QUrl(QLatin1Literal("/shd/CTC/TOOLS/ArcGIS/Proof_of_concept_Explosion_DAE/Proof_of_concept_Explosion_3ds_NoAnimation.3ds")), 10.0); // m_symbol3D = new Esri::ArcGISRuntime::ModelSceneSymbol(QUrl(QLatin1Literal("/shd/CTC/TOOLS/ArcGIS/Runtime/Data/3D/3dexport/explosion/explosionFBX.fbx")), 10.0); // m_symbol3D = new Esri::ArcGISRuntime::ModelSceneSymbol(QUrl(QLatin1Literal("/shd/CTC/TOOLS/ArcGIS/Runtime/Data/3D/3dexport/JetAnim/jet anim.fbx")), 10.0); // works // m_symbol3D = new Esri::ArcGISRuntime::ModelSceneSymbol(QUrl(QLatin1Literal("/shd/CTC/TOOLS/ArcGIS/Runtime/Data/3D/bradley_low_3ds/bradle.3ds")), 10.0); // works m_symbol3D = new Esri::ArcGISRuntime::ModelSceneSymbol(QUrl(QStringLiteral("/shd/CTC/TOOLS/ArcGIS/Runtime/Data/3D/dolmus_3ds/dolmus.3ds")), 10.0); QObject::connect(m_symbol3D, &Esri::ArcGISRuntime::ModelSceneSymbol::errorOccurred, m_animation, [](const Esri::ArcGISRuntime::Error &loadError){ qCritical() << " Error: : isEmpty:" << loadError.isEmpty(); qCritical() << " Error: : code:" << loadError.code(); qCritical() << " Error: : loadError:" << loadError.message(); }); QObject::connect(m_symbol3D, &Esri::ArcGISRuntime::ModelSceneSymbol::doneLoading, m_animation, [](const Esri::ArcGISRuntime::Error &loadError){ qCritical() << " ModelSceneSymbol: doneLoading: isEmpty:" << loadError.isEmpty(); qCritical() << " ModelSceneSymbol: doneLoading: code:" << loadError.code(); qCritical() << " ModelSceneSymbol: doneLoading: loadError:" << loadError.message(); }); m_symbol3D->load(); if (!m_graphic3D) { Point3D pos = m_detonationOrigin.value().originTranslated(); m_graphic3D = new Esri::ArcGISRuntime::Graphic( Esri::ArcGISRuntime::Point(pos.x(), pos.y(), 20, m_mapImpl->getEsriSpatialReference()), m_symbol3D); m_graphicsLayer->graphics()->append(m_graphic3D); } } return true; } AesEffectState SingleFireCentralImpl::aesState() const { return BaseClass::aesState(); } void SingleFireCentralImpl::setAesState(AesEffectState aesState) { BaseClass::setAesState(aesState); } SymbolImage SingleFireCentralImpl::symbolImage() const { SymbolImage symImage = m_tacticalAppearance->symbolImage(); return symImage; } bool SingleFireCentralImpl::updateViewImpl() { TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " positions =" << this->positions() << " radius =" << this->radius() << " partyId =" << this->partyId() << " visibility=" << m_visibility << " visiTechn=" << m_visibilityTechnical << " visiTact=" << m_visibilityTactical; if (m_tacticalAppearance) { if (partyChanged()) m_symbol.refValue().color = partyColor(); } // centerImage: if (!m_centerImage) { m_centerImage = new GraphicalObjectPictureMarker(m_mapImpl->getEsriGeoView(), m_graphicsLayer, m_debugInfo + QLatin1String("#CenterImage"), m_uniqueMapId); } if (partyChanged()) { QImage img = SingleFireImpl::renderImpactSymbol(partyColor(), 20, true); // filled m_centerImage->setImage(img); } // m_centerImage->setScale(m_mainGraphicalObject->scale()); // do not scale centerImage, equal to mine of MineArea m_centerImage->setOrigin(m_tacticalOrigin.value().originTranslated()); m_centerImage->setVisibility(m_visibility && m_visibilityTechnical); bool success = BaseClass::updateViewImpl(); // will call onMapExtentChanged and therefore m_centerImage->updateView bool successDetonationSceneMarker = true; switch (m_mapImpl->mode()) { case Mode::Mode_2D: successDetonationSceneMarker = updateDetonationPath(); break; case Mode::Mode_3D: successDetonationSceneMarker = updateDetonationSceneMarker(); break; case Mode::Undefined: // empty break; } success = success && successDetonationSceneMarker; if (!success) ERROR_LOG(m_logger) << LOGFUNCTION << " updateViewImpl failed"; TRACE_LOG(m_logger) << LOGFUNCTION << " END, success=" << success; return success; } bool SingleFireCentralImpl::updateDetonationPath() { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; bool success = true; // do we have a detonationPoint / impactOrigin? if (m_detonationOrigin.value().origin().isNull() && (m_detonationRadius.value() < 1.0)) { delete m_detonationPath; m_detonationPath = nullptr; } else { if (!m_detonationPath) { m_detonationPath = new GraphicalObjectEllipse(m_mapImpl->getEsriGeoView(), m_graphicsLayer, m_debugInfo + QLatin1String("#DetonationEllipse"), m_uniqueMapId); } { EllipseParameters ellipsePara; ellipsePara.setLengthX(m_detonationRadius.value()); ellipsePara.setLengthY(m_detonationRadius.value()); ellipsePara.setMaxSegmentLength(1); ellipsePara.setMaxPointCount(30); // limit to 30 to reduce the number of vertices. If to high, keep performance impact to 3D in mind!!! m_detonationPath->setEllipseParameters(ellipsePara); } m_detonationPath->setOrigin(m_detonationOrigin.value().originTranslated()); m_detonationPath->setPickable(m_pickable); // path == 0; indicationCont == 1; Marker == 2 m_detonationPath->setDrawOrder(m_internalDrawOrder+2); QColor col = partyColor(); m_detonationPath->setLineStyle(LineStyle(col, 2)); col.setAlphaF(col.alphaF() / 2.0); m_detonationPath->setFillStyle(FillStyle(col, m_mainGraphicalObject->fillStyle().fillPattern())); // take fillpattern m_detonationPath->setScale(this->scale()); success = m_detonationPath->updateView(); } TRACE_LOG(m_logger) << LOGFUNCTION << " END, success=" << success; return success; } bool SingleFireCentralImpl::updateDetonationSceneMarker() { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; bool success = true; // do we have a detonationPoint / impactOrigin? if (m_detonationOrigin.value().origin().isNull() && (m_detonationRadius.value() < 1.0)) { delete m_detonationSceneMarker; m_detonationSceneMarker = nullptr; } else { if (!m_detonationSceneMarker) { m_detonationSceneMarker = new GraphicalObjectSceneMarker(m_mapImpl->getEsriGeoView(), m_graphicsLayer, m_debugInfo + QLatin1String("#DetonationSceneMarker"), m_uniqueMapId); } m_detonationSceneMarker->setOrigin(m_detonationOrigin.value().originTranslated()); m_detonationSceneMarker->setDiameter(m_detonationRadius.value()*2.0); m_detonationSceneMarker->setPickable(m_pickable); // path == 0; indicationCont == 1; Marker == 2 m_detonationSceneMarker->setDrawOrder(m_internalDrawOrder+2); QColor col = partyColor(); col.setAlphaF(col.alphaF() / 2.0); m_detonationSceneMarker->setFillStyle(FillStyle(col, FillPattern::Solid)); success = m_detonationSceneMarker->updateView(); } // DEBUG: Animation in a loop startDetonationAnimation(); // check intersect if (m_detonationSceneMarker && m_mainGraphicalObject ){ Esri::ArcGISRuntime::GeometryEngine* geoEngine = Esri::ArcGISRuntime::GeometryEngine::instance(); Esri::ArcGISRuntime::Geometry geoLine = m_mainGraphicalObject->getGraphicGeometry(); qCritical() << " geoLine " << geoLine.toJson(); Esri::ArcGISRuntime::Geometry geoSphere = m_detonationSceneMarker->getGraphicGeometry(); qCritical() << " geoSphere " << geoSphere.toJson(); Esri::ArcGISRuntime::Geometry resultGeometry = geoEngine->intersection(geoLine, geoSphere); qCritical() << " resultGeometry " << resultGeometry.toJson(); } if (m_animation) QObject::connect(m_animation, &QVariantAnimation::finished, [this]() { QTimer::singleShot(2000, m_animation, [this]() { m_animation->start(); }); }); TRACE_LOG(m_logger) << LOGFUNCTION << " END, success=" << success; return success; } bool SingleFireCentralImpl::init(MapImpl *mapImpl, const QString &logicalLayerName) { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; bool success = BaseClass::init(mapImpl, logicalLayerName, GraphicalObjectPathType::Polyline); if (!success) ERROR_LOG(m_logger) << LOGFUNCTION << " init failed"; setLineStyle(LineStyle(Qt::black, 2)); m_detonationOrigin.refValue().setMapObjectImpl(this); TRACE_LOG(m_logger) << LOGFUNCTION << " END, success=" << success; return success; } bool SingleFireCentralImpl::onMapExtentChanged() { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; bool successCenterImage = true; bool visiScale = m_visibilityScaleRange.scaleHasVisibility(m_mapImpl->scale()); if (m_centerImage) { m_centerImage->setVisibility(visiScale && m_visibility && m_visibilityTechnical); successCenterImage = m_centerImage->updateView(); } bool successDetonationSceneMarker = true; if (m_detonationSceneMarker) { m_detonationSceneMarker->setVisibility(visiScale && m_visibility && m_visibilityTechnical); successCenterImage = m_detonationSceneMarker->updateView(); } bool success = BaseClass::onMapExtentChanged() && successCenterImage && successDetonationSceneMarker; TRACE_LOG(m_logger) << LOGFUNCTION << " END, success=" << success; return success; } } // namespace SituationMap