def remove_spikes(poly,threshold=0.01): """ Looks for spikes (angles < threshold degrees) in the polygons exterior ring. If there are spikes, they will be removed and a polygon (without spikes) will be returned. If no spikes are found, method will return original geometry. NOTE: This method does not examine or fix interior rings. So far those haven't seemed to have been a problem. """ line_ring = poly.exterior_ring spike_indecies = spike_ring_indecies(line_ring,threshold=threshold) if( spike_indecies ): for i,org_index in enumerate(spike_indecies): if(org_index==0): # special case, must remove first and last point, and add end point that overlaps new first point # get the list of points pnts = list(line_ring.coords) # remove the first point pnts.remove(pnts[0]) # remove the last point pnts.remove(pnts[-1]) # append a copy of the new first point (old second point) onto the end so it makes a closed ring pnts.append(pnts[0]) # replace the old line ring line_ring = LinearRing(pnts) else: line_ring.remove(line_ring.coords[org_index]) poly.exterior_ring = line_ring return poly
def test_sublrng(self): """Test sublrng returns aaa subset of lnrg """ # Plain square (no reflex points) lrng0 = LinearRing(((0, 0), (0, 1), (1, 1), (1, 0), (0, 0))) pt0 = (0, 0) pt1 = (0, 1) pt2 = (1, 1) pt3 = (1, 0) # Return lrng from pt0 to pt2, (inclusive) self.assertEqual(sublrng(pt0, pt2, lrng0), LinearRing((pt0, pt1, pt2, pt0))) # Return lrng from pt0 to pt3, (=lrng0) self.assertEqual(sublrng(pt0, pt3, lrng0), lrng0) # Return lrng from pt1 to pt0, # (=lrng0, but starts at pt1 now) aaa = sublrng(pt2, pt1, lrng0) bbb = LinearRing((pt2, pt3, pt0, pt1, pt2)) self.assertEqual(aaa, bbb)
def parsekmlpoly(kmlstring): e = fromstring(kmlstring) coords = coords = e.find('{http://www.opengis.net/kml/2.2}Placemark/{http://www.opengis.net/kml/2.2}Polygon/{http://www.opengis.net/kml/2.2}outerBoundaryIs/{http://www.opengis.net/kml/2.2}LinearRing/{http://www.opengis.net/kml/2.2}coordinates').text coords = coords.lstrip(' ').rstrip(' ').replace('\n', '').replace('\t', ''); lra = [] for yxz in coords.split(' '): a = yxz.split(',') if len(a) > 1: lra.append((float(a[0]), float(a[1]))) lr = LinearRing(lra) poly = Polygon(lr) return poly
def get_polygon_with_switched_coordinates(polygon): switched_poly = [] linear_rings = list(polygon) for ring in linear_rings: switched_ring = [] points = list(ring) for point in points: switched_point = (point[1], point[0]) switched_ring.append(switched_point) switched_poly.append(LinearRing(switched_ring)) return Polygon(*switched_poly)
def convert_linestring_to_multiploygon(linestring): points = linestring.coords # close the LineString so we can transform to LinearRing points = list(points) points.append(points[0]) ring = LinearRing(points) # now we have a LinearRing we can make a Polygon.. and the rest is simple poly = Polygon(ring) multipoly = MultiPolygon(poly) return multipoly
def handle(self, name, file, *args, **options): name = name[0] file = file[0] if Region.objects.filter(name__iexact=name).exists(): message = ( "WARNING: This will replace an existing region with the same name: {}. Do you want to continue? [y/n]" ).format(name) if input(message).lower() not in {"y", "yes"}: return temp_dir = None try: if file.endswith(".zip"): temp_dir = mkdtemp() with ZipFile(file) as zf: zf.extractall(temp_dir) try: file = glob.glob(os.path.join(temp_dir, "*.shp"))[0] except IndexError: raise ValueError("No shapefile in zip archive") polygons = [] with fiona.open(file, "r") as shp: for feature in shp: geometry = transform_geom(shp.crs, {"init": "EPSG:4326"}, feature["geometry"]) if geometry["type"] == "MultiPolygon": coordinate_set = geometry["coordinates"] else: coordinate_set = [geometry["coordinates"]] for coordinates in coordinate_set: polygons.append( Polygon(*[LinearRing(x) for x in coordinates])) with transaction.atomic(): Region.objects.filter(name__iexact=name).delete() # Buffer by 0 to make polygons valid Region.objects.create( name=name, polygons=MultiPolygon(polygons).buffer(0)) finally: if temp_dir is not None: try: shutil.rmtree(temp_dir) except OSError: pass
def test_geometryfield(self): "Testing the general GeometryField." Feature(name='Point', geom=Point(1, 1)).save() Feature(name='LineString', geom=LineString((0, 0), (1, 1), (5, 5))).save() Feature(name='Polygon', geom=Polygon(LinearRing((0, 0), (0, 5), (5, 5), (5, 0), (0, 0)))).save() Feature(name='GeometryCollection', geom=GeometryCollection(Point(2, 2), LineString((0, 0), (2, 2)), Polygon(LinearRing((0, 0), (0, 5), (5, 5), (5, 0), (0, 0))))).save() f_1 = Feature.objects.get(name='Point') self.assertEqual(True, isinstance(f_1.geom, Point)) self.assertEqual((1.0, 1.0), f_1.geom.tuple) f_2 = Feature.objects.get(name='LineString') self.assertEqual(True, isinstance(f_2.geom, LineString)) self.assertEqual(((0.0, 0.0), (1.0, 1.0), (5.0, 5.0)), f_2.geom.tuple) f_3 = Feature.objects.get(name='Polygon') self.assertEqual(True, isinstance(f_3.geom, Polygon)) f_4 = Feature.objects.get(name='GeometryCollection') self.assertEqual(True, isinstance(f_4.geom, GeometryCollection)) self.assertEqual(f_3.geom, f_4.geom[2])
def test_linearring(self): "Testing LinearRing objects." for rr in self.geometries.linearrings: lr = fromstr(rr.wkt) self.assertEqual(lr.geom_type, 'LinearRing') self.assertEqual(lr.geom_typeid, 2) self.assertEqual(lr.dims, 1) self.assertEqual(rr.n_p, len(lr)) self.assertEqual(True, lr.valid) self.assertEqual(False, lr.empty) # Creating a LinearRing from a tuple, list, and numpy array self.assertEqual(lr, LinearRing(lr.tuple)) self.assertEqual(lr, LinearRing(*lr.tuple)) self.assertEqual(lr, LinearRing([list(tup) for tup in lr.tuple])) if numpy: self.assertEqual(lr, LinearRing(numpy.array(lr.tuple))) with self.assertRaisesMessage( TypeError, 'LinearRing requires at least 4 points, got 3.'): LinearRing((0, 0), (1, 1), (0, 0)) with self.assertRaisesMessage( TypeError, 'LinearRing requires at least 4 points, got 1.'): LinearRing([(0, 0)])
def _coerce_polygon(self, geometry, dimensions=2, z_value=0): coords = geometry.coords if not geometry.hasz and dimensions == 3: new_rings = [ self._coerce_linearring(LinearRing(ring, srid=geometry.srid), dimensions=3, z_value=z_value) for ring in coords ] if geometry.hasz and dimensions == 2: new_rings = [ self._coerce_linearring(LinearRing(ring, srid=geometry.srid)) for ring in coords ] outer_ring = new_rings[0].coords inner_rings = [r.coords for r in new_rings[1:] if r is not None] return Polygon(outer_ring, *inner_rings, srid=geometry.srid)
def setUp(self): self.cache = ServiceRedisStorage(redis_db=randint(1, 15)) self.faker = Faker() self.provider = Provider.objects.create(name=self.faker.company(), email=self.faker.email(), cur=self.faker.currency_code()) self.service1 = Service.objects.create( provider=self.provider, name=self.faker.job(), price=randint(10, 100) / 5, poly=Polygon(LinearRing((0, 0), (0, 5), (5, 5), (5, 0), (0, 0)))) self.search = lambda point: search_services(point, self.cache) self.search_list = lambda point: list(self.search(point).instance)
def build_box(self): ''' top_left = (west, north) top_right = (east, north) bottom_right = (east, south) bottom_left = (west, south) ''' try: box = Polygon( LinearRing([ Point( float(self.west), float(self.north) ), Point( float(self.east), float(self.north) ), Point( float(self.east), float(self.south) ), Point( float(self.west), float(self.south) ), Point( float(self.west), float(self.north))])) box.set_srid(settings.GEOMETRY_CLIENT_SRID) return box except Exception, e: raise self.InternalException("Exception raised in ClipToGraticuleManipulator while initializing graticule geometry: " + e.message)
def build_footprint(record): ''' take a pds record and return a geos polygon with the image footprint ''' fieldnames = zip(longitude_fields, latitude_fields) points = [] for lonfield, latfield in fieldnames: points.append( Point(getattr(record, lonfield), getattr(record, latfield), srid=mars_srid)) points.append(points[0]) poly = Polygon(LinearRing(*points)) return poly
def test_creep_line_at_angle(self): """ Test creeping line generation over convex LinearRing, at various angles. """ # Angle 0deg = West to East, South to North progression # Width = The distance across South to North # Angle +90deg = East # Plain square lrng0 = LinearRing(((0, 0), (0, 1), (1, 1), (1, 0), (0, 0))) # Creeping line @ same size as square lstr0aaa = creep_line_at_angle(lrng0, 1, 0) lstr0aaa_expected = LineString((0, 0), (1, 0), (1, 1), (0, 1))
def test05_Polygon(self): 'Testing Polygon mutations' for pg in (Polygon(((1, 0), (4, 1), (6, -1), (8, 10), (1, 0)), ((5, 4), (6, 4), (6, 3), (5, 4))), fromstr('POLYGON ((1 0,4 1,6 -1,8 10,1 0),(5 4,6 4,6 3,5 4))')): self.assertEqual(pg._get_single_external(0), LinearRing((1, 0), (4, 1), (6, -1), (8, 10), (1, 0)), 'Polygon _get_single_external(0)') self.assertEqual(pg._get_single_external(1), LinearRing((5, 4), (6, 4), (6, 3), (5, 4)), 'Polygon _get_single_external(1)') # _set_list pg._set_list(2, (((1, 2), (10, 0), (12, 9), (-1, 15), (1, 2)), ((4, 2), (5, 2), (5, 3), (4, 2)))) self.assertEqual( pg.coords, (((1.0, 2.0), (10.0, 0.0), (12.0, 9.0), (-1.0, 15.0), (1.0, 2.0)), ((4.0, 2.0), (5.0, 2.0), (5.0, 3.0), (4.0, 2.0))), 'Polygon _set_list') lsa = Polygon(*pg.coords) for f in geos_function_tests: self.assertEqual(f(lsa), f(pg), 'Polygon ' + f.__name__)
def test_creep_line(self): """ Test creeping line generation over convex LinearRing. """ # Plain square lrng0 = LinearRing(((0, 0), (0, 1), (1, 1), (1, 0), (0, 0))) # Creeping line @ same size as square lstr0aaa = creep_line(lrng0, 1) lstr0aaa_expected = LineString((0, 0), (1, 0), (1, 1), (0, 1)) # Creeping line @ 1.1 spacing lstr0bbb = creep_line(lrng0, 1.1) lstr0bbb_expected = LineString((0, 0), (1, 0), (1, 1), (0, 1)) # Triangle (half-square) lrng1 = LinearRing(((0, 0), (0, 1), (1, 1), (0, 0))) # Creeping line @ same size as square lstr1aaa = creep_line(lrng1, 1) lstr1aaa_expected = LineString((0, 0), (0, 1), (1, 1)) self.assertEqual(lstr0aaa, lstr0aaa_expected) self.assertEqual(lstr0bbb, lstr0bbb_expected) self.assertEqual(lstr1aaa, lstr1aaa_expected)
def test_cross(self): """ Test cross product of lrng method """ # Plain square (no reflex points) lrng0 = LinearRing(((0, 0), (0, 1), (1, 1), (1, 0), (0, 0))) # Square with aaa notch (1 reflex point @ (2,1)) lrng1 = LinearRing( ((0, 0), (0, 2), (4, 2), (4, 0), (3, 0), (2, 1), (1, 0), (0, 0))) self.assertEqual(lrng_cross(lrng0), [-1, -1, -1, -1]) lrng0.reverse() self.assertEqual(lrng_cross(lrng0), [1, 1, 1, 1]) self.assertEqual(lrng_cross(lrng1), [-2, -8, -8, -2, -1, 2, -1]) lrng1.reverse() self.assertEqual(lrng_cross(lrng1), [2, 1, -2, 1, 2, 8, 8])
def test_search_model(self): sdate = timezone.datetime(2016,1,1,tzinfo=timezone.utc) date0 = timezone.datetime(2010,1,1,tzinfo=timezone.utc) date1 = timezone.datetime(2010,1,2,tzinfo=timezone.utc) source = Source.objects.get(pk=1) ext_coords = ((0, 0), (0, 1), (1, 1), (1, 0), (0, 0)) polygon = Polygon(LinearRing(ext_coords)) search = Search(sdate=sdate, date0=date0, date1=date1, polygon=polygon) search.save() search.source.add(source) search.save() self.assertEqual(search.date0, date0) self.assertIsInstance(search.__str__(), str)
def new_project(request, group=None): (profile, permissions, is_default) = cv.get_profile_and_permissions(request) if request.method == 'POST': form = CreateProjectForm(request.POST) if form.is_valid(): project = LandUseProject() project.name = form.cleaned_data["project_name"] project.group = group # !!! Warning, Google lists geo data lat,lon. # everyone else, including better dem portal, does lon, lat poly_data = [(x[1], x[0]) for x in form.cleaned_data["polygon_field"]] poly_data.append( poly_data[0] ) # polygon must be instantiated with a closed ring project.polygon = Polygon(LinearRing(tuple(poly_data))) project.owner_profile = profile project.save() goals = FeedbackGoal.objects.all() for goal in goals: var_name = goal.name + "_pref" if form.cleaned_data[var_name]: project.feedback_goals.add(goal) ct.finalize_project(project) return render( request, 'core/thanks.html', { "action_description": "creating a new land use planning project", "link": "/apps/land_use_planning/administer_project/" + str(project.id) }) else: return render(request, 'core/generic_form.html', { 'form': form, 'action_path': request.path }) else: form = CreateProjectForm() return render(request, 'core/generic_form.html', { 'form': form, 'action_path': request.path })
def test_coerce_linearring_3d(self): c = GeometryCoercer() linearring2d = LinearRing(((0, 0), (1, 1), (1.5, 1.5), (0, 0)), srid=4326) self.assertFalse(linearring2d.hasz) linearring3d = c.coerce(linearring2d, dimensions=3, z_value=10) self.assertEquals(linearring2d.srid, linearring3d.srid) self.assertTrue(linearring3d.hasz) for tupla in linearring3d.coords: self.assertEquals(10, tupla[2])
def test_decomp_example1(self): """ Real Example 1 :: Pair of Pants """ # Real Data lrng0 = LinearRing( ((172.79159545898438, -43.41801639874423), (172.7974319458008, -43.33866308542216), (172.86712646484375, -43.327924949879176), (172.9344177246094, -43.33491743983), (172.93510437011722, -43.42749192352219), (172.90489196777347, -43.422504990087994), (172.87742614746094, -43.374110416762214), (172.85545349121097, -43.42001136931237), (172.79159545898438, -43.41801639874423))) result0 = decomp(lrng0) self.assertEqual(len(result0), 2)
def LoadPixels(shp_path=os.path.join( os.getcwd(), 'vismet/scripts/data/pixel/ES_Pixel_Eta5km_Shapefile.shp')): setPixelVariables() # Pega o elemento "Categoria" category, created = ElementCategory.objects.get_or_create(name='simulados') # Pega o objeto "Fonte da estação" source, created = ElementSource.objects.get_or_create(name='eta por pixel', category=category) state = 'ES' shp_df = gpd.read_file(shp_path) dist = 0.025 for index, row in shp_df.iterrows(): lat = row["Latitude"] lon = row["Longitude"] centroid = row["geometry"] x1 = float(centroid.x) - dist y1 = float(centroid.y) + dist x2 = float(centroid.x) + dist y2 = float(centroid.y) - dist pt1 = (x1, y1) pt2 = (x2, y1) pt3 = (x2, y2) pt4 = (x1, y2) coords = LinearRing(pt1, pt2, pt3, pt4, pt1) polygon_geom = Polygon(coords) pixel, created = Pixel.objects.get_or_create( latitude=lat, longitude=lon, ) pixel.geom = polygon_geom pixel.save() print(pixel) print("\n\n") print("Os pixels foram carregados.") print("\n\n")
def test_length(self): "Testing the length property." # Points have 0 length. pnt = Point(0, 0) self.assertEqual(0.0, pnt.length) # Should be ~ sqrt(2) ls = LineString((0, 0), (1, 1)) self.assertAlmostEqual(1.41421356237, ls.length, 11) # Should be circumference of Polygon poly = Polygon(LinearRing((0, 0), (0, 1), (1, 1), (1, 0), (0, 0))) self.assertEqual(4.0, poly.length) # Should be sum of each element's length in collection. mpoly = MultiPolygon(poly.clone(), poly) self.assertEqual(8.0, mpoly.length)
def get_bounded_stops(request): lat_sw, lon_sw, lat_ne, lon_ne = map(float, request.REQUEST.get('bounds').split(",")) pbox = ((lon_sw, lat_sw), (lon_sw, lat_ne), (lon_ne, lat_ne), (lon_ne, lat_sw), (lon_sw, lat_sw)) lr = LinearRing(*pbox, srid=4326) stops = Stop.objects.filter(the_geom__contained=lr) result = [{'lat': s.stop_lat, 'lon': s.stop_lon, 'name': s.stop_name, 'id': s.stop_id} for s in stops] return {'err': 'ok', 'result': result}
def osm_get_multipolygon_for_location_general(location, country="Belgium", level=8): url = 'http://overpass-api.de/api/interpreter' query = '[out:json];node["is_in:country"="' + str( country) + '"][name="' + location + '"];<;out geom;' payload = {'data': query} r = requests.post(url, payload) if r.status_code == 200: r.encoding = 'utf-8' try: recup = json.loads(r.text) if 'elements' in recup.keys(): elements = recup.get('elements') for el in elements: if 'tags' in el.keys(): tags = el.get('tags') if 'admin_level' in tags: if tags.get('admin_level') == level: if 'members' in el.keys(): members = el.get('members') ways = [] for m in members: if 'geometry' in m.keys() and m.get( "type") == "way": ways.append(m.get('geometry')) points = order_ways(ways) points.append(points[0]) line = LinearRing(points) polygon = Polygon(line) multipolygon = MultiPolygon(polygon) return multipolygon print("Location found but can't make the boundary") return False except Exception as e: print( 'osm_get_multipolygon_for_location_general() : Decoding JSON has failed' ) print(str(e)) else: print("No data found") return False
def osm_get_multipolygon_for_location(location, country="België - Belgique - Belgien", level=8): url = 'http://overpass-api.de/api/interpreter' query = '[out:json];area[name="' + str(country) + '"];(rel[name="' + str( location) + '"][admin_level=' + str( level) + '][boundary=administrative](area););out geom;' payload = {'data': query} r = requests.post(url, payload) if r.status_code == 200: r.encoding = 'utf-8' try: recup = json.loads(r.text) if 'elements' in recup.keys(): elements = recup.get('elements') for el in elements: if 'members' in el.keys(): members = el.get('members') ways = [] for m in members: if 'geometry' in m.keys() and m.get( "type") == "way": ways.append(m.get('geometry')) points = order_ways(ways) points.append(points[0]) line = LinearRing(points) return Polygon(line) print("Location found but can't make the boundary") print("Query sent to OSM : {}".format(query)) print("OSM response : {}".format(recup)) return False except Exception as e: print( 'osm_get_multipolygon_for_location() : Decoding JSON has failed' ) print(str(e)) else: print("Query sent to OSM : {}".format(query)) print('HTTP {} status code'.format(r.status_code)) print("No data found") return False
def _load_mapinfo(self, ds, id_field_name, id_fixer=None): geom_map = {} lyr = ds[0] for idx, feat in enumerate(lyr): origin_id = feat[id_field_name].as_string().strip() if id_fixer: origin_id = id_fixer(origin_id) geom = feat.geom geom.srid = GK25_SRID geom.transform(settings.PROJECTION_SRID) if origin_id not in geom_map: plan = {'geometry': None} geom_map[origin_id] = plan else: plan = geom_map[origin_id] poly = GEOSGeometry(geom.wkb, srid=geom.srid) if isinstance(poly, LineString): try: ring = LinearRing(poly.tuple) except Exception: self.logger.error( "Skipping plan %s, it's linestring doesn't close." % origin_id) # if the LineString doesn't form a polygon, skip it. continue poly = Polygon(ring) if plan['geometry']: if isinstance(plan['geometry'], Polygon): plan['geometry'] = MultiPolygon(plan['geometry']) if isinstance(poly, MultiPolygon): plan['geometry'].extend(poly) else: plan['geometry'].append(poly) else: plan['geometry'] = poly for key, e in geom_map.items(): geom = e['geometry'] if not geom.valid: self.logger.warning("geometry for %s not OK, fixing" % key) geom = geom.simplify() assert geom.valid e['geometry'] = geom return geom_map
def test_coerce_linearring_2d(self): c = GeometryCoercer() linearring3d = LinearRing( ((0, 0, 2), (1, 1, 2), (1.5, 1.5, 2), (0, 0, 2)), srid=4326) self.assertTrue(linearring3d.hasz) linearring2d = c.coerce(linearring3d) self.assertFalse(linearring2d.hasz) self.assertEquals(linearring2d.srid, linearring3d.srid) zip_coords = zip(linearring3d.coords, linearring2d.coords) for zc in zip_coords: self.assertEquals(zc[0][0], zc[1][0]) self.assertEquals(zc[0][1], zc[1][1])
def osm_get_multipolygon_for_rel_id(id, level=8): url = 'http://overpass-api.de/api/interpreter' query = '[out:json];rel(' + str(id) + ');out geom;' payload = {'data': query} r = requests.post(url, payload) info = [] if r.status_code == 200: r.encoding = 'utf-8' try: recup = json.loads(r.text) if 'elements' in recup.keys(): elements = recup.get('elements') for el in elements: if 'tags' in el.keys(): tags = el.get('tags') if 'admin_level' in tags: if tags.get('admin_level') == str(level): info.append(str(tags.get('name'))) if 'members' in el.keys(): members = el.get('members') ways = [] for m in members: if 'geometry' in m.keys() and m.get( "type") == "way": ways.append(m.get('geometry')) points = order_ways(ways) points.append(points[0]) line = LinearRing(points) info.append(Polygon(line)) return info print("Town found but can't make the boundary") return False except Exception as e: print( 'osm_get_multipolygon_for_rel_id(id) : Decoding JSON has failed' ) print(str(e)) else: print("No data found id") return False
def tile(self, lonlat, zoom): """ Returns a Polygon corresponding to the region represented by a fictional Google Tile for the given longitude/latitude pair and zoom level. This tile is used to determine the size of a tile at the given point. """ # The given lonlat is the center of the tile. delta = self._tilesize / 2 # Getting the pixel coordinates corresponding to the # the longitude/latitude. px = self.lonlat_to_pixel(lonlat, zoom) # Getting the lower-left and upper-right lat/lon coordinates # for the bounding box of the tile. ll = self.pixel_to_lonlat((px[0]-delta, px[1]-delta), zoom) ur = self.pixel_to_lonlat((px[0]+delta, px[1]+delta), zoom) # Constructing the Polygon, representing the tile and returning. return Polygon(LinearRing(ll, (ll[0], ur[1]), ur, (ur[0], ll[1]), ll), srid=4326)
def setUpClass(cls): super(PolygonRecordViewTestCase, cls).setUpClass() # Create dummy data for a Polygon RecordType. cls.coords = ((0, 0), (0, 1), (1, 1), (1, 0), (0, 0)) cls.polygon_record_type = RecordType.objects.create( label='Polygon', plural_label='Polygons', geometry_type='polygon', temporal=True) cls.polygon_schema = RecordSchema.objects.create( record_type=cls.polygon_record_type, version=1, schema={}) cls.polygon_record = Record.objects.create( schema=cls.polygon_schema, data='{}', occurred_from=timezone.now(), occurred_to=timezone.now(), geom=Polygon(LinearRing(cls.coords))) # The base endpoint for listing records. cls.record_endpt = reverse('record-list')
def test_geometry_field_option(self): """ When a model has several geometry fields, the 'geometry_field' option can be used to specify the field to use as the 'geometry' key. """ MultiFields.objects.create(city=City.objects.first(), name='Name', point=Point(5, 23), poly=Polygon( LinearRing((0, 0), (0, 5), (5, 5), (5, 0), (0, 0)))) geojson = serializers.serialize('geojson', MultiFields.objects.all()) geodata = json.loads(geojson) self.assertEqual(geodata['features'][0]['geometry']['type'], 'Point') geojson = serializers.serialize('geojson', MultiFields.objects.all(), geometry_field='poly') geodata = json.loads(geojson) self.assertEqual(geodata['features'][0]['geometry']['type'], 'Polygon')