diff --git a/python/core/auto_generated/layout/qgslayoutitemhtml.sip.in b/python/core/auto_generated/layout/qgslayoutitemhtml.sip.in index 84c7348fb956..2a5740f3ef64 100644 --- a/python/core/auto_generated/layout/qgslayoutitemhtml.sip.in +++ b/python/core/auto_generated/layout/qgslayoutitemhtml.sip.in @@ -45,6 +45,13 @@ Ownership is transferred to the layout. static QgsLayoutItemHtml *create( QgsLayout *layout ) /Factory/; %Docstring Returns a new QgsLayoutItemHtml for the specified parent ``layout``. +%End + + static QgsLayoutItemHtml *createFromLabel( QgsLayoutItemLabel *label ) /Factory/; +%Docstring +Returns a new QgsLayoutItemHtml matching the content and rendering of a given ``label``. + +.. versionadded:: 3.32 %End void setContentMode( ContentMode mode ); diff --git a/src/core/layout/qgslayout.cpp b/src/core/layout/qgslayout.cpp index c6947b011d5d..0eca5f6a6b8c 100644 --- a/src/core/layout/qgslayout.cpp +++ b/src/core/layout/qgslayout.cpp @@ -16,6 +16,8 @@ #include "qgslayout.h" #include "qgslayoutitem.h" +#include "qgslayoutitemhtml.h" +#include "qgslayoutitemlabel.h" #include "qgslayoutmodel.h" #include "qgslayoutpagecollection.h" #include "qgslayoutguidecollection.h" @@ -1106,6 +1108,21 @@ QList< QgsLayoutItem * > QgsLayout::addItemsFromXml( const QDomElement &parentEl } } + // When restoring items on project load saved with QGIS < 3.32, convert HTML-enabled labels into HTML items + if ( !position && QgsProjectVersion( 3, 31, 0 ) > mProject->lastSaveVersion() ) + { + if ( QgsLayoutItemLabel *label = qobject_cast( item.get() ) ) + { + if ( label->mode() == QgsLayoutItemLabel::ModeHtml ) + { + QgsLayoutMultiFrame *html = QgsLayoutItemHtml::createFromLabel( label ); + addMultiFrame( html ); + newMultiFrames << html; + continue; + } + } + } + QgsLayoutItem *layoutItem = item.get(); addLayoutItem( item.release() ); layoutItem->setZValue( layoutItem->zValue() + zOrderOffset ); diff --git a/src/core/layout/qgslayoutitemhtml.cpp b/src/core/layout/qgslayoutitemhtml.cpp index 2de3bcbb1582..c233d56c84de 100644 --- a/src/core/layout/qgslayoutitemhtml.cpp +++ b/src/core/layout/qgslayoutitemhtml.cpp @@ -28,6 +28,7 @@ #include "qgsmapsettings.h" #include "qgswebpage.h" #include "qgswebframe.h" +#include "qgslayoutitemlabel.h" #include "qgslayoutitemmap.h" #include "qgslayoutreportcontext.h" #include "qgslayoutrendercontext.h" @@ -99,6 +100,33 @@ QgsLayoutItemHtml *QgsLayoutItemHtml::create( QgsLayout *layout ) return new QgsLayoutItemHtml( layout ); } +QgsLayoutItemHtml *QgsLayoutItemHtml::createFromLabel( QgsLayoutItemLabel *label ) +{ + QgsLayoutItemHtml *html = new QgsLayoutItemHtml( label->layout() ); + QgsLayoutFrame *frame = new QgsLayoutFrame( label->layout(), html ); + frame->setVisible( label->isVisible() ); + frame->setLocked( label->isLocked() ); + frame->setItemOpacity( label->itemOpacity() ); + frame->setRotation( label->rotation() ); + frame->setReferencePoint( label->referencePoint() ); + frame->attemptMove( label->positionWithUnits() ); + frame->attemptResize( label->sizeWithUnits() ); + frame->setZValue( label->zValue() ); + frame->setParentGroup( label->parentGroup() ); + frame->setBackgroundColor( label->backgroundColor() ); + frame->setFrameEnabled( label->frameEnabled() ); + frame->setFrameJoinStyle( label->frameJoinStyle() ); + frame->setFrameStrokeWidth( label->frameStrokeWidth() ); + frame->setFrameStrokeColor( label->frameStrokeColor() ); + html->addFrame( frame ); + html->setContentMode( QgsLayoutItemHtml::ManualHtml ); + html->setHtml( label->currentText() ); + html->setUserStylesheetEnabled( true ); + html->setUserStylesheet( label->createStylesheet() ); + html->loadHtml(); + return html; +} + void QgsLayoutItemHtml::setUrl( const QUrl &url ) { if ( !mWebPage ) diff --git a/src/core/layout/qgslayoutitemhtml.h b/src/core/layout/qgslayoutitemhtml.h index 98d2aa9e5990..ec1a5a02b112 100644 --- a/src/core/layout/qgslayoutitemhtml.h +++ b/src/core/layout/qgslayoutitemhtml.h @@ -25,6 +25,7 @@ class QgsWebPage; class QImage; +class QgsLayoutItemLabel; class QgsVectorLayer; class QgsNetworkContentFetcher; @@ -63,6 +64,13 @@ class CORE_EXPORT QgsLayoutItemHtml: public QgsLayoutMultiFrame */ static QgsLayoutItemHtml *create( QgsLayout *layout ) SIP_FACTORY; + /** + * Returns a new QgsLayoutItemHtml matching the content and rendering of a given \a label. + * + * \since QGIS 3.32 + */ + static QgsLayoutItemHtml *createFromLabel( QgsLayoutItemLabel *label ) SIP_FACTORY; + /** * Sets the source \a mode for item's HTML content. * \see contentMode() diff --git a/src/core/layout/qgslayoutitemlabel.cpp b/src/core/layout/qgslayoutitemlabel.cpp index 35df2f93cafc..9c1f20096740 100644 --- a/src/core/layout/qgslayoutitemlabel.cpp +++ b/src/core/layout/qgslayoutitemlabel.cpp @@ -33,16 +33,11 @@ #include "qgslayoutrendercontext.h" #include "qgslayoutreportcontext.h" -#include "qgswebpage.h" -#include "qgswebframe.h" - #include #include #include #include -#include -#include -#include +#include QgsLayoutItemLabel::QgsLayoutItemLabel( QgsLayout *layout ) : QgsLayoutItem( layout ) @@ -70,32 +65,6 @@ QgsLayoutItemLabel::QgsLayoutItemLabel( QgsLayout *layout ) //a label added while atlas preview is enabled needs to have the expression context set, //otherwise fields in the label aren't correctly evaluated until atlas preview feature changes (#9457) refreshExpressionContext(); - - // only possible on the main thread! - if ( QThread::currentThread() == QApplication::instance()->thread() ) - { - mWebPage.reset( new QgsWebPage( this ) ); - } - else - { - QgsMessageLog::logMessage( QObject::tr( "Cannot load HTML based item label in background threads" ) ); - } - if ( mWebPage ) - { - mWebPage->setIdentifier( tr( "Layout label item" ) ); - mWebPage->setNetworkAccessManager( QgsNetworkAccessManager::instance() ); - - //This makes the background transparent. Found on http://blog.qt.digia.com/blog/2009/06/30/transparent-qwebview-or-qwebpage/ - QPalette palette = mWebPage->palette(); - palette.setBrush( QPalette::Base, Qt::transparent ); - mWebPage->setPalette( palette ); - - mWebPage->mainFrame()->setZoomFactor( 10.0 ); - mWebPage->mainFrame()->setScrollBarPolicy( Qt::Horizontal, Qt::ScrollBarAlwaysOff ); - mWebPage->mainFrame()->setScrollBarPolicy( Qt::Vertical, Qt::ScrollBarAlwaysOff ); - - connect( mWebPage.get(), &QWebPage::loadFinished, this, &QgsLayoutItemLabel::loadingHtmlFinished ); - } } QgsLayoutItemLabel *QgsLayoutItemLabel::create( QgsLayout *layout ) @@ -118,42 +87,49 @@ void QgsLayoutItemLabel::draw( QgsLayoutItemRenderContext &context ) QPainter *painter = context.renderContext().painter(); const QgsScopedQPainterState painterState( painter ); - double rectScale = 1.0; + const double penWidth = frameEnabled() ? ( pen().widthF() / 2.0 ) : 0; + const double xPenAdjust = mMarginX < 0 ? -penWidth : penWidth; + const double yPenAdjust = mMarginY < 0 ? -penWidth : penWidth; + + QRectF painterRect; if ( mMode == QgsLayoutItemLabel::ModeFont ) { - rectScale = context.renderContext().scaleFactor(); + const double rectScale = context.renderContext().scaleFactor(); + painterRect = QRectF( ( xPenAdjust + mMarginX ) * rectScale, + ( yPenAdjust + mMarginY ) * rectScale, + ( rect().width() - 2 * xPenAdjust - 2 * mMarginX ) * rectScale, + ( rect().height() - 2 * yPenAdjust - 2 * mMarginY ) * rectScale ); } else { - // painter is scaled to dots, so scale back to layout units - painter->scale( context.renderContext().scaleFactor(), context.renderContext().scaleFactor() ); + // The 3.77 adjustment value was found through trial and error, the author has however no clue as to where it comes from + const double adjustmentFactor = 3.77; + const double rectScale = context.renderContext().scaleFactor() * adjustmentFactor; + // The left/right margin is handled by the stylesheet while the top/bottom margin is ignored by QTextDocument + painterRect = QRectF( 0, 0, + ( rect().width() ) * rectScale, + ( rect().height() - yPenAdjust - mMarginY ) * rectScale ); + painter->translate( 0, ( yPenAdjust + mMarginY ) * context.renderContext().scaleFactor() ); + painter->scale( context.renderContext().scaleFactor() / adjustmentFactor, context.renderContext().scaleFactor() / adjustmentFactor ); } - const double penWidth = frameEnabled() ? ( pen().widthF() / 2.0 ) : 0; - const double xPenAdjust = mMarginX < 0 ? -penWidth : penWidth; - const double yPenAdjust = mMarginY < 0 ? -penWidth : penWidth; - const QRectF painterRect( ( xPenAdjust + mMarginX ) * rectScale, - ( yPenAdjust + mMarginY ) * rectScale, - ( rect().width() - 2 * xPenAdjust - 2 * mMarginX ) * rectScale, - ( rect().height() - 2 * yPenAdjust - 2 * mMarginY ) * rectScale ); - switch ( mMode ) { case ModeHtml: { - if ( mFirstRender ) - { - contentChanged(); - mFirstRender = false; - } + QTextDocument document; + document.setDocumentMargin( 0 ); + document.setPageSize( QSizeF( painterRect.width() / context.renderContext().scaleFactor(), painterRect.height() / context.renderContext().scaleFactor() ) ); + document.setDefaultStyleSheet( createStylesheet() ); - if ( mWebPage ) - { - painter->scale( 1.0 / mHtmlUnitsToLayoutUnits / 10.0, 1.0 / mHtmlUnitsToLayoutUnits / 10.0 ); - mWebPage->setViewportSize( QSize( painterRect.width() * mHtmlUnitsToLayoutUnits * 10.0, painterRect.height() * mHtmlUnitsToLayoutUnits * 10.0 ) ); - mWebPage->settings()->setUserStyleSheetUrl( createStylesheetUrl() ); - mWebPage->mainFrame()->render( painter ); - } + document.setDefaultFont( createDefaultFont() ); + + QTextOption textOption = document.defaultTextOption(); + textOption.setAlignment( mHAlignment ); + document.setDefaultTextOption( textOption ); + + document.setHtml( QStringLiteral( "%1" ).arg( currentText() ) ); + document.drawContents( painter, painterRect ); break; } @@ -179,44 +155,7 @@ void QgsLayoutItemLabel::contentChanged() { case ModeHtml: { - const QString textToDraw = currentText(); - if ( !mWebPage ) - { - mHtmlLoaded = true; - return; - } - - //mHtmlLoaded tracks whether the QWebPage has completed loading - //its html contents, set it initially to false. The loadingHtmlFinished slot will - //set this to true after html is loaded. - mHtmlLoaded = false; - - const QUrl baseUrl = mLayout ? QUrl::fromLocalFile( mLayout->project()->absoluteFilePath() ) : QUrl(); - mWebPage->mainFrame()->setHtml( textToDraw, baseUrl ); - - //For very basic html labels with no external assets, the html load will already be - //complete before we even get a chance to start the QEventLoop. Make sure we check - //this before starting the loop - - // important -- we CAN'T do this when it's a render inside the designer, otherwise the - // event loop will mess with the paint event and cause it to be deleted, and BOOM! - if ( !mHtmlLoaded && ( !mLayout || !mLayout->renderContext().isPreviewRender() ) ) - { - //Setup event loop and timeout for rendering html - QEventLoop loop; - - //Connect timeout and webpage loadFinished signals to loop - connect( mWebPage.get(), &QWebPage::loadFinished, &loop, &QEventLoop::quit ); - - // Start a 20 second timeout in case html loading will never complete - QTimer timeoutTimer; - timeoutTimer.setSingleShot( true ); - connect( &timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit ); - timeoutTimer.start( 20000 ); - - // Pause until html is loaded - loop.exec( QEventLoop::ExcludeUserInputEvents ); - } + invalidateCache(); break; } case ModeFont: @@ -225,25 +164,6 @@ void QgsLayoutItemLabel::contentChanged() } } -void QgsLayoutItemLabel::loadingHtmlFinished( bool result ) -{ - Q_UNUSED( result ) - mHtmlLoaded = true; - invalidateCache(); - update(); -} - -double QgsLayoutItemLabel::htmlUnitsToLayoutUnits() -{ - if ( !mLayout ) - { - return 1.0; - } - - //TODO : fix this more precisely so that the label's default text size is the same with or without "display as html" - return mLayout->convertToLayoutUnits( QgsLayoutMeasurement( mLayout->renderContext().dpi() / 72.0, Qgis::LayoutUnit::Millimeters ) ); //webkit seems to assume a standard dpi of 72 -} - void QgsLayoutItemLabel::setText( const QString &text ) { mText = text; @@ -663,10 +583,8 @@ void QgsLayoutItemLabel::itemShiftAdjustSize( double newWidth, double newHeight, } } -QUrl QgsLayoutItemLabel::createStylesheetUrl() const +QFont QgsLayoutItemLabel::createDefaultFont() const { - QString stylesheet; - stylesheet += QStringLiteral( "body { margin: %1 %2;" ).arg( std::max( mMarginY * mHtmlUnitsToLayoutUnits, 0.0 ) ).arg( std::max( mMarginX * mHtmlUnitsToLayoutUnits, 0.0 ) ); QFont f = mFormat.font(); switch ( mFormat.sizeUnit() ) { @@ -688,13 +606,38 @@ QUrl QgsLayoutItemLabel::createStylesheetUrl() const case Qgis::RenderUnit::MapUnits: break; } + return f; +} +double QgsLayoutItemLabel::htmlUnitsToLayoutUnits() +{ + if ( !mLayout ) + { + return 1.0; + } + + //TODO : fix this more precisely so that the label's default text size is the same with or without "display as html" + return mLayout->convertToLayoutUnits( QgsLayoutMeasurement( mLayout->renderContext().dpi() / 72.0, Qgis::LayoutUnit::Millimeters ) ); //webkit seems to assume a standard dpi of 72 +} + +QString QgsLayoutItemLabel::createStylesheet() const +{ + QString stylesheet; + stylesheet += QStringLiteral( "body { margin: %1 %2;" ).arg( std::max( mMarginY * mHtmlUnitsToLayoutUnits, 0.0 ) ).arg( std::max( mMarginX * mHtmlUnitsToLayoutUnits, 0.0 ) ); + + QFont f = createDefaultFont(); stylesheet += QgsFontUtils::asCSS( f, 0.352778 * mHtmlUnitsToLayoutUnits ); + stylesheet += QStringLiteral( "color: rgba(%1,%2,%3,%4);" ).arg( mFormat.color().red() ).arg( mFormat.color().green() ).arg( mFormat.color().blue() ).arg( QString::number( mFormat.color().alphaF(), 'f', 4 ) ); stylesheet += QStringLiteral( "text-align: %1; }" ).arg( mHAlignment == Qt::AlignLeft ? QStringLiteral( "left" ) : mHAlignment == Qt::AlignRight ? QStringLiteral( "right" ) : mHAlignment == Qt::AlignHCenter ? QStringLiteral( "center" ) : QStringLiteral( "justify" ) ); + return stylesheet; +} + +QUrl QgsLayoutItemLabel::createStylesheetUrl() const +{ QByteArray ba; - ba.append( stylesheet.toUtf8() ); + ba.append( createStylesheet().toUtf8() ); QUrl cssFileURL = QUrl( QString( "data:text/css;charset=utf-8;base64," + ba.toBase64() ) ); return cssFileURL; diff --git a/src/core/layout/qgslayoutitemlabel.h b/src/core/layout/qgslayoutitemlabel.h index 3a4a9329dcd8..16bbc4c34b3d 100644 --- a/src/core/layout/qgslayoutitemlabel.h +++ b/src/core/layout/qgslayoutitemlabel.h @@ -19,7 +19,6 @@ #include "qgis_core.h" #include "qgslayoutitem.h" -#include "qgswebpage.h" #include "qgstextformat.h" #include #include @@ -253,9 +252,6 @@ class CORE_EXPORT QgsLayoutItemLabel: public QgsLayoutItem private slots: - //! Track when QWebPage has finished loading its html contents - void loadingHtmlFinished( bool ); - void refreshExpressionContext(); private: @@ -267,7 +263,6 @@ class CORE_EXPORT QgsLayoutItemLabel: public QgsLayoutItem Mode mMode = ModeFont; double mHtmlUnitsToLayoutUnits = 1.0; double htmlUnitsToLayoutUnits(); //calculate scale factor - bool mHtmlLoaded = false; //! Helper function to calculate x/y shift for adjustSizeToText() depending on rotation, current size and alignment void itemShiftAdjustSize( double newWidth, double newHeight, double &xShift, double &yShift ) const; @@ -291,12 +286,18 @@ class CORE_EXPORT QgsLayoutItemLabel: public QgsLayoutItem //! Replaces replace '$CURRENT_DATE<(FORMAT)>' with the current date (e.g. $CURRENT_DATE(d 'June' yyyy) void replaceDateText( QString &text ) const; + //! Creates the default font used when rendering labels in HTML mode + QFont createDefaultFont() const; + //! Creates an encoded stylesheet url using the current font and label appearance settings QUrl createStylesheetUrl() const; + //! Creates a stylesheet string using the current font and label appearance settings + QString createStylesheet() const; + std::unique_ptr< QgsDistanceArea > mDistanceArea; - std::unique_ptr< QgsWebPage > mWebPage; + friend class QgsLayoutItemHtml; }; #endif //QGSLAYOUTITEMLABEL_H diff --git a/tests/src/core/testqgslayoutlabel.cpp b/tests/src/core/testqgslayoutlabel.cpp index 17a69e5e672c..7df029e424be 100644 --- a/tests/src/core/testqgslayoutlabel.cpp +++ b/tests/src/core/testqgslayoutlabel.cpp @@ -17,6 +17,9 @@ #include "qgsapplication.h" #include "qgslayoutitemlabel.h" +#include "qgslayoutitemhtml.h" +#include "qgslayoutmanager.h" +#include "qgslayoutmultiframe.h" #include "qgsvectorlayer.h" #include "qgsmultirenderchecker.h" #include "qgsfontutils.h" @@ -51,8 +54,9 @@ class TestQgsLayoutLabel : public QgsTest void pageSizeEvaluation(); void marginMethods(); //tests getting/setting margins void render(); -#ifdef WITH_QTWEBKIT void renderAsHtml(); +#ifdef WITH_QTWEBKIT + void convertToHtml(); void renderAsHtmlRelative(); #endif void labelRotation(); @@ -285,7 +289,6 @@ void TestQgsLayoutLabel::render() QVERIFY( checker.testLayout( mReport, 0, 0 ) ); } -#ifdef WITH_QTWEBKIT void TestQgsLayoutLabel::renderAsHtml() { QgsLayout l( QgsProject::instance() ); @@ -314,6 +317,23 @@ void TestQgsLayoutLabel::renderAsHtml() QVERIFY( checker.testLayout( mReport, 0, 10 ) ); } +#ifdef WITH_QTWEBKIT +void TestQgsLayoutLabel::convertToHtml() +{ + QgsProject project; + project.read( QStringLiteral( TEST_DATA_DIR ) + "/layouts/sample_label_html.qgs" ); + + QgsLayout *layout = project.layoutManager()->printLayouts().at( 0 ); + QVERIFY( layout ); + + QgsLayoutMultiFrame *html = layout->multiFrames().at( 0 ); + QVERIFY( html ); + + QgsLayoutChecker checker( QStringLiteral( "composerlabel_converttohtml" ), layout ); + checker.setControlPathPrefix( QStringLiteral( "composer_label" ) ); + QVERIFY( checker.testLayout( mReport, 0, 10 ) ); +} + void TestQgsLayoutLabel::renderAsHtmlRelative() { QgsLayout l( QgsProject::instance() ); diff --git a/tests/testdata/control_images/composer_label/expected_composerlabel_converttohtml/expected_composerlabel_converttohtml.png b/tests/testdata/control_images/composer_label/expected_composerlabel_converttohtml/expected_composerlabel_converttohtml.png new file mode 100644 index 000000000000..7158cf9d9235 Binary files /dev/null and b/tests/testdata/control_images/composer_label/expected_composerlabel_converttohtml/expected_composerlabel_converttohtml.png differ diff --git a/tests/testdata/control_images/composer_label/expected_composerlabel_renderhtml/expected_composerlabel_renderhtml_mask.png b/tests/testdata/control_images/composer_label/expected_composerlabel_renderhtml/expected_composerlabel_renderhtml_mask.png index 63f0d6d04210..2bc20cb31b10 100644 Binary files a/tests/testdata/control_images/composer_label/expected_composerlabel_renderhtml/expected_composerlabel_renderhtml_mask.png and b/tests/testdata/control_images/composer_label/expected_composerlabel_renderhtml/expected_composerlabel_renderhtml_mask.png differ diff --git a/tests/testdata/control_images/composer_label/expected_composerlabel_renderhtmlrelative/expected_composerlabel_renderhtmlrelative_mask.png b/tests/testdata/control_images/composer_label/expected_composerlabel_renderhtmlrelative/expected_composerlabel_renderhtmlrelative_mask.png index 5736f2b0a13b..8b1f011c7fdb 100644 Binary files a/tests/testdata/control_images/composer_label/expected_composerlabel_renderhtmlrelative/expected_composerlabel_renderhtmlrelative_mask.png and b/tests/testdata/control_images/composer_label/expected_composerlabel_renderhtmlrelative/expected_composerlabel_renderhtmlrelative_mask.png differ diff --git a/tests/testdata/control_images/compositionconverter/expected_importComposerTemplate_0/expected_importComposerTemplate_0.png b/tests/testdata/control_images/compositionconverter/expected_importComposerTemplate_0/expected_importComposerTemplate_0.png index 1ff3b8bd2796..f3bbe73b7737 100644 Binary files a/tests/testdata/control_images/compositionconverter/expected_importComposerTemplate_0/expected_importComposerTemplate_0.png and b/tests/testdata/control_images/compositionconverter/expected_importComposerTemplate_0/expected_importComposerTemplate_0.png differ diff --git a/tests/testdata/layouts/sample_label_html.qgs b/tests/testdata/layouts/sample_label_html.qgs new file mode 100644 index 000000000000..677c5c59f649 --- /dev/null +++ b/tests/testdata/layouts/sample_label_html.qgs @@ -0,0 +1,423 @@ + + + + + + + + + GEOGCRS["WGS 84",ENSEMBLE["World Geodetic System 1984 ensemble",MEMBER["World Geodetic System 1984 (Transit)"],MEMBER["World Geodetic System 1984 (G730)"],MEMBER["World Geodetic System 1984 (G873)"],MEMBER["World Geodetic System 1984 (G1150)"],MEMBER["World Geodetic System 1984 (G1674)"],MEMBER["World Geodetic System 1984 (G1762)"],MEMBER["World Geodetic System 1984 (G2139)"],ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]],ENSEMBLEACCURACY[2.0]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Horizontal component of 3D system."],AREA["World."],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + + + + + + + + + + + + + degrees + + -190574.44781700032763183 + 5198333.26109800022095442 + -49487.06329900026321411 + 5313802.14684799965471029 + + 0 + + + GEOGCRS["WGS 84",ENSEMBLE["World Geodetic System 1984 ensemble",MEMBER["World Geodetic System 1984 (Transit)"],MEMBER["World Geodetic System 1984 (G730)"],MEMBER["World Geodetic System 1984 (G873)"],MEMBER["World Geodetic System 1984 (G1150)"],MEMBER["World Geodetic System 1984 (G1674)"],MEMBER["World Geodetic System 1984 (G1762)"],MEMBER["World Geodetic System 1984 (G2139)"],ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]],ENSEMBLEACCURACY[2.0]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Horizontal component of 3D system."],AREA["World."],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + 0 + + + + + + + Annotations_326000a5_a362_49b4_83aa_5dc951b8107f + + + + + + + + GEOGCRS["WGS 84",ENSEMBLE["World Geodetic System 1984 ensemble",MEMBER["World Geodetic System 1984 (Transit)"],MEMBER["World Geodetic System 1984 (G730)"],MEMBER["World Geodetic System 1984 (G873)"],MEMBER["World Geodetic System 1984 (G1150)"],MEMBER["World Geodetic System 1984 (G1674)"],MEMBER["World Geodetic System 1984 (G1762)"],MEMBER["World Geodetic System 1984 (G2139)"],ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]],ENSEMBLEACCURACY[2.0]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Horizontal component of 3D system."],AREA["World."],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + false + + + + + + + 1 + 1 + 1 + 0 + + + + 1 + 0 + + + + + + + 0 + + + 255 + 255 + 255 + 255 + 0 + 255 + 255 + + + false + + + EPSG:7030 + + + m2 + meters + + + 5 + 2.5 + false + false + false + 1 + 0 + false + false + true + 0 + 255,0,0,255 + + + false + + + true + 2 + + + 1 + + + + + + + + + + + + + + + + + + + webmaster + 2023-05-25T14:02:28 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GEOGCRS["WGS 84",ENSEMBLE["World Geodetic System 1984 ensemble",MEMBER["World Geodetic System 1984 (Transit)"],MEMBER["World Geodetic System 1984 (G730)"],MEMBER["World Geodetic System 1984 (G873)"],MEMBER["World Geodetic System 1984 (G1150)"],MEMBER["World Geodetic System 1984 (G1674)"],MEMBER["World Geodetic System 1984 (G1762)"],MEMBER["World Geodetic System 1984 (G2139)"],ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]],ENSEMBLEACCURACY[2.0]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Horizontal component of 3D system."],AREA["World."],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + + + + + + + + + + + + + + + + + + + + GEOGCRS["WGS 84",ENSEMBLE["World Geodetic System 1984 ensemble",MEMBER["World Geodetic System 1984 (Transit)"],MEMBER["World Geodetic System 1984 (G730)"],MEMBER["World Geodetic System 1984 (G873)"],MEMBER["World Geodetic System 1984 (G1150)"],MEMBER["World Geodetic System 1984 (G1674)"],MEMBER["World Geodetic System 1984 (G1762)"],MEMBER["World Geodetic System 1984 (G2139)"],ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]],ENSEMBLEACCURACY[2.0]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Horizontal component of 3D system."],AREA["World."],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + + + + +