From 1b6d3ca95866432a36d670d236924ffb80e0e924 Mon Sep 17 00:00:00 2001 From: Valentin Platzgummer Date: Tue, 19 Mar 2019 14:20:53 +0100 Subject: [PATCH] fly area edited --- UnitTest.qrc | 15 +++-- qgcresources.qrc | 1 + qgroundcontrol.pro | 6 +- qgroundcontrol.qrc | 1 + src/MissionManager/WimaController.cc | 9 +++ src/MissionManager/WimaController.h | 26 +++++++- src/MissionManager/WimaFlyArea.cc | 25 ++++++++ src/MissionManager/WimaFlyArea.h | 42 +++++++++++++ src/QGCApplication.cc | 5 ++ src/WimaView/FlyAreaMapVisual.qml | 79 ++++++++++++++++++++++++ src/WimaView/FlyAreaPolygonMapVisual.qml | 79 ++++++++++++++++++++++++ src/WimaView/WimaView.qml | 21 +++++-- src/WimaView/flyAreaPolygonMapVisual.qml | 79 ++++++++++++++++++++++++ 13 files changed, 374 insertions(+), 14 deletions(-) create mode 100644 src/MissionManager/WimaFlyArea.cc create mode 100644 src/MissionManager/WimaFlyArea.h create mode 100644 src/WimaView/FlyAreaMapVisual.qml create mode 100644 src/WimaView/FlyAreaPolygonMapVisual.qml create mode 100644 src/WimaView/flyAreaPolygonMapVisual.qml diff --git a/UnitTest.qrc b/UnitTest.qrc index 2bfa5bbb8..674df436d 100644 --- a/UnitTest.qrc +++ b/UnitTest.qrc @@ -1,6 +1,6 @@ - src/MissionManager/UnitTest/SectionTest.plan + src/MissionManager/UnitTest/SectionTest.plan src/MissionManager/UnitTest/MavCmdInfoCommon.json src/MissionManager/UnitTest/MavCmdInfoFixedWing.json src/MissionManager/UnitTest/MavCmdInfoMultiRotor.json @@ -9,10 +9,13 @@ src/MissionManager/UnitTest/MavCmdInfoVTOL.json src/MissionManager/UnitTest/MissionPlanner.waypoints src/MissionManager/UnitTest/OldFileFormat.mission - src/MissionManager/UnitTest/PolygonAreaTest.kml - src/MissionManager/UnitTest/PolygonGood.kml - src/MissionManager/UnitTest/PolygonMissingNode.kml - src/MissionManager/UnitTest/PolygonBadXml.kml - src/MissionManager/UnitTest/PolygonBadCoordinatesNode.kml + src/MissionManager/UnitTest/PolygonAreaTest.kml + src/MissionManager/UnitTest/PolygonGood.kml + src/MissionManager/UnitTest/PolygonMissingNode.kml + src/MissionManager/UnitTest/PolygonBadXml.kml + src/MissionManager/UnitTest/PolygonBadCoordinatesNode.kml + + + src/WimaView/FlyAreaMapVisual.qml diff --git a/qgcresources.qrc b/qgcresources.qrc index a334c0e8e..44396e942 100644 --- a/qgcresources.qrc +++ b/qgcresources.qrc @@ -351,4 +351,5 @@ resources/calibration/joystick/mode4/joystickYawLeft.png resources/calibration/joystick/mode4/joystickYawRight.png + diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index 82e355e5f..39e79245d 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -407,7 +407,8 @@ HEADERS += \ src/api/QmlComponentInfo.h \ src/comm/MavlinkMessagesTimer.h \ src/GPS/Drivers/src/base_station.h \ - src/MissionManager/WimaController.h + src/MissionManager/WimaController.h \ + src/MissionManager/WimaFlyArea.h SOURCES += \ src/api/QGCCorePlugin.cc \ @@ -415,7 +416,8 @@ SOURCES += \ src/api/QGCSettings.cc \ src/api/QmlComponentInfo.cc \ src/comm/MavlinkMessagesTimer.cc \ - src/MissionManager/WimaController.cc + src/MissionManager/WimaController.cc \ + src/MissionManager/WimaFlyArea.cc # # Unit Test specific configuration goes here (requires full debug build with all plugins) diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc index 027b75bb6..317324095 100644 --- a/qgroundcontrol.qrc +++ b/qgroundcontrol.qrc @@ -210,6 +210,7 @@ src/FlightDisplay/VirtualJoystick.qml src/WimaView/WimaToolBar.qml src/WimaView/WimaView.qml + src/WimaView/FlyAreaMapVisual.qml src/Settings/APMMavlinkStreamRate.SettingsGroup.json diff --git a/src/MissionManager/WimaController.cc b/src/MissionManager/WimaController.cc index 0a54782d9..c507d748e 100644 --- a/src/MissionManager/WimaController.cc +++ b/src/MissionManager/WimaController.cc @@ -1,6 +1,15 @@ #include "WimaController.h" +#include "MissionController.h" WimaController::WimaController(QObject *parent) : QObject(parent) { + this->_flyArea = WimaFlyArea(parent); +} + +void WimaController::initWimaFlyArea() +{ + this->_flyArea.setReady(); + return; } + diff --git a/src/MissionManager/WimaController.h b/src/MissionManager/WimaController.h index 4996dede5..e5266fa21 100644 --- a/src/MissionManager/WimaController.h +++ b/src/MissionManager/WimaController.h @@ -1,7 +1,10 @@ -#ifndef WIMACONTROLLER_H +#ifndef WIMACONTROLLER_H #define WIMACONTROLLER_H #include +#include "QGCMapPolygon.h" +#include "QmlObjectListModel.h" +#include "WimaFlyArea.h" class WimaController : public QObject { @@ -9,9 +12,28 @@ class WimaController : public QObject public: explicit WimaController(QObject *parent = nullptr); + Q_PROPERTY(WimaFlyArea *flyArea READ flyArea CONSTANT) + //Q_PROPERTY(QmlObjectListModel* visualItems READ visualItems NOTIFY visualItemsChanged) + + /// Add a fly area to the list + /// @param itemName: Name of complex item to create (from complexMissionItemNames) + /// @param mapCenterCoordinate: coordinate for current center of map + /// @param i: index to insert at + /// @return Sequence number for new item + Q_INVOKABLE void initWimaFlyArea(); + + //Property Accessors + WimaFlyArea *flyArea (void) { return &_flyArea; } + //QmlObjectListModel* visualItems (void) { return _visualItems; } + signals: + public slots: + +private: + //QmlObjectListModel* _visualItems; + WimaFlyArea _flyArea; }; -#endif // WIMACONTROLLER_H \ No newline at end of file +#endif // WIMACONTROLLER_H diff --git a/src/MissionManager/WimaFlyArea.cc b/src/MissionManager/WimaFlyArea.cc new file mode 100644 index 000000000..90953cd1a --- /dev/null +++ b/src/MissionManager/WimaFlyArea.cc @@ -0,0 +1,25 @@ +#include "WimaFlyArea.h" + +WimaFlyArea::WimaFlyArea(QObject *parent) : QObject(parent) +{ + this->_isReady = false; +} + +WimaFlyArea::WimaFlyArea(const WimaFlyArea &other, QObject *parent): QObject(parent) +{ + *this = other; +} + +const WimaFlyArea& WimaFlyArea::operator=(const WimaFlyArea& other) +{ + this->_flyAreaPolygon = other._flyAreaPolygon; + this->_isReady = other._isReady; + + return *this; +} + +void WimaFlyArea::setReady() +{ + this->_isReady = true; + emit readyStateChanged(); +} diff --git a/src/MissionManager/WimaFlyArea.h b/src/MissionManager/WimaFlyArea.h new file mode 100644 index 000000000..8d9de2866 --- /dev/null +++ b/src/MissionManager/WimaFlyArea.h @@ -0,0 +1,42 @@ +#ifndef WIMAFLYAREA_H +#define WIMAFLYAREA_H + +#include +#include "QGCMapPolygon.h" + +class WimaFlyArea : public QObject +{ + Q_OBJECT +public: + WimaFlyArea(QObject *parent = nullptr); + WimaFlyArea(const WimaFlyArea& other, QObject *parent = nullptr); + + const WimaFlyArea& operator=(const WimaFlyArea& other); + + + + Q_PROPERTY(QString mapVisualQML READ mapVisualQML CONSTANT) + Q_PROPERTY(bool isReady READ isReady NOTIFY readyStateChanged) + Q_PROPERTY(QGCMapPolygon flyAreaPolygon READ flyAreaPolygon CONSTANT) + + // Property Accessors + QString mapVisualQML (void) const { return QStringLiteral("FlyAreaMapVisual.qml"); } + bool isReady (void) { return _isReady;} + QGCMapPolygon flyAreaPolygon (void) { return _flyAreaPolygon;} + + + // Methodes + void setReady(); + +signals: + void readyStateChanged(void); + + +public slots: + +private: + QGCMapPolygon _flyAreaPolygon; + bool _isReady; +}; + +#endif // WIMAFLYAREA_H diff --git a/src/QGCApplication.cc b/src/QGCApplication.cc index 109b5ab0a..86c017cab 100644 --- a/src/QGCApplication.cc +++ b/src/QGCApplication.cc @@ -67,6 +67,8 @@ #include "FlightMapSettings.h" #include "CoordinateVector.h" #include "PlanMasterController.h" +#include "WimaController.h" //custom +#include "WimaFlyArea.h" //custom #include "VideoManager.h" #include "VideoSurface.h" #include "VideoReceiver.h" @@ -422,6 +424,7 @@ void QGCApplication::_initCommon(void) qmlRegisterUncreatableType(kQGCControllers, 1, 0, "RallyPointController", kRefOnly); qmlRegisterUncreatableType (kQGCControllers, 1, 0, "VisualMissionItem", kRefOnly); + qmlRegisterUncreatableType ("QGroundControl", 1, 0, "CoordinateVector", kRefOnly); qmlRegisterUncreatableType ("QGroundControl", 1, 0, "QmlObjectListModel", kRefOnly); qmlRegisterUncreatableType ("QGroundControl", 1, 0, "MissionCommandTree", kRefOnly); @@ -435,6 +438,7 @@ void QGCApplication::_initCommon(void) qmlRegisterUncreatableType("QGroundControl.FactControls", 1, 0, "FactValueSliderListModel", kRefOnly); qmlRegisterUncreatableType ("QGroundControl.FlightMap", 1, 0, "QGCMapPolygon", kRefOnly); + qmlRegisterUncreatableType ("QGroundControl.FlightMap", 1, 0, "WimaFlyArea", kRefOnly); //custom qmlRegisterUncreatableType ("QGroundControl.FlightMap", 1, 0, "QGCGeoBoundingCube", kRefOnly); qmlRegisterType ("QGroundControl.FlightMap", 1, 0, "QGCMapCircle"); @@ -443,6 +447,7 @@ void QGCApplication::_initCommon(void) qmlRegisterType (kQGCControllers, 1, 0, "ESP8266ComponentController"); qmlRegisterType (kQGCControllers, 1, 0, "ScreenToolsController"); qmlRegisterType (kQGCControllers, 1, 0, "PlanMasterController"); + qmlRegisterType (kQGCControllers, 1, 0, "WimaController"); //custom qmlRegisterType (kQGCControllers, 1, 0, "ValuesWidgetController"); qmlRegisterType (kQGCControllers, 1, 0, "QGCFileDialogController"); qmlRegisterType (kQGCControllers, 1, 0, "RCChannelMonitorController"); diff --git a/src/WimaView/FlyAreaMapVisual.qml b/src/WimaView/FlyAreaMapVisual.qml new file mode 100644 index 000000000..e32b8c688 --- /dev/null +++ b/src/WimaView/FlyAreaMapVisual.qml @@ -0,0 +1,79 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtLocation 5.3 +import QtPositioning 5.3 + +import QGroundControl 1.0 +import QGroundControl.ScreenTools 1.0 +import QGroundControl.Palette 1.0 +import QGroundControl.Controls 1.0 +import QGroundControl.FlightMap 1.0 + +/// Fly Area Map visuals +Item { + id: _root + + property var map ///< Map control to place item in + property var qgcView ///< QGCView to use for popping dialogs + property var _flyAreaPolygon + + + + + /// Add an initial 4 sided polygon if there is none + function _addInitialPolygon() { + if (_flyAreaPolygon.count < 3) { + // Initial polygon is inset to take 2/3rds space + var rect = Qt.rect(map.centerViewport.x, map.centerViewport.y, map.centerViewport.width, map.centerViewport.height) + rect.x += (rect.width * 0.25) / 2 + rect.y += (rect.height * 0.25) / 2 + rect.width *= 0.75 + rect.height *= 0.75 + + var centerCoord = map.toCoordinate(Qt.point(rect.x + (rect.width / 2), rect.y + (rect.height / 2)), false /* clipToViewPort */) + var topLeftCoord = map.toCoordinate(Qt.point(rect.x, rect.y), false /* clipToViewPort */) + var topRightCoord = map.toCoordinate(Qt.point(rect.x + rect.width, rect.y), false /* clipToViewPort */) + var bottomLeftCoord = map.toCoordinate(Qt.point(rect.x, rect.y + rect.height), false /* clipToViewPort */) + var bottomRightCoord = map.toCoordinate(Qt.point(rect.x + rect.width, rect.y + rect.height), false /* clipToViewPort */) + + // Adjust polygon to max size + var maxSize = 100 + var halfWidthMeters = Math.min(topLeftCoord.distanceTo(topRightCoord), maxSize) / 2 + var halfHeightMeters = Math.min(topLeftCoord.distanceTo(bottomLeftCoord), maxSize) / 2 + topLeftCoord = centerCoord.atDistanceAndAzimuth(halfWidthMeters, -90).atDistanceAndAzimuth(halfHeightMeters, 0) + topRightCoord = centerCoord.atDistanceAndAzimuth(halfWidthMeters, 90).atDistanceAndAzimuth(halfHeightMeters, 0) + bottomLeftCoord = centerCoord.atDistanceAndAzimuth(halfWidthMeters, -90).atDistanceAndAzimuth(halfHeightMeters, 180) + bottomRightCoord = centerCoord.atDistanceAndAzimuth(halfWidthMeters, 90).atDistanceAndAzimuth(halfHeightMeters, 180) + + _flyAreaPolygon.appendVertex(topLeftCoord) + _flyAreaPolygon.appendVertex(topRightCoord) + _flyAreaPolygon.appendVertex(bottomRightCoord) + _flyAreaPolygon.appendVertex(bottomLeftCoord) + } + } + + Component.onCompleted: { + _addInitialPolygon() + } + + QGCMapPolygonVisuals { + qgcView: _root.qgcView + mapControl: map + mapPolygon: _flyAreaPolygon + interactive: true + borderWidth: 1 + borderColor: "black" + interiorColor: "green" + interiorOpacity: 0.25 + } + +} diff --git a/src/WimaView/FlyAreaPolygonMapVisual.qml b/src/WimaView/FlyAreaPolygonMapVisual.qml new file mode 100644 index 000000000..4c751114f --- /dev/null +++ b/src/WimaView/FlyAreaPolygonMapVisual.qml @@ -0,0 +1,79 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtLocation 5.3 +import QtPositioning 5.3 + +import QGroundControl 1.0 +import QGroundControl.ScreenTools 1.0 +import QGroundControl.Palette 1.0 +import QGroundControl.Controls 1.0 +import QGroundControl.FlightMap 1.0 + +/// Survey Complex Mission Item visuals +Item { + id: _root + + property var map ///< Map control to place item in + property var qgcView ///< QGCView to use for popping dialogs + property var _flyAreaPolygon + + + + + /// Add an initial 4 sided polygon if there is none + function _addInitialPolygon() { + if (_structurePolygon.count < 3) { + // Initial polygon is inset to take 2/3rds space + var rect = Qt.rect(map.centerViewport.x, map.centerViewport.y, map.centerViewport.width, map.centerViewport.height) + rect.x += (rect.width * 0.25) / 2 + rect.y += (rect.height * 0.25) / 2 + rect.width *= 0.75 + rect.height *= 0.75 + + var centerCoord = map.toCoordinate(Qt.point(rect.x + (rect.width / 2), rect.y + (rect.height / 2)), false /* clipToViewPort */) + var topLeftCoord = map.toCoordinate(Qt.point(rect.x, rect.y), false /* clipToViewPort */) + var topRightCoord = map.toCoordinate(Qt.point(rect.x + rect.width, rect.y), false /* clipToViewPort */) + var bottomLeftCoord = map.toCoordinate(Qt.point(rect.x, rect.y + rect.height), false /* clipToViewPort */) + var bottomRightCoord = map.toCoordinate(Qt.point(rect.x + rect.width, rect.y + rect.height), false /* clipToViewPort */) + + // Adjust polygon to max size + var maxSize = 100 + var halfWidthMeters = Math.min(topLeftCoord.distanceTo(topRightCoord), maxSize) / 2 + var halfHeightMeters = Math.min(topLeftCoord.distanceTo(bottomLeftCoord), maxSize) / 2 + topLeftCoord = centerCoord.atDistanceAndAzimuth(halfWidthMeters, -90).atDistanceAndAzimuth(halfHeightMeters, 0) + topRightCoord = centerCoord.atDistanceAndAzimuth(halfWidthMeters, 90).atDistanceAndAzimuth(halfHeightMeters, 0) + bottomLeftCoord = centerCoord.atDistanceAndAzimuth(halfWidthMeters, -90).atDistanceAndAzimuth(halfHeightMeters, 180) + bottomRightCoord = centerCoord.atDistanceAndAzimuth(halfWidthMeters, 90).atDistanceAndAzimuth(halfHeightMeters, 180) + + _structurePolygon.appendVertex(topLeftCoord) + _structurePolygon.appendVertex(topRightCoord) + _structurePolygon.appendVertex(bottomRightCoord) + _structurePolygon.appendVertex(bottomLeftCoord) + } + } + + Component.onCompleted: { + _addInitialPolygon() + } + + QGCMapPolygonVisuals { + qgcView: _root.qgcView + mapControl: map + mapPolygon: _flyAreaPolygon + interactive: true + borderWidth: 1 + borderColor: "black" + interiorColor: "green" + interiorOpacity: 0.25 + } + +} diff --git a/src/WimaView/WimaView.qml b/src/WimaView/WimaView.qml index a308c6902..8f038a33b 100644 --- a/src/WimaView/WimaView.qml +++ b/src/WimaView/WimaView.qml @@ -51,6 +51,8 @@ QGCView { readonly property bool _waypointsOnlyMode: QGroundControl.corePlugin.options.missionWaypointsOnly property bool _airspaceEnabled: QGroundControl.airmapSupported ? (QGroundControl.settingsManager.airMapSettings.enableAirMap.rawValue && QGroundControl.airspaceManager.connected): false + property var _wimaController: wimaController + property var _flyArea: wimaController.flyArea property var _planMasterController: masterController property var _missionController: _planMasterController.missionController property var _geoFenceController: _planMasterController.geoFenceController @@ -197,6 +199,9 @@ QGCView { message: qsTr("You need at least one item to create a KML.") } } + WimaController { + id:wimaController + } PlanMasterController { id: masterController @@ -511,7 +516,6 @@ QGCView { // Add the mission item visuals to the map Repeater { model: _editingLayer == _layerMission ? _missionController.visualItems : undefined - delegate: MissionItemMapVisual { map: editorMap qgcView: _qgcView @@ -525,6 +529,14 @@ QGCView { model: _editingLayer == _layerMission ? _missionController.waypointLines : undefined } + //Add fly area + FlyAreaMapVisual { + map: editorMap + qgcView: _qgcView + _flyAreaPolygon: _flyArea.flyAreaPolygon + } + + // Add the vehicles to the map MapItemView { model: QGroundControl.multiVehicleManager.vehicles @@ -601,7 +613,7 @@ QGCView { dropPanelComponent: syncDropPanel }, { - name: qsTr("ROI"), + name: qsTr("Fly Area"), iconSource: "/qmlimages/Target.svg", toggle: true }, @@ -638,12 +650,13 @@ QGCView { onClicked: { switch (index) { case 1: - addComplexItem(_missionController.complexMissionItemNames[2]) + wimaController.initWimaFlyArea(); + //addComplexItem(_missionController.complexMissionItemNames[2]) /*_addWaypointOnClick = checked _addROIOnClick = false*/ break case 2: - addComplexItem(_missionController.complexMissionItemNames[2]) + /* _addROIOnClick = checked _addWaypointOnClick = false*/ diff --git a/src/WimaView/flyAreaPolygonMapVisual.qml b/src/WimaView/flyAreaPolygonMapVisual.qml new file mode 100644 index 000000000..4c751114f --- /dev/null +++ b/src/WimaView/flyAreaPolygonMapVisual.qml @@ -0,0 +1,79 @@ +/**************************************************************************** + * + * (c) 2009-2016 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtLocation 5.3 +import QtPositioning 5.3 + +import QGroundControl 1.0 +import QGroundControl.ScreenTools 1.0 +import QGroundControl.Palette 1.0 +import QGroundControl.Controls 1.0 +import QGroundControl.FlightMap 1.0 + +/// Survey Complex Mission Item visuals +Item { + id: _root + + property var map ///< Map control to place item in + property var qgcView ///< QGCView to use for popping dialogs + property var _flyAreaPolygon + + + + + /// Add an initial 4 sided polygon if there is none + function _addInitialPolygon() { + if (_structurePolygon.count < 3) { + // Initial polygon is inset to take 2/3rds space + var rect = Qt.rect(map.centerViewport.x, map.centerViewport.y, map.centerViewport.width, map.centerViewport.height) + rect.x += (rect.width * 0.25) / 2 + rect.y += (rect.height * 0.25) / 2 + rect.width *= 0.75 + rect.height *= 0.75 + + var centerCoord = map.toCoordinate(Qt.point(rect.x + (rect.width / 2), rect.y + (rect.height / 2)), false /* clipToViewPort */) + var topLeftCoord = map.toCoordinate(Qt.point(rect.x, rect.y), false /* clipToViewPort */) + var topRightCoord = map.toCoordinate(Qt.point(rect.x + rect.width, rect.y), false /* clipToViewPort */) + var bottomLeftCoord = map.toCoordinate(Qt.point(rect.x, rect.y + rect.height), false /* clipToViewPort */) + var bottomRightCoord = map.toCoordinate(Qt.point(rect.x + rect.width, rect.y + rect.height), false /* clipToViewPort */) + + // Adjust polygon to max size + var maxSize = 100 + var halfWidthMeters = Math.min(topLeftCoord.distanceTo(topRightCoord), maxSize) / 2 + var halfHeightMeters = Math.min(topLeftCoord.distanceTo(bottomLeftCoord), maxSize) / 2 + topLeftCoord = centerCoord.atDistanceAndAzimuth(halfWidthMeters, -90).atDistanceAndAzimuth(halfHeightMeters, 0) + topRightCoord = centerCoord.atDistanceAndAzimuth(halfWidthMeters, 90).atDistanceAndAzimuth(halfHeightMeters, 0) + bottomLeftCoord = centerCoord.atDistanceAndAzimuth(halfWidthMeters, -90).atDistanceAndAzimuth(halfHeightMeters, 180) + bottomRightCoord = centerCoord.atDistanceAndAzimuth(halfWidthMeters, 90).atDistanceAndAzimuth(halfHeightMeters, 180) + + _structurePolygon.appendVertex(topLeftCoord) + _structurePolygon.appendVertex(topRightCoord) + _structurePolygon.appendVertex(bottomRightCoord) + _structurePolygon.appendVertex(bottomLeftCoord) + } + } + + Component.onCompleted: { + _addInitialPolygon() + } + + QGCMapPolygonVisuals { + qgcView: _root.qgcView + mapControl: map + mapPolygon: _flyAreaPolygon + interactive: true + borderWidth: 1 + borderColor: "black" + interiorColor: "green" + interiorOpacity: 0.25 + } + +} -- 2.22.0