Skip to content

Commit

Permalink
[FEATURE]: possibility to set the segmentation tolerance (maximum ang…
Browse files Browse the repository at this point in the history
…le or maximum difference)
  • Loading branch information
mhugent committed May 19, 2016
1 parent 3ac9364 commit c0d12dc
Show file tree
Hide file tree
Showing 34 changed files with 338 additions and 310 deletions.
12 changes: 11 additions & 1 deletion python/core/geometry/qgsabstractgeometryv2.sip
Expand Up @@ -70,6 +70,14 @@ class QgsAbstractGeometryV2

public:

/** Segmentation tolerance as maximum angle or maximum difference between approximation and circle*/
enum SegmentationToleranceType
{
MaximumAngle = 0,
MaximumDifference
};


QgsAbstractGeometryV2();
virtual ~QgsAbstractGeometryV2();
QgsAbstractGeometryV2( const QgsAbstractGeometryV2& geom );
Expand Down Expand Up @@ -303,8 +311,10 @@ class QgsAbstractGeometryV2

/** Returns a version of the geometry without curves. Caller takes ownership of
* the returned geometry.
* @param tolerance segmentation tolerance
* @param toleranceType maximum segmentation angle or maximum difference between approximation and curve
*/
virtual QgsAbstractGeometryV2* segmentize() const /Factory/;
virtual QgsAbstractGeometryV2* segmentize( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const /Factory/;

/** Returns the geometry converted to the more generic curve type.
E.g. QgsLineStringV2 -> QgsCompoundCurveV2, QgsPolygonV2 -> QgsCurvePolygonV2,
Expand Down
9 changes: 5 additions & 4 deletions python/core/geometry/qgscircularstringv2.sip
Expand Up @@ -54,10 +54,11 @@ class QgsCircularStringV2: public QgsCurveV2
* @copydoc QgsCurveV2::endPoint()
*/
virtual QgsPointV2 endPoint() const;
/**
* @copydoc QgsCurveV2::curveToLine()
*/
virtual QgsLineStringV2* curveToLine() const;
/** Returns a new line string geometry corresponding to a segmentized approximation
* of the curve.
* @param tolerance segmentation tolerance
* @param toleranceType maximum segmentation angle or maximum difference between approximation and curve*/
virtual QgsLineStringV2* curveToLine( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const;

void draw( QPainter& p ) const;

Expand Down
6 changes: 5 additions & 1 deletion python/core/geometry/qgscompoundcurvev2.sip
Expand Up @@ -34,7 +34,11 @@ class QgsCompoundCurveV2: public QgsCurveV2
virtual QgsPointV2 endPoint() const;
virtual void points( QList<QgsPointV2>& pts ) const;
virtual int numPoints() const;
virtual QgsLineStringV2* curveToLine() const;
/** Returns a new line string geometry corresponding to a segmentized approximation
* of the curve.
* @param tolerance segmentation tolerance
* @param toleranceType maximum segmentation angle or maximum difference between approximation and curve*/
virtual QgsLineStringV2* curveToLine( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const;

/** Returns the number of curves in the geometry.
*/
Expand Down
11 changes: 9 additions & 2 deletions python/core/geometry/qgscurvepolygonv2.sip
Expand Up @@ -34,7 +34,11 @@ class QgsCurvePolygonV2: public QgsSurfaceV2
int numInteriorRings() const;
const QgsCurveV2* exteriorRing() const;
const QgsCurveV2* interiorRing( int i ) const;
virtual QgsPolygonV2* toPolygon() const;
/** Returns a new polygon geometry corresponding to a segmentized approximation
* of the curve.
* @param tolerance segmentation tolerance
* @param toleranceType maximum segmentation angle or maximum difference between approximation and curve*/
virtual QgsPolygonV2* toPolygon( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const;

/** Sets the exterior ring of the polygon. The CurvePolygon type will be updated to match the dimensionality
* of the exterior ring. For instance, setting a 2D exterior ring on a 3D CurvePolygon will drop the z dimension
Expand Down Expand Up @@ -69,7 +73,10 @@ class QgsCurvePolygonV2: public QgsSurfaceV2
bool nextVertex( QgsVertexId& id, QgsPointV2& vertex ) const;

bool hasCurvedSegments() const;
QgsAbstractGeometryV2* segmentize() const /Factory/;
/** Returns a geometry without curves. Caller takes ownership
* @param tolerance segmentation tolerance
* @param toleranceType maximum segmentation angle or maximum difference between approximation and curve*/
QgsAbstractGeometryV2* segmentize( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const /Factory/;

/** Returns approximate rotation angle for a vertex. Usually average angle between adjacent segments.
* @param vertex the vertex id
Expand Down
10 changes: 7 additions & 3 deletions python/core/geometry/qgscurvev2.sip
Expand Up @@ -32,8 +32,10 @@ class QgsCurveV2: public QgsAbstractGeometryV2

/** Returns a new line string geometry corresponding to a segmentized approximation
* of the curve.
* @param tolerance segmentation tolerance
* @param toleranceType maximum segmentation angle or maximum difference between approximation and curve
*/
virtual QgsLineStringV2* curveToLine() const = 0;
virtual QgsLineStringV2* curveToLine( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const = 0;

/** Adds a curve to a painter path.
*/
Expand Down Expand Up @@ -73,8 +75,10 @@ class QgsCurveV2: public QgsAbstractGeometryV2
*/
virtual QgsCurveV2* reversed() const = 0 /Factory/;

/** Returns a geometry without curves. Caller takes ownership*/
virtual QgsCurveV2* segmentize() const /Factory/;
/** Returns a geometry without curves. Caller takes ownership
* @param tolerance segmentation tolerance
* @param toleranceType maximum segmentation angle or maximum difference between approximation and curve*/
virtual QgsCurveV2* segmentize( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const /Factory/;

virtual int vertexCount( int part = 0, int ring = 0 ) const;
virtual int ringCount( int part = 0 ) const;
Expand Down
6 changes: 4 additions & 2 deletions python/core/geometry/qgsgeometrycollectionv2.sip
Expand Up @@ -83,8 +83,10 @@ class QgsGeometryCollectionV2: public QgsAbstractGeometryV2

bool hasCurvedSegments() const;

/** Returns a geometry without curves. Caller takes ownership*/
QgsAbstractGeometryV2* segmentize() const;
/** Returns a geometry without curves. Caller takes ownership
* @param tolerance segmentation tolerance
* @param toleranceType maximum segmentation angle or maximum difference between approximation and curve*/
QgsAbstractGeometryV2* segmentize( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const;

/** Returns approximate rotation angle for a vertex. Usually average angle between adjacent segments.
* @param vertex the vertex id
Expand Down
6 changes: 5 additions & 1 deletion python/core/geometry/qgslinestringv2.sip
Expand Up @@ -131,7 +131,11 @@ class QgsLineStringV2: public QgsCurveV2
virtual double length() const;
virtual QgsPointV2 startPoint() const;
virtual QgsPointV2 endPoint() const;
virtual QgsLineStringV2* curveToLine() const /Factory/;
/** Returns a new line string geometry corresponding to a segmentized approximation
* of the curve.
* @param tolerance segmentation tolerance
* @param toleranceType maximum segmentation angle or maximum difference between approximation and curve*/
virtual QgsLineStringV2* curveToLine( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const /Factory/;

int numPoints() const;
void points( QList<QgsPointV2>& pt ) const;
Expand Down
12 changes: 12 additions & 0 deletions python/core/qgsmapsettings.sip
Expand Up @@ -211,6 +211,18 @@ class QgsMapSettings

void writeXML( QDomNode& theNode, QDomDocument& theDoc );

/** Sets the segmentation tolerance applied when rendering curved geometries
@param tolerance the segmentation tolerance*/
void setSegmentationTolerance( double tolerance );
/** Gets the segmentation tolerance applied when rendering curved geometries*/
double segmentationTolerance() const;
/** Sets segmentation tolerance type (maximum angle or maximum difference between curve and approximation)
@param type the segmentation tolerance typename*/
void setSegmentationToleranceType( QgsAbstractGeometryV2::SegmentationToleranceType type );
/** Gets segmentation tolerance type (maximum angle or maximum difference between curve and approximation)*/
QgsAbstractGeometryV2::SegmentationToleranceType segmentationToleranceType() const;


protected:

void updateDerived();
Expand Down
12 changes: 12 additions & 0 deletions python/core/qgsrendercontext.sip
Expand Up @@ -177,4 +177,16 @@ class QgsRenderContext
* @see setFeatureFilterProvider()
*/
const QgsFeatureFilterProvider* featureFilterProvider() const;

/** Sets the segmentation tolerance applied when rendering curved geometries
@param tolerance the segmentation tolerance*/
void setSegmentationTolerance( double tolerance );
/** Gets the segmentation tolerance applied when rendering curved geometries*/
double segmentationTolerance() const;

/** Sets segmentation tolerance type (maximum angle or maximum difference between curve and approximation)
@param type the segmentation tolerance typename*/
void setSegmentationToleranceType( QgsAbstractGeometryV2::SegmentationToleranceType type );
/** Gets segmentation tolerance type (maximum angle or maximum difference between curve and approximation)*/
QgsAbstractGeometryV2::SegmentationToleranceType segmentationToleranceType() const;
};
7 changes: 7 additions & 0 deletions python/gui/qgsmapcanvas.sip
Expand Up @@ -393,6 +393,13 @@ class QgsMapCanvas : QGraphicsView
*/
// const QgsExpressionContextScope& expressionContextScope() const;

/** Sets the segmentation tolerance applied when rendering curved geometries
@param tolerance the segmentation tolerance*/
void setSegmentationTolerance( double tolerance );
/** Sets segmentation tolerance type (maximum angle or maximum difference between curve and approximation)
@param type the segmentation tolerance typename*/
void setSegmentationToleranceType( QgsAbstractGeometryV2::SegmentationToleranceType type );

public slots:

/** Repaints the canvas map*/
Expand Down
3 changes: 3 additions & 0 deletions src/app/qgisapp.cpp
Expand Up @@ -8641,6 +8641,9 @@ void QgisApp::showOptionsDialog( QWidget *parent, const QString& currentPage )

bool otfTransformAutoEnable = mySettings.value( "/Projections/otfTransformAutoEnable", true ).toBool();
mLayerTreeCanvasBridge->setAutoEnableCrsTransform( otfTransformAutoEnable );

mMapCanvas->setSegmentationTolerance( mySettings.value( "/qgis/segmentationTolerance", "0.01745" ).toDouble() );
mMapCanvas->setSegmentationToleranceType( QgsAbstractGeometryV2::SegmentationToleranceType( mySettings.value( "/qgis/segmentationToleranceType", "0" ).toInt() ) );
}

delete optionsDialog;
Expand Down
27 changes: 27 additions & 0 deletions src/app/qgsoptions.cpp
Expand Up @@ -584,6 +584,23 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WindowFlags fl )
mSimplifyDrawingSpinBox->setValue( mSettings->value( "/qgis/simplifyDrawingTol", QGis::DEFAULT_MAPTOPIXEL_THRESHOLD ).toFloat() );
mSimplifyDrawingAtProvider->setChecked( !mSettings->value( "/qgis/simplifyLocal", true ).toBool() );

//segmentation tolerance type
mToleranceTypeComboBox->addItem( tr( "Maximum angle" ), 0 );
mToleranceTypeComboBox->addItem( tr( "Maximum difference" ), 1 );
int toleranceType = mSettings->value( "/qgis/segmentationToleranceType", "0" ).toInt();
int toleranceTypeIndex = mToleranceTypeComboBox->findData( toleranceType );
if ( toleranceTypeIndex != -1 )
{
mToleranceTypeComboBox->setCurrentIndex( toleranceTypeIndex );
}

double tolerance = mSettings->value( "/qgis/segmentationTolerance", "0.01745" ).toDouble();
if ( toleranceType == 0 )
{
tolerance = tolerance * 180.0 / M_PI; //value shown to the user is degree, not rad
}
mSegmentationToleranceSpinBox->setValue( tolerance );

QStringList myScalesList = PROJECT_SCALES.split( ',' );
myScalesList.append( "1:1" );
mSimplifyMaximumScaleComboBox->updateScales( myScalesList );
Expand Down Expand Up @@ -1202,6 +1219,16 @@ void QgsOptions::saveOptions()
// magnification
mSettings->setValue( "/qgis/magnifier_level", doubleSpinBoxMagnifierDefault->value() );

//curve segmentation
int segmentationType = mToleranceTypeComboBox->itemData( mToleranceTypeComboBox->currentIndex() ).toInt();
mSettings->setValue( "/qgis/segmentationToleranceType", segmentationType );
double segmentationTolerance = mSegmentationToleranceSpinBox->value();
if ( segmentationType == 0 )
{
segmentationTolerance = segmentationTolerance / 180.0 * M_PI; //user sets angle tolerance in degrees, internal classes need value in rad
}
mSettings->setValue( "/qgis/segmentationTolerance", segmentationTolerance );

// project
mSettings->setValue( "/qgis/projOpenAtLaunch", mProjectOnLaunchCmbBx->currentIndex() );
mSettings->setValue( "/qgis/projOpenAtLaunchPath", mProjectOnLaunchLineEdit->text() );
Expand Down
9 changes: 9 additions & 0 deletions src/core/geometry/qgsabstractgeometryv2.cpp
Expand Up @@ -244,3 +244,12 @@ bool QgsAbstractGeometryV2::isEmpty() const
QgsPointV2 vertex;
return !nextVertex( vId, vertex );
}


QgsAbstractGeometryV2* QgsAbstractGeometryV2::segmentize( double tolerance, SegmentationToleranceType toleranceType ) const
{
Q_UNUSED( tolerance );
Q_UNUSED( toleranceType );
return clone();
}

12 changes: 11 additions & 1 deletion src/core/geometry/qgsabstractgeometryv2.h
Expand Up @@ -43,6 +43,14 @@ typedef QList< QgsRingSequenceV2 > QgsCoordinateSequenceV2;
class CORE_EXPORT QgsAbstractGeometryV2
{
public:

/** Segmentation tolerance as maximum angle or maximum difference between approximation and circle*/
enum SegmentationToleranceType
{
MaximumAngle = 0,
MaximumDifference
};

QgsAbstractGeometryV2();
virtual ~QgsAbstractGeometryV2();
QgsAbstractGeometryV2( const QgsAbstractGeometryV2& geom );
Expand Down Expand Up @@ -288,8 +296,10 @@ class CORE_EXPORT QgsAbstractGeometryV2

/** Returns a version of the geometry without curves. Caller takes ownership of
* the returned geometry.
* @param tolerance segmentation tolerance
* @param toleranceType maximum segmentation angle or maximum difference between approximation and curve
*/
virtual QgsAbstractGeometryV2* segmentize() const { return clone(); }
virtual QgsAbstractGeometryV2* segmentize( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const;

/** Returns the geometry converted to the more generic curve type.
E.g. QgsLineStringV2 -> QgsCompoundCurveV2, QgsPolygonV2 -> QgsCurvePolygonV2,
Expand Down
13 changes: 9 additions & 4 deletions src/core/geometry/qgscircularstringv2.cpp
Expand Up @@ -351,15 +351,15 @@ QgsPointV2 QgsCircularStringV2::endPoint() const
return pointN( numPoints() - 1 );
}

QgsLineStringV2* QgsCircularStringV2::curveToLine() const
QgsLineStringV2* QgsCircularStringV2::curveToLine( double tolerance, SegmentationToleranceType toleranceType ) const
{
QgsLineStringV2* line = new QgsLineStringV2();
QgsPointSequenceV2 points;
int nPoints = numPoints();

for ( int i = 0; i < ( nPoints - 2 ) ; i += 2 )
{
segmentize( pointN( i ), pointN( i + 1 ), pointN( i + 2 ), points );
segmentize( pointN( i ), pointN( i + 1 ), pointN( i + 2 ), points, tolerance, toleranceType );
}

line->setPoints( points );
Expand Down Expand Up @@ -473,7 +473,7 @@ void QgsCircularStringV2::setPoints( const QgsPointSequenceV2 &points )
}
}

void QgsCircularStringV2::segmentize( const QgsPointV2& p1, const QgsPointV2& p2, const QgsPointV2& p3, QgsPointSequenceV2 &points ) const
void QgsCircularStringV2::segmentize( const QgsPointV2& p1, const QgsPointV2& p2, const QgsPointV2& p3, QgsPointSequenceV2 &points, double tolerance, SegmentationToleranceType toleranceType ) const
{
//adapted code from postgis
double radius = 0;
Expand All @@ -496,7 +496,12 @@ void QgsCircularStringV2::segmentize( const QgsPointV2& p1, const QgsPointV2& p2
clockwise = true;
}

double increment = fabs( M_PI_2 / 90 ); //one segment per degree
double increment = tolerance; //one segment per degree
if ( toleranceType == QgsAbstractGeometryV2::MaximumDifference )
{
double halfAngle = acos( -tolerance / radius + 1 );
increment = 2 * halfAngle;
}

//angles of pt1, pt2, pt3
double a1 = atan2( p1.y() - centerY, p1.x() - centerX );
Expand Down
11 changes: 6 additions & 5 deletions src/core/geometry/qgscircularstringv2.h
Expand Up @@ -79,10 +79,11 @@ class CORE_EXPORT QgsCircularStringV2: public QgsCurveV2
* @copydoc QgsCurveV2::endPoint()
*/
virtual QgsPointV2 endPoint() const override;
/**
* @copydoc QgsCurveV2::curveToLine()
*/
virtual QgsLineStringV2* curveToLine() const override;
/** Returns a new line string geometry corresponding to a segmentized approximation
* of the curve.
* @param tolerance segmentation tolerance
* @param toleranceType maximum segmentation angle or maximum difference between approximation and curve*/
virtual QgsLineStringV2* curveToLine( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const override;

void draw( QPainter& p ) const override;

Expand Down Expand Up @@ -143,7 +144,7 @@ class CORE_EXPORT QgsCircularStringV2: public QgsCurveV2
QVector<double> mM;

//helper methods for curveToLine
void segmentize( const QgsPointV2& p1, const QgsPointV2& p2, const QgsPointV2& p3, QgsPointSequenceV2 &points ) const;
void segmentize( const QgsPointV2& p1, const QgsPointV2& p2, const QgsPointV2& p3, QgsPointSequenceV2 &points, double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const;
int segmentSide( const QgsPointV2& pt1, const QgsPointV2& pt3, const QgsPointV2& pt2 ) const;
double interpolateArc( double angle, double a1, double a2, double a3, double zm1, double zm2, double zm3 ) const;
static void arcTo( QPainterPath& path, QPointF pt1, QPointF pt2, QPointF pt3 );
Expand Down
4 changes: 2 additions & 2 deletions src/core/geometry/qgscompoundcurvev2.cpp
Expand Up @@ -357,14 +357,14 @@ int QgsCompoundCurveV2::numPoints() const
return nPoints;
}

QgsLineStringV2* QgsCompoundCurveV2::curveToLine() const
QgsLineStringV2* QgsCompoundCurveV2::curveToLine( double tolerance, SegmentationToleranceType toleranceType ) const
{
QList< QgsCurveV2* >::const_iterator curveIt = mCurves.constBegin();
QgsLineStringV2* line = new QgsLineStringV2();
QgsLineStringV2* currentLine = nullptr;
for ( ; curveIt != mCurves.constEnd(); ++curveIt )
{
currentLine = ( *curveIt )->curveToLine();
currentLine = ( *curveIt )->curveToLine( tolerance, toleranceType );
line->append( currentLine );
delete currentLine;
}
Expand Down
6 changes: 5 additions & 1 deletion src/core/geometry/qgscompoundcurvev2.h
Expand Up @@ -58,7 +58,11 @@ class CORE_EXPORT QgsCompoundCurveV2: public QgsCurveV2
virtual QgsPointV2 endPoint() const override;
virtual void points( QgsPointSequenceV2 &pts ) const override;
virtual int numPoints() const override;
virtual QgsLineStringV2* curveToLine() const override;
/** Returns a new line string geometry corresponding to a segmentized approximation
* of the curve.
* @param tolerance segmentation tolerance
* @param toleranceType maximum segmentation angle or maximum difference between approximation and curve*/
virtual QgsLineStringV2* curveToLine( double tolerance = M_PI_2 / 90, SegmentationToleranceType toleranceType = MaximumAngle ) const override;

/** Returns the number of curves in the geometry.
*/
Expand Down

0 comments on commit c0d12dc

Please sign in to comment.