As we did with the geocaching points and political boundaries, we will implement the ability of the program to import lines (that is, linestrings). These lines can represent roads, rivers, power lines, and so on. With this kind of features, we will be able to search for points that are close to a given road for example.
The lines and the collection of lines will also be the subclasses of BaseGeoObject
and BaseGeoCollection
. Let's start by making a LineString
and a LineStringCollection
class, as follows:
models.py
file. It could be anywhere after the base classes' definition:class LineString(BaseGeoObject): """Represents a single linestring.""" def __repr__(self): return self.get_attribute('name')
Again, we only implement the __repr__
method. The other functionalities are inherited from the BaseGeoObject
class.
_parse_data
method:class LineStringCollection(BaseGeoCollection): """Represents a collection of linestrings.""" def _parse_data(self, features): for feature in features: geom = feature['geometry']['coordinates'] attributes = feature['properties'] line = wkt.loads(geom) linestring = LineString(geometry=line, attributes=attributes) self.data.append(linestring)
In order to test our new classes, we are going to use a shapefile containing USA's main roads.
if __name__ == '__main__':
block at the end of the file. You can comment the previous code if you wish instead of deleting it:if __name__ == '__main__': usa_roads = LineStringCollection('../data/roads.shp') for item in usa_roads.data: print(item)
File imported: ../data/roads.shp State Route 131 State Route 3 State Route 3 State Route 3 State Route 411 State Route 3 State Route 3 State Route 5, State Route 786 ... Process finished with exit code 0
In order to make our output more meaningful, we can change how each LineString
class is printed. Remember that the special method named __repr__
is called when you use the print()
function on an object, and it should return a string to be printed. Let's return more information when LineString
is printed.
LineString
class and change the __repr__
method, so it returns the road name and length:class LineString(BaseGeoObject): """Represents a single linestring.""" def __repr__(self): length = self.geom.length return "{} - {}".format(self.get_attribute('name'), length)
Here, we used Python's string formatting to compose a string that can be returned by this method.
File imported: ../data/roads.shp US Route 395-0.16619770512 US Route 30-0.0432070790491 State Route 84-0.0256320861143 US Route 6-0.336460513878 US Route 40-0.107844768871 State Route 272-0.0264889614357 ... Process finished with exit code 0
Although it's much better than before, it still has a problem. The length is in degrees, and it means little or nothing to us because we are used to meters, miles, or any other linear unity. So, we need to convert the unity before we print the length.
3.15.137.75