Skip to content

Commit

Permalink
Refactoring of rectangle maptools
Browse files Browse the repository at this point in the history
Adds a new geometry class QgsQuadrilateral, for 4 sided geometries.
  • Loading branch information
lbartoletti authored and nyalldawson committed Jan 14, 2019
1 parent 046bec4 commit edadcb7
Show file tree
Hide file tree
Showing 15 changed files with 1,179 additions and 186 deletions.
201 changes: 201 additions & 0 deletions python/core/auto_generated/geometry/qgsquadrilateral.sip.in
@@ -0,0 +1,201 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/geometry/qgsquadrilateral.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/





class QgsQuadrilateral
{
%Docstring
Quadrilateral geometry type.
A quadrilateral is a polygon with four edges (or sides) and four vertices or corners.
This class allows the creation of simple quadrilateral (which does not self-intersect).

.. versionadded:: 3.6
%End

%TypeHeaderCode
#include "qgsquadrilateral.h"
%End
public:
QgsQuadrilateral();

QgsQuadrilateral( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p3, const QgsPoint &p4 );
%Docstring
Construct a QgsQuadrilateral from four :py:class:`QgsPoint`.

:param p1: first point
:param p2: second point
:param p3: third point
:param p4: fourth point

.. seealso:: :py:func:`setPoints`
%End

explicit QgsQuadrilateral( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3, const QgsPointXY &p4 );
%Docstring
Construct a QgsQuadrilateral from four :py:class:`QgsPointXY`.

:param p1: first point
:param p2: second point
:param p3: third point
:param p4: fourth point

.. seealso:: :py:func:`setPoints`
%End


enum ConstructionOption
{
Distance,
Projected,
};

static QgsQuadrilateral rectangleFrom3Points( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p3, ConstructionOption mode );
%Docstring
Construct a QgsQuadrilateral as a Rectangle from 3 points.
In the case where one of the points is of type PointZ. The other points
will also be of type Z, even if they are of type Point. In addition,
the z used will be the one of the first point with a Z.
This ensures consistency in point types and the ability to export to a
Polygon or LineString.

:param p1: first point
:param p2: second point
:param p3: third point
:param mode: Construction mode to construct the rectangle from 3 points

.. seealso:: ConstructionOption
%End

static QgsQuadrilateral rectangleFromExtent( const QgsPoint &p1, const QgsPoint &p2 );
%Docstring
Construct a QgsQuadrilateral as a rectangle from an extent, defined by
two opposite corner points.
Z is taken from point ``p1``.

:param p1: first point
:param p2: second point
%End


static QgsQuadrilateral squareFromDiagonal( const QgsPoint &p1, const QgsPoint &p2 );
%Docstring
Construct a QgsQuadrilateral as a square from a diagonal.
Z is taken from point ``p1``.

:param p1: first point
:param p2: second point
%End

static QgsQuadrilateral rectangleFromCenterPoint( const QgsPoint &center, const QgsPoint &point );
%Docstring
Construct a QgsQuadrilateral as a rectangle from center point ``center``
and another point ``point``.
Z is taken from ``center`` point.

:param center: center point
:param point: corner point
%End

static QgsQuadrilateral fromRectangle( const QgsRectangle &rectangle );
%Docstring
Construct a QgsQuadrilateral as a rectangle from a :py:class:`QgsRectangle`.

:param rectangle: rectangle
%End


bool equals( const QgsQuadrilateral &other, double epsilon = 4 * DBL_EPSILON ) const;
%Docstring
Compares two QgsQuadrilateral, allowing specification of the maximum allowable difference between points.

:param other: the QgsQuadrilateral to compare
:param epsilon: the maximum difference allowed / tolerance
%End
bool operator==( const QgsQuadrilateral &other ) const;
bool operator!=( const QgsQuadrilateral &other ) const;

bool isValid() const;
%Docstring
Convenient method to determine if a QgsQuadrilateral is valid.
A QgsQuadrilateral must be simple (not self-intersecting) and
cannot have collinear points.
%End

enum Point
{
Point1,
Point2,
Point3,
Point4,
};

bool setPoint( const QgsPoint &newPoint, Point index );
%Docstring
Sets the point ``newPoint`` at the ``index``.
Returns false if the QgsQuadrilateral is not valid.

.. seealso:: Point
%End

bool setPoints( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p3, const QgsPoint &p4 );
%Docstring
Set all points
Returns false if the QgsQuadrilateral is not valid:
- The points do not have the same type
- The quadrilateral would have auto intersections
- The quadrilateral has double points
- The quadrilateral has collinear points
%End

QgsPointSequence points() const;
%Docstring
Returns a list including the vertices of the quadrilateral.
%End

QgsPolygon *toPolygon( bool force2D = false ) const /Factory/;
%Docstring
Returns the quadrilateral as a new polygon. Ownership is transferred to the caller.
%End

QgsLineString *toLineString( bool force2D = false ) const /Factory/;
%Docstring
Returns the quadrilateral as a new linestring. Ownership is transferred to the caller.
%End

QString toString( int pointPrecision = 17 ) const;
%Docstring
Returns a string representation of the quadrilateral.
Members will be truncated to the specified precision.
%End

double area() const;
%Docstring
Returns the area of the quadrilateral, or 0 if the quadrilateral is empty.
%End

double perimeter() const;
%Docstring
Returns the perimeter of the quadrilateral, or 0 if the quadrilateral is empty.
%End
SIP_PYOBJECT __repr__();
%MethodCode
QString str = QStringLiteral( "<QgsQuadrilateral: %1>" ).arg( sipCpp->toString() );
sipRes = PyUnicode_FromString( str.toUtf8().constData() );
%End
};

/************************************************************************
* This file has been generated automatically from *
* *
* src/core/geometry/qgsquadrilateral.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
20 changes: 20 additions & 0 deletions python/core/auto_generated/qgsvector3d.sip.in
Expand Up @@ -89,7 +89,27 @@ Returns the length of the vector
Normalizes the current vector in place.
%End

double distance( const QgsVector3D &other ) const;
%Docstring
Returns the distance with the ``other`` :py:class:`QgsVector3`
%End

static QgsVector3D perpendicularPoint( const QgsVector3D &v1, const QgsVector3D &v2, const QgsVector3D &vp );
%Docstring
Returns the perpendicular point of vector ``vp`` from [``v1`` - ``v2``]
%End

QString toString( int precision = 17 ) const;
%Docstring
Returns a string representation of the 3D vector.
Members will be truncated to the specified ``precision``.
%End

SIP_PYOBJECT __repr__();
%MethodCode
QString str = QStringLiteral( "<QgsVector3D: %1>" ).arg( sipCpp->toString() );
sipRes = PyUnicode_FromString( str.toUtf8().constData() );
%End
};

/************************************************************************
Expand Down
1 change: 1 addition & 0 deletions python/core/core_auto.sip
Expand Up @@ -288,6 +288,7 @@
%Include auto_generated/geometry/qgsmultipolygon.sip
%Include auto_generated/geometry/qgsmultisurface.sip
%Include auto_generated/geometry/qgspolygon.sip
%Include auto_generated/geometry/qgsquadrilateral.sip
%Include auto_generated/geometry/qgsrectangle.sip
%Include auto_generated/geometry/qgsreferencedgeometry.sip
%Include auto_generated/geometry/qgsregularpolygon.sip
Expand Down
94 changes: 4 additions & 90 deletions src/app/qgsmaptooladdrectangle.cpp
Expand Up @@ -35,26 +35,6 @@ QgsMapToolAddRectangle::QgsMapToolAddRectangle( QgsMapToolCapture *parentTool, Q
connect( QgisApp::instance(), &QgisApp::projectRead, this, &QgsMapToolAddRectangle::stopCapturing );
}

void QgsMapToolAddRectangle::setAzimuth( const double azimuth )
{
mAzimuth = azimuth;
}

void QgsMapToolAddRectangle::setDistance1( const double distance1 )
{
mDistance1 = distance1;
}

void QgsMapToolAddRectangle::setDistance2( const double distance2 )
{
mDistance2 = distance2;
}

void QgsMapToolAddRectangle::setSide( const int side )
{
mSide = side;
}

QgsMapToolAddRectangle::~QgsMapToolAddRectangle()
{
clean();
Expand Down Expand Up @@ -83,81 +63,15 @@ void QgsMapToolAddRectangle::keyReleaseEvent( QKeyEvent *e )
}
}

QgsLineString *QgsMapToolAddRectangle::rectangleToLinestring( const bool isOriented ) const
{
std::unique_ptr<QgsLineString> ext( new QgsLineString() );
if ( mRectangle.toRectangle().isEmpty() )
{
return ext.release();
}

QgsPoint x0( mRectangle.xMinimum(), mRectangle.yMinimum() );

QgsPoint x1, x2, x3;
if ( isOriented )
{
const double perpendicular = 90.0 * mSide;
x1 = x0.project( mDistance1, mAzimuth );
x3 = x0.project( mDistance2, mAzimuth + perpendicular );
x2 = x1.project( mDistance2, mAzimuth + perpendicular );
}
else
{
x1 = QgsPoint( mRectangle.xMinimum(), mRectangle.yMaximum() );
x2 = QgsPoint( mRectangle.xMaximum(), mRectangle.yMaximum() );
x3 = QgsPoint( mRectangle.xMaximum(), mRectangle.yMinimum() );
}

ext->addVertex( x0 );
ext->addVertex( x1 );
ext->addVertex( x2 );
ext->addVertex( x3 );
ext->addVertex( x0 );

// keep z value from the first snapped point
for ( const QgsPoint point : qgis::as_const( mPoints ) )
{
if ( QgsWkbTypes::hasZ( point.wkbType() ) )
{
if ( point.z() != defaultZValue() )
{
ext->dropZValue();
ext->addZValue( point.z() );
break;
}
else
{
ext->dropZValue();
ext->addZValue( defaultZValue() );
}
}
}

return ext.release();
}

QgsPolygon *QgsMapToolAddRectangle::rectangleToPolygon( const bool isOriented ) const
{
std::unique_ptr<QgsPolygon> polygon( new QgsPolygon() );
if ( mRectangle.toRectangle().isEmpty() )
{
return polygon.release();
}

polygon->setExteriorRing( rectangleToLinestring( isOriented ) );

return polygon.release();
}

void QgsMapToolAddRectangle::deactivate( const bool isOriented )
void QgsMapToolAddRectangle::deactivate( )
{
if ( !mParentTool || mRectangle.toRectangle().isEmpty() )
if ( !mParentTool || !mRectangle.isValid() )
{
return;
}

mParentTool->clearCurve( );
mParentTool->addCurve( rectangleToLinestring( isOriented ) );
mParentTool->addCurve( mRectangle.toLineString( !QgsWkbTypes::hasZ( qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() )->wkbType() ) ) );
clean();

QgsMapToolCapture::deactivate();
Expand All @@ -184,7 +98,7 @@ void QgsMapToolAddRectangle::clean()
mParentTool->deleteTempRubberBand();
}

mRectangle = QgsBox3d();
mRectangle = QgsQuadrilateral();

QgsVectorLayer *vLayer = static_cast<QgsVectorLayer *>( QgisApp::instance()->activeLayer() );
if ( vLayer )
Expand Down

0 comments on commit edadcb7

Please sign in to comment.