Skip to content

Commit

Permalink
Merge pull request #5359 from nyalldawson/primitive
Browse files Browse the repository at this point in the history
Rename (and make safe) QgsGeometry::geometry()
  • Loading branch information
nyalldawson committed Oct 26, 2017
2 parents 93f8abe + 3888192 commit 55203a0
Show file tree
Hide file tree
Showing 133 changed files with 616 additions and 550 deletions.
4 changes: 4 additions & 0 deletions doc/api_break.dox
Expand Up @@ -1269,6 +1269,10 @@ QgsGeometry {#qgis_api_break_3_0_QgsGeometry}
value instead of a pointer. The biggest impact with this change is that PyQGIS code should not compare a geometry
result to None, but instead either use a boolean test (`if g.buffer(10):`) or explicitly use the isNull()
method to determine if a geometry is valid.
- The QgsAbstractGeometry getter was renamed from geometry() to get(), and the setter from setGeometry() to set().
This was done to avoid the awkward "feature.geometry().geometry()" expression! Note that calling QgsGeometry.get()
can force a detach and full clone of the geometry, so it is preferable to use the faster QgsGeometry::constGet()
method if the geometry is not being modified.
- isEmpty() was renamed to isNull() to differentiate a missing geometry from a geometry which is empty (eg an
empty geometry collection)
- wkbSize() and asWkb() has been replaced by exportToWkb(). WKB representation is no longer cached within QgsGeometry
Expand Down
2 changes: 1 addition & 1 deletion python/core/geometry/qgsabstractgeometry.sip
Expand Up @@ -269,7 +269,7 @@ class QgsAbstractGeometry
:rtype: bool
%End

virtual void adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex /Out/, QgsVertexId &nextVertex /Out/ ) = 0;
virtual void adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex /Out/, QgsVertexId &nextVertex /Out/ ) const = 0;
%Docstring
Returns the vertices adjacent to a specified ``vertex`` within a geometry.
.. versionadded:: 3.0
Expand Down
2 changes: 1 addition & 1 deletion python/core/geometry/qgscurve.sip
Expand Up @@ -102,7 +102,7 @@ class QgsCurve: QgsAbstractGeometry

virtual bool nextVertex( QgsVertexId &id, QgsPoint &vertex /Out/ ) const;

virtual void adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex /Out/, QgsVertexId &nextVertex /Out/ );
virtual void adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex /Out/, QgsVertexId &nextVertex /Out/ ) const;

virtual int vertexNumberFromVertexId( QgsVertexId id ) const;

Expand Down
2 changes: 1 addition & 1 deletion python/core/geometry/qgscurvepolygon.sip
Expand Up @@ -152,7 +152,7 @@ Adds an interior ring to the geometry (takes ownership)

virtual bool nextVertex( QgsVertexId &id, QgsPoint &vertex /Out/ ) const;

virtual void adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex /Out/, QgsVertexId &nextVertex /Out/ );
virtual void adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex /Out/, QgsVertexId &nextVertex /Out/ ) const;

virtual bool hasCurvedSegments() const;

Expand Down
45 changes: 38 additions & 7 deletions python/core/geometry/qgsgeometry.sip
Expand Up @@ -84,19 +84,50 @@ Copy constructor will prompt a deep copy of the object

~QgsGeometry();

QgsAbstractGeometry *geometry() const;
const QgsAbstractGeometry *constGet() const;
%Docstring
Returns the underlying geometry store.
.. versionadded:: 2.10
.. seealso:: setGeometry
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.

This is much faster then calling the non-const get() method.

.. note::

In QGIS 2.x this method was named geometry().

.. versionadded:: 3.0
.. seealso:: primitive()
.. seealso:: set()
:rtype: QgsAbstractGeometry
%End

QgsAbstractGeometry *get();
%Docstring
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.

This method can be slow to call, as it may trigger a detachment of the geometry
and a deep copy. Where possible, use constGet() instead.

.. note::

In QGIS 2.x this method was named geometry().

.. versionadded:: 3.0
.. seealso:: constGet()
.. seealso:: set()
:rtype: QgsAbstractGeometry
%End

void setGeometry( QgsAbstractGeometry *geometry /Transfer/ );
void set( QgsAbstractGeometry *geometry /Transfer/ );
%Docstring
Sets the underlying geometry store. Ownership of geometry is transferred.
.. versionadded:: 2.10
.. seealso:: geometry

.. note::

In QGIS 2.x this method was named setGeometry().

.. versionadded:: 3.0
.. seealso:: get()
.. seealso:: constGet()
%End

bool isNull() const;
Expand Down
2 changes: 1 addition & 1 deletion python/core/geometry/qgsgeometrycollection.sip
Expand Up @@ -53,7 +53,7 @@ class QgsGeometryCollection: QgsAbstractGeometry

virtual QgsAbstractGeometry *boundary() const /Factory/;

virtual void adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex /Out/, QgsVertexId &nextVertex /Out/ );
virtual void adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex /Out/, QgsVertexId &nextVertex /Out/ ) const;

virtual int vertexNumberFromVertexId( QgsVertexId id ) const;

Expand Down
2 changes: 1 addition & 1 deletion python/core/geometry/qgspoint.sip
Expand Up @@ -380,7 +380,7 @@ class QgsPoint: QgsAbstractGeometry

virtual bool nextVertex( QgsVertexId &id, QgsPoint &vertex /Out/ ) const;

virtual void adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex /Out/, QgsVertexId &nextVertex /Out/ );
virtual void adjacentVertices( QgsVertexId vertex, QgsVertexId &previousVertex /Out/, QgsVertexId &nextVertex /Out/ ) const;


virtual double vertexAngle( QgsVertexId vertex ) const;
Expand Down
4 changes: 2 additions & 2 deletions python/plugins/processing/algs/qgis/EliminateSelection.py
Expand Up @@ -147,7 +147,7 @@ def processAlgorithm(self, parameters, context, feedback):
selFeat = QgsFeature()

# use prepared geometries for faster intersection tests
engine = QgsGeometry.createGeometryEngine(geom2Eliminate.geometry())
engine = QgsGeometry.createGeometryEngine(geom2Eliminate.constGet())
engine.prepareGeometry()

while fit.nextFeature(selFeat):
Expand All @@ -156,7 +156,7 @@ def processAlgorithm(self, parameters, context, feedback):

selGeom = selFeat.geometry()

if engine.intersects(selGeom.geometry()):
if engine.intersects(selGeom.constGet()):
# We have a candidate
iGeom = geom2Eliminate.intersection(selGeom)

Expand Down
6 changes: 3 additions & 3 deletions python/plugins/processing/algs/qgis/Explode.py
Expand Up @@ -89,11 +89,11 @@ def processAlgorithm(self, parameters, context, feedback):
def extractAsSingleSegments(self, geom):
segments = []
if geom.isMultipart():
for part in range(geom.geometry().numGeometries()):
segments.extend(self.getPolylineAsSingleSegments(geom.geometry().geometryN(part)))
for part in range(geom.constGet().numGeometries()):
segments.extend(self.getPolylineAsSingleSegments(geom.constGet().geometryN(part)))
else:
segments.extend(self.getPolylineAsSingleSegments(
geom.geometry()))
geom.constGet()))
return segments

def getPolylineAsSingleSegments(self, polyline):
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/algs/qgis/ExportGeometryInfo.py
Expand Up @@ -155,7 +155,7 @@ def processAlgorithm(self, parameters, context, feedback):
def point_attributes(self, geometry):
pt = None
if not geometry.isMultipart():
pt = geometry.geometry()
pt = geometry.constGet()
else:
if geometry.numGeometries() > 0:
pt = geometry.geometryN(0)
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/algs/qgis/ExtractNodes.py
Expand Up @@ -99,7 +99,7 @@ def processAlgorithm(self, parameters, context, feedback):
sink.addFeature(f, QgsFeatureSink.FastInsert)
else:
i = 0
for part in input_geometry.geometry().coordinateSequence():
for part in input_geometry.constGet().coordinateSequence():
for ring in part:
if feedback.isCanceled():
break
Expand Down
Expand Up @@ -104,7 +104,7 @@ def processAlgorithm(self, parameters, context, feedback):
if not input_geometry:
sink.addFeature(f, QgsFeatureSink.FastInsert)
else:
total_nodes = input_geometry.geometry().nCoordinates()
total_nodes = input_geometry.constGet().nCoordinates()

for node in indices:
if node < 0:
Expand Down
4 changes: 2 additions & 2 deletions python/plugins/processing/algs/qgis/FindProjection.py
Expand Up @@ -95,7 +95,7 @@ def processAlgorithm(self, parameters, context, feedback):
fields, QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem())

# make intersection tests nice and fast
engine = QgsGeometry.createGeometryEngine(target_geom.geometry())
engine = QgsGeometry.createGeometryEngine(target_geom.constGet())
engine.prepareGeometry()

layer_bounds = QgsGeometry.fromRect(source.sourceExtent())
Expand All @@ -121,7 +121,7 @@ def processAlgorithm(self, parameters, context, feedback):
except:
continue

if engine.intersects(transformed_bounds.geometry()):
if engine.intersects(transformed_bounds.constGet()):
feedback.pushInfo(self.tr('Found candidate CRS: {}').format(candidate_crs.authid()))
f = QgsFeature(fields)
f.setAttributes([candidate_crs.authid()])
Expand Down
18 changes: 9 additions & 9 deletions python/plugins/processing/algs/qgis/GeometryConvert.py
Expand Up @@ -151,7 +151,7 @@ def convertToNodes(self, geom):
mp = QgsMultiPointV2()
# TODO: mega inefficient - needs rework when geometry iterators land
# (but at least it doesn't lose Z/M values)
for g in geom.geometry().coordinateSequence():
for g in geom.constGet().coordinateSequence():
for r in g:
for p in r:
mp.addGeometry(p)
Expand All @@ -170,7 +170,7 @@ def convertToLineStrings(self, geom):
else:
# polygons to lines
# we just use the boundary here - that consists of all rings in the (multi)polygon
boundary = QgsGeometry(geom.geometry().boundary())
boundary = QgsGeometry(geom.constGet().boundary())
# boundary will be multipart
return boundary.asGeometryCollection()

Expand All @@ -184,23 +184,23 @@ def convertToMultiLineStrings(self, geom):
else:
# line to multiLine
ml = QgsMultiLineString()
ml.addGeometry(geom.geometry().clone())
ml.addGeometry(geom.constGet().clone())
return [QgsGeometry(ml)]
else:
# polygons to multilinestring
# we just use the boundary here - that consists of all rings in the (multi)polygon
return [QgsGeometry(geom.geometry().boundary())]
return [QgsGeometry(geom.constGet().boundary())]

def convertToPolygon(self, geom):
if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PointGeometry and geom.geometry().nCoordinates() < 3:
if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PointGeometry and geom.constGet().nCoordinates() < 3:
raise QgsProcessingException(
self.tr('Cannot convert from Point to Polygon').format(QgsWkbTypes.displayString(geom.wkbType())))
elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PointGeometry:
# multipoint with at least 3 points
# TODO: mega inefficient - needs rework when geometry iterators land
# (but at least it doesn't lose Z/M values)
points = []
for g in geom.geometry().coordinateSequence():
for g in geom.constGet().coordinateSequence():
for r in g:
for p in r:
points.append(p)
Expand All @@ -212,17 +212,17 @@ def convertToPolygon(self, geom):
elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.LineGeometry:
if QgsWkbTypes.isMultiType(geom):
parts = []
for i in range(geom.geometry().numGeometries()):
for i in range(geom.constGet().numGeometries()):
p = QgsPolygonV2()
linestring = geom.geometry().geometryN(i).clone()
linestring = geom.constGet().geometryN(i).clone()
linestring.close()
p.setExteriorRing(linestring)
parts.append(QgsGeometry(p))
return QgsGeometry.collectGeometry(parts)
else:
# linestring to polygon
p = QgsPolygonV2()
linestring = geom.geometry().clone()
linestring = geom.constGet().clone()
linestring.close()
p.setExteriorRing(linestring)
return [QgsGeometry(p)]
Expand Down
6 changes: 3 additions & 3 deletions python/plugins/processing/algs/qgis/Intersection.py
Expand Up @@ -152,19 +152,19 @@ def processAlgorithm(self, parameters, context, feedback):
engine = None
if len(intersects) > 0:
# use prepared geometries for faster intersection tests
engine = QgsGeometry.createGeometryEngine(geom.geometry())
engine = QgsGeometry.createGeometryEngine(geom.constGet())
engine.prepareGeometry()

for featB in sourceB.getFeatures(request):
if feedback.isCanceled():
break

tmpGeom = featB.geometry()
if engine.intersects(tmpGeom.geometry()):
if engine.intersects(tmpGeom.constGet()):
out_attributes = [featA.attributes()[i] for i in field_indices_a]
out_attributes.extend([featB.attributes()[i] for i in field_indices_b])
int_geom = QgsGeometry(geom.intersection(tmpGeom))
if int_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(int_geom.geometry().wkbType()) == QgsWkbTypes.GeometryCollection:
if int_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(int_geom.wkbType()) == QgsWkbTypes.GeometryCollection:
int_com = geom.combine(tmpGeom)
int_geom = QgsGeometry()
if int_com:
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/algs/qgis/LinesToPolygons.py
Expand Up @@ -101,7 +101,7 @@ def convertWkbToPolygons(self, wkb):
return multi_wkb

def convertToPolygons(self, geometry):
surfaces = self.getSurfaces(geometry.geometry())
surfaces = self.getSurfaces(geometry.constGet())
output_wkb = self.convertWkbToPolygons(geometry.wkbType())
out_geom = None
if QgsWkbTypes.flatType(output_wkb) == QgsWkbTypes.MultiPolygon:
Expand Down
Expand Up @@ -238,7 +238,7 @@ def createFeature(self, feedback, feature_id, type, geometries, class_field=None
while True:
if feedback.isCanceled():
break
found, point = g.geometry().nextVertex(vid)
found, point = g.constGet().nextVertex(vid)
if found:
multi_point.addGeometry(point)
else:
Expand Down Expand Up @@ -270,8 +270,8 @@ def createFeature(self, feedback, feature_id, type, geometries, class_field=None
elif type == 3:
# convex hull
output_geometry = geometry.convexHull()
attrs.append(output_geometry.geometry().area())
attrs.append(output_geometry.geometry().perimeter())
attrs.append(output_geometry.constGet().area())
attrs.append(output_geometry.constGet().perimeter())
f = QgsFeature()
f.setAttributes(attrs)
f.setGeometry(output_geometry)
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/algs/qgis/PointsAlongGeometry.py
Expand Up @@ -108,7 +108,7 @@ def processAlgorithm(self, parameters, context, feedback):
sink.addFeature(input_feature, QgsFeatureSink.FastInsert)
else:
if input_geometry.type == QgsWkbTypes.PolygonGeometry:
length = input_geometry.geometry().perimeter()
length = input_geometry.constGet().perimeter()
else:
length = input_geometry.length() - end_offset
current_distance = start_offset
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/algs/qgis/PointsDisplacement.py
Expand Up @@ -169,7 +169,7 @@ def searchRect(p):
dy = radius * cosinusCurrentAngle

# we want to keep any existing m/z values
point = f.geometry().geometry().clone()
point = f.geometry().constGet().clone()
point.setX(old_point.x() + dx)
point.setY(old_point.y() + dy)
f.setGeometry(QgsGeometry(point))
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/algs/qgis/PointsFromPolygons.py
Expand Up @@ -117,7 +117,7 @@ def processAlgorithm(self, parameters, context, feedback):
(endRow, endColumn) = raster.mapToPixel(xMax, yMin, geoTransform)

# use prepared geometries for faster intersection tests
engine = QgsGeometry.createGeometryEngine(geom.geometry())
engine = QgsGeometry.createGeometryEngine(geom.constGet())
engine.prepareGeometry()

for row in range(startRow, endRow + 1):
Expand Down
4 changes: 2 additions & 2 deletions python/plugins/processing/algs/qgis/PointsInPolygon.py
Expand Up @@ -129,7 +129,7 @@ def processAlgorithm(self, parameters, context, feedback):
output_feature = QgsFeature()
if polygon_feature.hasGeometry():
geom = polygon_feature.geometry()
engine = QgsGeometry.createGeometryEngine(geom.geometry())
engine = QgsGeometry.createGeometryEngine(geom.constGet())
engine.prepareGeometry()

count = 0
Expand All @@ -143,7 +143,7 @@ def processAlgorithm(self, parameters, context, feedback):
if feedback.isCanceled():
break

if engine.contains(point_feature.geometry().geometry()):
if engine.contains(point_feature.geometry().constGet()):
if weight_field_index >= 0:
weight = point_feature.attributes()[weight_field_index]
try:
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/algs/qgis/PointsToPaths.py
Expand Up @@ -133,7 +133,7 @@ def processAlgorithm(self, parameters, context, feedback):
if not f.hasGeometry():
continue

point = f.geometry().geometry().clone()
point = f.geometry().constGet().clone()
if group_field_index >= 0:
group = f.attributes()[group_field_index]
else:
Expand Down
6 changes: 3 additions & 3 deletions python/plugins/processing/algs/qgis/Polygonize.py
Expand Up @@ -104,13 +104,13 @@ def processAlgorithm(self, parameters, context, feedback):

if not polygons.isEmpty():
feedback.pushInfo('Saving polygons...')
total = 50.0 / polygons.geometry().numGeometries()
for i in range(polygons.geometry().numGeometries()):
total = 50.0 / polygons.constGet().numGeometries()
for i in range(polygons.constGet().numGeometries()):
if feedback.isCanceled():
break

outFeat = QgsFeature()
geom = QgsGeometry(polygons.geometry().geometryN(i).clone())
geom = QgsGeometry(polygons.constGet().geometryN(i).clone())
outFeat.setGeometry(geom)
sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
feedback.setProgress(50 + int(current * total))
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/algs/qgis/PolygonsToLines.py
Expand Up @@ -92,7 +92,7 @@ def convertWkbToLines(self, wkb):
return multi_wkb

def convertToLines(self, geometry):
rings = self.getRings(geometry.geometry())
rings = self.getRings(geometry.constGet())
output_wkb = self.convertWkbToLines(geometry.wkbType())
out_geom = None
if QgsWkbTypes.flatType(output_wkb) == QgsWkbTypes.MultiLineString:
Expand Down

0 comments on commit 55203a0

Please sign in to comment.