Skip to content

Commit

Permalink
[FEATURE] New class for triangle
Browse files Browse the repository at this point in the history
Adds a new geometry class for Triangle geometries

Methods include orthocenter, bisectors, medians, medial, circumscribed (center,
radius), inscribed (center, radius)

Also adds make_triangle expression function for creating triangles
  • Loading branch information
lbartoletti authored and nyalldawson committed Mar 21, 2017
1 parent 0710fb5 commit fb3d07f
Show file tree
Hide file tree
Showing 15 changed files with 1,624 additions and 0 deletions.
1 change: 1 addition & 0 deletions python/core/core.sip
Expand Up @@ -370,5 +370,6 @@
%Include geometry/qgspointv2.sip
%Include geometry/qgspolygon.sip
%Include geometry/qgssurface.sip
%Include geometry/qgstriangle.sip
%Include geometry/qgswkbtypes.sip
%Include geometry/qgswkbptr.sip
6 changes: 6 additions & 0 deletions python/core/geometry/qgsgeometryutils.sip
Expand Up @@ -67,4 +67,10 @@ class QgsGeometryUtils

static QgsPointV2 midpoint (const QgsPointV2& pt1, const QgsPointV2& pt2);

static double gradient( const QgsPointV2& pt1, const QgsPointV2& pt2 );

static void coefficients(const QgsPointV2 &pt1, const QgsPointV2 &pt2, double& a /Out/, double& b /Out/, double& c /Out/);

static QgsLineString perpendicularSegment( const QgsPointV2& p, const QgsPointV2& s1, const QgsPointV2& s2 );

};
63 changes: 63 additions & 0 deletions python/core/geometry/qgstriangle.sip
@@ -0,0 +1,63 @@
class QgsTriangle : public QgsPolygonV2
{
%TypeHeaderCode
#include <qgstriangle.h>
%End

public:
QgsTriangle();
QgsTriangle( const QgsPointV2 &p1, const QgsPointV2 &p2, const QgsPointV2 &p3 );
explicit QgsTriangle( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p3 );
explicit QgsTriangle( const QPointF p1, const QPointF p2, const QPointF p3 );

// inherited: bool operator==( const QgsTriangle& other ) const;
// inherited: bool operator!=( const QgsTriangle& other ) const;

virtual QString geometryType() const;
virtual QgsTriangle* clone() const /Factory/;
void clear();

virtual bool fromWkb( QgsConstWkbPtr& wkbPtr );
bool fromWkt( const QString &wkt );
// inherited: QString asWkt( int precision = 17 ) const;
// inherited: QDomElement asGML2( QDomDocument& doc, int precision = 17, const QString& ns = "gml" ) const;
// inherited: QDomElement asGML3( QDomDocument& doc, int precision = 17, const QString& ns = "gml" ) const;
// inherited: QString asJSON( int precision = 17 ) const;

QgsPolygonV2* surfaceToPolygon() const /Factory/;
QgsAbstractGeometry* toCurveType() const /Factory/;

//overridden to handle LineString25D rings
virtual void setExteriorRing( QgsCurve* ring /Transfer/ );
virtual QgsAbstractGeometry* boundary() const /Factory/;
// inherited: double pointDistanceToBoundary( double x, double y ) const;
QgsPointV2 vertexAt( int atVertex ) const;

void addInteriorRing( QgsCurve* ring /Transfer/ ); // NOTE: no interior ring for triangle.
bool deleteVertex( QgsVertexId position );
bool insertVertex( QgsVertexId position, const QgsPointV2 &vertex );
bool moveVertex( QgsVertexId vId, const QgsPointV2& newPos );

QVector<double> lengths() const;
QVector<double> angles() const;

bool isIsocele( double lengthTolerance = 0.0001 ) const;
bool isEquilateral( double lengthTolerance = 0.0001 ) const;
bool isRight( double angleTolerance = 0.0001 ) const;
bool isScalene( double lengthTolerance = 0.0001 ) const;

QVector<QgsLineString> altitudes( ) const;
QVector<QgsLineString> medians( ) const;
QVector<QgsLineString> bisectors( double lengthTolerance = 0.0001 ) const;

QgsTriangle medial( ) const;
QgsPointV2 orthocenter( double lengthTolerance = 0.0001 ) const;
QgsPointV2 circumscribedCenter( ) const;
double circumscribedRadius( ) const;
// TODO:
// QgsCircle circumscribedCircle ( ) const; // need QgsCircle (from CADDigitize.CADCircle)
QgsPointV2 inscribedCenter( ) const;
double inscribedRadius( ) const;
// TODO:
// QgsCircle inscribedCircle ( ) const; // need QgsCircle (from CADDigitize.CADCircle)
};
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
Expand Up @@ -383,6 +383,7 @@ SET(QGIS_CORE_SRCS
geometry/qgsmultisurface.cpp
geometry/qgspointv2.cpp
geometry/qgspolygon.cpp
geometry/qgstriangle.cpp
geometry/qgswkbptr.cpp
geometry/qgswkbtypes.cpp

Expand Down Expand Up @@ -922,6 +923,7 @@ SET(QGIS_CORE_HDRS
geometry/qgsmultisurface.h
geometry/qgspointv2.h
geometry/qgspolygon.h
geometry/qgstriangle.h
geometry/qgssurface.h
geometry/qgswkbptr.h
geometry/qgswkbtypes.h
Expand Down
74 changes: 74 additions & 0 deletions src/core/geometry/qgsgeometryutils.cpp
Expand Up @@ -21,6 +21,7 @@ email : marco.hugentobler at sourcepole dot com
#include "qgslinestring.h"
#include "qgswkbptr.h"

#include <memory>
#include <QStringList>
#include <QVector>
#include <QRegularExpression>
Expand Down Expand Up @@ -834,6 +835,79 @@ QgsPointV2 QgsGeometryUtils::midpoint( const QgsPointV2 &pt1, const QgsPointV2 &
return QgsPointV2( pType, x, y, z, m );
}

double QgsGeometryUtils::gradient( const QgsPointV2 &pt1, const QgsPointV2 &pt2 )
{
double delta_x = pt2.x() - pt1.x();
double delta_y = pt2.y() - pt1.y();
if ( qgsDoubleNear( delta_x, 0.0 ) )
{
return INFINITY;
}

return delta_y / delta_x;
}

void QgsGeometryUtils::coefficients( const QgsPointV2 &pt1, const QgsPointV2 &pt2, double &a, double &b, double &c )
{
if ( qgsDoubleNear( pt1.x(), pt2.x() ) )
{
a = 1;
b = 0;
c = -pt1.x();
}
else if ( qgsDoubleNear( pt1.y(), pt2.y() ) )
{
a = 0;
b = 1;
c = -pt1.y();
}
else
{
a = pt1.y() - pt2.y();
b = pt2.x() - pt1.x();
c = pt1.x() * pt2.y() - pt1.y() * pt2.x();
}

}

QgsLineString QgsGeometryUtils::perpendicularSegment( const QgsPointV2 &p, const QgsPointV2 &s1, const QgsPointV2 &s2 )
{
QgsLineString line;
QgsPointV2 p2;

if ( ( p == s1 ) || ( p == s2 ) )
{
return line;
}

double a, b, c;
coefficients( s1, s2, a, b, c );

if ( qgsDoubleNear( a, 0 ) )
{
p2 = QgsPointV2( p.x(), s1.y() );
}
else if ( qgsDoubleNear( b, 0 ) )
{
p2 = QgsPointV2( s1.x(), p.y() );
}
else
{
double y = ( -c - a * p.x() ) / b;
double m = gradient( s1, s2 );
double d2 = 1 + m * m;
double H = p.y() - y;
double dx = m * H / d2;
double dy = m * dx;
p2 = QgsPointV2( p.x() + dx, y + dy );
}

line.addVertex( p );
line.addVertex( p2 );

return line;
}

double QgsGeometryUtils::lineAngle( double x1, double y1, double x2, double y2 )
{
double at = atan2( y2 - y1, x2 - x1 );
Expand Down
27 changes: 27 additions & 0 deletions src/core/geometry/qgsgeometryutils.h
Expand Up @@ -291,6 +291,33 @@ class CORE_EXPORT QgsGeometryUtils
*/
static QgsPointV2 midpoint( const QgsPointV2 &pt1, const QgsPointV2 &pt2 );

/** Return the gradient of a line defined by points \a pt1 and \a pt2.
* @param pt1 first point.
* @param pt2 second point.
* @return The gradient of this linear entity, or infinity if vertical
* @note added in QGIS 3.0
*/
static double gradient( const QgsPointV2 &pt1, const QgsPointV2 &pt2 );

/** Return the coefficients (a, b, c for equation "ax + by + c = 0") of a line defined by points \a pt1 and \a pt2.
* @param pt1 first point.
* @param pt2 second point.
* @param a Output parameter, a coefficient of the equation.
* @param b Output parameter, b coefficient of the equation.
* @param c Output parameter, c coefficient of the equation.
* @note added in QGIS 3.0
*/
static void coefficients( const QgsPointV2 &pt1, const QgsPointV2 &pt2, double &a, double &b, double &c );

/**
* @brief Create a perpendicular line segment from p to segment [s1, s2]
* @param p The point
* @param s1 The segment start point
* @param s2 The segment end point
* @return A line (segment) from p to perpendicular point on segment [s1, s2]
*/
static QgsLineString perpendicularSegment( const QgsPointV2 &p, const QgsPointV2 &s1, const QgsPointV2 &s2 );

//! @note not available in Python bindings
enum ComponentType
{
Expand Down
1 change: 1 addition & 0 deletions src/core/geometry/qgslinestring.h
Expand Up @@ -210,6 +210,7 @@ class CORE_EXPORT QgsLineString: public QgsCurve
void fromWkbPoints( QgsWkbTypes::Type type, const QgsConstWkbPtr &wkb );

friend class QgsPolygonV2;
friend class QgsTriangle;

};

Expand Down

0 comments on commit fb3d07f

Please sign in to comment.