def testInsertVertex(self): linestring = QgsGeometry.fromWkt( "LINESTRING(1 0,2 0)" ) if TestQgsGeometry.wkbPtr: # CHANGE old implementation fails to insert vertex assert linestring.insertVertex( 0, 0, 0 ), "Insert vertex 0 0 at 0 failed" expwkt = "LINESTRING(0 0, 1 0, 2 0)" wkt = linestring.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert linestring.insertVertex( 1.5, 0, 2 if TestQgsGeometry.wkbPtr else 1 ), "Insert vertex 1.5 0 at 2 failed" expwkt = "LINESTRING(0 0, 1 0, 1.5 0, 2 0)" if TestQgsGeometry.wkbPtr else "LINESTRING(1 0, 1.5 0, 2 0)" wkt = linestring.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert not linestring.insertVertex( 3, 0, 5 ), "Insert vertex 3 0 at 5 should have failed" polygon = QgsGeometry.fromWkt( "MULTIPOLYGON(((0 0,1 0,1 1,2 1,2 2,0 2,0 0)),((4 0,5 0,5 2,3 2,3 1,4 1,4 0)))" ) assert polygon.insertVertex( 0, 0, 8 ), "Insert vertex 0 0 at 8 failed" expwkt = "MULTIPOLYGON(((0 0,1 0,1 1,2 1,2 2,0 2,0 0)),((4 0,0 0,5 0,5 2,3 2,3 1,4 1,4 0)))" wkt = polygon.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) polygon = QgsGeometry.fromWkt( "MULTIPOLYGON(((0 0,1 0,1 1,2 1,2 2,0 2,0 0)),((4 0,5 0,5 2,3 2,3 1,4 1,4 0)))" ) assert polygon.insertVertex( 0, 0, 7 ), "Insert vertex 0 0 at 7 failed" expwkt = "MULTIPOLYGON(((0 0,1 0,1 1,2 1,2 2,0 2,0 0)),((0 0,4 0,5 0,5 2,3 2,3 1,4 1,0 0)))" wkt = polygon.exportToWkt() if TestQgsGeometry.wkbPtr: # CHANGE old implementation produces: MULTIPOLYGON(((0 0,1 0,1 1,2 1,2 2,0 2,0 0)),()) assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt )
def testAsWktPolygon(self): """Test that we can get a proper rect wkt polygon representation for rect""" rect1 = QgsRectangle(0.0, 0.0, 5.0, 5.0) myExpectedWkt = "POLYGON((0 0, " "5 0, " "5 5, " "0 5, " "0 0))" myWkt = rect1.asWktPolygon() myMessage = "Expected: %s\nGot: %s\n" % (myExpectedWkt, myWkt) assert compareWkt(myWkt, myExpectedWkt), myMessage
def testWriteShapefileWithMultiConversion(self): """Check writing geometries to an ESRI shapefile with conversion to multi.""" ml = QgsVectorLayer(("Point?crs=epsg:4326&field=id:int"), "test", "memory") self.assertIsNotNone(ml, "Provider not initialized") self.assertTrue(ml.isValid(), "Source layer not valid") provider = ml.dataProvider() self.assertIsNotNone(provider) ft = QgsFeature() ft.setGeometry(QgsGeometry.fromWkt("Point (1 2)")) ft.setAttributes([1]) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) dest_file_name = os.path.join(str(QDir.tempPath()), "to_multi.shp") crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, "utf-8", crs, "ESRI Shapefile", forceMulti=True ) self.assertEqual(write_result, QgsVectorFileWriter.NoError) # Open result and check created_layer = QgsVectorLayer("{}|layerid=0".format(dest_file_name), "test", "ogr") f = next(created_layer.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.exportToWkt() expWkt = "MultiPoint ((1 2))" self.assertTrue( compareWkt(expWkt, wkt), "saving geometry with multi conversion failed: mismatch Expected:\n%s\nGot:\n%s\n" % (expWkt, wkt), )
def testGeometry(self): """ Test calculation of aggregates on geometry expressions """ layer = QgsVectorLayer("Point?", "layer", "memory") pr = layer.dataProvider() # must be same length: geometry_values = [ QgsGeometry.fromWkt("Point ( 0 0 )"), QgsGeometry.fromWkt("Point ( 1 1 )"), QgsGeometry.fromWkt("Point ( 2 2 )"), ] features = [] for i in range(len(geometry_values)): f = QgsFeature() f.setGeometry(geometry_values[i]) features.append(f) self.assertTrue(pr.addFeatures(features)) agg = QgsAggregateCalculator(layer) val, ok = agg.calculate(QgsAggregateCalculator.GeometryCollect, "$geometry") self.assertTrue(ok) expwkt = "MultiPoint ((0 0), (1 1), (2 2))" wkt = val.exportToWkt() self.assertTrue(compareWkt(expwkt, wkt), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt))
def testAsWktCoordinates(self): """Test that we can get a proper wkt representation fo the rect""" rect1 = QgsRectangle(0.0, 0.0, 5.0, 5.0) myExpectedWkt = "0 0, " "5 5" myWkt = rect1.asWktCoordinates() myMessage = "Expected: %s\nGot: %s\n" % (myExpectedWkt, myWkt) assert compareWkt(myWkt, myExpectedWkt), myMessage
def testMoveVertex(self): multipoint = QgsGeometry.fromWkt( "MULTIPOINT(5 0,0 0,0 4,5 4,5 1,1 1,1 3,4 3,4 2,2 2)" ) for i in range(0,10): assert multipoint.moveVertex( i+1, -1-i, i ), "move vertex %d failed" % i expwkt = "MULTIPOINT(1 -1, 2 -2, 3 -3, 4 -4, 5 -5, 6 -6, 7 -7, 8 -8, 9 -9, 10 -10)" wkt = multipoint.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) # 2-+-+-+-+-3 # | | # + 6-+-+-7 + # | | | | # + + 9-+-8 + # | | | # ! 5-+-+-+-4 ! # | # 1-+-+-+-+-0 ! polyline = QgsGeometry.fromWkt( "LINESTRING(5 0,0 0,0 4,5 4,5 1,1 1,1 3,4 3,4 2,2 2)" ) assert polyline.moveVertex( 5.5, 4.5, 3 ), "move vertex failed" expwkt = "LINESTRING(5 0, 0 0, 0 4, 5.5 4.5, 5 1, 1 1, 1 3, 4 3, 4 2, 2 2)" wkt = polyline.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) # 5-+-4 0-+-9 # | | | | # 6 2-3 1-2!+ # | | | | # 0-1 7-8 polygon = QgsGeometry.fromWkt( "MULTIPOLYGON(((0 0,1 0,1 1,2 1,2 2,0 2,0 0)),((4 0,5 0,5 2,3 2,3 1,4 1,4 0)))" ) assert polygon.moveVertex( 6, 2, 9 ), "move vertex failed" expwkt = "MULTIPOLYGON(((0 0,1 0,1 1,2 1,2 2,0 2,0 0)),((4 0,5 0,6 2,3 2,3 1,4 1,4 0)))" wkt = polygon.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert polygon.moveVertex( 1, 2, 0 ), "move vertex failed" expwkt = "MULTIPOLYGON(((1 2,1 0,1 1,2 1,2 2,0 2,1 2)),((4 0,5 0,6 2,3 2,3 1,4 1,4 0)))" wkt = polygon.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert polygon.moveVertex( 2, 1, 7 ), "move vertex failed" expwkt = "MULTIPOLYGON(((1 2,1 0,1 1,2 1,2 2,0 2,1 2)),((2 1,5 0,6 2,3 2,3 1,4 1,2 1)))" wkt = polygon.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt )
def testAddPart(self): # 2-3 6-+-7 # | | | | # 0-1 4 5 8-9 points = [ [ QgsPoint(0,0), QgsPoint(1,0), QgsPoint(1,1), QgsPoint(2,1), QgsPoint(2,0), ], [ QgsPoint(3,0), QgsPoint(3,1), QgsPoint(5,1), QgsPoint(5,0), QgsPoint(6,0), ] ] polyline = QgsGeometry.fromPolyline( points[0] ) assert polyline.addPart( points[1][0:1] ) == 2, "addPart with one point line unexpectedly succeeded." assert polyline.addPart( points[1][0:2] ) == 0, "addPart with two point line failed." expwkt = "MULTILINESTRING((0 0, 1 0, 1 1, 2 1, 2 0), (3 0, 3 1))" wkt = polyline.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) polyline = QgsGeometry.fromPolyline( points[0] ) assert polyline.addPart( points[1] ) == 0, "addPart with %d point line failed." % len(points[1]) expwkt = "MULTILINESTRING((0 0, 1 0, 1 1, 2 1, 2 0), (3 0, 3 1, 5 1, 5 0, 6 0))" # 5-+-4 0-+-9 # | | | | # | 2-3 1-2 | # | | | | # 0-1 7-8 points = [ [ [ QgsPoint(0,0), QgsPoint(1,0), QgsPoint(1,1), QgsPoint(2,1), QgsPoint(2,2), QgsPoint(0,2), QgsPoint(0,0), ] ], [ [ QgsPoint(4,0), QgsPoint(5,0), QgsPoint(5,2), QgsPoint(3,2), QgsPoint(3,1), QgsPoint(4,1), QgsPoint(4,0), ] ] ] polygon = QgsGeometry.fromPolygon( points[0] ) assert polygon.addPart( points[1][0][0:1] ) == 2, "addPart with one point ring unexpectedly succeeded." assert polygon.addPart( points[1][0][0:2] ) == 2, "addPart with two point ring unexpectedly succeeded." assert polygon.addPart( points[1][0][0:3] ) == 2, "addPart with unclosed three point ring unexpectedly succeeded." assert polygon.addPart( [ QgsPoint(4,0), QgsPoint(5,0), QgsPoint(4,0) ] ) == 2, "addPart with 'closed' three point ring unexpectedly succeeded." assert polygon.addPart( points[1][0] ) == 0, "addPart failed" expwkt = "MULTIPOLYGON(((0 0,1 0,1 1,2 1,2 2,0 2,0 0)),((4 0,5 0,5 2,3 2,3 1,4 1,4 0)))" wkt = polygon.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt )
def testAsWktPolygon(self): """Test that we can get a proper rect wkt polygon representation for rect""" rect1 = QgsRectangle(0.0, 0.0, 5.0, 5.0) myExpectedWkt = ('POLYGON((0 0, ' '5 0, ' '5 5, ' '0 5, ' '0 0))') myWkt = rect1.asWktPolygon() myMessage = ('Expected: %s\nGot: %s\n' % (myExpectedWkt, myWkt)) assert compareWkt(myWkt, myExpectedWkt), myMessage
def testDeleteVertex(self): # 2-+-+-+-+-3 # | | # + 6-+-+-7 + # | | | | # + + 9-+-8 + # | | | # ! 5-+-+-+-4 # | # 1-+-+-+-+-0 polyline = QgsGeometry.fromWkt( "LINESTRING(5 0,0 0,0 4,5 4,5 1,1 1,1 3,4 3,4 2,2 2)" ) assert polyline.deleteVertex( 3 ), "Delete vertex 5 4 failed" expwkt = "LINESTRING(5 0, 0 0, 0 4, 5 1, 1 1, 1 3, 4 3, 4 2, 2 2)" wkt = polyline.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert not polyline.deleteVertex( -5 ), "Delete vertex -5 unexpectedly succeeded" assert not polyline.deleteVertex( 100 ), "Delete vertex 100 unexpectedly succeeded" # 5-+-4 0-+-9 # | | | | # 6 2-3 1-2 + # | | | | # 0-1 7-8 polygon = QgsGeometry.fromWkt( "MULTIPOLYGON(((0 0,1 0,1 1,2 1,2 2,0 2,0 0)),((4 0,5 0,5 2,3 2,3 1,4 1,4 0)))" ) assert polygon.deleteVertex( 9 ), "Delete vertex 5 2 failed" expwkt = "MULTIPOLYGON(((0 0,1 0,1 1,2 1,2 2,0 2,0 0)),((4 0,5 0,3 2,3 1,4 1,4 0)))" wkt = polygon.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert polygon.deleteVertex( 0 ), "Delete vertex 0 failed" expwkt = "MULTIPOLYGON(((1 0,1 1,2 1,2 2,0 2,1 0)),((4 0,5 0,3 2,3 1,4 1,4 0)))" wkt = polygon.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert polygon.deleteVertex( 6 ), "Delete vertex 6 failed" expwkt = "MULTIPOLYGON(((1 0,1 1,2 1,2 2,0 2,1 0)),((5 0,3 2,3 1,4 1,5 0)))" wkt = polygon.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt )
def testAddFeatures(self): layer = QgsVectorLayer("Point", "test", "pythonprovider") provider = layer.dataProvider() res = provider.addAttributes([QgsField("name", QVariant.String), QgsField("age", QVariant.Int), QgsField("size", QVariant.Double)]) assert res, "Failed to add attributes" myMessage = ('Expected: %s\nGot: %s\n' % (3, len(provider.fields()))) assert len(provider.fields()) == 3, myMessage ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) ft.setAttributes(["Johny", 20, 0.3]) res, t = provider.addFeatures([ft]) assert res, "Failed to add feature" myMessage = ('Expected: %s\nGot: %s\n' % (1, provider.featureCount())) assert provider.featureCount() == 1, myMessage for f in provider.getFeatures(QgsFeatureRequest()): myMessage = ('Expected: %s\nGot: %s\n' % ("Johny", f[0])) assert f[0] == "Johny", myMessage myMessage = ('Expected: %s\nGot: %s\n' % (20, f[1])) assert f[1] == 20, myMessage myMessage = ('Expected: %s\nGot: %s\n' % (0.3, f[2])) assert (f[2] - 0.3) < 0.0000001, myMessage geom = f.geometry() myMessage = ('Expected: %s\nGot: %s\n' % ("Point (10 10)", str(geom.asWkt()))) assert compareWkt(str(geom.asWkt()), "Point (10 10)"), myMessage
def testGetFeatures(self): """ Test that expected results are returned when fetching all features """ # IMPORTANT - we do not use `for f in provider.getFeatures()` as we are also # testing that existing attributes & geometry in f are overwritten correctly # (for f in ... uses a new QgsFeature for every iteration) it = self.provider.getFeatures() f = QgsFeature() attributes = {} geometries = {} while it.nextFeature(f): # expect feature to be valid self.assertTrue(f.isValid()) # split off the first 5 attributes only - some provider test datasets will include # additional attributes which we ignore attrs = f.attributes()[0:5] # force the num_char attribute to be text - some providers (eg delimited text) will # automatically detect that this attribute contains numbers and set it as a numeric # field attrs[4] = str(attrs[4]) attributes[f["pk"]] = attrs geometries[f["pk"]] = f.hasGeometry() and f.geometry().exportToWkt() expected_attributes = { 5: [5, -200, NULL, "NuLl", "5"], 3: [3, 300, "Pear", "PEaR", "3"], 1: [1, 100, "Orange", "oranGe", "1"], 2: [2, 200, "Apple", "Apple", "2"], 4: [4, 400, "Honey", "Honey", "4"], } self.assertEqual(attributes, expected_attributes, "Expected {}, got {}".format(expected_attributes, attributes)) expected_geometries = { 1: "Point (-70.332 66.33)", 2: "Point (-68.2 70.8)", 3: None, 4: "Point(-65.32 78.3)", 5: "Point(-71.123 78.23)", } for pk, geom in list(expected_geometries.items()): if geom: assert compareWkt(geom, geometries[pk]), "Geometry {} mismatch Expected:\n{}\nGot:\n{}\n".format( pk, geom, geometries[pk].exportToWkt() ) else: self.assertFalse(geometries[pk], "Expected null geometry for {}".format(pk))
def recordDifference(self, record1, record2): # Compare a record defined as a dictionary for k in list(record1.keys()): if k not in record2: return "Field {0} is missing".format(k) r1k = record1[k] r2k = record2[k] if k == geomkey: if not compareWkt(r1k, r2k): return "Geometry differs: {0:.50} versus {1:.50}".format(r1k, r2k) else: if record1[k] != record2[k]: return "Field {0} differs: {1:.50} versus {2:.50}".format(k, repr(r1k), repr(r2k)) for k in list(record2.keys()): if k not in record1: return "Output contains extra field {0}".format(k) return ''
def testCurves(self): vl = QgsVectorLayer('%s table="QGIS"."LINE_DATA" (GEOM) srid=4326 type=LINESTRING sql=' % (self.dbconn), "testlines", "oracle") self.assertTrue(vl.isValid()) features = {f['pk']: f for f in vl.getFeatures()} self.assertTrue(compareWkt(features[1].geometry().asWkt(), 'LineString (1 2, 3 4, 5 6)', 0.00001), features[1].geometry().asWkt()) self.assertTrue(compareWkt(features[2].geometry().asWkt(), 'CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4)', 0.00001), features[2].geometry().asWkt()) self.assertTrue( compareWkt(features[3].geometry().asWkt(), 'CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.20, 10 0.1, 13 4),(13 4, 17 -6))', 0.00001), features[3].geometry().asWkt()) self.assertTrue( compareWkt(features[4].geometry().asWkt(), 'LineStringZ (1 2 3, 4 5 6, 7 8 9)', 0.00001), features[4].geometry().asWkt()) self.assertTrue( compareWkt(features[5].geometry().asWkt(), 'MultiLineString ((1 2, 3 4),(5 6, 7 8, 9 10))', 0.00001), features[5].geometry().asWkt()) self.assertTrue( compareWkt(features[6].geometry().asWkt(), 'MultiLineStringZ ((1 2 11, 3 4 -11),(5 6 9, 7 8 1, 9 10 -3))', 0.00001), features[6].geometry().asWkt()) self.assertTrue( compareWkt(features[7].geometry().asWkt(), 'MultiCurve (CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),CircularString (-11 -3, 5 7, 10 -1))', 0.00001), features[7].geometry().asWkt()) self.assertTrue( compareWkt(features[8].geometry().asWkt(), 'MultiCurve (CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4),(13 4, 17 -6)),CompoundCurve (CircularString (1 2, 5 4, 7 2.2, 10 0.1, 13 4)),CompoundCurve ((-11 -3, 5 7, 10 -1)))', 0.00001), features[8].geometry().asWkt())
def testMultipoint(self): # CHANGE previous implementation didn't support multipoint too much if not TestQgsGeometry.wkbPtr: return # #9423 points = [ QgsPoint(10, 30), QgsPoint(40, 20), QgsPoint(30,10), QgsPoint(20,10) ] wkt = "MULTIPOINT (10 30, 40 20, 30 10, 20 10)" multipoint = QgsGeometry.fromWkt(wkt) assert multipoint.isMultipart(), "Expected MULTIPOINT to be multipart" assert multipoint.wkbType() == QGis.WKBMultiPoint, "Expected wkbType to be WKBMultipoint" i = 0 for p in multipoint.asMultiPoint(): assert p == points[i], "Expected %s at %d, got %s" % (points[i].toString(), i, p.toString()) i+=1 multipoint = QgsGeometry.fromWkt( "MULTIPOINT(5 5)" ) assert multipoint.vertexAt( 0 ) == QgsPoint(5,5), "MULTIPOINT fromWkt failed" assert multipoint.insertVertex(4, 4, 0), "MULTIPOINT insert 4,4 at 0 failed" expwkt = "MULTIPOINT(4 4, 5 5)" wkt = multipoint.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert multipoint.insertVertex(7, 7, 2), "MULTIPOINT append 7,7 at 2 failed" expwkt = "MULTIPOINT(4 4, 5 5, 7 7)" wkt = multipoint.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert multipoint.insertVertex(6, 6, 2), "MULTIPOINT append 6,6 at 2 failed" expwkt = "MULTIPOINT(4 4, 5 5, 6 6, 7 7)" wkt = multipoint.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert not multipoint.deleteVertex(4), "MULTIPOINT delete at 4 unexpectedly succeeded" assert not multipoint.deleteVertex(-1), "MULTIPOINT delete at -1 unexpectedly succeeded" assert multipoint.deleteVertex(1), "MULTIPOINT delete at 1 failed" expwkt = "MULTIPOINT(4 4, 6 6, 7 7)" wkt = multipoint.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert multipoint.deleteVertex(2), "MULTIPOINT delete at 2 failed" expwkt = "MULTIPOINT(4 4, 6 6)" wkt = multipoint.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert multipoint.deleteVertex(0), "MULTIPOINT delete at 2 failed" expwkt = "MULTIPOINT(6 6)" wkt = multipoint.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt )
def testTranslate(self): point = QgsGeometry.fromWkt( "POINT(1 1)" ) assert point.translate( 1, 1 )==0, "Translate failed" expwkt = "POINT(2 2)" wkt = point.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) point = QgsGeometry.fromWkt( "MULTIPOINT(1 1,2 2,3 3)" ) assert point.translate( 1, 1 )==0, "Translate failed" expwkt = "MULTIPOINT(2 2, 3 3, 4 4)" wkt = point.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) linestring = QgsGeometry.fromWkt( "LINESTRING(1 0,2 0)" ) assert linestring.translate( 1, 1 )==0, "Translate failed" expwkt = "LINESTRING(2 1, 3 1)" wkt = linestring.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) polygon = QgsGeometry.fromWkt( "MULTIPOLYGON(((0 0,1 0,1 1,2 1,2 2,0 2,0 0)),((4 0,5 0,5 2,3 2,3 1,4 1,4 0)))" ) assert polygon.translate( 1, 1 )==0, "Translate failed" expwkt = "MULTIPOLYGON(((1 1,2 1,2 2,3 2,3 3,1 3,1 1)),((5 1,6 1,6 1,4 3,4 2,5 2,5 1)))" wkt = polygon.exportToWkt() ct = QgsCoordinateTransform() point = QgsGeometry.fromWkt( "POINT(1 1)" ) assert point.transform( ct )==0, "Translate failed" expwkt = "POINT(1 1)" wkt = point.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) point = QgsGeometry.fromWkt( "MULTIPOINT(1 1,2 2,3 3)" ) assert point.transform( ct )==0, "Translate failed" expwkt = "MULTIPOINT(1 1, 2 2, 3 3)" wkt = point.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) linestring = QgsGeometry.fromWkt( "LINESTRING(1 0,2 0)" ) assert linestring.transform( ct )==0, "Translate failed" expwkt = "LINESTRING(1 0, 2 0)" wkt = linestring.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) polygon = QgsGeometry.fromWkt( "MULTIPOLYGON(((0 0,1 0,1 1,2 1,2 2,0 2,0 0)),((4 0,5 0,5 2,3 2,3 1,4 1,4 0)))" ) assert polygon.transform( ct )==0, "Translate failed" expwkt = "MULTIPOLYGON(((0 0,1 0,1 1,2 1,2 2,0 2,0 0)),((4 0,5 0,5 2,3 2,3 1,4 1,4 0)))" wkt = polygon.exportToWkt()
def testWriteShapefileWithMultiConversion(self): """Check writing geometries to an ESRI shapefile with conversion to multi.""" ml = QgsVectorLayer( ('Point?crs=epsg:4326&field=id:int'), 'test', 'memory') self.assertIsNotNone(ml, 'Provider not initialized') self.assertTrue(ml.isValid(), 'Source layer not valid') provider = ml.dataProvider() self.assertIsNotNone(provider) ft = QgsFeature() ft.setGeometry(QgsGeometry.fromWkt('Point (1 2)')) ft.setAttributes([1]) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) dest_file_name = os.path.join(str(QDir.tempPath()), 'to_multi.shp') crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile', forceMulti=True) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr') f = next(created_layer.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.asWkt() expWkt = 'MultiPoint ((1 2))' self.assertTrue(compareWkt(expWkt, wkt), "saving geometry with multi conversion failed: mismatch Expected:\n%s\nGot:\n%s\n" % ( expWkt, wkt))
def testGetFeatures(self): """ Test that expected results are returned when fetching all features """ # IMPORTANT - we do not use `for f in provider.getFeatures()` as we are also # testing that existing attributes & geometry in f are overwritten correctly # (for f in ... uses a new QgsFeature for every iteration) it = self.provider.getFeatures() f = QgsFeature() attributes = {} geometries = {} while it.nextFeature(f): # split off the first 5 attributes only - some provider test datasets will include # additional attributes which we ignore attrs = f.attributes()[0:5] # force the num_char attribute to be text - some providers (eg delimited text) will # automatically detect that this attribute contains numbers and set it as a numeric # field attrs[4] = str(attrs[4]) attributes[f['pk']] = attrs geometries[f['pk']] = f.constGeometry() and f.constGeometry().exportToWkt() expected_attributes = {5: [5, -200, NULL, 'NuLl', '5'], 3: [3, 300, 'Pear', 'PEaR', '3'], 1: [1, 100, 'Orange', 'oranGe', '1'], 2: [2, 200, 'Apple', 'Apple', '2'], 4: [4, 400, 'Honey', 'Honey', '4']} self.assertEqual(attributes, expected_attributes, 'Expected {}, got {}'.format(expected_attributes, attributes)) expected_geometries = {1: 'Point (-70.332 66.33)', 2: 'Point (-68.2 70.8)', 3: None, 4: 'Point(-65.32 78.3)', 5: 'Point(-71.123 78.23)'} for pk, geom in expected_geometries.iteritems(): if geom: assert compareWkt(geom, geometries[pk]), "Geometry {} mismatch Expected:\n{}\nGot:\n{}\n".format(pk, geom, geometries[pk].exportToWkt()) else: self.assertFalse(geometries[pk], 'Expected null geometry for {}'.format(pk))
def testMultipoint(self): # CHANGE previous implementation didn't support multipoint too much if not TestQgsGeometry.wkbPtr: return multipoint = QgsGeometry.fromWkt( "MULTIPOINT(5 5)" ) assert multipoint.vertexAt( 0 ) == QgsPoint(5,5), "MULTIPOINT fromWkt failed" assert multipoint.insertVertex(4, 4, 0), "MULTIPOINT insert 4,4 at 0 failed" expwkt = "MULTIPOINT(4 4, 5 5)" wkt = multipoint.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert multipoint.insertVertex(7, 7, 2), "MULTIPOINT append 7,7 at 2 failed" expwkt = "MULTIPOINT(4 4, 5 5, 7 7)" wkt = multipoint.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert multipoint.insertVertex(6, 6, 2), "MULTIPOINT append 6,6 at 2 failed" expwkt = "MULTIPOINT(4 4, 5 5, 6 6, 7 7)" wkt = multipoint.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert not multipoint.deleteVertex(4), "MULTIPOINT delete at 4 unexpectedly succeeded" assert not multipoint.deleteVertex(-1), "MULTIPOINT delete at -1 unexpectedly succeeded" assert multipoint.deleteVertex(1), "MULTIPOINT delete at 1 failed" expwkt = "MULTIPOINT(4 4, 6 6, 7 7)" wkt = multipoint.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert multipoint.deleteVertex(2), "MULTIPOINT delete at 2 failed" expwkt = "MULTIPOINT(4 4, 6 6)" wkt = multipoint.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert multipoint.deleteVertex(0), "MULTIPOINT delete at 2 failed" expwkt = "MULTIPOINT(6 6)" wkt = multipoint.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt )
def test_render_via_job_with_transform(self): """ Test rendering an annotation layer via a map render job """ layer = QgsAnnotationLayer( 'test', QgsAnnotationLayer.LayerOptions( QgsProject.instance().transformContext())) self.assertTrue(layer.isValid()) item = QgsAnnotationPolygonItem( QgsPolygon( QgsLineString([ QgsPoint(11.5, 13), QgsPoint(12, 13), QgsPoint(12, 13.5), QgsPoint(11.5, 13) ]))) item.setSymbol( QgsFillSymbol.createSimple({ 'color': '200,100,100', 'outline_color': 'black', 'outline_width': '2' })) item.setZIndex(1) i1_id = layer.addItem(item) item = QgsAnnotationLineItem( QgsLineString( [QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)])) item.setSymbol( QgsLineSymbol.createSimple({ 'color': '#ffff00', 'line_width': '3' })) item.setZIndex(2) i2_id = layer.addItem(item) item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) item.setSymbol( QgsMarkerSymbol.createSimple({ 'color': '100,200,200', 'size': '6', 'outline_color': 'black' })) item.setZIndex(3) i3_id = layer.addItem(item) layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) settings = QgsMapSettings() settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) settings.setExtent(QgsRectangle(1250958, 1386945, 1420709, 1532518)) settings.setOutputSize(QSize(200, 200)) settings.setLayers([layer]) job = QgsMapRendererSequentialJob(settings) job.start() job.waitForFinished() # check rendered item results item_results = job.takeRenderedItemResults() item_details = item_results.renderedItems() self.assertEqual(len(item_details), 3) self.assertEqual([i.layerId() for i in item_details], [layer.id()] * 3) self.assertCountEqual([i.itemId() for i in item_details], [i1_id, i2_id, i3_id]) # bounds should be in map crs self.assertEqual( [ QgsGeometry.fromRect(i.boundingBox()).asWkt(0) for i in item_details if i.itemId() == i1_id ][0], 'Polygon ((1280174 1459732, 1335834 1459732, 1335834 1516914, 1280174 1516914, 1280174 1459732))' ) self.assertEqual( [ QgsGeometry.fromRect(i.boundingBox()).asWkt(0) for i in item_details if i.itemId() == i2_id ][0], 'Polygon ((1224514 1459732, 1335834 1459732, 1335834 1689200, 1224514 1689200, 1224514 1459732))' ) expected = 'Polygon ((1325786 1449684, 1345882 1449684, 1345882 1469780, 1325786 1469780, 1325786 1449684))' result = [ QgsGeometry.fromRect(i.boundingBox()).asWkt(0) for i in item_details if i.itemId() == i3_id ][0] self.assertTrue( compareWkt(result, expected, tol=1000), "mismatch Expected:\n{}\nGot:\n{}\n".format(expected, result))
def testClipping(self): """Test that we can clip geometries using other geometries.""" myMemoryLayer = QgsVectorLayer( ('LineString?crs=epsg:4326&field=name:string(20)&index=yes'), 'clip-in', 'memory') assert myMemoryLayer is not None, 'Provider not initialised' myProvider = myMemoryLayer.dataProvider() assert myProvider is not None myFeature1 = QgsFeature() myFeature1.setGeometry( QgsGeometry.fromPolyline([ QgsPoint(10, 10), QgsPoint(20, 10), QgsPoint(30, 10), QgsPoint(40, 10), ])) myFeature1.setAttributes(['Johny']) myFeature2 = QgsFeature() myFeature2.setGeometry( QgsGeometry.fromPolyline([ QgsPoint(10, 10), QgsPoint(20, 20), QgsPoint(30, 30), QgsPoint(40, 40), ])) myFeature2.setAttributes(['Be']) myFeature3 = QgsFeature() myFeature3.setGeometry( QgsGeometry.fromPolyline([ QgsPoint(10, 10), QgsPoint(10, 20), QgsPoint(10, 30), QgsPoint(10, 40), ])) myFeature3.setAttributes(['Good']) myResult, myFeatures = myProvider.addFeatures( [myFeature1, myFeature2, myFeature3]) assert myResult == True assert len(myFeatures) == 3 myClipPolygon = QgsGeometry.fromPolygon([[ QgsPoint(20, 20), QgsPoint(20, 30), QgsPoint(30, 30), QgsPoint(30, 20), QgsPoint(20, 20), ]]) print 'Clip: %s' % myClipPolygon.exportToWkt() writeShape(myMemoryLayer, 'clipGeometryBefore.shp') fit = myProvider.getFeatures() myFeatures = [] myFeature = QgsFeature() while fit.nextFeature(myFeature): myGeometry = myFeature.geometry() if myGeometry.intersects(myClipPolygon): # Adds nodes where the clip and the line intersec myCombinedGeometry = myGeometry.combine(myClipPolygon) # Gives you the areas inside the clip mySymmetricalGeometry = myGeometry.symDifference( myCombinedGeometry) # Gives you areas outside the clip area # myDifferenceGeometry = myCombinedGeometry.difference( # myClipPolygon) #print 'Original: %s' % myGeometry.exportToWkt() #print 'Combined: %s' % myCombinedGeometry.exportToWkt() #print 'Difference: %s' % myDifferenceGeometry.exportToWkt() print 'Symmetrical: %s' % mySymmetricalGeometry.exportToWkt() myExpectedWkt = 'LINESTRING(20 20, 30 30)' # There should only be one feature that intersects this clip # poly so this assertion should work. assert compareWkt(myExpectedWkt, mySymmetricalGeometry.exportToWkt()) myNewFeature = QgsFeature() myNewFeature.setAttributes(myFeature.attributes()) myNewFeature.setGeometry(mySymmetricalGeometry) myFeatures.append(myNewFeature) myNewMemoryLayer = QgsVectorLayer( ('LineString?crs=epsg:4326&field=name:string(20)&index=yes'), 'clip-out', 'memory') myNewProvider = myNewMemoryLayer.dataProvider() myResult, myFeatures = myNewProvider.addFeatures(myFeatures) self.assertTrue(myResult) self.assertEqual(len(myFeatures), 1) writeShape(myNewMemoryLayer, 'clipGeometryAfter.shp')
def testDeleteVertex(self): # 2-+-+-+-+-3 # | | # + 6-+-+-7 + # | | | | # + + 9-+-8 + # | | | # ! 5-+-+-+-4 # | # 1-+-+-+-+-0 polyline = QgsGeometry.fromWkt( "LINESTRING(5 0,0 0,0 4,5 4,5 1,1 1,1 3,4 3,4 2,2 2)" ) assert polyline.deleteVertex( 3 ), "Delete vertex 5 4 failed" expwkt = "LINESTRING(5 0, 0 0, 0 4, 5 1, 1 1, 1 3, 4 3, 4 2, 2 2)" wkt = polyline.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert not polyline.deleteVertex( -5 ), "Delete vertex -5 unexpectedly succeeded" assert not polyline.deleteVertex( 100 ), "Delete vertex 100 unexpectedly succeeded" # 2-3 6-+-7 # | | | | # 0-1 4 5 8-9 polyline = QgsGeometry.fromWkt("MULTILINESTRING((0 0, 1 0, 1 1, 2 1,2 0),(3 0, 3 1, 5 1, 5 0, 6 0))") assert polyline.deleteVertex(5), "Delete vertex 5 failed" expwkt = "MULTILINESTRING((0 0, 1 0, 1 1, 2 1, 2 0), (3 1, 5 1, 5 0, 6 0))" wkt = polyline.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert not polyline.deleteVertex(-100), "Delete vertex -100 unexpectedly succeeded" assert not polyline.deleteVertex(100), "Delete vertex 100 unexpectedly succeeded" assert polyline.deleteVertex(0), "Delete vertex 0 failed" expwkt = "MULTILINESTRING((1 0, 1 1, 2 1, 2 0), (3 1, 5 1, 5 0, 6 0))" wkt = polyline.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) # 5---4 # | | # | 2-3 # | | # 0-1 polygon = QgsGeometry.fromWkt("POLYGON((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0))") assert polygon.deleteVertex(2), "Delete vertex 2 failed" print "FIXME: exportToWkt doesn't put a blanks behind the comma" expwkt = "POLYGON((0 0,1 0,2 1,2 2,0 2,0 0))" wkt = polygon.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert polygon.deleteVertex(0), "Delete vertex 0 failed" expwkt = "POLYGON((1 0,2 1,2 2,0 2,1 0))" wkt = polygon.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert polygon.deleteVertex(4), "Delete vertex 4 failed" expwkt = "POLYGON((2 1,2 2,0 2,2 1))" wkt = polygon.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert not polygon.deleteVertex(-100), "Delete vertex -100 unexpectedly succeeded" assert not polygon.deleteVertex(100), "Delete vertex 100 unexpectedly succeeded" # 5-+-4 0-+-9 # | | | | # 6 2-3 1-2 + # | | | | # 0-1 7-8 polygon = QgsGeometry.fromWkt( "MULTIPOLYGON(((0 0,1 0,1 1,2 1,2 2,0 2,0 0)),((4 0,5 0,5 2,3 2,3 1,4 1,4 0)))" ) assert polygon.deleteVertex( 9 ), "Delete vertex 5 2 failed" expwkt = "MULTIPOLYGON(((0 0,1 0,1 1,2 1,2 2,0 2,0 0)),((4 0,5 0,3 2,3 1,4 1,4 0)))" wkt = polygon.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert polygon.deleteVertex( 0 ), "Delete vertex 0 failed" expwkt = "MULTIPOLYGON(((1 0,1 1,2 1,2 2,0 2,1 0)),((4 0,5 0,3 2,3 1,4 1,4 0)))" wkt = polygon.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt ) assert polygon.deleteVertex( 6 ), "Delete vertex 6 failed" expwkt = "MULTIPOLYGON(((1 0,1 1,2 1,2 2,0 2,1 0)),((5 0,3 2,3 1,4 1,5 0)))" wkt = polygon.exportToWkt() assert compareWkt( expwkt, wkt ), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt )
def testWriteShapefileWithZ(self): """Check writing geometries with Z dimension to an ESRI shapefile.""" #start by saving a memory layer and forcing z ml = QgsVectorLayer( ('Point?crs=epsg:4326&field=id:int'), 'test', 'memory') assert ml is not None, 'Provider not initialized' assert ml.isValid(), 'Source layer not valid' provider = ml.dataProvider() assert provider is not None ft = QgsFeature() ft.setGeometry(QgsGeometry.fromWkt('PointZ (1 2 3)')) ft.setAttributes([1]) res, features = provider.addFeatures([ft]) assert res assert len(features) > 0 # check with both a standard PointZ and 25d style Point25D type for t in [QgsWKBTypes.PointZ, QgsWKBTypes.Point25D]: dest_file_name = os.path.join(str(QDir.tempPath()), 'point_{}.shp'.format(QgsWKBTypes.displayString(t))) print(dest_file_name) crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile', overrideGeometryType=t) self.assertEqual(write_result, QgsVectorFileWriter.NoError) # Open result and check created_layer = QgsVectorLayer(u'{}|layerid=0'.format(dest_file_name), u'test', u'ogr') f = created_layer.getFeatures(QgsFeatureRequest()).next() g = f.geometry() wkt = g.exportToWkt() expWkt = 'PointZ (1 2 3)' assert compareWkt(expWkt, wkt), "saving geometry with Z failed: mismatch Expected:\n%s\nGot:\n%s\n" % (expWkt, wkt) #also try saving out the shapefile version again, as an extra test #this tests that saving a layer with z WITHOUT explicitly telling the writer to keep z values, #will stay retain the z values dest_file_name = os.path.join(str(QDir.tempPath()), 'point_{}_copy.shp'.format(QgsWKBTypes.displayString(t))) print(dest_file_name) crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result = QgsVectorFileWriter.writeAsVectorFormat( created_layer, dest_file_name, 'utf-8', crs, 'ESRI Shapefile') self.assertEqual(write_result, QgsVectorFileWriter.NoError) # Open result and check created_layer_from_shp = QgsVectorLayer(u'{}|layerid=0'.format(dest_file_name), u'test', u'ogr') f = created_layer_from_shp.getFeatures(QgsFeatureRequest()).next() g = f.geometry() wkt = g.exportToWkt() assert compareWkt(expWkt, wkt), "saving geometry with Z failed: mismatch Expected:\n%s\nGot:\n%s\n" % (expWkt, wkt)
def testSurfaces(self): vl = QgsVectorLayer('%s table="QGIS"."POLY_DATA" (GEOM) srid=4326 type=POLYGON sql=' % (self.dbconn), "testpoly", "oracle") self.assertTrue(vl.isValid()) features = {f['pk']: f for f in vl.getFeatures()} self.assertTrue(compareWkt(features[1].geometry().asWkt(), 'Polygon ((1 2, 11 2, 11 22, 1 22, 1 2))', 0.00001), features[1].geometry().asWkt()) self.assertTrue(compareWkt(features[2].geometry().asWkt(), 'PolygonZ ((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3))', 0.00001), features[2].geometry().asWkt()) self.assertTrue( compareWkt(features[3].geometry().asWkt(), 'Polygon ((1 2, 11 2, 11 22, 1 22, 1 2),(5 6, 8 9, 8 6, 5 6),(3 4, 5 6, 3 6, 3 4))', 0.00001), features[3].geometry().asWkt()) self.assertTrue( compareWkt(features[4].geometry().asWkt(), 'PolygonZ ((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3),(5 6 1, 8 9 -1, 8 6 2, 5 6 1))', 0.00001), features[4].geometry().asWkt()) self.assertTrue( compareWkt(features[5].geometry().asWkt(), 'Polygon ((1 2, 11 2, 11 22, 1 22, 1 2))', 0.00001), features[5].geometry().asWkt()) self.assertTrue( compareWkt(features[6].geometry().asWkt(), 'CurvePolygon (CircularString (6.76923076923076916 22.82875364393326834, 17.98259979777942519 11.61538461538461497, 6.76923076923076916 0.40201558683595984, -4.44413825931788598 11.61538461538461497, 6.76923076923076916 22.82875364393326834))', 0.00001), features[6].geometry().asWkt()) self.assertTrue( compareWkt(features[7].geometry().asWkt(), 'MultiPolygon (((1 2, 11 2, 11 22, 1 22, 1 2)),((1 2, 11 2, 11 22, 1 22, 1 2),(5 6, 8 9, 8 6, 5 6),(3 4, 5 6, 3 6, 3 4)))', 0.00001), features[7].geometry().asWkt()) self.assertTrue( compareWkt(features[8].geometry().asWkt(), 'MultiPolygonZ (((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3)),((1 2 3, 11 2 13, 11 22 15, 1 22 7, 1 2 3),(5 6 1, 8 9 -1, 8 6 2, 5 6 1)))', 0.00001), features[8].geometry().asWkt()) self.assertTrue( compareWkt(features[9].geometry().asWkt(), 'CurvePolygon (CircularString (1 3, 3 5, 4 7, 7 3, 1 3))', 0.00001), features[9].geometry().asWkt()) self.assertTrue( compareWkt(features[10].geometry().asWkt(), 'CurvePolygon (CircularString (1 3, 3 5, 4 7, 7 3, 1 3),CircularString (3.1 3.3, 3.3 3.5, 3.4 3.7, 3.7 3.3, 3.1 3.3))', 0.00001), features[10].geometry().asWkt()) self.assertTrue( compareWkt(features[11].geometry().asWkt(), 'CurvePolygon(CompoundCurve ((-1 -5, 1 2),CircularString (1 2, 5 4, 7 2.20, 10 0.1, 13 4),(13 4, 17 -6),CircularString (17 -6, 5 -7, -1 -5)))', 0.00001), features[11].geometry().asWkt()) self.assertTrue( compareWkt(features[12].geometry().asWkt(), 'MultiSurface (CurvePolygon (CircularString (1 3, 3 5, 4 7, 7 3, 1 3)),CurvePolygon (CircularString (11 3, 13 5, 14 7, 17 3, 11 3)))', 0.00001), features[12].geometry().asWkt())
def testClipping(self): """Test that we can clip geometries using other geometries.""" myMemoryLayer = QgsVectorLayer( ('LineString?crs=epsg:4326&field=name:string(20)&index=yes'), 'clip-in', 'memory') assert myMemoryLayer is not None, 'Provider not initialised' myProvider = myMemoryLayer.dataProvider() assert myProvider is not None myFeature1 = QgsFeature() myFeature1.setGeometry(QgsGeometry.fromPolyline([ QgsPoint(10,10), QgsPoint(20,10), QgsPoint(30,10), QgsPoint(40,10), ] )) myFeature1.setAttributes(['Johny']) myFeature2 = QgsFeature() myFeature2.setGeometry(QgsGeometry.fromPolyline([ QgsPoint(10,10), QgsPoint(20,20), QgsPoint(30,30), QgsPoint(40,40), ] )) myFeature2.setAttributes(['Be']) myFeature3 = QgsFeature() myFeature3.setGeometry(QgsGeometry.fromPolyline([ QgsPoint(10,10), QgsPoint(10,20), QgsPoint(10,30), QgsPoint(10,40), ] )) myFeature3.setAttributes(['Good']) myResult, myFeatures = myProvider.addFeatures( [myFeature1, myFeature2, myFeature3]) assert myResult == True assert len(myFeatures) == 3 myClipPolygon = QgsGeometry.fromPolygon([[ QgsPoint(20,20), QgsPoint(20,30), QgsPoint(30,30), QgsPoint(30,20), QgsPoint(20,20), ]] ) print 'Clip: %s' % myClipPolygon.exportToWkt() writeShape(myMemoryLayer, 'clipGeometryBefore.shp') fit = myProvider.getFeatures() myFeatures = [] myFeature = QgsFeature() while fit.nextFeature(myFeature): myGeometry = myFeature.geometry() if myGeometry.intersects(myClipPolygon): # Adds nodes where the clip and the line intersec myCombinedGeometry = myGeometry.combine(myClipPolygon) # Gives you the areas inside the clip mySymmetricalGeometry = myGeometry.symDifference( myCombinedGeometry) # Gives you areas outside the clip area # myDifferenceGeometry = myCombinedGeometry.difference( # myClipPolygon) #print 'Original: %s' % myGeometry.exportToWkt() #print 'Combined: %s' % myCombinedGeometry.exportToWkt() #print 'Difference: %s' % myDifferenceGeometry.exportToWkt() print 'Symmetrical: %s' % mySymmetricalGeometry.exportToWkt() myExpectedWkt = 'LINESTRING(20 20, 30 30)' # There should only be one feature that intersects this clip # poly so this assertion should work. assert compareWkt( myExpectedWkt, mySymmetricalGeometry.exportToWkt() ) myNewFeature = QgsFeature() myNewFeature.setAttributes(myFeature.attributes()) myNewFeature.setGeometry(mySymmetricalGeometry) myFeatures.append(myNewFeature) myNewMemoryLayer = QgsVectorLayer( ('LineString?crs=epsg:4326&field=name:string(20)&index=yes'), 'clip-out', 'memory') myNewProvider = myNewMemoryLayer.dataProvider() myResult, myFeatures = myNewProvider.addFeatures(myFeatures) self.assertTrue(myResult) self.assertEqual(len(myFeatures), 1) writeShape(myNewMemoryLayer, 'clipGeometryAfter.shp')
def testWriteShapefileWithAttributeSubsets(self): """Tests writing subsets of attributes to files.""" ml = QgsVectorLayer( ('Point?crs=epsg:4326&field=id:int&field=field1:int&field=field2:int&field=field3:int'), 'test', 'memory') self.assertIsNotNone(ml, 'Provider not initialized') self.assertTrue(ml.isValid(), 'Source layer not valid') provider = ml.dataProvider() self.assertIsNotNone(provider) ft = QgsFeature() ft.setGeometry(QgsGeometry.fromWkt('Point (1 2)')) ft.setAttributes([1, 11, 12, 13]) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) # first write out with all attributes dest_file_name = os.path.join(str(QDir.tempPath()), 'all_attributes.shp') crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile', attributes=[]) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr') self.assertEqual(created_layer.fields().count(), 4) f = next(created_layer.getFeatures(QgsFeatureRequest())) self.assertEqual(f['id'], 1) self.assertEqual(f['field1'], 11) self.assertEqual(f['field2'], 12) self.assertEqual(f['field3'], 13) # now test writing out only a subset of attributes dest_file_name = os.path.join(str(QDir.tempPath()), 'subset_attributes.shp') write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile', attributes=[1, 3]) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr') self.assertEqual(created_layer.fields().count(), 2) f = next(created_layer.getFeatures(QgsFeatureRequest())) self.assertEqual(f['field1'], 11) self.assertEqual(f['field3'], 13) # finally test writing no attributes dest_file_name = os.path.join(str(QDir.tempPath()), 'no_attributes.shp') write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile', skipAttributeCreation=True) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr') # expect only a default 'FID' field for shapefiles self.assertEqual(created_layer.fields().count(), 1) self.assertEqual(created_layer.fields()[0].name(), 'FID') # in this case we also check that the geometry exists, to make sure feature has been correctly written # even without attributes f = next(created_layer.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.asWkt() expWkt = 'Point (1 2)' self.assertTrue(compareWkt(expWkt, wkt), "geometry not saved correctly when saving without attributes : mismatch Expected:\n%s\nGot:\n%s\n" % ( expWkt, wkt)) self.assertEqual(f['FID'], 0)
def testGetFeatures(self, source=None, extra_features=[], skip_features=[], changed_attributes={}, changed_geometries={}): """ Test that expected results are returned when fetching all features """ # IMPORTANT - we do not use `for f in source.getFeatures()` as we are also # testing that existing attributes & geometry in f are overwritten correctly # (for f in ... uses a new QgsFeature for every iteration) if not source: source = self.source it = source.getFeatures() f = QgsFeature() attributes = {} geometries = {} while it.nextFeature(f): # expect feature to be valid self.assertTrue(f.isValid()) # some source test datasets will include additional attributes which we ignore, # so cherry pick desired attributes attrs = [f['pk'], f['cnt'], f['name'], f['name2'], f['num_char']] # force the num_char attribute to be text - some sources (e.g., delimited text) will # automatically detect that this attribute contains numbers and set it as a numeric # field attrs[4] = str(attrs[4]) attributes[f['pk']] = attrs geometries[f['pk']] = f.hasGeometry() and f.geometry().asWkt() expected_attributes = {5: [5, -200, NULL, 'NuLl', '5'], 3: [3, 300, 'Pear', 'PEaR', '3'], 1: [1, 100, 'Orange', 'oranGe', '1'], 2: [2, 200, 'Apple', 'Apple', '2'], 4: [4, 400, 'Honey', 'Honey', '4']} expected_geometries = {1: 'Point (-70.332 66.33)', 2: 'Point (-68.2 70.8)', 3: None, 4: 'Point(-65.32 78.3)', 5: 'Point(-71.123 78.23)'} for f in extra_features: expected_attributes[f[0]] = f.attributes() if f.hasGeometry(): expected_geometries[f[0]] = f.geometry().asWkt() else: expected_geometries[f[0]] = None for i in skip_features: del expected_attributes[i] del expected_geometries[i] for i, a in changed_attributes.items(): for attr_idx, v in a.items(): expected_attributes[i][attr_idx] = v for i, g, in changed_geometries.items(): if g: expected_geometries[i] = g.asWkt() else: expected_geometries[i] = None self.assertEqual(attributes, expected_attributes, 'Expected {}, got {}'.format(expected_attributes, attributes)) self.assertEqual(len(expected_geometries), len(geometries)) for pk, geom in list(expected_geometries.items()): if geom: assert compareWkt(geom, geometries[pk]), "Geometry {} mismatch Expected:\n{}\nGot:\n{}\n".format(pk, geom, geometries[pk]) else: self.assertFalse(geometries[pk], 'Expected null geometry for {}'.format(pk))
def testGetFeatures(self, source=None, extra_features=[], skip_features=[], changed_attributes={}, changed_geometries={}): """ Test that expected results are returned when fetching all features """ # IMPORTANT - we do not use `for f in source.getFeatures()` as we are also # testing that existing attributes & geometry in f are overwritten correctly # (for f in ... uses a new QgsFeature for every iteration) if not source: source = self.source it = source.getFeatures() f = QgsFeature() attributes = {} geometries = {} while it.nextFeature(f): # expect feature to be valid self.assertTrue(f.isValid()) # some source test datasets will include additional attributes which we ignore, # so cherry pick desired attributes attrs = [f['pk'], f['cnt'], f['name'], f['name2'], f['num_char']] # force the num_char attribute to be text - some sources (e.g., delimited text) will # automatically detect that this attribute contains numbers and set it as a numeric # field attrs[4] = str(attrs[4]) attributes[f['pk']] = attrs geometries[f['pk']] = f.hasGeometry() and f.geometry().asWkt() expected_attributes = { 5: [5, -200, NULL, 'NuLl', '5'], 3: [3, 300, 'Pear', 'PEaR', '3'], 1: [1, 100, 'Orange', 'oranGe', '1'], 2: [2, 200, 'Apple', 'Apple', '2'], 4: [4, 400, 'Honey', 'Honey', '4'] } expected_geometries = { 1: 'Point (-70.332 66.33)', 2: 'Point (-68.2 70.8)', 3: None, 4: 'Point(-65.32 78.3)', 5: 'Point(-71.123 78.23)' } for f in extra_features: expected_attributes[f[0]] = f.attributes() if f.hasGeometry(): expected_geometries[f[0]] = f.geometry().asWkt() else: expected_geometries[f[0]] = None for i in skip_features: del expected_attributes[i] del expected_geometries[i] for i, a in changed_attributes.items(): for attr_idx, v in a.items(): expected_attributes[i][attr_idx] = v for i, g, in changed_geometries.items(): if g: expected_geometries[i] = g.asWkt() else: expected_geometries[i] = None self.assertEqual( attributes, expected_attributes, 'Expected {}, got {}'.format(expected_attributes, attributes)) self.assertEqual(len(expected_geometries), len(geometries)) for pk, geom in list(expected_geometries.items()): if geom: assert compareWkt( geom, geometries[pk] ), "Geometry {} mismatch Expected:\n{}\nGot:\n{}\n".format( pk, geom, geometries[pk]) else: self.assertFalse(geometries[pk], 'Expected null geometry for {}'.format(pk))
def testWriteShapefileWithAttributeSubsets(self): """Tests writing subsets of attributes to files.""" ml = QgsVectorLayer( ("Point?crs=epsg:4326&field=id:int&field=field1:int&field=field2:int&field=field3:int"), "test", "memory" ) self.assertIsNotNone(ml, "Provider not initialized") self.assertTrue(ml.isValid(), "Source layer not valid") provider = ml.dataProvider() self.assertIsNotNone(provider) ft = QgsFeature() ft.setGeometry(QgsGeometry.fromWkt("Point (1 2)")) ft.setAttributes([1, 11, 12, 13]) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) # first write out with all attributes dest_file_name = os.path.join(str(QDir.tempPath()), "all_attributes.shp") crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, "utf-8", crs, "ESRI Shapefile", attributes=[] ) self.assertEqual(write_result, QgsVectorFileWriter.NoError) # Open result and check created_layer = QgsVectorLayer("{}|layerid=0".format(dest_file_name), "test", "ogr") self.assertEqual(created_layer.fields().count(), 4) f = next(created_layer.getFeatures(QgsFeatureRequest())) self.assertEqual(f["id"], 1) self.assertEqual(f["field1"], 11) self.assertEqual(f["field2"], 12) self.assertEqual(f["field3"], 13) # now test writing out only a subset of attributes dest_file_name = os.path.join(str(QDir.tempPath()), "subset_attributes.shp") write_result = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, "utf-8", crs, "ESRI Shapefile", attributes=[1, 3] ) self.assertEqual(write_result, QgsVectorFileWriter.NoError) # Open result and check created_layer = QgsVectorLayer("{}|layerid=0".format(dest_file_name), "test", "ogr") self.assertEqual(created_layer.fields().count(), 2) f = next(created_layer.getFeatures(QgsFeatureRequest())) self.assertEqual(f["field1"], 11) self.assertEqual(f["field3"], 13) # finally test writing no attributes dest_file_name = os.path.join(str(QDir.tempPath()), "no_attributes.shp") write_result = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, "utf-8", crs, "ESRI Shapefile", skipAttributeCreation=True ) self.assertEqual(write_result, QgsVectorFileWriter.NoError) # Open result and check created_layer = QgsVectorLayer("{}|layerid=0".format(dest_file_name), "test", "ogr") # expect only a default 'FID' field for shapefiles self.assertEqual(created_layer.fields().count(), 1) self.assertEqual(created_layer.fields()[0].name(), "FID") # in this case we also check that the geometry exists, to make sure feature has been correctly written # even without attributes f = next(created_layer.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.exportToWkt() expWkt = "Point (1 2)" self.assertTrue( compareWkt(expWkt, wkt), "geometry not saved correctly when saving without attributes : mismatch Expected:\n%s\nGot:\n%s\n" % (expWkt, wkt), ) self.assertEqual(f["FID"], 0)
def testWriteShapefileWithZ(self): """Check writing geometries with Z dimension to an ESRI shapefile.""" # start by saving a memory layer and forcing z ml = QgsVectorLayer( ('Point?crs=epsg:4326&field=id:int'), 'test', 'memory') self.assertIsNotNone(ml, 'Provider not initialized') self.assertTrue(ml.isValid(), 'Source layer not valid') provider = ml.dataProvider() self.assertIsNotNone(provider) ft = QgsFeature() ft.setGeometry(QgsGeometry.fromWkt('PointZ (1 2 3)')) ft.setAttributes([1]) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) # check with both a standard PointZ and 25d style Point25D type for t in [QgsWkbTypes.PointZ, QgsWkbTypes.Point25D]: dest_file_name = os.path.join(str(QDir.tempPath()), 'point_{}.shp'.format(QgsWkbTypes.displayString(t))) crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile', overrideGeometryType=t) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr') f = next(created_layer.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.asWkt() expWkt = 'PointZ (1 2 3)' self.assertTrue(compareWkt(expWkt, wkt), "saving geometry with Z failed: mismatch Expected:\n%s\nGot:\n%s\n" % (expWkt, wkt)) # also try saving out the shapefile version again, as an extra test # this tests that saving a layer with z WITHOUT explicitly telling the writer to keep z values, # will stay retain the z values dest_file_name = os.path.join(str(QDir.tempPath()), 'point_{}_copy.shp'.format(QgsWkbTypes.displayString(t))) crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( created_layer, dest_file_name, 'utf-8', crs, 'ESRI Shapefile') self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer_from_shp = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr') f = next(created_layer_from_shp.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.asWkt() self.assertTrue(compareWkt(expWkt, wkt), "saving geometry with Z failed: mismatch Expected:\n%s\nGot:\n%s\n" % (expWkt, wkt))
def testWriteShapefileWithZ(self): """Check writing geometries with Z dimension to an ESRI shapefile.""" # start by saving a memory layer and forcing z ml = QgsVectorLayer(("Point?crs=epsg:4326&field=id:int"), "test", "memory") self.assertIsNotNone(ml, "Provider not initialized") self.assertTrue(ml.isValid(), "Source layer not valid") provider = ml.dataProvider() self.assertIsNotNone(provider) ft = QgsFeature() ft.setGeometry(QgsGeometry.fromWkt("PointZ (1 2 3)")) ft.setAttributes([1]) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) # check with both a standard PointZ and 25d style Point25D type for t in [QgsWkbTypes.PointZ, QgsWkbTypes.Point25D]: dest_file_name = os.path.join(str(QDir.tempPath()), "point_{}.shp".format(QgsWkbTypes.displayString(t))) crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, "utf-8", crs, "ESRI Shapefile", overrideGeometryType=t ) self.assertEqual(write_result, QgsVectorFileWriter.NoError) # Open result and check created_layer = QgsVectorLayer("{}|layerid=0".format(dest_file_name), "test", "ogr") f = next(created_layer.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.exportToWkt() expWkt = "PointZ (1 2 3)" self.assertTrue( compareWkt(expWkt, wkt), "saving geometry with Z failed: mismatch Expected:\n%s\nGot:\n%s\n" % (expWkt, wkt), ) # also try saving out the shapefile version again, as an extra test # this tests that saving a layer with z WITHOUT explicitly telling the writer to keep z values, # will stay retain the z values dest_file_name = os.path.join( str(QDir.tempPath()), "point_{}_copy.shp".format(QgsWkbTypes.displayString(t)) ) crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result = QgsVectorFileWriter.writeAsVectorFormat( created_layer, dest_file_name, "utf-8", crs, "ESRI Shapefile" ) self.assertEqual(write_result, QgsVectorFileWriter.NoError) # Open result and check created_layer_from_shp = QgsVectorLayer("{}|layerid=0".format(dest_file_name), "test", "ogr") f = next(created_layer_from_shp.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.exportToWkt() self.assertTrue( compareWkt(expWkt, wkt), "saving geometry with Z failed: mismatch Expected:\n%s\nGot:\n%s\n" % (expWkt, wkt), )