Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Advanced digitizing: respect units for distance
- respect project settings for distance units
- format angle
- format geographic coordintates
  • Loading branch information
elpaso authored and nyalldawson committed May 11, 2023
1 parent c9af189 commit 49d1b61
Show file tree
Hide file tree
Showing 5 changed files with 345 additions and 142 deletions.
41 changes: 40 additions & 1 deletion python/gui/auto_generated/qgsadvanceddigitizingdockwidget.sip.in
Expand Up @@ -45,7 +45,7 @@ by implementing filters called from :py:class:`QgsMapToolAdvancedDigitizing`.
class CadConstraint
{
%Docstring(signature="appended")
The CadConstraint is an abstract class for all basic constraints (angle/distance/x/y).
The CadConstraint is a class for all basic constraints (angle/distance/x/y).
It contains all values (locked, value, relative) and pointers to corresponding widgets.

.. note::
Expand All @@ -65,6 +65,17 @@ It contains all values (locked, value, relative) and pointers to corresponding w
HardLock
};

enum ConstraintType
{
Generic,
Angle,
Distance,
XCoordinate,
YCoordinate,
ZValue,
MValue,
};

CadConstraint( QLineEdit *lineEdit, QToolButton *lockerButton, QToolButton *relativeButton = 0, QToolButton *repeatingLockButton = 0 );
%Docstring
Constructor for CadConstraint.
Expand Down Expand Up @@ -140,6 +151,13 @@ Set the value of the constraint

:param value: new value for constraint
:param updateWidget: set to ``False`` to prevent automatically updating the associated widget's value
%End

QString displayValue() const;
%Docstring
Returns a localized formatted string representation of the value.

.. versionadded:: 3.32
%End

void toggleLocked();
Expand Down Expand Up @@ -168,6 +186,27 @@ Sets the numeric precision (decimal places) to show in the associated widget.
.. seealso:: :py:func:`precision`

.. versionadded:: 3.22
%End

ConstraintType constraintType() const;
%Docstring
Returns the constraint type

.. versionadded:: 3.32
%End

void setConstraintType( ConstraintType constraintType );
%Docstring
Sets the constraint type to ``constraintType``

.. versionadded:: 3.32
%End

void setMapCanvas( QgsMapCanvas *mapCanvas );
%Docstring
Sets the map canvas to ``mapCanvas``

.. versionadded:: 3.32
%End

};
Expand Down
111 changes: 103 additions & 8 deletions src/gui/qgsadvanceddigitizingdockwidget.cpp
Expand Up @@ -34,6 +34,7 @@
#include "qgsproject.h"
#include "qgsmapmouseevent.h"
#include "qgsmeshlayer.h"
#include "qgsunittypes.h"

#include <QActionGroup>

Expand All @@ -48,14 +49,27 @@ QgsAdvancedDigitizingDockWidget::QgsAdvancedDigitizingDockWidget( QgsMapCanvas *
mCadPaintItem = new QgsAdvancedDigitizingCanvasItem( canvas, this );

mAngleConstraint.reset( new CadConstraint( mAngleLineEdit, mLockAngleButton, mRelativeAngleButton, mRepeatingLockAngleButton ) );
mAngleConstraint->setConstraintType( CadConstraint::ConstraintType::Angle );
mAngleConstraint->setMapCanvas( mMapCanvas );
mDistanceConstraint.reset( new CadConstraint( mDistanceLineEdit, mLockDistanceButton, nullptr, mRepeatingLockDistanceButton ) );
mDistanceConstraint->setConstraintType( CadConstraint::ConstraintType::Distance );
mDistanceConstraint->setMapCanvas( mMapCanvas );
mXConstraint.reset( new CadConstraint( mXLineEdit, mLockXButton, mRelativeXButton, mRepeatingLockXButton ) );
mXConstraint->setConstraintType( CadConstraint::ConstraintType::XCoordinate );
mXConstraint->setMapCanvas( mMapCanvas );
mYConstraint.reset( new CadConstraint( mYLineEdit, mLockYButton, mRelativeYButton, mRepeatingLockYButton ) );
mYConstraint->setConstraintType( CadConstraint::ConstraintType::YCoordinate );
mYConstraint->setMapCanvas( mMapCanvas );
mZConstraint.reset( new CadConstraint( mZLineEdit, mLockZButton, mRelativeZButton, mRepeatingLockZButton ) );
mZConstraint->setConstraintType( CadConstraint::ConstraintType::ZValue );
mZConstraint->setMapCanvas( mMapCanvas );
mMConstraint.reset( new CadConstraint( mMLineEdit, mLockMButton, mRelativeMButton, mRepeatingLockMButton ) );
mMConstraint->setConstraintType( CadConstraint::ConstraintType::MValue );
mMConstraint->setMapCanvas( mMapCanvas );

mLineExtensionConstraint.reset( new CadConstraint( new QLineEdit(), new QToolButton() ) );
mXyVertexConstraint.reset( new CadConstraint( new QLineEdit(), new QToolButton() ) );
mXyVertexConstraint->setMapCanvas( mMapCanvas );

mBetweenLineConstraint = Qgis::BetweenLineConstraint::NoConstraint;

Expand Down Expand Up @@ -689,13 +703,42 @@ QgsAdvancedDigitizingDockWidget::CadConstraint *QgsAdvancedDigitizingDockWidget:
return constraint;
}

double QgsAdvancedDigitizingDockWidget::parseUserInput( const QString &inputValue, bool &ok ) const
double QgsAdvancedDigitizingDockWidget::parseUserInput( const QString &inputValue, const CadConstraint::ConstraintType type, bool &ok ) const
{
ok = false;
double value = qgsPermissiveToDouble( inputValue, ok );

QString cleanedInputValue { inputValue };

// Remove angle suffix
if ( type == QgsAdvancedDigitizingDockWidget::CadConstraint::ConstraintType::Angle )
cleanedInputValue.remove( QStringLiteral( "°" ) );

// Remove distance unit suffix
const Qgis::DistanceUnit distanceUnit { QgsProject::instance()->distanceUnits() };
if ( type == QgsAdvancedDigitizingDockWidget::CadConstraint::ConstraintType::Distance )
cleanedInputValue.remove( QgsUnitTypes::toAbbreviatedString( distanceUnit ) );

double value = qgsPermissiveToDouble( cleanedInputValue, ok );

if ( ok )
{
return value;
switch ( type )
{
case QgsAdvancedDigitizingDockWidget::CadConstraint::ConstraintType::Distance:
{
// Convert distance to meters
const double factorUnits = QgsUnitTypes::fromUnitToUnitFactor( distanceUnit, Qgis::DistanceUnit::Meters );
value *= factorUnits;
break;
}
case QgsAdvancedDigitizingDockWidget::CadConstraint::ConstraintType::Generic:
case QgsAdvancedDigitizingDockWidget::CadConstraint::ConstraintType::Angle:
case QgsAdvancedDigitizingDockWidget::CadConstraint::ConstraintType::ZValue:
case QgsAdvancedDigitizingDockWidget::CadConstraint::ConstraintType::MValue:
case QgsAdvancedDigitizingDockWidget::CadConstraint::ConstraintType::XCoordinate:
case QgsAdvancedDigitizingDockWidget::CadConstraint::ConstraintType::YCoordinate:
break;
}
}
else
{
Expand Down Expand Up @@ -734,8 +777,8 @@ double QgsAdvancedDigitizingDockWidget::parseUserInput( const QString &inputValu
{
value = result.toDouble( &ok );
}
return value;
}
return value;
}

void QgsAdvancedDigitizingDockWidget::updateConstraintValue( CadConstraint *constraint, const QString &textValue, bool convertExpression )
Expand All @@ -749,7 +792,7 @@ void QgsAdvancedDigitizingDockWidget::updateConstraintValue( CadConstraint *cons
return;

bool ok;
const double value = parseUserInput( textValue, ok );
const double value = parseUserInput( textValue, constraint->constraintType(), ok );
if ( !ok )
return;

Expand All @@ -772,7 +815,7 @@ void QgsAdvancedDigitizingDockWidget::lockConstraint( bool activate /* default t
if ( !textValue.isEmpty() )
{
bool ok;
const double value = parseUserInput( textValue, ok );
const double value = parseUserInput( textValue, constraint->constraintType(), ok );
if ( ok )
{
constraint->setValue( value );
Expand Down Expand Up @@ -1841,7 +1884,44 @@ void QgsAdvancedDigitizingDockWidget::CadConstraint::setValue( double value, boo
{
mValue = value;
if ( updateWidget && mLineEdit->isEnabled() )
mLineEdit->setText( QLocale().toString( value, 'f', mPrecision ) );
mLineEdit->setText( displayValue() );
}

QString QgsAdvancedDigitizingDockWidget::CadConstraint::displayValue() const
{
switch ( mConstraintType )
{
case CadConstraint::ConstraintType::Angle:
{
return QLocale().toString( mValue, 'f', mPrecision ).append( QStringLiteral( " °" ) );
}
case CadConstraint::ConstraintType::XCoordinate:
case CadConstraint::ConstraintType::YCoordinate:
{
if ( mMapCanvas->mapSettings().destinationCrs().isGeographic() )
{
return QLocale().toString( mValue, 'f', mPrecision ).append( QStringLiteral( " °" ) );
}
else
{
return QLocale().toString( mValue, 'f', mPrecision );
}
}
case CadConstraint::ConstraintType::Distance:
{
// Value is always in meters (cartesian) #spellok
const Qgis::DistanceUnit units { QgsProject::instance()->distanceUnits() };
const double factorUnits = QgsUnitTypes::fromUnitToUnitFactor( Qgis::DistanceUnit::Meters, units );
const double convertedValue { mValue * factorUnits };
return QgsDistanceArea::formatDistance( convertedValue, mPrecision, units, true );
}
case CadConstraint::ConstraintType::Generic:
case CadConstraint::ConstraintType::ZValue:
case CadConstraint::ConstraintType::MValue:
default:
break;
}
return QLocale().toString( mValue, 'f', mPrecision );
}

void QgsAdvancedDigitizingDockWidget::CadConstraint::toggleLocked()
Expand All @@ -1858,7 +1938,22 @@ void QgsAdvancedDigitizingDockWidget::CadConstraint::setPrecision( int precision
{
mPrecision = precision;
if ( mLineEdit->isEnabled() )
mLineEdit->setText( QLocale().toString( mValue, 'f', mPrecision ) );
mLineEdit->setText( displayValue() );
}

QgsAdvancedDigitizingDockWidget::CadConstraint::ConstraintType QgsAdvancedDigitizingDockWidget::CadConstraint::constraintType() const
{
return mConstraintType;
}

void QgsAdvancedDigitizingDockWidget::CadConstraint::setConstraintType( QgsAdvancedDigitizingDockWidget::CadConstraint::ConstraintType constraintType )
{
mConstraintType = constraintType;
}

void QgsAdvancedDigitizingDockWidget::CadConstraint::setMapCanvas( QgsMapCanvas *mapCanvas )
{
mMapCanvas = mapCanvas;
}

QgsPoint QgsAdvancedDigitizingDockWidget::currentPointV2( bool *exist ) const
Expand Down
46 changes: 43 additions & 3 deletions src/gui/qgsadvanceddigitizingdockwidget.h
Expand Up @@ -30,7 +30,6 @@
#include "qgspointxy.h"
#include "qgspointlocator.h"
#include "qgssnapindicator.h"
#include "qgscadutils.h"


class QgsAdvancedDigitizingCanvasItem;
Expand Down Expand Up @@ -81,7 +80,7 @@ class GUI_EXPORT QgsAdvancedDigitizingDockWidget : public QgsDockWidget, private

/**
* \ingroup gui
* \brief The CadConstraint is an abstract class for all basic constraints (angle/distance/x/y).
* \brief The CadConstraint is a class for all basic constraints (angle/distance/x/y).
* It contains all values (locked, value, relative) and pointers to corresponding widgets.
* \note Relative is not mandatory since it is not used for distance.
*/
Expand All @@ -99,6 +98,21 @@ class GUI_EXPORT QgsAdvancedDigitizingDockWidget : public QgsDockWidget, private
HardLock
};

/**
* Constraint type
* \since QGIS 3.32
*/
enum ConstraintType
{
Generic, //!< Generic value
Angle, //!< Angle value
Distance, //!< Distance value
XCoordinate, //!< X Coordinate value
YCoordinate, //!< Y Coordinate value
ZValue, //!< Z value
MValue, //!< M value
};

/**
* Constructor for CadConstraint.
* \param lineEdit associated line edit for constraint value
Expand Down Expand Up @@ -177,6 +191,12 @@ class GUI_EXPORT QgsAdvancedDigitizingDockWidget : public QgsDockWidget, private
*/
void setValue( double value, bool updateWidget = true );

/**
* Returns a localized formatted string representation of the value.
* \since QGIS 3.32
*/
QString displayValue() const;

/**
* Toggle lock mode
*/
Expand All @@ -203,6 +223,24 @@ class GUI_EXPORT QgsAdvancedDigitizingDockWidget : public QgsDockWidget, private
*/
void setPrecision( int precision );

/**
* Returns the constraint type
* \since QGIS 3.32
*/
ConstraintType constraintType() const;

/**
* Sets the constraint type to \a constraintType
* \since QGIS 3.32
*/
void setConstraintType( ConstraintType constraintType );

/**
* Sets the map canvas to \a mapCanvas
* \since QGIS 3.32
*/
void setMapCanvas( QgsMapCanvas *mapCanvas );

private:
QLineEdit *mLineEdit = nullptr;
QToolButton *mLockerButton = nullptr;
Expand All @@ -213,6 +251,8 @@ class GUI_EXPORT QgsAdvancedDigitizingDockWidget : public QgsDockWidget, private
bool mRelative;
double mValue;
int mPrecision = 6;
ConstraintType mConstraintType = ConstraintType::Generic;
QgsMapCanvas *mMapCanvas = nullptr;
};

/**
Expand Down Expand Up @@ -969,7 +1009,7 @@ class GUI_EXPORT QgsAdvancedDigitizingDockWidget : public QgsDockWidget, private
CadConstraint *objectToConstraint( const QObject *obj ) const;

//! Attempts to convert a user input value to double, either directly or via expression
double parseUserInput( const QString &inputValue, bool &ok ) const;
double parseUserInput( const QString &inputValue, const CadConstraint::ConstraintType type, bool &ok ) const;

/**
* Updates a constraint value based on a text input.
Expand Down

0 comments on commit 49d1b61

Please sign in to comment.