Skip to content

Commit

Permalink
Merge pull request #5714 from opengisch/grid_decoration
Browse files Browse the repository at this point in the history
Support grid decoration
  • Loading branch information
nirvn authored Oct 8, 2024
2 parents e082450 + 6b7afc7 commit 2000f33
Show file tree
Hide file tree
Showing 9 changed files with 757 additions and 3 deletions.
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ set(QFIELD_CORE_SRCS
focusstack.cpp
geometry.cpp
geometryeditorsmodel.cpp
gridmodel.cpp
identifytool.cpp
layerobserver.cpp
featurehistory.cpp
Expand Down Expand Up @@ -186,6 +187,7 @@ set(QFIELD_CORE_HDRS
focusstack.h
geometry.h
geometryeditorsmodel.h
gridmodel.h
identifytool.h
layerobserver.h
featurehistory.h
Expand Down
285 changes: 285 additions & 0 deletions src/core/gridmodel.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
/***************************************************************************
gridmodel.cpp - GridModel
---------------------
begin : 4.10.2024
copyright : (C) 2024 by Mathieu Pellerin
email : [email protected]
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "gridmodel.h"

GridModel::GridModel( QObject *parent )
: QObject( parent )
{
}

void GridModel::setEnabled( bool enabled )
{
if ( mEnabled == enabled )
return;

mEnabled = enabled;
emit enabledChanged();

if ( mEnabled )
{
update();
}
else
{
if ( !mLines.isEmpty() || !mMarkers.isEmpty() || !mAnnotations.isEmpty() )
{
mLines.clear();
mMarkers.clear();
mAnnotations.clear();
emit gridChanged();
}
}
}

void GridModel::setMapSettings( QgsQuickMapSettings *mapSettings )
{
if ( mMapSettings == mapSettings )
{
return;
}

if ( mMapSettings )
{
disconnect( mMapSettings, &QgsQuickMapSettings::visibleExtentChanged, this, &GridModel::update );
}

mMapSettings = mapSettings;
emit mapSettingsChanged();


if ( mMapSettings )
{
connect( mMapSettings, &QgsQuickMapSettings::visibleExtentChanged, this, &GridModel::update );
}
}

void GridModel::setXInterval( double interval )
{
if ( mXInterval == interval )
return;

mXInterval = interval;
emit xIntervalChanged();

update();
}

void GridModel::setYInterval( double interval )
{
if ( mYInterval == interval )
return;

mYInterval = interval;
emit yIntervalChanged();

update();
}

void GridModel::setXOffset( double offset )
{
if ( mXOffset == offset )
return;

mXOffset = offset;
emit xOffsetChanged();

update();
}

void GridModel::setYOffset( double offset )
{
if ( mYOffset == offset )
return;

mYOffset = offset;
emit yOffsetChanged();

update();
}

void GridModel::setPrepareLines( bool prepare )
{
if ( mPrepareLines == prepare )
return;

mPrepareLines = prepare;
emit prepareLinesChanged();

if ( mPrepareLines )
{
update();
}
else
{
if ( !mLines.isEmpty() )
{
mLines.clear();
emit gridChanged();
}
}
}

void GridModel::setPrepareMarkers( bool prepare )
{
if ( mPrepareMarkers == prepare )
return;

mPrepareMarkers = prepare;
emit prepareMarkersChanged();

if ( mPrepareMarkers )
{
update();
}
else
{
if ( !mMarkers.isEmpty() )
{
mMarkers.clear();
emit gridChanged();
}
}
}

void GridModel::setPrepareAnnotations( bool prepare )
{
if ( mPrepareAnnotations == prepare )
return;

mPrepareAnnotations = prepare;
emit prepareAnnotationsChanged();

if ( mPrepareAnnotations )
{
update();
}
else
{
if ( !mAnnotations.isEmpty() )
{
mAnnotations.clear();
emit gridChanged();
}
}
}

void GridModel::update()
{
if ( !mEnabled || !mMapSettings )
{
return;
}

bool hadGrid = !mLines.isEmpty() || !mMarkers.isEmpty() || !mAnnotations.isEmpty();

mLines.clear();
mMarkers.clear();
mAnnotations.clear();

const QgsRectangle visibleExtent = mMapSettings->visibleExtent();
double smallestScreenInterval = std::min( mXInterval / mMapSettings->mapUnitsPerPoint(), mYInterval / mMapSettings->mapUnitsPerPoint() );
if ( smallestScreenInterval < ( mPrepareMarkers ? 20 : 10 ) )
{
if ( hadGrid )
{
emit gridChanged();
}
return;
}

QList<QPointF> line;
QPointF intersectionPoint;

if ( mPrepareMarkers )
{
double xPos = visibleExtent.xMinimum() - std::fmod( visibleExtent.xMinimum(), mXInterval ) + mXOffset;
while ( xPos <= visibleExtent.xMaximum() )
{
double yPos = visibleExtent.yMinimum() - std::fmod( visibleExtent.yMinimum(), mYInterval ) + mYOffset;
while ( yPos <= visibleExtent.yMaximum() )
{
mMarkers << mMapSettings->coordinateToScreen( QgsPoint( xPos, yPos ) );
yPos += mYInterval;
}
xPos += mXInterval;
}
}

const QSizeF sceneSize = mMapSettings->outputSize() / mMapSettings->devicePixelRatio();
if ( mPrepareLines || mPrepareAnnotations )
{
double xPos = visibleExtent.xMinimum() - std::fmod( visibleExtent.xMinimum(), mXInterval ) + mXOffset;
const QLineF topBorder( QPointF( 0, 0 ), QPointF( sceneSize.width(), 0 ) );
const QLineF bottomBorder( QPointF( 0, sceneSize.height() ), QPointF( sceneSize.width(), sceneSize.height() ) );
while ( xPos <= visibleExtent.xMaximum() )
{
const QLineF currentLine( mMapSettings->coordinateToScreen( QgsPoint( xPos, visibleExtent.yMinimum() ) ), mMapSettings->coordinateToScreen( QgsPoint( xPos, visibleExtent.yMaximum() ) ) );

if ( mPrepareAnnotations )
{
if ( currentLine.intersects( topBorder, &intersectionPoint ) )
{
mAnnotations << GridAnnotation( GridAnnotation::Top, intersectionPoint, xPos );
}
if ( currentLine.intersects( bottomBorder, &intersectionPoint ) )
{
mAnnotations << GridAnnotation( GridAnnotation::Bottom, intersectionPoint, xPos );
}
}

if ( mPrepareLines )
{
line << currentLine.p1() << currentLine.p2();
mLines << line;
line.clear();
}

xPos += mXInterval;
}

double yPos = visibleExtent.yMinimum() - std::fmod( visibleExtent.yMinimum(), mYInterval ) + mYOffset;
const QLineF leftBorder( QPointF( 0, 0 ), QPointF( 0, sceneSize.height() ) );
const QLineF rightBorder( QPointF( sceneSize.width(), 0 ), QPointF( sceneSize.width(), sceneSize.height() ) );
while ( yPos <= visibleExtent.yMaximum() )
{
const QLineF currentLine( mMapSettings->coordinateToScreen( QgsPoint( visibleExtent.xMinimum(), yPos ) ), mMapSettings->coordinateToScreen( QgsPoint( visibleExtent.xMaximum(), yPos ) ) );

if ( mPrepareAnnotations )
{
if ( currentLine.intersects( leftBorder, &intersectionPoint ) )
{
mAnnotations << GridAnnotation( GridAnnotation::Left, intersectionPoint, yPos );
}
if ( currentLine.intersects( rightBorder, &intersectionPoint ) )
{
mAnnotations << GridAnnotation( GridAnnotation::Right, intersectionPoint, yPos );
}
}

if ( mPrepareLines )
{
line << currentLine.p1() << currentLine.p2();
mLines << line;
line.clear();
}

yPos += mYInterval;
}
}

emit gridChanged();
}
Loading

1 comment on commit 2000f33

@qfield-fairy
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.