1
0
mirror of https://github.com/qgis/QGIS.git synced 2025-04-29 00:03:59 -04:00
QGIS/tests/src/python/test_layer_dependencies.py
Nyall Dawson e656c63ab7 Remove duplicate QgsFeature::setFeatureId method
Leave just QgsFeature::setId and document api break
2017-01-11 10:05:31 +01:00

268 lines
11 KiB
Python

# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsSnappingUtils (complement to C++-based tests)
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
__author__ = 'Hugo Mercier'
__date__ = '12/07/2016'
__copyright__ = 'Copyright 2016, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import qgis # NOQA
import os
from qgis.core import (QgsProject,
QgsVectorLayer,
QgsMapSettings,
QgsSnappingUtils,
QgsSnappingConfig,
QgsPointLocator,
QgsTolerance,
QgsRectangle,
QgsPoint,
QgsFeature,
QgsGeometry,
QgsProject,
QgsLayerDefinition,
QgsMapLayerDependency
)
from qgis.testing import start_app, unittest
from utilities import unitTestDataPath
from qgis.PyQt.QtCore import QSize, QPoint
import tempfile
from qgis.utils import spatialite_connect
# Convenience instances in case you may need them
start_app()
class TestLayerDependencies(unittest.TestCase):
@classmethod
def setUpClass(cls):
"""Run before all tests"""
# create a temp spatialite db with a trigger
fo = tempfile.NamedTemporaryFile()
fn = fo.name
fo.close()
cls.fn = fn
con = spatialite_connect(fn)
cur = con.cursor()
cur.execute("SELECT InitSpatialMetadata(1)")
cur.execute("create table node(id integer primary key autoincrement);")
cur.execute("select AddGeometryColumn('node', 'geom', 4326, 'POINT');")
cur.execute("create table section(id integer primary key autoincrement, node1 integer, node2 integer);")
cur.execute("select AddGeometryColumn('section', 'geom', 4326, 'LINESTRING');")
cur.execute("create trigger add_nodes after insert on section begin insert into node (geom) values (st_startpoint(NEW.geom)); insert into node (geom) values (st_endpoint(NEW.geom)); end;")
cur.execute("insert into node (geom) values (geomfromtext('point(0 0)', 4326));")
cur.execute("insert into node (geom) values (geomfromtext('point(1 0)', 4326));")
cur.execute("create table node2(id integer primary key autoincrement);")
cur.execute("select AddGeometryColumn('node2', 'geom', 4326, 'POINT');")
cur.execute("create trigger add_nodes2 after insert on node begin insert into node2 (geom) values (st_translate(NEW.geom, 0.2, 0, 0)); end;")
con.commit()
con.close()
cls.pointsLayer = QgsVectorLayer("dbname='%s' table=\"node\" (geom) sql=" % fn, "points", "spatialite")
assert (cls.pointsLayer.isValid())
cls.linesLayer = QgsVectorLayer("dbname='%s' table=\"section\" (geom) sql=" % fn, "lines", "spatialite")
assert (cls.linesLayer.isValid())
cls.pointsLayer2 = QgsVectorLayer("dbname='%s' table=\"node2\" (geom) sql=" % fn, "_points2", "spatialite")
assert (cls.pointsLayer2.isValid())
QgsProject.instance().addMapLayers([cls.pointsLayer, cls.linesLayer, cls.pointsLayer2])
# save the project file
fo = tempfile.NamedTemporaryFile()
fn = fo.name
fo.close()
cls.projectFile = fn
QgsProject.instance().setFileName(cls.projectFile)
QgsProject.instance().write()
@classmethod
def tearDownClass(cls):
"""Run after all tests"""
pass
def setUp(self):
"""Run before each test."""
pass
def tearDown(self):
"""Run after each test."""
pass
def test_resetSnappingIndex(self):
self.pointsLayer.setDependencies([])
self.linesLayer.setDependencies([])
self.pointsLayer2.setDependencies([])
ms = QgsMapSettings()
ms.setOutputSize(QSize(100, 100))
ms.setExtent(QgsRectangle(0, 0, 1, 1))
self.assertTrue(ms.hasValidSettings())
u = QgsSnappingUtils()
u.setMapSettings(ms)
cfg = u.config()
cfg.setEnabled(True)
cfg.setMode(QgsSnappingConfig.AdvancedConfiguration)
cfg.setIndividualLayerSettings(self.pointsLayer,
QgsSnappingConfig.IndividualLayerSettings(True,
QgsSnappingConfig.Vertex, 20, QgsTolerance.Pixels))
u.setConfig(cfg)
m = u.snapToMap(QPoint(95, 100))
self.assertTrue(m.isValid())
self.assertTrue(m.hasVertex())
self.assertEqual(m.point(), QgsPoint(1, 0))
f = QgsFeature(self.linesLayer.fields())
f.setId(1)
geom = QgsGeometry.fromWkt("LINESTRING(0 0,1 1)")
f.setGeometry(geom)
self.linesLayer.startEditing()
self.linesLayer.addFeatures([f])
self.linesLayer.commitChanges()
l1 = len([f for f in self.pointsLayer.getFeatures()])
self.assertEqual(l1, 4)
m = u.snapToMap(QPoint(95, 0))
# snapping not updated
self.pointsLayer.setDependencies([])
self.assertEqual(m.isValid(), False)
# set layer dependencies
self.pointsLayer.setDependencies([QgsMapLayerDependency(self.linesLayer.id())])
# add another line
f = QgsFeature(self.linesLayer.fields())
f.setId(2)
geom = QgsGeometry.fromWkt("LINESTRING(0 0,0.5 0.5)")
f.setGeometry(geom)
self.linesLayer.startEditing()
self.linesLayer.addFeatures([f])
self.linesLayer.commitChanges()
# check the snapped point is ok
m = u.snapToMap(QPoint(45, 50))
self.assertTrue(m.isValid())
self.assertTrue(m.hasVertex())
self.assertEqual(m.point(), QgsPoint(0.5, 0.5))
self.pointsLayer.setDependencies([])
# test chained layer dependencies A -> B -> C
cfg.setIndividualLayerSettings(self.pointsLayer2,
QgsSnappingConfig.IndividualLayerSettings(True,
QgsSnappingConfig.Vertex, 20, QgsTolerance.Pixels))
u.setConfig(cfg)
self.pointsLayer.setDependencies([QgsMapLayerDependency(self.linesLayer.id())])
self.pointsLayer2.setDependencies([QgsMapLayerDependency(self.pointsLayer.id())])
# add another line
f = QgsFeature(self.linesLayer.fields())
f.setId(3)
geom = QgsGeometry.fromWkt("LINESTRING(0 0.2,0.5 0.8)")
f.setGeometry(geom)
self.linesLayer.startEditing()
self.linesLayer.addFeatures([f])
self.linesLayer.commitChanges()
# check the second snapped point is ok
m = u.snapToMap(QPoint(75, 100 - 80))
self.assertTrue(m.isValid())
self.assertTrue(m.hasVertex())
self.assertEqual(m.point(), QgsPoint(0.7, 0.8))
self.pointsLayer.setDependencies([])
self.pointsLayer2.setDependencies([])
def test_cycleDetection(self):
self.assertTrue(self.pointsLayer.setDependencies([QgsMapLayerDependency(self.linesLayer.id())]))
self.assertFalse(self.linesLayer.setDependencies([QgsMapLayerDependency(self.pointsLayer.id())]))
self.pointsLayer.setDependencies([])
self.linesLayer.setDependencies([])
def test_layerDefinitionRewriteId(self):
tmpfile = os.path.join(tempfile.tempdir, "test.qlr")
ltr = QgsProject.instance().layerTreeRoot()
self.pointsLayer.setDependencies([QgsMapLayerDependency(self.linesLayer.id())])
QgsLayerDefinition.exportLayerDefinition(tmpfile, [ltr])
grp = ltr.addGroup("imported")
QgsLayerDefinition.loadLayerDefinition(tmpfile, grp)
newPointsLayer = None
newLinesLayer = None
for l in grp.findLayers():
if l.layerId().startswith('points'):
newPointsLayer = l.layer()
elif l.layerId().startswith('lines'):
newLinesLayer = l.layer()
self.assertFalse(newPointsLayer is None)
self.assertFalse(newLinesLayer is None)
self.assertTrue(newLinesLayer.id() in [dep.layerId() for dep in newPointsLayer.dependencies()])
self.pointsLayer.setDependencies([])
def test_signalConnection(self):
# remove all layers
QgsProject.instance().removeAllMapLayers()
# set dependencies and add back layers
self.pointsLayer = QgsVectorLayer("dbname='%s' table=\"node\" (geom) sql=" % self.fn, "points", "spatialite")
assert (self.pointsLayer.isValid())
self.linesLayer = QgsVectorLayer("dbname='%s' table=\"section\" (geom) sql=" % self.fn, "lines", "spatialite")
assert (self.linesLayer.isValid())
self.pointsLayer2 = QgsVectorLayer("dbname='%s' table=\"node2\" (geom) sql=" % self.fn, "_points2", "spatialite")
assert (self.pointsLayer2.isValid())
self.pointsLayer.setDependencies([QgsMapLayerDependency(self.linesLayer.id())])
self.pointsLayer2.setDependencies([QgsMapLayerDependency(self.pointsLayer.id())])
# this should update connections between layers
QgsProject.instance().addMapLayers([self.pointsLayer])
QgsProject.instance().addMapLayers([self.linesLayer])
QgsProject.instance().addMapLayers([self.pointsLayer2])
ms = QgsMapSettings()
ms.setOutputSize(QSize(100, 100))
ms.setExtent(QgsRectangle(0, 0, 1, 1))
self.assertTrue(ms.hasValidSettings())
u = QgsSnappingUtils()
u.setMapSettings(ms)
cfg = u.config()
cfg.setEnabled(True)
cfg.setMode(QgsSnappingConfig.AdvancedConfiguration)
cfg.setIndividualLayerSettings(self.pointsLayer,
QgsSnappingConfig.IndividualLayerSettings(True,
QgsSnappingConfig.Vertex, 20, QgsTolerance.Pixels))
cfg.setIndividualLayerSettings(self.pointsLayer2,
QgsSnappingConfig.IndividualLayerSettings(True,
QgsSnappingConfig.Vertex, 20, QgsTolerance.Pixels))
u.setConfig(cfg)
# add another line
f = QgsFeature(self.linesLayer.fields())
f.setId(4)
geom = QgsGeometry.fromWkt("LINESTRING(0.5 0.2,0.6 0)")
f.setGeometry(geom)
self.linesLayer.startEditing()
self.linesLayer.addFeatures([f])
self.linesLayer.commitChanges()
# check the second snapped point is ok
m = u.snapToMap(QPoint(75, 100 - 0))
self.assertTrue(m.isValid())
self.assertTrue(m.hasVertex())
self.assertEqual(m.point(), QgsPoint(0.8, 0.0))
self.pointsLayer.setDependencies([])
self.pointsLayer2.setDependencies([])
if __name__ == '__main__':
unittest.main()