def accept(self): """Process the layer and field and generate a new layer. .. note:: This is called on OK click. """ index = self.cboFields.currentIndex() field_name = self.cboFields.itemData( index, QtCore.Qt.UserRole) index = self.cboPolygonLayers.currentIndex() layer_id = self.cboPolygonLayers.itemData( index, QtCore.Qt.UserRole) # noinspection PyArgumentList layer = QgsMapLayerRegistry.instance().mapLayer(layer_id) file_name = str(layer.source()) input_layer = safe_read_layer(file_name) try: output_layer = self.minimum_needs(input_layer, str(field_name)) except ValueError: return new_file = file_name[:-4] + '_perka7' + '.shp' output_layer.write_to_file(new_file) new_layer = QgsVectorLayer(new_file, 'Minimum Needs', 'ogr') # noinspection PyArgumentList QgsMapLayerRegistry.instance().addMapLayers([new_layer]) self.done(QtGui.QDialog.Accepted)
def accept(self): """Process the layer and field and generate a new layer. .. note:: This is called on ok click. """ myIndex = self.cboFields.currentIndex() myFieldName = self.cboFields.itemData( myIndex, QtCore.Qt.UserRole).toString() myIndex = self.cboPolygonLayers.currentIndex() myLayerId = self.cboPolygonLayers.itemData( myIndex, QtCore.Qt.UserRole).toString() myLayer = QgsMapLayerRegistry.instance().mapLayer(myLayerId) myFileName = str(myLayer.source()) myInputLayer = safe_read_layer(myFileName) try: myOutputLayer = self.minimum_needs(myInputLayer, str(myFieldName)) except ValueError: return myNewFile = myFileName[:-4] + '_perka7' + '.shp' myOutputLayer.write_to_file(myNewFile) myNewLayer = QgsVectorLayer(myNewFile, 'Minimum Needs', 'ogr') QgsMapLayerRegistry.instance().addMapLayers([myNewLayer]) self.done(QtGui.QDialog.Accepted)
def deintersect(self, theHazardLayer, theExposureLayer): """Ensure there are no intersecting features with self.layer. This should only happen after initial checks have been made. Buildings are not split up by this method. """ if not self.isValid: raise InvalidAggregatorError # These should have already been clipped to analysis extents self.hazardLayer = theHazardLayer self.exposureLayer = theExposureLayer self._prepareLayer() if not self.aoiMode: # This is a safe version of the aggregation layer self.safeLayer = safe_read_layer(str(self.layer.source())) if is_polygon_layer(self.hazardLayer): self.hazardLayer = self._preparePolygonLayer(self.hazardLayer) if is_polygon_layer(self.exposureLayer): # Find out the subcategory for this layer mySubcategory = self.keywordIO.read_keywords( self.exposureLayer, 'subcategory') # We dont want to chop up buildings! if mySubcategory != 'structure': self.exposureLayer = self._preparePolygonLayer( self.exposureLayer)
def accept(self): """Process the layer and field and generate a new layer. .. note:: This is called on OK click. """ index = self.cboFields.currentIndex() field_name = self.cboFields.itemData(index, QtCore.Qt.UserRole) index = self.cboPolygonLayers.currentIndex() layer_id = self.cboPolygonLayers.itemData(index, QtCore.Qt.UserRole) # noinspection PyArgumentList layer = QgsMapLayerRegistry.instance().mapLayer(layer_id) file_name = str(layer.source()) input_layer = safe_read_layer(file_name) try: output_layer = self.minimum_needs(input_layer, str(field_name)) except ValueError: return new_file = file_name[:-4] + '_perka7' + '.shp' output_layer.write_to_file(new_file) new_layer = QgsVectorLayer(new_file, 'Minimum Needs', 'ogr') # noinspection PyArgumentList QgsMapLayerRegistry.instance().addMapLayers([new_layer]) self.done(QtGui.QDialog.Accepted)
def accept(self): """Process the layer and field and generate a new layer. .. note:: This is called on ok click. """ myIndex = self.cboFields.currentIndex() myFieldName = self.cboFields.itemData(myIndex, QtCore.Qt.UserRole).toString() myIndex = self.cboPolygonLayers.currentIndex() myLayerId = self.cboPolygonLayers.itemData( myIndex, QtCore.Qt.UserRole).toString() myLayer = QgsMapLayerRegistry.instance().mapLayer(myLayerId) myFileName = str(myLayer.source()) myInputLayer = safe_read_layer(myFileName) try: myOutputLayer = self.minimum_needs(myInputLayer, str(myFieldName)) except ValueError: return myNewFile = myFileName[:-4] + '_perka7' + '.shp' myOutputLayer.write_to_file(myNewFile) myNewLayer = QgsVectorLayer(myNewFile, 'Minimum Needs', 'ogr') QgsMapLayerRegistry.instance().addMapLayers([myNewLayer]) self.done(QtGui.QDialog.Accepted)
def test_minimum_needs(self): """Test behaviour of the minimum needs function. """ dialog = MinimumNeeds(PARENT) layer = safe_read_layer(shapefile_path) attribute = 'displaced' new_layer = dialog.minimum_needs(layer, attribute) assert new_layer is not None attributes = { 'drinking_water': 17500, 'family_kits': 200, 'rice': 2800, 'toilets': 50, 'water': 105000} self.assertDictEqual(attributes, new_layer.data[0])
def test_minimum_needs(self): """Test behaviour of the minimum needs function. """ dialog = NeedsCalculatorDialog(PARENT) layer = safe_read_layer(shapefile_path) attribute = 'displaced' new_layer = dialog.minimum_needs(layer, attribute) assert new_layer is not None attributes = { 'Drinking Water': 17500, 'Family Kits': 200, 'Rice': 2800, 'Toilets': 50, 'Clean Water': 67000} self.assertDictEqual(attributes, dict(new_layer.data[0]))
def test_minimum_needs(self): """Test behaviour of the minimum needs function. """ dialog = NeedsCalculatorDialog(PARENT) layer = safe_read_layer(shapefile_path) attribute = 'displaced' new_layer = dialog.minimum_needs(layer, attribute) assert new_layer is not None attributes = { 'Drinking Water': 17500, 'Family Kits': 200, 'Rice': 2800, 'Toilets': 50, 'Clean Water': 67000 } self.assertDictEqual(attributes, dict(new_layer.data[0]))
def _aggregate(self, myImpactLayer, myExpectedResults): myAggregationLayer = QgsVectorLayer( os.path.join(BOUNDDATA, 'kabupaten_jakarta.shp'), 'test aggregation', 'ogr') # create a copy of aggregation layer myGeoExtent = extent_to_geo_array( myAggregationLayer.extent(), myAggregationLayer.crs()) myAggrAttribute = self.keywordIO.read_keywords( myAggregationLayer, self.defaults['AGGR_ATTR_KEY']) # noinspection PyArgumentEqualDefault myAggregationLayer = clip_layer( layer=myAggregationLayer, extent=myGeoExtent, explode_flag=True, explode_attribute=myAggrAttribute) myAggregator = Aggregator(None, myAggregationLayer) # setting up myAggregator.isValid = True myAggregator.layer = myAggregationLayer myAggregator.safeLayer = safe_read_layer( str(myAggregator.layer.source())) myAggregator.aoiMode = False myAggregator.aggregate(myImpactLayer) myProvider = myAggregator.layer.dataProvider() myProvider.select(myProvider.attributeIndexes()) myFeature = QgsFeature() myResults = [] while myProvider.nextFeature(myFeature): myFeatureResults = {} myAtMap = myFeature.attributeMap() for (k, attr) in myAtMap.iteritems(): myFeatureResults[k] = str(attr.toString()) myResults.append(myFeatureResults) self.assertEqual(myExpectedResults, myResults)
def _aggregate(self, myImpactLayer, myExpectedResults, useNativeZonalStats=False): """Helper to calculate aggregation. Expected results is split into two lists - one list contains numeric attributes, the other strings. This is done so that we can use numpy .testing.assert_allclose which doesn't work on strings """ myExpectedStringResults = [] myExpectedNumericResults = [] for item in myExpectedResults: myItemNumResults = [] myItemStrResults = [] for field in item: try: value = float(field) myItemNumResults.append(value) except ValueError: myItemStrResults.append(str(field)) myExpectedNumericResults.append(myItemNumResults) myExpectedStringResults.append(myItemStrResults) myAggregationLayer = QgsVectorLayer( os.path.join(BOUNDDATA, 'kabupaten_jakarta.shp'), 'test aggregation', 'ogr') # create a copy of aggregation layer myGeoExtent = extent_to_geo_array( myAggregationLayer.extent(), myAggregationLayer.crs()) myAggrAttribute = self.keywordIO.read_keywords( myAggregationLayer, self.defaults['AGGR_ATTR_KEY']) # noinspection PyArgumentEqualDefault myAggregationLayer = clip_layer( layer=myAggregationLayer, extent=myGeoExtent, explode_flag=True, explode_attribute=myAggrAttribute) myAggregator = Aggregator(None, myAggregationLayer) # setting up myAggregator.isValid = True myAggregator.layer = myAggregationLayer myAggregator.safeLayer = safe_read_layer( str(myAggregator.layer.source())) myAggregator.aoiMode = False myAggregator.useNativeZonalStats = useNativeZonalStats myAggregator.aggregate(myImpactLayer) myProvider = myAggregator.layer.dataProvider() myNumericResults = [] myStringResults = [] for myFeature in myProvider.getFeatures(): myFeatureNumResults = [] myFeatureStrResults = [] myAttrs = myFeature.attributes() for attr in myAttrs: if isinstance(attr, (int, float)): myFeatureNumResults.append(attr) else: myFeatureStrResults.append(attr) myNumericResults.append(myFeatureNumResults) myStringResults.append(myFeatureStrResults) # check string attributes self.assertEqual(myExpectedStringResults, myStringResults) # check numeric attributes with a 0.01% tolerance compared to the # native QGIS stats numpy.testing.assert_allclose(myExpectedNumericResults, myNumericResults, rtol=0.01)
def _aggregate(self, impact_layer, expected_results, use_native_zonal_stats=False): """Helper to calculate aggregation. Expected results is split into two lists - one list contains numeric attributes, the other strings. This is done so that we can use numpy .testing.assert_allclose which doesn't work on strings """ expected_string_results = [] expected_numeric_results = [] for item in expected_results: string_results = [] numeric_results = [] for field in item: try: value = float(field) numeric_results.append(value) except ValueError: string_results.append(str(field)) expected_numeric_results.append(numeric_results) expected_string_results.append(string_results) aggregation_layer = QgsVectorLayer( os.path.join(BOUNDDATA, 'kabupaten_jakarta.shp'), 'test aggregation', 'ogr') # create a copy of aggregation layer geo_extent = extent_to_geo_array(aggregation_layer.extent(), aggregation_layer.crs()) aggregation_attribute = self.keywordIO.read_keywords( aggregation_layer, self.defaults['AGGR_ATTR_KEY']) # noinspection PyArgumentEqualDefault aggregation_layer = clip_layer(layer=aggregation_layer, extent=geo_extent, explode_flag=True, explode_attribute=aggregation_attribute) aggregator = Aggregator(None, aggregation_layer) # setting up aggregator.is_valid = True aggregator.layer = aggregation_layer aggregator.safe_layer = safe_read_layer(str(aggregator.layer.source())) aggregator.aoi_mode = False aggregator.use_native_zonal_stats = use_native_zonal_stats aggregator.aggregate(impact_layer) provider = aggregator.layer.dataProvider() string_results = [] numeric_results = [] for feature in provider.getFeatures(): feature_string_results = [] feature_numeric_results = [] attributes = feature.attributes() for attr in attributes: if isinstance(attr, (int, float)): feature_numeric_results.append(attr) else: feature_string_results.append(attr) numeric_results.append(feature_numeric_results) string_results.append(feature_string_results) # check string attributes self.assertEqual(expected_string_results, string_results) # check numeric attributes with a 0.01% tolerance compared to the # native QGIS stats numpy.testing.assert_allclose(expected_numeric_results, numeric_results, rtol=0.01)
def _aggregate( self, impact_layer, expected_results, use_native_zonal_stats=False): """Helper to calculate aggregation. Expected results is split into two lists - one list contains numeric attributes, the other strings. This is done so that we can use numpy .testing.assert_allclose which doesn't work on strings """ expected_string_results = [] expected_numeric_results = [] for item in expected_results: string_results = [] numeric_results = [] for field in item: try: value = float(field) numeric_results.append(value) except ValueError: string_results.append(str(field)) expected_numeric_results.append(numeric_results) expected_string_results.append(string_results) aggregation_layer = QgsVectorLayer( os.path.join(BOUNDDATA, 'kabupaten_jakarta.shp'), 'test aggregation', 'ogr') # create a copy of aggregation layer geo_extent = extent_to_geo_array( aggregation_layer.extent(), aggregation_layer.crs()) aggregation_attribute = self._keywordIO.read_keywords( aggregation_layer, self._defaults['AGGR_ATTR_KEY']) # noinspection PyArgumentEqualDefault aggregation_layer = clip_layer( layer=aggregation_layer, extent=geo_extent, explode_flag=True, explode_attribute=aggregation_attribute) aggregator = Aggregator(None, aggregation_layer) # setting up aggregator.is_valid = True aggregator.layer = aggregation_layer aggregator.safe_layer = safe_read_layer( str(aggregator.layer.source())) aggregator.aoi_mode = False aggregator.use_native_zonal_stats = use_native_zonal_stats aggregator.aggregate(impact_layer) provider = aggregator.layer.dataProvider() string_results = [] numeric_results = [] for feature in provider.getFeatures(): feature_string_results = [] feature_numeric_results = [] attributes = feature.attributes() for attr in attributes: if isinstance(attr, (int, float)): feature_numeric_results.append(attr) else: feature_string_results.append(attr) numeric_results.append(feature_numeric_results) string_results.append(feature_string_results) # check string attributes self.assertEqual(expected_string_results, string_results) # check numeric attributes with a 0.01% tolerance compared to the # native QGIS stats numpy.testing.assert_allclose(expected_numeric_results, numeric_results, rtol=0.01)
def _preparePolygonLayer(self, theQgisLayer): """Create a new layer with no intersecting features to self.layer. A helper function to align the polygons to the postprocLayer polygons. If one input polygon is in two or more postprocLayer polygons then it is divided so that each part is within only one of the postprocLayer polygons. this allows to aggregate in postrocessing using centroid in polygon. The function assumes EPSG:4326 but no checks are enforced Args: theQgisLayer of the file to be processed Returns: QgisLayer of the processed file Raises: Any exceptions raised by the InaSAFE library will be propagated. """ # import time # startTime = time.clock() myMessage = m.Message( m.Heading(self.tr('Preclipping input data...')), m.Paragraph(self.tr( 'Modifying %1 to avoid intersections with the aggregation ' 'layer' ).arg(theQgisLayer.name()))) self._sendMessage(myMessage) theLayerFilename = str(theQgisLayer.source()) myPostprocPolygons = self.safeLayer.get_geometry() myPolygonsLayer = safe_read_layer(theLayerFilename) myRemainingPolygons = numpy.array(myPolygonsLayer.get_geometry()) # myRemainingAttributes = numpy.array(myPolygonsLayer.get_data()) myRemainingIndexes = numpy.array(range(len(myRemainingPolygons))) #used for unit tests only self.preprocessedFeatureCount = 0 # FIXME (MB) the intersecting array is used only for debugging and # could be safely removed myIntersectingPolygons = [] myInsidePolygons = [] # FIXME (MB) maybe do raw geos without qgis #select all postproc polygons with no attributes aggregationProvider = self.layer.dataProvider() aggregationProvider.select([]) # copy polygons to a memory layer myQgisMemoryLayer = create_memory_layer(theQgisLayer) polygonsProvider = myQgisMemoryLayer.dataProvider() allPolygonAttrs = polygonsProvider.attributeIndexes() polygonsProvider.select(allPolygonAttrs) myQgisPostprocPoly = QgsFeature() myQgisFeat = QgsFeature() myInsideFeat = QgsFeature() fields = polygonsProvider.fields() myTempdir = temp_dir(sub_dir='preprocess') myOutFilename = unique_filename(suffix='.shp', dir=myTempdir) self.keywordIO.copy_keywords(theQgisLayer, myOutFilename) mySHPWriter = QgsVectorFileWriter(myOutFilename, 'UTF-8', fields, polygonsProvider.geometryType(), polygonsProvider.crs()) if mySHPWriter.hasError(): raise InvalidParameterError(mySHPWriter.errorMessage()) # end FIXME for (myPostprocPolygonIndex, myPostprocPolygon) in enumerate(myPostprocPolygons): LOGGER.debug('PostprocPolygon %s' % myPostprocPolygonIndex) myPolygonsCount = len(myRemainingPolygons) aggregationProvider.featureAtId( myPostprocPolygonIndex, myQgisPostprocPoly, True, []) myQgisPostprocGeom = QgsGeometry(myQgisPostprocPoly.geometry()) # myPostprocPolygon bounding box values A = numpy.array(myPostprocPolygon) minx = miny = sys.maxint maxx = maxy = -minx myPostprocPolygonMinx = min(minx, min(A[:, 0])) myPostprocPolygonMaxx = max(maxx, max(A[:, 0])) myPostprocPolygonMiny = min(miny, min(A[:, 1])) myPostprocPolygonMaxy = max(maxy, max(A[:, 1])) # create an array full of False to store if a BB vertex is inside # or outside the myPostprocPolygon myAreVerticesInside = numpy.zeros(myPolygonsCount * 4, dtype=numpy.bool) # Create Nx2 vector of vertices of bounding boxes myBBVertices = [] # Compute bounding box for each geometry type for myPoly in myRemainingPolygons: minx = miny = sys.maxint maxx = maxy = -minx # Do outer ring only as the BB is outside anyway A = numpy.array(myPoly) minx = min(minx, numpy.min(A[:, 0])) maxx = max(maxx, numpy.max(A[:, 0])) miny = min(miny, numpy.min(A[:, 1])) maxy = max(maxy, numpy.max(A[:, 1])) myBBVertices.extend([(minx, miny), (minx, maxy), (maxx, maxy), (maxx, miny)]) # see if BB vertices are in myPostprocPolygon myBBVertices = numpy.array(myBBVertices) inside, _ = points_in_and_outside_polygon(myBBVertices, myPostprocPolygon) # make True if the vertice was in myPostprocPolygon myAreVerticesInside[inside] = True # myNextIterPolygons has the 0:count indexes # myOutsidePolygons has the mapped to original indexes # and is overwritten at every iteration because we care only of # the outside polygons remaining after the last iteration myNextIterPolygons = [] myOutsidePolygons = [] for i in range(myPolygonsCount): k = i * 4 myMappedIndex = myRemainingIndexes[i] # memory layers counting starts at 1 instead of 0 as in our # indexes myFeatId = myMappedIndex + 1 doIntersection = False # summ the isInside bool for each of the boundingbox vertices # of each poygon. for example True + True + False + True is 3 myPolygonLocation = numpy.sum(myAreVerticesInside[k:k + 4]) if myPolygonLocation == 4: # all vertices are inside -> polygon is inside #ignore this polygon from further analysis myInsidePolygons.append(myMappedIndex) polygonsProvider.featureAtId(myFeatId, myQgisFeat, True, allPolygonAttrs) mySHPWriter.addFeature(myQgisFeat) self.preprocessedFeatureCount += 1 # LOGGER.debug('Polygon %s is fully inside' %myMappedIndex) # tmpWriter.addFeature(myQgisFeat) elif myPolygonLocation == 0: # all vertices are outside # check if the polygon BB is completely outside of the # myPostprocPolygon BB. myPolyMinx = numpy.min(myBBVertices[k:k + 4, 0]) myPolyMaxx = numpy.max(myBBVertices[k:k + 4, 0]) myPolyMiny = numpy.min(myBBVertices[k:k + 4, 1]) myPolyMaxy = numpy.max(myBBVertices[k:k + 4, 1]) # check if myPoly is all E,W,N,S of myPostprocPolygon if ((myPolyMinx > myPostprocPolygonMaxx) or (myPolyMaxx < myPostprocPolygonMinx) or (myPolyMiny > myPostprocPolygonMaxy) or (myPolyMaxy < myPostprocPolygonMiny)): #polygon is surely outside myOutsidePolygons.append(myMappedIndex) # we need this polygon in the next iteration myNextIterPolygons.append(i) else: # polygon might be outside or intersecting. consider # it intersecting so it goes into further analysis doIntersection = True else: # some vertices are outside some inside -> polygon is # intersecting doIntersection = True #intersect using qgis if doIntersection: # LOGGER.debug('Intersecting polygon %s' % myMappedIndex) myIntersectingPolygons.append(myMappedIndex) ok = polygonsProvider.featureAtId(myFeatId, myQgisFeat, True, allPolygonAttrs) if not ok: LOGGER.debug('Couldn\'t fetch feature: %s' % myFeatId) LOGGER.debug([str(error) for error in polygonsProvider.errors()]) myQgisPolyGeom = QgsGeometry(myQgisFeat.geometry()) myAtMap = myQgisFeat.attributeMap() # for (k, attr) in myAtMap.iteritems(): # LOGGER.debug( "%d: %s" % (k, attr.toString())) # make intersection of the myQgisFeat and the postprocPoly # write the inside part to a shp file and the outside part # back to the original QGIS layer try: myIntersec = myQgisPostprocGeom.intersection( myQgisPolyGeom) # if myIntersec is not None: myIntersecGeom = QgsGeometry(myIntersec) #from ftools myUnknownGeomType = 0 if myIntersecGeom.wkbType() == myUnknownGeomType: int_com = myQgisPostprocGeom.combine( myQgisPolyGeom) int_sym = myQgisPostprocGeom.symDifference( myQgisPolyGeom) myIntersecGeom = QgsGeometry( int_com.difference(int_sym)) # LOGGER.debug('wkbType type of intersection: %s' % # myIntersecGeom.wkbType()) polygonTypesList = [QGis.WKBPolygon, QGis.WKBMultiPolygon] if myIntersecGeom.wkbType() in polygonTypesList: myInsideFeat.setGeometry(myIntersecGeom) myInsideFeat.setAttributeMap(myAtMap) mySHPWriter.addFeature(myInsideFeat) self.preprocessedFeatureCount += 1 else: pass # LOGGER.debug('Intersection not a polygon so ' # 'the two polygons either touch ' # 'only or do not intersect. Not ' # 'adding this to the inside list') #Part of the polygon that is outside the postprocpoly myOutside = myQgisPolyGeom.difference(myIntersecGeom) # if myOutside is not None: myOutsideGeom = QgsGeometry(myOutside) if myOutsideGeom.wkbType() in polygonTypesList: # modifiy the original geometry to the part # outside of the postproc polygon polygonsProvider.changeGeometryValues( {myFeatId: myOutsideGeom}) # we need this polygon in the next iteration myOutsidePolygons.append(myMappedIndex) myNextIterPolygons.append(i) except TypeError: LOGGER.debug('ERROR with FID %s', myMappedIndex) # LOGGER.debug('Inside %s' % myInsidePolygons) # LOGGER.debug('Outside %s' % myOutsidePolygons) # LOGGER.debug('Intersec %s' % myIntersectingPolygons) if len(myNextIterPolygons) > 0: #some polygons are still completely outside of the postprocPoly #so go on and reiterate using only these nextIterPolygonsIndex = numpy.array(myNextIterPolygons) myRemainingPolygons = myRemainingPolygons[ nextIterPolygonsIndex] # myRemainingAttributes = myRemainingAttributes[ # nextIterPolygonsIndex] myRemainingIndexes = myRemainingIndexes[nextIterPolygonsIndex] LOGGER.debug('Remaining: %s' % len(myRemainingPolygons)) else: print 'no more polygons to be checked' break # del tmpWriter # here the full polygon set is represented by: # myInsidePolygons + myIntersectingPolygons + myNextIterPolygons # the a polygon intersecting multiple postproc polygons appears # multiple times in the array # noinspection PyUnboundLocalVariable LOGGER.debug('Results:\nInside: %s\nIntersect: %s\nOutside: %s' % ( myInsidePolygons, myIntersectingPolygons, myOutsidePolygons)) #add in- and outside polygons for i in myOutsidePolygons: myFeatId = i + 1 polygonsProvider.featureAtId(myFeatId, myQgisFeat, True, allPolygonAttrs) mySHPWriter.addFeature(myQgisFeat) self.preprocessedFeatureCount += 1 del mySHPWriter # LOGGER.debug('Created: %s' % self.preprocessedFeatureCount) myName = '%s %s' % (theQgisLayer.name(), self.tr('preprocessed')) myOutLayer = QgsVectorLayer(myOutFilename, myName, 'ogr') if not myOutLayer.isValid(): #TODO (MB) use a better exception raise Exception('Invalid qgis Layer') if self.showIntermediateLayers: self.keywordIO.update_keywords(myOutLayer, {'title': myName}) QgsMapLayerRegistry.instance().addMapLayer(myOutLayer) return myOutLayer