Skip to content
Permalink
Browse files

Merge pull request #2290 from mhugent/geometry_marker

Geometry marker
  • Loading branch information
mhugent committed Sep 5, 2015
2 parents cb5054f + 557701c commit 86115435f556cbb929aa092d6b70b1ebce4679c1
Showing with 592 additions and 79 deletions.
  1. +4 −0 python/core/geometry/qgsabstractgeometryv2.sip
  2. +5 −0 python/core/geometry/qgscircularstringv2.sip
  3. +5 −0 python/core/geometry/qgscompoundcurvev2.sip
  4. +5 −0 python/core/geometry/qgscurvepolygonv2.sip
  5. +5 −0 python/core/geometry/qgsgeometrycollectionv2.sip
  6. +5 −0 python/core/geometry/qgslinestringv2.sip
  7. +5 −0 python/core/geometry/qgspointv2.sip
  8. +7 −0 python/core/qgsrendercontext.sip
  9. +5 −0 src/core/geometry/qgsabstractgeometryv2.h
  10. +55 −0 src/core/geometry/qgscircularstringv2.cpp
  11. +5 −0 src/core/geometry/qgscircularstringv2.h
  12. +22 −0 src/core/geometry/qgscompoundcurvev2.cpp
  13. +5 −0 src/core/geometry/qgscompoundcurvev2.h
  14. +11 −0 src/core/geometry/qgscurvepolygonv2.cpp
  15. +5 −0 src/core/geometry/qgscurvepolygonv2.h
  16. +16 −0 src/core/geometry/qgsgeometrycollectionv2.cpp
  17. +5 −0 src/core/geometry/qgsgeometrycollectionv2.h
  18. +88 −0 src/core/geometry/qgsgeometryutils.cpp
  19. +12 −0 src/core/geometry/qgsgeometryutils.h
  20. +31 −0 src/core/geometry/qgslinestringv2.cpp
  21. +5 −0 src/core/geometry/qgslinestringv2.h
  22. +5 −0 src/core/geometry/qgspointv2.h
  23. +1 −0 src/core/qgsrendercontext.cpp
  24. +9 −0 src/core/qgsrendercontext.h
  25. +64 −3 src/core/symbology-ng/qgslinesymbollayerv2.cpp
  26. +2 −1 src/core/symbology-ng/qgslinesymbollayerv2.h
  27. +55 −27 src/core/symbology-ng/qgsrendererv2.cpp
  28. +31 −26 src/gui/symbology-ng/qgssymbollayerv2widget.cpp
  29. +29 −22 src/ui/symbollayer/widget_markerline.ui
  30. +90 −0 tests/src/core/testqgsgeometryutils.cpp
@@ -116,4 +116,8 @@ class QgsAbstractGeometryV2
virtual bool hasCurvedSegments() const;
/** Returns a geometry without curves. Caller takes ownership*/
virtual QgsAbstractGeometryV2* segmentize() const /Factory/;

/** Returns approximate rotation angle for a vertex. Usually average angle between adjacent segments.
@return rotation in radians, clockwise from north*/
virtual double vertexAngle( const QgsVertexId& vertex ) const = 0;
};
@@ -55,6 +55,11 @@ class QgsCircularStringV2: public QgsCurveV2

bool hasCurvedSegments() const;

/** Returns approximate rotation angle for a vertex. Usually average angle between adjacent segments.
@param vertex the vertex id
@return rotation in radians, clockwise from north*/
double vertexAngle( const QgsVertexId& vertex ) const;

private:
void segmentize( const QgsPointV2& p1, const QgsPointV2& p2, const QgsPointV2& p3, QList<QgsPointV2>& points ) const;
};
@@ -60,4 +60,9 @@ class QgsCompoundCurveV2: public QgsCurveV2
void sumUpArea( double& sum ) const;

bool hasCurvedSegments() const;

/** Returns approximate rotation angle for a vertex. Usually average angle between adjacent segments.
@param vertex the vertex id
@return rotation in radians, clockwise from north*/
double vertexAngle( const QgsVertexId& vertex ) const;
};
@@ -62,4 +62,9 @@ class QgsCurvePolygonV2: public QgsSurfaceV2

bool hasCurvedSegments() const;
QgsAbstractGeometryV2* segmentize() const /Factory/;

/** Returns approximate rotation angle for a vertex. Usually average angle between adjacent segments.
@param vertex the vertex id
@return rotation in radians, clockwise from north*/
double vertexAngle( const QgsVertexId& vertex ) const;
};
@@ -51,4 +51,9 @@ class QgsGeometryCollectionV2: public QgsAbstractGeometryV2
virtual double area() const;

bool hasCurvedSegments() const;

/** Returns approximate rotation angle for a vertex. Usually average angle between adjacent segments.
@param vertex the vertex id
@return rotation in radians, clockwise from north*/
double vertexAngle( const QgsVertexId& vertex ) const;
};
@@ -55,4 +55,9 @@ class QgsLineStringV2: public QgsCurveV2
bool pointAt( int i, QgsPointV2& vertex, QgsVertexId::VertexType& type ) const;

void sumUpArea( double& sum ) const;

/** Returns approximate rotation angle for a vertex. Usually average angle between adjacent segments.
@param vertex the vertex id
@return rotation in radians, clockwise from north*/
double vertexAngle( const QgsVertexId& vertex ) const;
};
@@ -55,4 +55,9 @@ class QgsPointV2: public QgsAbstractGeometryV2

double closestSegment( const QgsPointV2& pt, QgsPointV2& segmentPt, QgsVertexId& vertexAfter, bool* leftOf, double epsilon ) const;
bool nextVertex( QgsVertexId& id, QgsPointV2& vertex ) const;

/** Angle undefined. Always returns 0.0
@param vertex the vertex id
@return 0.0*/
double vertexAngle( const QgsVertexId& vertex ) const;
};
@@ -85,4 +85,11 @@ class QgsRenderContext
//! Added in QGIS v2.4
const QgsVectorSimplifyMethod& vectorSimplifyMethod() const;
void setVectorSimplifyMethod( const QgsVectorSimplifyMethod& simplifyMethod );

/** Returns pointer to the unsegmentized geometry
@return the geometry*/
const QgsAbstractGeometryV2* geometry() const;
/** Sets pointer to original (unsegmentized) geometry
@geometry the geometry*/
void setGeometry( const QgsAbstractGeometryV2* geometry );
};
@@ -317,6 +317,11 @@ class CORE_EXPORT QgsAbstractGeometryV2
*/
virtual QgsAbstractGeometryV2* segmentize() const { return clone(); }

/** Returns approximate rotation angle for a vertex. Usually average angle between adjacent segments.
@param vertex the vertex id
@return rotation in radians, clockwise from north*/
virtual double vertexAngle( const QgsVertexId& vertex ) const = 0;

protected:
QgsWKBTypes::Type mWkbType;
mutable QgsRectangle mBoundingBox;
@@ -953,3 +953,58 @@ void QgsCircularStringV2::insertVertexBetween( int after, int before, int pointO
mM.insert( before, ( mM[after] + mM[before] ) / 2.0 );
}
}

double QgsCircularStringV2::vertexAngle( const QgsVertexId& vId ) const
{
int before = vId.vertex - 1;
int vertex = vId.vertex;
int after = vId.vertex + 1;

if ( vId.vertex % 2 != 0 ) // a curve vertex
{
if ( vId.vertex >= 1 && vId.vertex < numPoints() - 1 )
{
return QgsGeometryUtils::circleTangentDirection( QgsPointV2( mX[vertex], mY[vertex] ), QgsPointV2( mX[before], mY[before] ),
QgsPointV2( mX[vertex], mY[vertex] ), QgsPointV2( mX[after], mY[after] ) );
}
}
else //a point vertex
{
if ( vId.vertex == 0 )
{
return QgsGeometryUtils::circleTangentDirection( QgsPointV2( mX[0], mY[0] ), QgsPointV2( mX[0], mY[0] ),
QgsPointV2( mX[1], mY[1] ), QgsPointV2( mX[2], mY[2] ) );
}
if ( vId.vertex >= numPoints() - 1 )
{
if ( numPoints() < 3 )
{
return 0.0;
}
int a = numPoints() - 3;
int b = numPoints() - 2;
int c = numPoints() - 1;
return QgsGeometryUtils::circleTangentDirection( QgsPointV2( mX[c], mY[c] ), QgsPointV2( mX[a], mY[a] ),
QgsPointV2( mX[b], mY[b] ), QgsPointV2( mX[c], mY[c] ) );
}
else
{
if ( vId.vertex + 2 > numPoints() - 1 )
{
return 0.0;
}

int vertex1 = vId.vertex - 2;
int vertex2 = vId.vertex - 1;
int vertex3 = vId.vertex;
double angle1 = QgsGeometryUtils::circleTangentDirection( QgsPointV2( mX[vertex3], mY[vertex3] ),
QgsPointV2( mX[vertex1], mY[vertex1] ), QgsPointV2( mX[vertex2], mY[vertex2] ), QgsPointV2( mX[vertex3], mY[vertex3] ) );
int vertex4 = vId.vertex + 1;
int vertex5 = vId.vertex + 2;
double angle2 = QgsGeometryUtils::circleTangentDirection( QgsPointV2( mX[vertex3], mY[vertex3] ),
QgsPointV2( mX[vertex3], mY[vertex3] ), QgsPointV2( mX[vertex4], mY[vertex4] ), QgsPointV2( mX[vertex5], mY[vertex5] ) );
return QgsGeometryUtils::averageAngle( angle1, angle2 );
}
}
return 0.0;
}
@@ -91,6 +91,11 @@ class CORE_EXPORT QgsCircularStringV2: public QgsCurveV2

bool hasCurvedSegments() const override { return true; }

/** Returns approximate rotation angle for a vertex. Usually average angle between adjacent segments.
@param vertex the vertex id
@return rotation in radians, clockwise from north*/
double vertexAngle( const QgsVertexId& vertex ) const override;

private:
QVector<double> mX;
QVector<double> mY;
@@ -586,3 +586,25 @@ bool QgsCompoundCurveV2::hasCurvedSegments() const
return false;
}

double QgsCompoundCurveV2::vertexAngle( const QgsVertexId& vertex ) const
{
QList< QPair<int, QgsVertexId> > curveIds = curveVertexId( vertex );
if ( curveIds.size() == 1 )
{
QgsCurveV2* curve = mCurves[curveIds.at( 0 ).first];
return curve->vertexAngle( curveIds.at( 0 ).second );
}
else if ( curveIds.size() > 1 )
{
QgsCurveV2* curve1 = mCurves[curveIds.at( 0 ).first];
QgsCurveV2* curve2 = mCurves[curveIds.at( 1 ).first];
double angle1 = curve1->vertexAngle( curveIds.at( 0 ).second );
double angle2 = curve2->vertexAngle( curveIds.at( 1 ).second );
return QgsGeometryUtils::averageAngle( angle1, angle2 );
}
else
{
return 0.0;
}
}

@@ -104,6 +104,11 @@ class CORE_EXPORT QgsCompoundCurveV2: public QgsCurveV2

bool hasCurvedSegments() const override;

/** Returns approximate rotation angle for a vertex. Usually average angle between adjacent segments.
@param vertex the vertex id
@return rotation in radians, clockwise from north*/
double vertexAngle( const QgsVertexId& vertex ) const override;

private:
QList< QgsCurveV2* > mCurves;
/** Turns a vertex id for the compound curve into one or more ids for the subcurves
@@ -665,3 +665,14 @@ QgsAbstractGeometryV2* QgsCurvePolygonV2::segmentize() const
{
return toPolygon();
}

double QgsCurvePolygonV2::vertexAngle( const QgsVertexId& vertex ) const
{
if ( !mExteriorRing || vertex.ring < 0 || vertex.ring >= 1 + mInteriorRings.size() )
{
return false;
}

QgsCurveV2* ring = vertex.ring == 0 ? mExteriorRing : mInteriorRings[vertex.ring - 1];
return ring->vertexAngle( vertex );
}
@@ -94,6 +94,11 @@ class CORE_EXPORT QgsCurvePolygonV2: public QgsSurfaceV2
bool hasCurvedSegments() const override;
QgsAbstractGeometryV2* segmentize() const override;

/** Returns approximate rotation angle for a vertex. Usually average angle between adjacent segments.
@param vertex the vertex id
@return rotation in radians, clockwise from north*/
double vertexAngle( const QgsVertexId& vertex ) const override;

protected:

QgsCurveV2* mExteriorRing;
@@ -509,3 +509,19 @@ QgsAbstractGeometryV2* QgsGeometryCollectionV2::segmentize() const
}
return geomCollection;
}

double QgsGeometryCollectionV2::vertexAngle( const QgsVertexId& vertex ) const
{
if ( vertex.part >= mGeometries.size() )
{
return 0.0;
}

QgsAbstractGeometryV2* geom = mGeometries[vertex.part];
if ( !geom )
{
return 0.0;
}

return geom->vertexAngle( vertex );
}
@@ -102,6 +102,11 @@ class CORE_EXPORT QgsGeometryCollectionV2: public QgsAbstractGeometryV2
/** Returns a geometry without curves. Caller takes ownership*/
QgsAbstractGeometryV2* segmentize() const override;

/** Returns approximate rotation angle for a vertex. Usually average angle between adjacent segments.
@param vertex the vertex id
@return rotation in radians, clockwise from north*/
double vertexAngle( const QgsVertexId& vertex ) const override;

protected:
QVector< QgsAbstractGeometryV2* > mGeometries;

@@ -357,6 +357,26 @@ bool QgsGeometryUtils::segmentMidPoint( const QgsPointV2& p1, const QgsPointV2&
return true;
}

double QgsGeometryUtils::circleTangentDirection( const QgsPointV2& tangentPoint, const QgsPointV2& cp1,
const QgsPointV2& cp2, const QgsPointV2& cp3 )
{
//calculate circle midpoint
double mX, mY, radius;
circleCenterRadius( cp1, cp2, cp3, radius, mX, mY );

double p1Angle = QgsGeometryUtils::ccwAngle( cp1.y() - mY, cp1.x() - mX );
double p2Angle = QgsGeometryUtils::ccwAngle( cp2.y() - mY, cp2.x() - mX );
double p3Angle = QgsGeometryUtils::ccwAngle( cp3.y() - mY, cp3.x() - mX );
if ( circleClockwise( p1Angle, p2Angle, p3Angle ) )
{
return lineAngle( tangentPoint.x(), tangentPoint.y(), mX, mY );
}
else
{
return lineAngle( mX, mY, tangentPoint.x(), tangentPoint.y() );
}
}

QList<QgsPointV2> QgsGeometryUtils::pointsFromWKT( const QString &wktCoordinateList, bool is3D, bool isMeasure )
{
int dim = 2 + is3D + isMeasure;
@@ -525,3 +545,71 @@ QStringList QgsGeometryUtils::wktGetChildBlocks( const QString &wkt, const QStri
}
return blocks;
}

double QgsGeometryUtils::lineAngle( double x1, double y1, double x2, double y2 )
{
double at = atan2( y2 - y1, x2 - x1 );
double a = -at + M_PI / 2.0;
if ( a < 0 )
{
a = 2 * M_PI + a;
}
if ( a >= 2 * M_PI )
{
a -= 2 * M_PI;
}
return a;
}

double QgsGeometryUtils::linePerpendicularAngle( double x1, double y1, double x2, double y2 )
{
double a = lineAngle( x1, y1, x2, y2 );
a += ( M_PI / 2.0 );
if ( a >= 2 * M_PI )
{
a -= ( 2 * M_PI );
}
return a;
}

double QgsGeometryUtils::averageAngle( double x1, double y1, double x2, double y2, double x3, double y3 )
{
// calc average angle between the previous and next point
double a1 = linePerpendicularAngle( x1, y1, x2, y2 );
double a2 = linePerpendicularAngle( x2, y2, x3, y3 );
return averageAngle( a1, a2 );
}

double QgsGeometryUtils::averageAngle( double a1, double a2 )
{
double clockwiseDiff = 0.0;
if ( a2 >= a1 )
{
clockwiseDiff = a2 - a1;
}
else
{
clockwiseDiff = a2 + ( 2 * M_PI - a1 );
}
double counterClockwiseDiff = 2 * M_PI - clockwiseDiff;

double resultAngle = 0;
if ( clockwiseDiff <= counterClockwiseDiff )
{
resultAngle = a1 + clockwiseDiff / 2.0;
}
else
{
resultAngle = a1 - counterClockwiseDiff / 2.0;
}

if ( resultAngle >= 2 * M_PI )
{
resultAngle -= 2 * M_PI;
}
else if ( resultAngle < 0 )
{
resultAngle = 2 * M_PI - resultAngle;
}
return resultAngle;
}
@@ -79,6 +79,9 @@ class CORE_EXPORT QgsGeometryUtils
/** Calculates midpoint on circle passing through p1 and p2, closest to given coordinate*/
static bool segmentMidPoint( const QgsPointV2& p1, const QgsPointV2& p2, QgsPointV2& result, double radius, const QgsPointV2& mousePos );

/** Calculates the direction angle of a circle tangent (clockwise from north in radians)*/
static double circleTangentDirection( const QgsPointV2& tangentPoint, const QgsPointV2& cp1, const QgsPointV2& cp2, const QgsPointV2& cp3 );

/** Returns a list of points contained in a WKT string.
*/
static QList<QgsPointV2> pointsFromWKT( const QString& wktCoordinateList, bool is3D, bool isMeasure );
@@ -92,6 +95,15 @@ class CORE_EXPORT QgsGeometryUtils
static QDomElement pointsToGML3( const QList<QgsPointV2>& points, QDomDocument &doc, int precision, const QString& ns, bool is3D );
/** Returns a geoJSON coordinates string */
static QString pointsToJSON( const QList<QgsPointV2>& points, int precision );
/**Calculates direction of line (clockwise from north direction) in radians*/
static double lineAngle( double x1, double y1, double x2, double y2 );
/**Calculates angle perpendicular to line*/
static double linePerpendicularAngle( double x1, double y1, double x2, double y2 );
/**Angle between two linear segments*/
static double averageAngle( double x1, double y1, double x2, double y2, double x3, double y3 );
/**Averages two angles*/
static double averageAngle( double a1, double a2 );


/** Parses a WKT block of the format "TYPE( contents )" and returns a pair of geometry type to contents ("Pair(wkbType, "contents")")
*/

0 comments on commit 8611543

Please sign in to comment.
You can’t perform that action at this time.