Importing lines

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:

  1. Insert this new class into the 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.

  2. Now, add the class representing a collection of linestrings and its _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.

    Importing lines
  3. Edit the 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)
  4. Run the code. You should get a big list of the road names in the output console:
    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.

  5. Edit your 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.

  6. Run the code and see the new output:
    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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.137.75