def create_layer(vector): """Create empty layer. The CRS and Geometry Type of new layer are the same as of vector layer. Attributes of the layer are copied from vector. :param vector: Vector layer :type vector: QgsVectorLayer :returns: Empty vector layer (stored in memory) :rtype: QgsVectorLayer """ crs = vector.crs().toWkt() if vector.geometryType() == 0: msg = "Points cant' be split" raise WrongDataTypeException(msg) elif vector.geometryType() == 1: uri = 'LineString?crs=' + crs elif vector.geometryType() == 2: uri = 'Polygon?crs=' + crs else: msg = "Received unexpected type of layer geometry: %s" \ % (vector.geometryType(),) raise WrongDataTypeException(msg) result_layer = QgsVectorLayer(uri, 'intersected', 'memory') result_provider = result_layer.dataProvider() result_layer.startEditing() # Copy fields from vector vector_provider = vector.dataProvider() fields = vector_provider.fields() result_provider.addAttributes(fields.toList()) result_layer.commitChanges() return result_layer
def split_by_polygon(vector, polygon, request=QgsFeatureRequest(), mark_value=None): """Split objects from vector layer by polygon. If request is specified, filter the objects before splitting. If part of vector object lies in the polygon, mark it by mark_value ( optional). :param vector: Vector layer :type vector: QgsVectorLayer :param polygon: Splitting polygon :type polygon: QgsGeometry :param request: Filter for vector objects :type request: QgsFeatureRequest :param mark_value: Field value to mark the objects. :type mark_value: (field_name, field_value).or None :returns: Vector layer with split geometry :rtype: QgsVectorLayer """ def _set_feature(geometry, feature_attributes): """ Helper to create and set up feature """ included_feature = QgsFeature() included_feature.setGeometry(geometry) included_feature.setAttributes(feature_attributes) return included_feature def _update_attr_list(attributes, index, value, add_attribute=False): """ Helper for update list of attributes. """ new_attributes = attributes[:] if add_attribute: new_attributes.append(value) else: new_attributes[index] = value return new_attributes # Create layer to store the splitted objects result_layer = create_layer(vector) result_provider = result_layer.dataProvider() fields = result_provider.fields() # If target_field does not exist, add it: new_field_added = False if mark_value is not None: target_field = mark_value[0] if fields.indexFromName(target_field) == -1: result_layer.startEditing() result_provider.addAttributes( [QgsField(target_field, QVariant.Int)]) new_field_added = True result_layer.commitChanges() target_value = None if mark_value is not None: target_field = mark_value[0] target_value = mark_value[1] target_field_index = result_provider.fieldNameIndex(target_field) if target_field_index == -1: raise WrongDataTypeException('Field not found for %s' % target_field) # Start split procedure result_layer.startEditing() for initial_feature in vector.getFeatures(request): initial_geom = initial_feature.geometry() attributes = initial_feature.attributes() geometry_type = initial_geom.type() if polygon.intersects(initial_geom): # Find parts of initial_geom, intersecting # with the polygon, then mark them if needed intersection = QgsGeometry( initial_geom.intersection(polygon)).asGeometryCollection() for g in intersection: if g.type() == geometry_type: if mark_value is not None: new_attributes = _update_attr_list( attributes, target_field_index, target_value, add_attribute=new_field_added) else: new_attributes = attributes feature = _set_feature(g, new_attributes) _ = result_layer.dataProvider().addFeatures([feature]) # Find parts of the initial_geom that do not lie in the polygon diff_geom = QgsGeometry( initial_geom.symDifference(polygon)).asGeometryCollection() for g in diff_geom: if g.type() == geometry_type: if mark_value is not None: new_attributes = _update_attr_list( attributes, target_field_index, 0, add_attribute=new_field_added) else: new_attributes = attributes feature = _set_feature(g, new_attributes) _ = result_layer.dataProvider().addFeatures([feature]) else: if mark_value is not None: new_attributes = _update_attr_list( attributes, target_field_index, 0, add_attribute=new_field_added) else: new_attributes = attributes feature = _set_feature(initial_geom, new_attributes) _ = result_layer.dataProvider().addFeatures([feature]) result_layer.commitChanges() result_layer.updateExtents() return result_layer
def split_by_polygon2( vector, polygon_layer, request=QgsFeatureRequest(), use_contains_operation=False, mark_value=None): """Split objects from vector layer by polygon. If request is specified, filter the objects before splitting. If part of vector object lies in the polygon, mark it by mark_value ( optional). :param vector: Vector layer :type vector: QgsVectorLayer :param polygon_layer: Splitting polygons layer :type polygon_layer: QgsVectorLayer :param request: Filter for vector objects :type request: QgsFeatureRequest :param use_contains_operation: Whether to use geometrical containment. :type use_contains_operation: bool :param mark_value: Field value to mark the objects. :type mark_value: (field_name, field_value).or None :returns: Vector layer with split geometry :rtype: QgsVectorLayer """ def _set_feature(geometry, attributes): """ Helper to create and set up feature """ included_feature = QgsFeature() included_feature.setGeometry(geometry) included_feature.setAttributes(attributes) return included_feature def _update_attr_list(attributes, index, value, add_attribute=False): """ Helper for update list of attributes. """ new_attributes = attributes[:] if add_attribute: new_attributes.append(value) else: new_attributes[index] = value return new_attributes # Create layer to store the split objects result_layer = create_layer(vector) result_provider = result_layer.dataProvider() fields = result_provider.fields() # If target_field does not exist, add it: new_field_added = False if mark_value is not None: target_field = mark_value[0] if fields.indexFromName(target_field) == -1: result_layer.startEditing() result_provider.addAttributes( [QgsField(target_field, QVariant.Int)]) new_field_added = True result_layer.commitChanges() target_value = None if mark_value is not None: target_field = mark_value[0] target_value = mark_value[1] target_field_index = result_provider.fieldNameIndex(target_field) if target_field_index == -1: raise WrongDataTypeException( 'Field not found for %s' % target_field) # Start split procedure line_geoms = [] line_attributes = [] for initial_feature in vector.getFeatures(request): initial_geom = initial_feature.geometry() line_geoms.append(QgsGeometry(initial_geom)) attributes = initial_feature.attributes() line_attributes.append(attributes) geometry_type = initial_geom.type() poly_geoms = [] for polygon_feature in polygon_layer.getFeatures(request): # Using simplify 1 should remove any pseudonodes on the polygon # and speed up polygon operations. TS # polygon = polygon_feature.geometry().simplify(1) # disabled for now (see #1300 Y.A.) polygon = polygon_feature.geometry() poly_geoms.append(QgsGeometry(polygon)) result_layer.startEditing() for polygon in poly_geoms: for initial_geom, attributes in \ itertools.izip(line_geoms, line_attributes): if use_contains_operation: poly_contains = polygon.contains(initial_geom) else: poly_contains = False poly_intersect = False if not poly_contains: poly_intersect = polygon.intersects(initial_geom) if poly_contains or poly_intersect: # Find parts of initial_geom, intersecting # with the polygon, then mark them if needed if poly_contains: g = initial_geom if mark_value is not None: new_attributes = _update_attr_list( attributes, target_field_index, target_value, add_attribute=new_field_added ) else: new_attributes = attributes feature = _set_feature(g, new_attributes) _ = result_layer.dataProvider().addFeatures([feature]) else: intersection = QgsGeometry( initial_geom.intersection(polygon) ).asGeometryCollection() for g in intersection: if g.type() == geometry_type: if mark_value is not None: new_attributes = _update_attr_list( attributes, target_field_index, target_value, add_attribute=new_field_added ) else: new_attributes = attributes feature = _set_feature(g, new_attributes) _ = result_layer.dataProvider().\ addFeatures([feature]) result_layer.commitChanges() result_layer.updateExtents() return result_layer